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 Mojo::Base 'Mojolicious::Controller', -signatures;
use CharmBoard::Crypt::Password; use CharmBoard::Crypt::Password;
use CharmBoard::Crypt::Seasoning; use CharmBoard::Crypt::Seasoning;
use Time::HiRes qw(time);
# initial registration page # initial registration page
sub register ($app) { 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 if ($userCheck && $emailCheck) { # notify user that username and email are both already being used
$app->flash(error => 'Username and email already in use.'); $app->flash(error => 'Username and email already in use.');
$app->redirect_to('register')} $app->redirect_to('register')}
elsif ($userCheck) { # notify user that only username is already in use elsif ($userCheck) { # notify user that only username is already in use
$app->flash(error => 'Username is already in use.'); $app->flash(error => 'Username is already in use.');
$app->redirect_to('register')} $app->redirect_to('register')}
elsif ($emailCheck) { # notify user that only email is already in use elsif ($emailCheck) { # notify user that only email is already in use
$app->flash(error => 'email is already in use.'); $app->flash(error => 'email is already in use.');
$app->redirect_to('register')}} $app->redirect_to('register')}}
else { # TODO: add more error handling here, in case SQL transact fails else { # TODO: add more error handling here, in case SQL transact fails
# append pepper to pass before hashing # append pepper to pass before hashing
$password = $app->pepper . ':' . $password; $password = $app->pepper . ':' . $password;
# return hashed result + salt # return hashed result + salt
my ($salt, $hash) = passgen($password); my ($salt, $hash) = passgen($password);
# add user info and pw/salt to DB # add user info and pw/salt to DB
$app->schema->resultset('Users')->create({ $app->schema->resultset('Users')->create({
username => $username, username => $username,
@ -59,6 +62,7 @@ sub register_do ($app) {
password => $hash, password => $hash,
salt => $salt, salt => $salt,
signup_date => time }); signup_date => time });
$app->flash(message => 'User registered successfully!'); $app->flash(message => 'User registered successfully!');
$app->redirect_to('register')}}; $app->redirect_to('register')}};
@ -70,20 +74,47 @@ sub login ($app) {
sub login_do ($app) { sub login_do ($app) {
my $username = $app->param('username'); my $username = $app->param('username');
my $password = $app->param('password'); my $password = $app->pepper . ':' . $app->param('password');
$password = $app->pepper . ':' . $password;
my $userInfoCheck = $app->schema->resultset('Users')->search({username => $username}); my $userInfoCheck = $app->schema->resultset('Users')->search({username => $username});
if ($userInfoCheck) { if ($userInfoCheck) {
my $savedSalt = $userInfoCheck->get_column('salt')->first; my $passCheckStatus = passchk($userInfoCheck->get_column('salt')->first,
my $savedHash = $userInfoCheck->get_column('password')->first; $userInfoCheck->get_column('password')->first, $password);
my $passCheckStatus = passchk($savedSalt, $savedHash, $password);
if ($passCheckStatus) { if ($passCheckStatus) {
$app->flash(message => 'Password correct, but auth isn\'t implemented yet'); my $userID = $userInfoCheck->get_column('user_id')->first;
$app->redirect_to('login')
} else { # 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->flash(error => 'Password incorrect');
$app->redirect_to('login')}} $app->redirect_to('login')}}
else {
else {
$app->flash(error => 'User ' . $username . ' does not exist.'); $app->flash(error => 'User ' . $username . ' does not exist.');
$app->redirect_to('login')}; $app->redirect_to('login')};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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