diff options
-rw-r--r-- | CHANGELOG.md | 1 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Contact.pm | 37 | ||||
-rw-r--r-- | t/app/controller/contact.t | 3 | ||||
-rw-r--r-- | templates/web/base/contact/index.html | 2 | ||||
-rw-r--r-- | templates/web/bathnes/contact/index.html | 12 |
5 files changed, 41 insertions, 14 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index cd2b3e11e..d176fbbd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - Delete cache photos upon photo moderation. #2374 - Remove any use of `my $x if $foo`. #2377 - Fix saving of inspect form data offline. + - Add CSRF and time to contact form. * v2.5 (21st December 2018) - Front end improvements: diff --git a/perllib/FixMyStreet/App/Controller/Contact.pm b/perllib/FixMyStreet/App/Controller/Contact.pm index 8850c37b4..fb525fc1f 100644 --- a/perllib/FixMyStreet/App/Controller/Contact.pm +++ b/perllib/FixMyStreet/App/Controller/Contact.pm @@ -4,6 +4,7 @@ use namespace::autoclean; BEGIN { extends 'Catalyst::Controller'; } +use MIME::Base64; use mySociety::EmailUtil; use FixMyStreet::Email; @@ -17,8 +18,19 @@ Contact us page =head1 METHODS +=head2 auto + +Functions to run on both GET and POST contact requests. + =cut +sub auto : Private { + my ($self, $c) = @_; + $c->forward('setup_request'); + $c->forward('determine_contact_type'); + $c->forward('/auth/get_csrf_token'); +} + =head2 index Display contact us page @@ -27,10 +39,6 @@ Display contact us page sub index : Path : Args(0) { my ( $self, $c ) = @_; - - return - unless $c->forward('setup_request') - && $c->forward('determine_contact_type'); } =head2 submit @@ -44,13 +52,10 @@ sub submit : Path('submit') : Args(0) { $c->res->redirect( '/contact' ) and return unless $c->req->method eq 'POST'; - return - unless $c->forward('setup_request') - && $c->forward('determine_contact_type') - && $c->forward('validate') - && $c->forward('prepare_params_for_email') - && $c->forward('send_email') - && $c->forward('redirect_on_success'); + $c->go('index') unless $c->forward('validate'); + $c->forward('prepare_params_for_email'); + $c->forward('send_email'); + $c->forward('redirect_on_success'); } =head2 determine_contact_type @@ -117,6 +122,10 @@ to index page if errors. sub validate : Private { my ( $self, $c ) = @_; + $c->forward('/auth/check_csrf_token'); + my $s = $c->stash->{s} = unpack("N", decode_base64($c->get_param('s'))); + return if !FixMyStreet->test_mode && time() < $s; # uncoverable statement + my ( %field_errors, @errors ); my %required = ( name => _('Please enter your name'), @@ -154,7 +163,7 @@ sub validate : Private { if ( @errors or scalar keys %field_errors ) { $c->stash->{errors} = \@errors; $c->stash->{field_errors} = \%field_errors; - $c->go('index'); + return 0; } return 1; @@ -230,6 +239,10 @@ sub setup_request : Private { # name is already used in the stash for the app class name $c->stash->{form_name} = $c->get_param('name'); + my $s = encode_base64(pack("N", time() + 10), ''); + $s =~ s/=+$//; + $c->stash->{s} = $s; + return 1; } diff --git a/t/app/controller/contact.t b/t/app/controller/contact.t index fe67e89ec..bf157d699 100644 --- a/t/app/controller/contact.t +++ b/t/app/controller/contact.t @@ -13,6 +13,7 @@ use FixMyStreet::TestMech; my $mech = FixMyStreet::TestMech->new; $mech->get_ok('/contact'); +my ($csrf) = $mech->content =~ /meta content="([^"]*)" name="csrf-token"/; $mech->title_like(qr/Contact Us/); $mech->content_contains("It's often quickest to "); @@ -444,6 +445,7 @@ for my $test ( { fields => { %common, + token => $csrf, dest => 'from_council', success_url => '/faq', }, @@ -452,6 +454,7 @@ for my $test ( { fields => { %common, + token => $csrf, dest => 'from_council', success_url => 'http://www.example.com', }, diff --git a/templates/web/base/contact/index.html b/templates/web/base/contact/index.html index f71c36fb1..85fa40f89 100644 --- a/templates/web/base/contact/index.html +++ b/templates/web/base/contact/index.html @@ -16,6 +16,8 @@ [% END %] <form method="post" action="/contact/submit" class="validate"> + <input type="hidden" name="token" value="[% csrf_token %]"> + <input type="hidden" name="s" value="[% s %]"> <fieldset> [% INCLUDE 'errors.html' %] diff --git a/templates/web/bathnes/contact/index.html b/templates/web/bathnes/contact/index.html index c6bca0350..f0589bd9e 100644 --- a/templates/web/bathnes/contact/index.html +++ b/templates/web/bathnes/contact/index.html @@ -1,3 +1,6 @@ +[% extra_js = [ + version('/js/contact.js') +] -%] [% INCLUDE 'header.html', title = loc('Contact Us') robots = 'noindex,nofollow' @@ -15,6 +18,8 @@ [% END %] <form method="post" action="/contact/submit" class="validate"> + <input type="hidden" name="token" value="[% csrf_token %]"> + <input type="hidden" name="s" value="[% s %]"> <fieldset> [% INCLUDE 'errors.html' %] @@ -75,6 +80,8 @@ [% END %] + [% INCLUDE 'contact/who.html' %] + [% IF NOT rejecting_report %] <label for="form_name">[% loc('Your name') %]</label> [% IF field_errors.name %] @@ -107,8 +114,6 @@ [% END %] - [% INCLUDE 'contact/who.html' %] - [% IF rejecting_report %] <label for="form_message">[% loc('Rejection reason') %]</label> [% ELSE %] @@ -127,6 +132,9 @@ </div> [% END %] + [% IF NOT problem AND NOT update %] + <p>[% loc('If you are contacting us about a specific report or update please include a link to the report in the message.') %]</p> + [% END %] <input class="final-submit green-btn" type="submit" value="[% loc('Send') %]"> |