aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--perllib/FixMyStreet/App/Controller/Contact.pm37
-rw-r--r--t/app/controller/contact.t3
-rw-r--r--templates/web/base/contact/index.html2
-rw-r--r--templates/web/bathnes/contact/index.html12
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') %]">