Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

fix csrf vulnerabilities, fixes #356

  • Loading branch information...
commit 0bfb6452ae1cbd908eda064065ef535b2cecee9a 1 parent 63497a9
Moritz Onken monken authored
30 lib/MetaCPAN/Web/Controller/Account.pm
@@ -8,8 +8,8 @@ use JSON::XS ();
8 8 BEGIN { extends 'MetaCPAN::Web::Controller' }
9 9
10 10 sub auto : Private {
11   - my ($self, $c) = @_;
12   - unless($c->user_exists) {
  11 + my ( $self, $c ) = @_;
  12 + unless ( $c->user_exists ) {
13 13 $c->forward('/forbidden');
14 14 }
15 15 return $c->user_exists;
@@ -17,6 +17,7 @@ sub auto : Private {
17 17
18 18 sub logout : Local {
19 19 my ( $self, $c ) = @_;
  20 + $c->detach('/forbidden') unless( $c->req->method eq 'POST' );
20 21 $c->req->session->expire;
21 22 $c->res->redirect('/');
22 23 }
@@ -27,7 +28,9 @@ sub settings : Local {
27 28
28 29 sub identities : Local {
29 30 my ( $self, $c ) = @_;
30   - if ( my $delete = $c->req->params->{delete} ) {
  31 + if ( $c->req->method eq 'POST'
  32 + && ( my $delete = $c->req->params->{delete} ) )
  33 + {
31 34 $c->model('API::User')->delete_identity( $delete, $c->token )->recv;
32 35 $c->res->redirect('/account/identities');
33 36 }
@@ -36,26 +39,33 @@ sub identities : Local {
36 39 sub profile : Local {
37 40 my ( $self, $c ) = @_;
38 41 my $author = $c->model('API::User')->get_profile( $c->token )->recv;
39   - $c->stash( $author->{error} ? { no_profile => 1 } : { author => $author } );
  42 + $c->stash(
  43 + $author->{error} ? { no_profile => 1 } : { author => $author } );
40 44 my $req = $c->req;
41 45 return unless ( $req->method eq 'POST' );
42 46
43 47 my $data = $author;
44   - $data->{blog} = $req->param('blog.url') ? [
  48 + $data->{blog} = $req->param('blog.url')
  49 + ? [
45 50 pairwise { { url => $a, feed => $b } }
46 51 @{ [ $req->param('blog.url') ] },
47 52 @{ [ $req->param('blog.feed') ] }
48   - ] : undef;
49   - $data->{donation} = $req->param('donation.name') ? [
  53 + ]
  54 + : undef;
  55 + $data->{donation} = $req->param('donation.name')
  56 + ? [
50 57 pairwise { { name => $a, id => $b } }
51 58 @{ [ $req->param('donation.name') ] },
52 59 @{ [ $req->param('donation.id') ] }
53   - ] : undef;
54   - $data->{profile} = $req->param('profile.name') ? [
  60 + ]
  61 + : undef;
  62 + $data->{profile} = $req->param('profile.name')
  63 + ? [
55 64 pairwise { { name => $a, id => $b } }
56 65 @{ [ $req->param('profile.name') ] },
57 66 @{ [ $req->param('profile.id') ] }
58   - ] : undef;
  67 + ]
  68 + : undef;
59 69
60 70 $data->{location}
61 71 = $req->params->{latitude}
20 root/account/identities.html
@@ -3,8 +3,22 @@
3 3 <p>Identities you are connected with allow you to log into MetaCPAN. MetaCPAN also drags in some information from them to help you with filling in your <a href="/account/profile">profile</a>. This information is not exposed to anyone unless you explicitly publish it.</p>
4 4 <br /><br />
5 5 <table width="300">
6   - <% FOREACH identity IN ['Facebook', 'GitHub', 'PAUSE', 'Twitter']; found = user.identity.grep(->(a){ a.name == identity.lower }) %>
7   - <tr><td><big><% identity %></big></td><td><div class="ds"><% IF found.size %><a class="g-button" href="/account/identities?delete=<% identity.lower %>">Disconnect</a><% ELSE %><a class="g-button" href="<% api_secure %>/oauth2/authorize?choice=<% identity.lower %>&amp;client_id=<% c.config.consumer_key %>" onclick="return logInPAUSE(this)">Connect</a><% END %></div></td></tr>
8   - <% END %>
  6 + <%- FOREACH identity IN ['Facebook', 'GitHub', 'PAUSE', 'Twitter']; found = user.identity.grep(->(a){ a.name == identity.lower }) %>
  7 + <tr>
  8 + <td><big><% identity %></big></td>
  9 + <td>
  10 + <div class="ds">
  11 + <%- IF found.size %>
  12 + <form action="<% c.uri_for("/account/identities") %>" method="POST">
  13 + <input type="hidden" name="delete" value="<% identity.lower %>" />
  14 + <button type="submit" class="g-button">Disconnect</a>
  15 + </form>
  16 + <%- ELSE %>
  17 + <a class="g-button" href="<% api_secure %>/oauth2/authorize?choice=<% identity.lower %>&amp;client_id=<% c.config.consumer_key %>" onclick="return logInPAUSE(this)">Connect</a>
  18 + <%- END %>
  19 + </div>
  20 + </td>
  21 + </tr>
  22 + <%- END %>
9 23 </table>
10 24 </div>
5 root/inc/account-bar.html
@@ -4,5 +4,6 @@
4 4 <a href="/account/identities"<% IF req.action == 'account/identities' %> class="active"<% END %>>Identities</a>
5 5 <!-- <a href="/account/settings"<% IF req.action == 'account/settings' %> class="active"<% END %>>Settings</a> -->
6 6 <a href="/account/profile"<% IF req.action == 'account/profile' %> class="active"<% END %>>Profile</a>
7   - <a href="/account/logout">Logout</a>
8   -</div>
  7 + <a href="#" onclick="$('#logout').submit(); return false">Logout</a>
  8 +</div>
  9 +<form action="<% c.uri_for("/account/logout") %>" method="POST" id="logout"></form>
4 root/static/css/style.css
@@ -396,6 +396,10 @@ button.favorite:hover, button.favorite.active, a.favorite.active, a.favorite:hov
396 396 width: 80px
397 397 }
398 398
  399 +.account-settings button.g-button {
  400 + width: 94px;
  401 +}
  402 +
399 403 .account-settings td {
400 404 padding: 5px;
401 405 }

0 comments on commit 0bfb645

Please sign in to comment.
Something went wrong with that request. Please try again.