Implement password resets

This commit is contained in:
Al Beano 2017-08-19 15:03:54 +01:00
parent 5e4ba72357
commit fb17a96c26
8 changed files with 207 additions and 2 deletions

2
dbupdate/2.sql Normal file
View File

@ -0,0 +1,2 @@
alter table user add column recoverytoken text;
update cyberman set dbrev=3;

View File

@ -9,6 +9,7 @@ use cyberman::Account;
use cyberman::Helper; use cyberman::Helper;
use cyberman::API; use cyberman::API;
use cyberman::Records; use cyberman::Records;
use cyberman::Forgot;
# Index route, hook and helper functions for authentication # Index route, hook and helper functions for authentication

117
lib/cyberman/Forgot.pm Normal file
View File

@ -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;

View File

@ -3,7 +3,7 @@ create table cyberman (
id integer primary key, id integer primary key,
dbrev integer not null dbrev integer not null
); );
insert into cyberman (dbrev) values (2); insert into cyberman (dbrev) values (3);
drop table if exists user; drop table if exists user;
create table user ( create table user (
@ -13,7 +13,8 @@ create table user (
salt text not null, salt text not null,
active integer not null default 0, active integer not null default 0,
conftoken text not null, conftoken text not null,
newemail text newemail text,
recoverytoken text
); );
drop table if exists session; drop table if exists session;

49
views/confirm_forgot.tt Normal file
View File

@ -0,0 +1,49 @@
<center>
<br />
<h1>Update your password</h1>
<br />
<% IF err %>
<div class="msgBox">
Error:
<% IF e_bad_link %>
The link you clicked on is invalid!
<% ELSIF e_no_pass %>
You must enter a password.
<% ELSIF e_pass_len %>
Your password must be at least 8 characters long.
<% ELSIF e_pass_mismatch %>
The two passwords you entered do not match.
<% END%>
</div>
<br /><br />
<% END %>
</center>
<div class="body">
Enter a new password and click update.
<br />
<form method="POST" class="login" action="confirm_forgot">
<input type="hidden" name="e" value="<% params.e | html_entity %>" />
<input type="hidden" name="t" value="<% params.t | html_entity %>" />
<table>
<tr>
<td>
<label for="password">New password:</label>
</td>
<td>
<input type="password" name="password" id="password" />
</td>
</tr>
<tr>
<td>
<label for="password2">New password (confirm):</label>
</td>
<td>
<input type="password" name="password2" id="password2" />
</td>
</tr>
</table>
<br />
[&nbsp;<button class="textButton" action="submit">update</button>&nbsp;]
</form>
</div>

6
views/email/forgot.tt Normal file
View File

@ -0,0 +1,6 @@
Hello!
You're receiving this email because someone tried to reset your cybNIC password. If this was you, please click the link below:
<% link %>
If it wasn't, you can safely ignore this email.

27
views/forgot.tt Normal file
View File

@ -0,0 +1,27 @@
<center>
<br />
<h1 >Forgotten password</h1>
<br />
<% IF err || success %>
<div class="msgBox">
<% IF e_no_user %>
Error: There is no user account associated with that email address.
<% END %>
<% IF success %>
An email has been sent to <% params.email | html_entity %>. Please click the link to reset your password.
<% END %>
</div>
<br /><br />
<% END %>
</center>
<div class="body">
Enter your email into the field below and we'll send an email with a link to reset your password.
<br />
<form method="POST">
<label for="email">Email address:</label>
<input type="email" name="email" id="email" value="<% params.email | html_entity %>"/>
<br />
[&nbsp;<button action="submit" class="textButton">submit</button>&nbsp;]
</form>
</div>

View File

@ -57,5 +57,7 @@
<br /> <br />
[&nbsp;<button action="submit" class="textButton">log&nbsp;in</button>&nbsp;] [&nbsp;<button action="submit" class="textButton">log&nbsp;in</button>&nbsp;]
[&nbsp;<a href="index" class="bracketButton">go&nbsp;back</a>&nbsp;] [&nbsp;<a href="index" class="bracketButton">go&nbsp;back</a>&nbsp;]
<br /><br />
[&nbsp;<a href="forgot" class="bracketButton">recover forgotten password</a>&nbsp;]
</form> </form>
</div> </div>