diff options
| author | Daniel Friesel <derf@finalrewind.org> | 2019-04-06 11:20:10 +0200 | 
|---|---|---|
| committer | Daniel Friesel <derf@finalrewind.org> | 2019-04-06 11:20:10 +0200 | 
| commit | 1405eb6ea3fe95fcb9c205c6c4c250433d48819c (patch) | |
| tree | 4845cce466ea882369242290855fc5de0c0ebb3d | |
| parent | 6630cdcd9e943a9a8c2cce49b6b5e59bd6ef6710 (diff) | |
Add password change form
| -rwxr-xr-x | lib/Travelynx.pm | 12 | ||||
| -rw-r--r-- | lib/Travelynx/Controller/Account.pm | 81 | ||||
| -rw-r--r-- | templates/account.html.ep | 10 | ||||
| -rw-r--r-- | templates/change_password.html.ep | 69 | 
4 files changed, 160 insertions, 12 deletions
| diff --git a/lib/Travelynx.pm b/lib/Travelynx.pm index 3de3b9e..b9132f3 100755 --- a/lib/Travelynx.pm +++ b/lib/Travelynx.pm @@ -583,7 +583,8 @@ qq{select * from pending_mails where email = ? and num_tries > 1;}  					elsif ( $user->{cancelled} ) {  						# Same -						$self->checkout($station, 1, $self->app->action_type->{cancelled_to}); +						$self->checkout( $station, 1, +							$self->app->action_type->{cancelled_to} );  					}  					my $success = $self->app->action_query->execute( @@ -877,6 +878,13 @@ qq{select * from pending_mails where email = ? and num_tries > 1;}  	);  	$self->helper( +		'set_user_password' => sub { +			my ( $self, $uid, $password ) = @_; +			$self->app->set_password_query->execute( $password, $uid ); +		} +	); + +	$self->helper(  		'check_if_user_name_exists' => sub {  			my ( $self, $user_name ) = @_; @@ -1322,12 +1330,14 @@ qq{select * from pending_mails where email = ? and num_tries > 1;}  	);  	$authed_r->get('/account')->to('account#account'); +	$authed_r->get('/change_password')->to('account#password_form');  	$authed_r->get('/export.json')->to('account#json_export');  	$authed_r->get('/history')->to('traveling#history');  	$authed_r->get('/history/:year/:month')->to('traveling#monthly_history');  	$authed_r->get('/history.json')->to('traveling#json_history');  	$authed_r->get('/journey/:id')->to('traveling#journey_details');  	$authed_r->get('/s/*station')->to('traveling#station'); +	$authed_r->post('/change_password')->to('account#change_password');  	$authed_r->post('/delete')->to('account#delete');  	$authed_r->post('/logout')->to('account#do_logout');  	$authed_r->post('/set_token')->to('api#set_token'); diff --git a/lib/Travelynx/Controller/Account.pm b/lib/Travelynx/Controller/Account.pm index 7360899..9e8c1fb 100644 --- a/lib/Travelynx/Controller/Account.pm +++ b/lib/Travelynx/Controller/Account.pm @@ -136,11 +136,12 @@ sub register {  	  .= "werden wir sie dauerhaft sperren und keine Mails mehr dorthin schicken.\n\n";  	$body .= "Daten zur Registrierung:\n";  	$body .= " * Datum: ${date}\n"; -	$body .= " * Verwendete IP: ${ip}\n"; -	$body .= " * Verwendeter Browser gemäß User Agent: ${ua}\n\n\n"; +	$body .= " * Client: ${ip}\n"; +	$body .= " * UserAgent: ${ua}\n\n\n";  	$body .= "Impressum: ${imprint_url}\n"; -	my $success = $self->sendmail->custom($email, 'Registrierung bei travelynx', $body); +	my $success +	  = $self->sendmail->custom( $email, 'Registrierung bei travelynx', $body );  	if ($success) {  		$self->app->dbh->commit;  		$self->render( 'login', from => 'register' ); @@ -214,6 +215,73 @@ sub do_logout {  	$self->redirect_to('/login');  } +sub password_form { +	my ($self) = @_; + +	$self->render('change_password'); +} + +sub change_password { +	my ($self)       = @_; +	my $old_password = $self->req->param('oldpw'); +	my $password     = $self->req->param('newpw'); +	my $password2    = $self->req->param('newpw2'); + +	if ( $self->validation->csrf_protect->has_error('csrf_token') ) { +		$self->render( 'change_password', invalid => 'csrf' ); +		return; +	} + +	if ( $password ne $password2 ) { +		$self->render( 'change_password', invalid => 'password_notequal' ); +		return; +	} + +	if ( length($password) < 8 ) { +		$self->render( 'change_password', invalid => 'password_short' ); +		return; +	} + +	if ( +		not $self->authenticate( +			$self->current_user->{name}, +			$self->param('oldpw') +		) +	  ) +	{ +		$self->render( 'change_password', invalid => 'password' ); +		return; +	} + +	my $pw_hash = hash_password($password); +	$self->set_user_password( $self->current_user->{id}, $pw_hash ); + +	$self->redirect_to('account'); + +	my $user  = $self->current_user->{name}; +	my $email = $self->current_user->{email}; +	my $ip    = $self->req->headers->header('X-Forwarded-For'); +	my $ua    = $self->req->headers->user_agent; +	my $date  = DateTime->now( time_zone => 'Europe/Berlin' ) +	  ->strftime('%d.%m.%Y %H:%M:%S %z'); + +	# In case Mojolicious is not running behind a reverse proxy +	$ip +	  //= sprintf( '%s:%s', $self->tx->remote_address, $self->tx->remote_port ); +	my $imprint_url = $self->url_for('impressum')->to_abs->scheme('https'); + +	my $body = "Hallo ${user},\n\n"; +	$body +	  .= "Das Passwort deines travelynx-Accounts wurde soeben geändert.\n\n"; +	$body .= "Daten zur Änderung:\n"; +	$body .= " * Datum: ${date}\n"; +	$body .= " * Client: ${ip}\n"; +	$body .= " * UserAgent: ${ua}\n\n\n"; +	$body .= "Impressum: ${imprint_url}\n"; + +	$self->sendmail->custom( $email, 'travelynx: Passwort geändert', $body ); +} +  sub account {  	my ($self) = @_; @@ -231,9 +299,10 @@ sub json_export {  	while ( my @row = $query->fetchrow_array ) {  		my ( -			$action_id, $action,       $raw_ts,      $ds100,     $name, -			$train_type,   $train_line,  $train_no,  $train_id, -			$raw_sched_ts, $raw_real_ts, $raw_route, $raw_messages +			$action_id, $action,       $raw_ts,      $ds100, +			$name,      $train_type,   $train_line,  $train_no, +			$train_id,  $raw_sched_ts, $raw_real_ts, $raw_route, +			$raw_messages  		) = @row;  		push( diff --git a/templates/account.html.ep b/templates/account.html.ep index 99178d9..dd808a6 100644 --- a/templates/account.html.ep +++ b/templates/account.html.ep @@ -39,6 +39,10 @@  				<td><%= $acc->{email} %></td>  			</tr>  			<tr> +				<th scope="row">Passwort</th> +				<td><a href="/change_password" class="waves-effect waves-light btn">ändern</a></td> +			</tr> +			<tr>  				<th scope="row">Registriert am</th>  				<td><%= $acc->{registered_at}->strftime('%d.%m.%Y %H:%M') %></td>  			</tr> @@ -46,9 +50,7 @@  	</div>  </div>  <div class="row"> -	<div class="col s1 m1 l3"> -	</div> -	<div class="col s10 m10 l6 center-align"> +	<div class="col s12 m12 l12 center-align">  		%= form_for 'logout' => begin  			%= csrf_field  			<button class="btn waves-effect waves-light" type="submit" name="action" value="logout"> @@ -56,8 +58,6 @@  			</button>  		%= end  	</div> -	<div class="col s1 m1 l3"> -	</div>  </div>  % my $token = get_api_token(); diff --git a/templates/change_password.html.ep b/templates/change_password.html.ep new file mode 100644 index 0000000..bae28d9 --- /dev/null +++ b/templates/change_password.html.ep @@ -0,0 +1,69 @@ +% if (my $invalid = stash('invalid')) { +	<div class="row"> +		<div class="col s12"> +			<div class="card red darken-4"> +				<div class="card-content white-text"> +					% if ($invalid eq 'csrf') { +						<span class="card-title">Ungültiger CSRF-Token</span> +						<p>Sind Cookies aktiviert? Ansonsten könnte es sich um einen +						Fall von <a +						href="https://de.wikipedia.org/wiki/Cross-Site-Request-Forgery">CSRF</a> +						handeln.</p> +					% } +					% elsif ($invalid eq 'password_notequal') { +						<span class="card-title">Passwort ungültig</span> +						<p>Die angegebenen neuen Passwörter sind nicht identisch.</p> +					% } +					% elsif ($invalid eq 'password_short') { +						<span class="card-title">Passwort zu kurz</span> +						<p>Das neue Passwort muss mindestens acht Zeichen lang sein.</p> +					% } +					% elsif ($invalid eq 'password') { +						<span class="card-title">Ungültiges Passwort</span> +						<p>Das aktuelle Passwort wurde nicht korrekt eingegeben.</p> +					% } +					% else { +						<span class="card-title">Unbekannter Fehler</span> +						<p>„<%= $invalid %>“</p> +					% } +				</div> +			</div> +		</div> +	</div> +% } + +<h1>Passwort ändern</h1> +%= form_for '/change_password' => (method => 'POST') => begin +	%= csrf_field +	<div class="row"> +		<div class="input-field col s12"> +			<i class="material-icons prefix">lock</i> +			%= password_field 'oldpw', id => 'oldpassword', class => 'validate', required => undef, autocomplete => 'current-password' +			<label for="oldpassword">Aktuelles Passwort</label> +		</div> +	</div> +	<div class="row"> +		<div class="input-field col l6 m12 s12"> +			<i class="material-icons prefix">lock</i> +			%= password_field 'newpw', id => 'password', class => 'validate', required => undef, minlength => 8, autocomplete => 'new-password' +			<label for="password">Neues Passwort</label> +		</div> +		<div class="input-field col l6 m12 s12"> +			<i class="material-icons prefix">lock</i> +			%= password_field 'newpw2', id => 'password2', class => 'validate', required => undef, minlength => 8, autocomplete => 'new-password' +			<label for="password2">Passwort wiederholen</label> +		</div> +	</div> +	<div class="row"> +		<div class="col s3 m3 l3"> +		</div> +		<div class="col s6 m6 l6 center-align"> +			<button class="btn waves-effect waves-light" type="submit" name="action" value="login"> +				Ändern +				<i class="material-icons right">send</i> +			</button> +		</div> +		<div class="col s3 m3 l3"> +		</div> +	</div> +%= end | 
