Implement login, fix more formatting

This commit is contained in:
ngoomie 2023-05-07 08:50:39 -06:00
parent c5785301ca
commit e12849508e
9 changed files with 68 additions and 21 deletions

View File

@ -2,7 +2,6 @@ package CharmBoard::Controller::Auth;
use Mojo::Base 'Mojolicious::Controller', -signatures;
use CharmBoard::Crypt::Password;
use CharmBoard::Crypt::Seasoning;
use Time::HiRes qw(time);
# initial registration page
sub register ($app) {
@ -41,17 +40,21 @@ sub register_do ($app) {
if ($userCheck && $emailCheck) { # notify user that username and email are both already being used
$app->flash(error => 'Username and email already in use.');
$app->redirect_to('register')}
elsif ($userCheck) { # notify user that only username is already in use
$app->flash(error => 'Username is already in use.');
$app->redirect_to('register')}
elsif ($emailCheck) { # notify user that only email is already in use
$app->flash(error => 'email is already in use.');
$app->redirect_to('register')}}
else { # TODO: add more error handling here, in case SQL transact fails
# append pepper to pass before hashing
$password = $app->pepper . ':' . $password;
# return hashed result + salt
my ($salt, $hash) = passgen($password);
# add user info and pw/salt to DB
$app->schema->resultset('Users')->create({
username => $username,
@ -59,6 +62,7 @@ sub register_do ($app) {
password => $hash,
salt => $salt,
signup_date => time });
$app->flash(message => 'User registered successfully!');
$app->redirect_to('register')}};
@ -70,20 +74,47 @@ sub login ($app) {
sub login_do ($app) {
my $username = $app->param('username');
my $password = $app->param('password');
$password = $app->pepper . ':' . $password;
my $password = $app->pepper . ':' . $app->param('password');
my $userInfoCheck = $app->schema->resultset('Users')->search({username => $username});
if ($userInfoCheck) {
my $savedSalt = $userInfoCheck->get_column('salt')->first;
my $savedHash = $userInfoCheck->get_column('password')->first;
my $passCheckStatus = passchk($savedSalt, $savedHash, $password);
my $passCheckStatus = passchk($userInfoCheck->get_column('salt')->first,
$userInfoCheck->get_column('password')->first, $password);
if ($passCheckStatus) {
$app->flash(message => 'Password correct, but auth isn\'t implemented yet');
$app->redirect_to('login')
} else {
my $userID = $userInfoCheck->get_column('user_id')->first;
# delete old session from DB if exists
if ($app->schema->resultset('Session')->search({user_id => $userID})) {
$app->schema->resultset('Session')->search({user_id => $userID})->delete; };
# gen session key and set expiry time
my $sessionKey = seasoning(16);
my $sessionExpiry = time + 604800;
# add session to database
$app->schema->resultset('Session')->create({
user_id => $userID,
session_key => $sessionKey,
session_expiry => $sessionExpiry,
is_ip_bound => 0,
bound_ip => undef });
# now create session cookie for user
$app->session(is_auth => 1);
$app->session(user_id => $userID);
$app->session(session_key => $sessionKey);
$app->session(expires => $sessionExpiry);
# redirect to index
$app->redirect_to('/')}
else {
$app->flash(error => 'Password incorrect');
$app->redirect_to('login')}}
else {
else {
$app->flash(error => 'User ' . $username . ' does not exist.');
$app->redirect_to('login')};

View File

@ -1,5 +1,6 @@
package CharmBoard::Crypt::Password;
use Authen::Passphrase::Argon2;
use CharmBoard::Crypt::Seasoning;
use Exporter qw(import);
our @EXPORT = qw(passgen passchk);
@ -10,26 +11,26 @@ our @EXPORT = qw(passgen passchk);
# `my ($salt, $hash) = passgen($password);`
sub passgen ($) {
my $argon2 = Authen::Passphrase::Argon2->new(
salt_random => 1,
salt => seasoning(32),
passphrase => $_[0],
cost => 3,
cost => 17,
factor => '32M',
parallelism => 1,
size => 16 );
size => 32 );
return ($argon2->salt, $argon2->as_crypt)};
return ($argon2->salt_hex, $argon2->hash_hex)};
# subroutine to check inputted password against one in DB
# `$_[0]` is the salt, `$_[1]` is the hashed pass, and
# `$_[2]` is the inputted plaintext pepper:password to check
sub passchk ($$$) {
my $argon2 = Authen::Passphrase::Argon2->new(
salt => $_[0],
hash => $_[1],
cost => 3,
salt_hex => $_[0],
hash_hex => $_[1],
cost => 17,
factor => '32M',
parallelism => 1,
size => 16 );
size => 32 );
return ($argon2->match($_[2]))}

View File

@ -10,6 +10,7 @@ __PACKAGE__->add_columns(
cat_name => {
data_type => 'text',
is_nullable => 0, });
__PACKAGE__->set_primary_key('cat_id');
1

View File

@ -19,7 +19,9 @@ __PACKAGE__->add_columns(
data_type => 'integer',
is_auto_increment => 0,
is_nullable => 0, });
__PACKAGE__->set_primary_key('post_id');
__PACKAGE__->belongs_to(
user_id =>
'CharmBoard::Schema::Result::Users',

View File

@ -23,7 +23,9 @@ __PACKAGE__->add_columns(
data_type => 'text',
is_auto_increment => 0,
is_nullable => 1, });
__PACKAGE__->set_primary_key('user_id');
__PACKAGE__->belongs_to(
user_id =>
'CharmBoard::Schema::Result::Users',

View File

@ -19,7 +19,9 @@ __PACKAGE__->add_columns(
data_type => 'text',
is_auto_increment => 0,
is_nullable => 1, });
__PACKAGE__->set_primary_key('subf_id');
__PACKAGE__->belongs_to(
subf_cat =>
'CharmBoard::Schema::Result::Categories',

View File

@ -13,7 +13,9 @@ __PACKAGE__->add_columns(
thread_subf => {
data_type => 'integer',
is_nullable => 1, });
__PACKAGE__->set_primary_key('thread_id');
__PACKAGE__->belongs_to(
thread_subf =>
'CharmBoard::Schema::Result::Subforums',

View File

@ -10,20 +10,25 @@ __PACKAGE__->add_columns(
is_auto_increment => 1, },
username => {
data_type => 'text',
is_numeric => 0,
is_nullable => 0, },
email => {
data_type => 'text',
is_numeric => 0,
is_nullable => 0, },
password => {
data_type => 'text',
is_numeric => 0,
is_nullable => 0, },
salt => {
data_type => 'text',
is_numeric => 0,
is_nullable => 0, },
signup_date => {
data_type => 'real',
data_type => 'integer',
is_numeric => 1,
is_nullable => 0, });
__PACKAGE__->set_primary_key('user_id');
1

View File

@ -1,3 +1,4 @@
% layout 'default', title => 'CharmBoard';
index page
% my $hpm = "you are not logged in";
% if ($self->session('is_auth')) {$hpm = "you're logged in!"};
<%= $hpm %>