diff options
Diffstat (limited to 'perllib')
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Auth.pm | 64 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Auth/Phone.pm | 8 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Auth/Profile.pm | 35 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Report/New.pm | 6 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Report/Update.pm | 7 | ||||
-rw-r--r-- | perllib/FixMyStreet/Cobrand/Borsetshire.pm | 2 | ||||
-rw-r--r-- | perllib/FixMyStreet/Cobrand/Default.pm | 8 | ||||
-rw-r--r-- | perllib/FixMyStreet/Cobrand/Oxfordshire.pm | 2 | ||||
-rw-r--r-- | perllib/FixMyStreet/DB/Result/User.pm | 9 | ||||
-rw-r--r-- | perllib/FixMyStreet/Test.pm | 13 |
10 files changed, 130 insertions, 24 deletions
diff --git a/perllib/FixMyStreet/App/Controller/Auth.pm b/perllib/FixMyStreet/App/Controller/Auth.pm index 455022e03..95f8bb9a2 100644 --- a/perllib/FixMyStreet/App/Controller/Auth.pm +++ b/perllib/FixMyStreet/App/Controller/Auth.pm @@ -5,6 +5,7 @@ use namespace::autoclean; BEGIN { extends 'Catalyst::Controller'; } use Email::Valid; +use Data::Password::Common 'found'; use Digest::HMAC_SHA1 qw(hmac_sha1); use JSON::MaybeXS; use MIME::Base64; @@ -84,6 +85,12 @@ sub sign_in : Private { my $parsed = FixMyStreet::SMS->parse_username($username); if ($parsed->{username} && $password && $c->forward('authenticate', [ $parsed->{type}, $parsed->{username}, $password ])) { + # Upgrade hash count if necessary + my $cost = sprintf("%02d", FixMyStreet::DB::Result::User->cost); + if ($c->user->password !~ /^\$2a\$$cost\$/) { + $c->user->update({ password => $password }); + } + # unless user asked to be remembered limit the session to browser $c->set_session_cookie_expire(0) unless $remember_me; @@ -143,6 +150,11 @@ sub email_sign_in : Private { return; } + my $password = $c->get_param('password_register'); + if ($password) { + return unless $c->forward('/auth/test_password', [ $password ]); + } + # If user registration is disabled then bail out at this point # if there's not already a user with this email address. # NB this uses the same template as a successful sign in to stop @@ -156,8 +168,7 @@ sub email_sign_in : Private { } my $user_params = {}; - $user_params->{password} = $c->get_param('password_register') - if $c->get_param('password_register'); + $user_params->{password} = $password if $password; my $user = $c->model('DB::User')->new( $user_params ); my $token_data = { @@ -348,6 +359,55 @@ sub no_csrf_token : Private { $c->detach('/page_error_400_bad_request', []); } +=item common_password + +Returns 1/0 depending on if password is common or not. + +=cut + +sub common_password : Local : Args(0) { + my ($self, $c) = @_; + + my $password = $c->get_param('password_register'); + + my $return = JSON->true; + if (!$c->cobrand->call_hook('bypass_password_checks') && found($password)) { + $return = _('Please choose a less commonly-used password'); + } + + my $body = JSON->new->utf8->allow_nonref->encode($return); + $c->res->content_type('application/json; charset=utf-8'); + $c->res->body($body); +} + +=item test_password + +Checks a password is not too weak; returns true if okay, +false if weak (and sets stash error). + +=cut + +sub test_password : Private { + my ($self, $c, $password) = @_; + + return 1 if $c->cobrand->call_hook('bypass_password_checks'); + + my @errors; + + my $min_length = $c->cobrand->password_minimum_length; + push @errors, sprintf(_('Please make sure your password is at least %d characters long'), $min_length) + if length($password) < $min_length; + + push @errors, _('Please choose a less commonly-used password') + if found($password); + + if (@errors) { + $c->stash->{field_errors}->{password_register} = join('<br>', @errors); + return 0; + } + return 1; +} + =head2 sign_out Log the user out. Tell them we've done so. diff --git a/perllib/FixMyStreet/App/Controller/Auth/Phone.pm b/perllib/FixMyStreet/App/Controller/Auth/Phone.pm index 8387b9d64..8e3150df9 100644 --- a/perllib/FixMyStreet/App/Controller/Auth/Phone.pm +++ b/perllib/FixMyStreet/App/Controller/Auth/Phone.pm @@ -59,6 +59,11 @@ sub sign_in : Private { return; } + my $password = $c->get_param('password_register'); + if ($password) { + return unless $c->forward('/auth/test_password', [ $password ]); + } + (my $number = $parsed->{phone}->format) =~ s/\s+//g; if ( FixMyStreet->config('SIGNUPS_DISABLED') @@ -70,8 +75,7 @@ sub sign_in : Private { } my $user_params = {}; - $user_params->{password} = $c->get_param('password_register') - if $c->get_param('password_register'); + $user_params->{password} = $password if $password; my $user = $c->model('DB::User')->new( $user_params ); my $token_data = { diff --git a/perllib/FixMyStreet/App/Controller/Auth/Profile.pm b/perllib/FixMyStreet/App/Controller/Auth/Profile.pm index 5e6fe6266..2d8ae081e 100644 --- a/perllib/FixMyStreet/App/Controller/Auth/Profile.pm +++ b/perllib/FixMyStreet/App/Controller/Auth/Profile.pm @@ -19,7 +19,7 @@ verifying email, phone, password. =cut -sub auto { +sub auto : Private { my ( $self, $c ) = @_; $c->detach( '/auth/redirect' ) unless $c->user; @@ -49,10 +49,20 @@ sub change_password : Path('/auth/change_password') { my $new = $c->get_param('new_password') // ''; my $confirm = $c->get_param('confirm') // ''; + my $password_error; + + # Check existing password, if available + if ($c->user->password) { + my $current = $c->get_param('current_password') // ''; + $c->stash->{current_password} = $current; + $password_error = 'incorrect' unless $c->user->check_password($current); + } + # check for errors - my $password_error = + $password_error ||= !$new && !$confirm ? 'missing' : $new ne $confirm ? 'mismatch' + : !$c->forward('/auth/test_password', [ $new ]) ? 'failed' : ''; if ($password_error) { @@ -62,10 +72,17 @@ sub change_password : Path('/auth/change_password') { return; } - # we should have a usable password - save it to the user - $c->user->obj->update( { password => $new } ); - $c->stash->{password_changed} = 1; - + if ($c->user->password) { + # we should have a usable password - save it to the user + $c->user->obj->update( { password => $new } ); + $c->stash->{password_changed} = 1; + } else { + # Set up arguments for code sign in + $c->set_param('username', $c->user->username); + $c->set_param('password_register', $new); + $c->set_param('r', 'auth/change_password/success'); + $c->detach('/auth/code_sign_in'); + } } =head2 change_email @@ -148,6 +165,12 @@ sub change_phone_success : Path('/auth/change_phone/success') { $c->res->redirect('/my'); } +sub change_password_success : Path('/auth/change_password/success') { + my ( $self, $c ) = @_; + $c->flash->{flash_message} = _('Your password has been changed'); + $c->res->redirect('/my'); +} + sub generate_token : Path('/auth/generate_token') { my ($self, $c) = @_; diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm index 166c0614d..05d082e45 100644 --- a/perllib/FixMyStreet/App/Controller/Report/New.pm +++ b/perllib/FixMyStreet/App/Controller/Report/New.pm @@ -813,8 +813,10 @@ sub process_user : Private { } $c->forward('update_user', [ \%params ]); - $report->user->password( Utils::trim_text( $params{password_register} ) ) - if $params{password_register}; + if ($params{password_register}) { + $c->forward('/auth/test_password', [ $params{password_register} ]); + $report->user->password(Utils::trim_text($params{password_register})); + } return 1; } diff --git a/perllib/FixMyStreet/App/Controller/Report/Update.pm b/perllib/FixMyStreet/App/Controller/Report/Update.pm index c28039808..c684e46ad 100644 --- a/perllib/FixMyStreet/App/Controller/Report/Update.pm +++ b/perllib/FixMyStreet/App/Controller/Report/Update.pm @@ -144,11 +144,14 @@ sub process_user : Private { $update->user->name( Utils::trim_text( $params{name} ) ) if $params{name}; - $update->user->password( Utils::trim_text( $params{password_register} ) ) - if $params{password_register}; $update->user->title( Utils::trim_text( $params{fms_extra_title} ) ) if $params{fms_extra_title}; + if ($params{password_register}) { + $c->forward('/auth/test_password', [ $params{password_register} ]); + $update->user->password(Utils::trim_text($params{password_register})); + } + return 1; } diff --git a/perllib/FixMyStreet/Cobrand/Borsetshire.pm b/perllib/FixMyStreet/Cobrand/Borsetshire.pm index 7ddcff469..d9b018d69 100644 --- a/perllib/FixMyStreet/Cobrand/Borsetshire.pm +++ b/perllib/FixMyStreet/Cobrand/Borsetshire.pm @@ -29,4 +29,6 @@ sub send_questionnaires { return 0; } +sub bypass_password_checks { 1 } + 1; diff --git a/perllib/FixMyStreet/Cobrand/Default.pm b/perllib/FixMyStreet/Cobrand/Default.pm index 7888f8ccf..c6ca5c56b 100644 --- a/perllib/FixMyStreet/Cobrand/Default.pm +++ b/perllib/FixMyStreet/Cobrand/Default.pm @@ -59,6 +59,14 @@ sub path_to_email_templates { return $paths; } +=item password_minimum_length + +Returns the minimum length a password can be set to. + +=cut + +sub password_minimum_length { 6 } + =item country Returns the country that this cobrand operates in, as an ISO3166-alpha2 code. diff --git a/perllib/FixMyStreet/Cobrand/Oxfordshire.pm b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm index 23324e763..00f099278 100644 --- a/perllib/FixMyStreet/Cobrand/Oxfordshire.pm +++ b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm @@ -15,8 +15,6 @@ sub is_council_with_case_management { return FixMyStreet->config('STAGING_SITE'); } -sub map_type { 'OSM' } - sub base_url { my $self = shift; return $self->next::method() if FixMyStreet->config('STAGING_SITE'); diff --git a/perllib/FixMyStreet/DB/Result/User.pm b/perllib/FixMyStreet/DB/Result/User.pm index d02039ac3..97f2132b1 100644 --- a/perllib/FixMyStreet/DB/Result/User.pm +++ b/perllib/FixMyStreet/DB/Result/User.pm @@ -125,11 +125,15 @@ with 'FixMyStreet::Roles::Extra'; __PACKAGE__->many_to_many( planned_reports => 'user_planned_reports', 'report' ); +sub cost { + FixMyStreet->test_mode ? 1 : 12; +} + __PACKAGE__->add_columns( "password" => { encode_column => 1, encode_class => 'Crypt::Eksblowfish::Bcrypt', - encode_args => { cost => 8 }, + encode_args => { cost => cost() }, encode_check_method => 'check_password', }, ); @@ -150,8 +154,9 @@ sub username { sub phone_display { my $self = shift; return $self->phone unless $self->phone; + my $country = FixMyStreet->config('PHONE_COUNTRY'); my $parsed = FixMyStreet::SMS->parse_username($self->phone); - return $parsed->{phone} ? $parsed->{phone}->format : $self->phone; + return $parsed->{phone} ? $parsed->{phone}->format_for_country($country) : $self->phone; } sub latest_anonymity { diff --git a/perllib/FixMyStreet/Test.pm b/perllib/FixMyStreet/Test.pm index 572ae0a44..aa1a63c21 100644 --- a/perllib/FixMyStreet/Test.pm +++ b/perllib/FixMyStreet/Test.pm @@ -7,6 +7,13 @@ use warnings FATAL => 'all'; use utf8; use Test::More; use mySociety::Locale; + +BEGIN { + use FixMyStreet; + FixMyStreet->test_mode(1); + mySociety::Locale::gettext_domain('FixMyStreet', 1); +} + use FixMyStreet::DB; my $db = FixMyStreet::DB->schema->storage; @@ -19,12 +26,6 @@ sub import { $db->txn_begin; } -BEGIN { - use FixMyStreet; - FixMyStreet->test_mode(1); - mySociety::Locale::gettext_domain('FixMyStreet', 1); -} - END { $db->txn_rollback if $db; } |