From 048767149e571469d888ec81d324caa7b3b64671 Mon Sep 17 00:00:00 2001 From: Daniel Friesel Date: Tue, 30 Apr 2019 18:05:07 +0200 Subject: [PATCH] use a separate table for registration tokens --- lib/Travelynx.pm | 37 ++++++++++++++++++++-------- lib/Travelynx/Command/database.pm | 32 ++++++++++++++++++++++++ lib/Travelynx/Command/maintenance.pm | 3 ++- lib/Travelynx/Controller/Account.pm | 10 +++----- t/02-registration.t | 8 +++--- templates/_invalid_input.html.ep | 2 +- 6 files changed, 70 insertions(+), 22 deletions(-) diff --git a/lib/Travelynx.pm b/lib/Travelynx.pm index 99d0fb2..b04526a 100755 --- a/lib/Travelynx.pm +++ b/lib/Travelynx.pm @@ -728,17 +728,26 @@ sub startup { ); $self->helper( - 'get_user_token' => sub { - my ( $self, $uid ) = @_; + 'verify_registration_token' => sub { + my ( $self, $uid, $token ) = @_; - my $res = $self->pg->db->select( - 'users', - [ 'name', 'status', 'token' ], - { id => $uid } + my $db = $self->pg->db; + my $tx = $db->begin; + + my $res = $db->select( + 'pending_registrations', + 'count(*) as count', + { + user_id => $uid, + token => $token + } ); - if ( my $ret = $res->array ) { - return @{$ret}; + if ( $res->hash->{count} ) { + $db->update( 'users', { status => 1 }, { id => $uid } ); + $db->delete( 'pending_registrations', { user_id => $uid } ); + $tx->commit; + return 1; } return; } @@ -976,15 +985,23 @@ sub startup { status => 0, public_level => 0, email => $email, - token => $token, password => $password, registered_at => $now, last_seen => $now, }, { returning => 'id' } ); + my $uid = $res->hash->{id}; - return $res->hash->{id}; + $db->insert( + 'pending_registrations', + { + user_id => $uid, + token => $token + } + ); + + return $uid; } ); diff --git a/lib/Travelynx/Command/database.pm b/lib/Travelynx/Command/database.pm index 05b43d6..79ff086 100644 --- a/lib/Travelynx/Command/database.pm +++ b/lib/Travelynx/Command/database.pm @@ -424,6 +424,38 @@ my @migrations = ( } ); }, + + # v9 -> v10 + # Add pending_registrations table. The users.token column is no longer + # needed. + sub { + my ($db) = @_; + $db->query( + qq{ + create table pending_registrations ( + user_id integer not null references users (id) primary key, + token varchar(80) not null + ); + comment on table pending_registrations is 'Verification tokens for newly registered accounts'; + update schema_version set version = 10; + } + ); + my $res = $db->select( 'users', [ 'id', 'token' ], { status => 0 } ); + for my $user ( $res->hashes->each ) { + $db->insert( + 'pending_registrations', + { + user_id => $user->{id}, + token => $user->{token} + } + ); + } + $db->query( + qq{ + alter table users drop column token; + } + ); + }, ); sub setup_db { diff --git a/lib/Travelynx/Command/maintenance.pm b/lib/Travelynx/Command/maintenance.pm index 8c07728..fc64884 100644 --- a/lib/Travelynx/Command/maintenance.pm +++ b/lib/Travelynx/Command/maintenance.pm @@ -59,7 +59,8 @@ sub run { } ); } - $db->delete( 'users', { id => $user->{id} } ); + $db->delete( 'pending_registrations', { user_id => $user->{id} } ); + $db->delete( 'users', { id => $user->{id} } ); printf( "Pruned unverified user %d\n", $user->{id} ); } diff --git a/lib/Travelynx/Controller/Account.pm b/lib/Travelynx/Controller/Account.pm index dc3adb4..e4b385c 100644 --- a/lib/Travelynx/Controller/Account.pm +++ b/lib/Travelynx/Controller/Account.pm @@ -159,20 +159,16 @@ sub verify { my $id = $self->stash('id'); my $token = $self->stash('token'); - my @db_user = $self->get_user_token($id); - - if ( not @db_user ) { + if ( not $id =~ m{ ^ \d+ $ }x ) { $self->render( 'register', invalid => 'token' ); return; } - my ( $db_name, $db_status, $db_token ) = @db_user; - - if ( not $db_name or $token ne $db_token or $db_status != 0 ) { + if ( not $self->verify_registration_token( $id, $token ) ) { $self->render( 'register', invalid => 'token' ); return; } - $self->app->pg->db->update( 'users', { status => 1 }, { id => $id } ); + $self->render( 'login', from => 'verification' ); } diff --git a/t/02-registration.t b/t/02-registration.t index 89bf475..b595337 100644 --- a/t/02-registration.t +++ b/t/02-registration.t @@ -71,9 +71,11 @@ $t->post_ok( ); $t->status_is(200)->content_like(qr{nicht freigeschaltet}); -my $res = $t->app->pg->db->select( 'users', [ 'id', 'token' ], - { name => 'someone' } ); -my ( $uid, $token ) = @{ $res->hash }{qw{id token}}; +my $res = $t->app->pg->db->select( 'users', ['id'], { name => 'someone' } ); +my $uid = $res->hash->{id}; +$res = $t->app->pg->db->select( 'pending_registrations', ['token'], + { user_id => $uid } ); +my $token = $res->hash->{token}; # Successful verification $t->get_ok("/reg/${uid}/${token}"); diff --git a/templates/_invalid_input.html.ep b/templates/_invalid_input.html.ep index b6353d7..ad01c15 100644 --- a/templates/_invalid_input.html.ep +++ b/templates/_invalid_input.html.ep @@ -47,7 +47,7 @@ % } % elsif ($invalid eq 'token') { Ungültiger Token -

Die Verifikation deiner Mail-Adresse ist fehlgeschlagen oder du hast den Token schon einmal verwendet.

+

Möglicherweise ist die Verifikation deiner Mail-Adresse fehlgeschlagen oder du hast den Token schon einmal verwendet.

% } % elsif ($invalid eq 'confirmation') { Account nicht freigeschaltet