diff --git a/dbupdate/2.sql b/dbupdate/2.sql new file mode 100644 index 0000000..5a11dae --- /dev/null +++ b/dbupdate/2.sql @@ -0,0 +1,2 @@ +alter table user add column recoverytoken text; +update cyberman set dbrev=3; diff --git a/lib/cyberman.pm b/lib/cyberman.pm index 18b949e..8949b7d 100644 --- a/lib/cyberman.pm +++ b/lib/cyberman.pm @@ -9,6 +9,7 @@ use cyberman::Account; use cyberman::Helper; use cyberman::API; use cyberman::Records; +use cyberman::Forgot; # Index route, hook and helper functions for authentication diff --git a/lib/cyberman/Forgot.pm b/lib/cyberman/Forgot.pm new file mode 100644 index 0000000..b10a26c --- /dev/null +++ b/lib/cyberman/Forgot.pm @@ -0,0 +1,117 @@ +package cyberman::Forgot; + +use Dancer2 appname => "cyberman"; +use Dancer2::Plugin::Database; +use URI::Escape; + +use cyberman::Helper; + +post '/forgot' => sub { + my $user = database->quick_select( + "user", + { + "email" => param("email"), + }, + ); + + if (!$user) { + return template 'forgot' => { + err => 1, + e_no_user => 1, + }; + } + + my $token = randstring(32); + database->quick_update( + "user", + { + "id" => $user->{"id"}, + }, + { + "recoverytoken" => $token, + }, + ); + + my $email = template 'email/forgot' => { + "link" => config->{"mail"}->{"baseurl"} . "/confirm_forgot?e=" . uri_escape(param("email")) . "&t=$token", + }, + { + "layout" => undef, + }; + send_email(param("email"), $email); + + template 'forgot' => { + success => 1, + }; +}; + +post '/confirm_forgot' => sub { + my %errs; + + if (!param("e") || !param("t")) { + $errs{"e_bad_link"} = 1; + } elsif (!param("password")) { + $errs{"e_no_pass"} = 1; + } elsif (length(param("password")) < 8) { + $errs{"e_pass_len"} = 1; + } elsif (param("password") ne param("password2")) { + $errs{"e_pass_mismatch"} = 1; + } + + if (scalar(keys(%errs)) == 0) { + my $user = database->quick_select( + "user", + { + "email" => param("e"), + "recoverytoken" => param("t"), + }, + ); + + if (!$user) { + $errs{"e_bad_link"} = 1; + } else { + # Update the password + my ($hash, $salt) = hash_password(param "password"); + database->quick_update( + "user", + { + "id" => $user->{"id"}, + }, + { + "password" => $hash, + "salt" => $salt, + }, + ); + + database->quick_delete( + "session", + { + "uid" => $user->{"id"}, + }, + ); + + database->quick_update( + "user", + { + "id" => $user->{"id"}, + }, + { + "recoverytoken" => "", + }, + ); + } + } + + if (scalar(keys(%errs)) != 0) { + return template 'confirm_forgot' => { + "err" => 1, + %errs, + }; + } + + template 'redir' => { + "redir" => "login?pwchange=1", + }; +}; + +true; diff --git a/schema.sql b/schema.sql index 9e0bb8a..17c3222 100644 --- a/schema.sql +++ b/schema.sql @@ -3,7 +3,7 @@ create table cyberman ( id integer primary key, dbrev integer not null ); -insert into cyberman (dbrev) values (2); +insert into cyberman (dbrev) values (3); drop table if exists user; create table user ( @@ -13,7 +13,8 @@ create table user ( salt text not null, active integer not null default 0, conftoken text not null, - newemail text + newemail text, + recoverytoken text ); drop table if exists session; diff --git a/views/confirm_forgot.tt b/views/confirm_forgot.tt new file mode 100644 index 0000000..1408ef2 --- /dev/null +++ b/views/confirm_forgot.tt @@ -0,0 +1,49 @@ +