Split auth code into a separate file

This commit is contained in:
Al Beano 2017-07-17 08:55:50 +01:00
parent b549ab3e79
commit c56ab7dfec
3 changed files with 149 additions and 140 deletions

View File

@ -1,20 +1,13 @@
package cyberman;
use Dancer2;
use Dancer2::Plugin::Database;
use cyberman::Domains;
use cyberman::Auth;
use cyberman::Helper;
use Dancer2::Plugin::Database;
use Digest::Bcrypt;
use Math::Random::Secure qw(rand irand);
#####
# cyberman.pm
# index page and authentication
# maybe this could be split into another file at a later juncture
#####
# misc authentication subs
# Index route, hook and helper functions for authentication
sub get_auth {
my $uid = shift;
@ -29,20 +22,6 @@ sub get_auth {
}
}
sub randstring {
my $len = shift;
my @chars = (0..9, "a".."z", "A".."Z");
my $ret;
for (1..$len) {
$ret .= $chars[irand(scalar(@chars))];
}
return $ret;
}
prefix undef;
hook 'before' => sub {
sub cookieval {
my $name = shift;
@ -83,118 +62,4 @@ get qr{^/(index)?$} => sub {
};
};
post '/register' => sub {
my %errs;
for my $param ("password", "password2", "email") {
if (!param($param)) {
$errs{"e_no_$param"} = 1;
}
}
if (!exists $errs{"e_no_password"} || !exists $errs{"e_no_password2"}) {
if (param("password") ne param("password2")) {
$errs{"e_pass_match"} = 1;
}
if (length param("password") < 8) {
$errs{"e_pass_len"} = 1;
}
}
if (scalar(keys(%errs)) != 0) {
return template 'register' => {
error => 1,
%errs,
};
}
# Hash password
my $salt = randstring(16);
my $b = new Digest::Bcrypt;
$b->cost(8);
$b->salt($salt);
$b->add(param "password");
# Create the account in the database
database->quick_insert(
"user",
{
"email" => param("email"),
"password" => $b->bcrypt_b64digest,
"salt" => $salt,
},
);
# TODO: send confirmation email
template 'login' => {
account_created => 1,
};
};
post '/login' => sub {
my %errs;
my $user = database->quick_select(
"user",
{
"email" => param("email"),
},
);
if (!$user) {
$errs{"e_no_user"} = 1;
}
if (scalar(keys(%errs)) == 0) {
my $b = new Digest::Bcrypt;
$b->cost(8);
$b->salt($user->{"salt"});
$b->add(param "password");
$errs{"e_pass"} = 1 unless $b->bcrypt_b64digest eq $user->{"password"};
}
if (scalar(keys(%errs)) == 0) {
$errs{"e_not_confirmed"} = 1 unless $user->{"active"};
}
if (scalar(keys(%errs)) != 0) {
return template 'login' => {
error => 1,
%errs,
};
}
# checks finished, we can create a session now
my $token = randstring(32);
database->quick_insert(
"session",
{
"token" => $token,
"uid" => $user->{"id"},
"since" => time,
},
);
cookie id => $user->{"id"}, http_only => 1;
cookie token => $token, http_only => 1;
template 'redir' => {
"redir" => "domains",
};
};
post '/logout' => sub {
cookie 'id' => undef;
cookie 'token' => undef;
template 'redir' => {
"redir" => "index",
};
};
true;

127
lib/cyberman/Auth.pm Normal file
View File

@ -0,0 +1,127 @@
package cyberman::Auth;
use Dancer2 appname => "cyberman";
use Dancer2::Plugin::Database;
use Digest::Bcrypt;
use Math::Random::Secure qw(irand);
use cyberman::Helper;
# This file: auth-related routes (register, login, logout)
# Hooks and helper functions for authentication are in cyberman.pm
post '/register' => sub {
my %errs;
for my $param ("password", "password2", "email") {
if (!param($param)) {
$errs{"e_no_$param"} = 1;
}
}
if (!exists $errs{"e_no_password"} || !exists $errs{"e_no_password2"}) {
if (param("password") ne param("password2")) {
$errs{"e_pass_match"} = 1;
}
if (length param("password") < 8) {
$errs{"e_pass_len"} = 1;
}
}
if (scalar(keys(%errs)) != 0) {
return template 'register' => {
error => 1,
%errs,
};
}
# Hash password
my $salt = randstring(16);
my $b = new Digest::Bcrypt;
$b->cost(8);
$b->salt($salt);
$b->add(param "password");
# Create the account in the database
database->quick_insert(
"user",
{
"email" => param("email"),
"password" => $b->bcrypt_b64digest,
"salt" => $salt,
},
);
# TODO: send confirmation email
template 'login' => {
account_created => 1,
};
};
post '/login' => sub {
my %errs;
my $user = database->quick_select(
"user",
{
"email" => param("email"),
},
);
if (!$user) {
$errs{"e_no_user"} = 1;
}
if (scalar(keys(%errs)) == 0) {
my $b = new Digest::Bcrypt;
$b->cost(8);
$b->salt($user->{"salt"});
$b->add(param "password");
$errs{"e_pass"} = 1 unless $b->bcrypt_b64digest eq $user->{"password"};
}
if (scalar(keys(%errs)) == 0) {
$errs{"e_not_confirmed"} = 1 unless $user->{"active"};
}
if (scalar(keys(%errs)) != 0) {
return template 'login' => {
error => 1,
%errs,
};
}
# checks finished, we can create a session now
my $token = randstring(32);
database->quick_insert(
"session",
{
"token" => $token,
"uid" => $user->{"id"},
"since" => time,
},
);
cookie id => $user->{"id"}, http_only => 1;
cookie token => $token, http_only => 1;
template 'redir' => {
"redir" => "domains",
};
};
post '/logout' => sub {
cookie 'id' => undef;
cookie 'token' => undef;
template 'redir' => {
"redir" => "index",
};
};
true;

View File

@ -1,9 +1,14 @@
package cyberman::Helper;
use base qw(Exporter);
use Dancer2 appname => "cyberman";
use Math::Random::Secure qw(irand);
use Exporter qw(import);
our @EXPORT = qw(auth_test);
our @EXPORT = qw(auth_test randstring);
# Helper functions
sub auth_test {
my $id = undef;
@ -24,4 +29,16 @@ sub auth_test {
}
}
sub randstring {
my $len = shift;
my @chars = (0..9, "a".."z", "A".."Z");
my $ret;
for (1..$len) {
$ret .= $chars[irand(scalar(@chars))];
}
return $ret;
}
1;