use a separate table for registration tokens

This commit is contained in:
Daniel Friesel 2019-04-30 18:05:07 +02:00
parent a57a24c2d6
commit 048767149e
6 changed files with 70 additions and 22 deletions

View file

@ -728,17 +728,26 @@ sub startup {
); );
$self->helper( $self->helper(
'get_user_token' => sub { 'verify_registration_token' => sub {
my ( $self, $uid ) = @_; my ( $self, $uid, $token ) = @_;
my $res = $self->pg->db->select( my $db = $self->pg->db;
'users', my $tx = $db->begin;
[ 'name', 'status', 'token' ],
{ id => $uid } my $res = $db->select(
'pending_registrations',
'count(*) as count',
{
user_id => $uid,
token => $token
}
); );
if ( my $ret = $res->array ) { if ( $res->hash->{count} ) {
return @{$ret}; $db->update( 'users', { status => 1 }, { id => $uid } );
$db->delete( 'pending_registrations', { user_id => $uid } );
$tx->commit;
return 1;
} }
return; return;
} }
@ -976,15 +985,23 @@ sub startup {
status => 0, status => 0,
public_level => 0, public_level => 0,
email => $email, email => $email,
token => $token,
password => $password, password => $password,
registered_at => $now, registered_at => $now,
last_seen => $now, last_seen => $now,
}, },
{ returning => 'id' } { returning => 'id' }
); );
my $uid = $res->hash->{id};
return $res->hash->{id}; $db->insert(
'pending_registrations',
{
user_id => $uid,
token => $token
}
);
return $uid;
} }
); );

View file

@ -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 { sub setup_db {

View file

@ -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} ); printf( "Pruned unverified user %d\n", $user->{id} );
} }

View file

@ -159,20 +159,16 @@ sub verify {
my $id = $self->stash('id'); my $id = $self->stash('id');
my $token = $self->stash('token'); my $token = $self->stash('token');
my @db_user = $self->get_user_token($id); if ( not $id =~ m{ ^ \d+ $ }x ) {
if ( not @db_user ) {
$self->render( 'register', invalid => 'token' ); $self->render( 'register', invalid => 'token' );
return; return;
} }
my ( $db_name, $db_status, $db_token ) = @db_user; if ( not $self->verify_registration_token( $id, $token ) ) {
if ( not $db_name or $token ne $db_token or $db_status != 0 ) {
$self->render( 'register', invalid => 'token' ); $self->render( 'register', invalid => 'token' );
return; return;
} }
$self->app->pg->db->update( 'users', { status => 1 }, { id => $id } );
$self->render( 'login', from => 'verification' ); $self->render( 'login', from => 'verification' );
} }

View file

@ -71,9 +71,11 @@ $t->post_ok(
); );
$t->status_is(200)->content_like(qr{nicht freigeschaltet}); $t->status_is(200)->content_like(qr{nicht freigeschaltet});
my $res = $t->app->pg->db->select( 'users', [ 'id', 'token' ], my $res = $t->app->pg->db->select( 'users', ['id'], { name => 'someone' } );
{ name => 'someone' } ); my $uid = $res->hash->{id};
my ( $uid, $token ) = @{ $res->hash }{qw{id token}}; $res = $t->app->pg->db->select( 'pending_registrations', ['token'],
{ user_id => $uid } );
my $token = $res->hash->{token};
# Successful verification # Successful verification
$t->get_ok("/reg/${uid}/${token}"); $t->get_ok("/reg/${uid}/${token}");

View file

@ -47,7 +47,7 @@
% } % }
% elsif ($invalid eq 'token') { % elsif ($invalid eq 'token') {
<span class="card-title">Ungültiger Token</span> <span class="card-title">Ungültiger Token</span>
<p>Die Verifikation deiner Mail-Adresse ist fehlgeschlagen oder du hast den Token schon einmal verwendet.</p> <p>Möglicherweise ist die Verifikation deiner Mail-Adresse fehlgeschlagen oder du hast den Token schon einmal verwendet.</p>
% } % }
% elsif ($invalid eq 'confirmation') { % elsif ($invalid eq 'confirmation') {
<span class="card-title">Account nicht freigeschaltet</span> <span class="card-title">Account nicht freigeschaltet</span>