Added log in/log out session functionality, added tests, updated schema and amended old tests.

This commit is contained in:
Paul Dill 2017-02-13 16:54:35 +00:00
parent 31fcb1bde8
commit 92bb78faba
7 changed files with 620 additions and 24 deletions

View file

@ -5,3 +5,4 @@ requires 'Mojo::JSON';
requires 'Email::Valid'; requires 'Email::Valid';
requires 'ORM::Date'; requires 'ORM::Date';
requires 'Authen::Passphrase::BlowfishCrypt'; requires 'Authen::Passphrase::BlowfishCrypt';
requires 'Time::Fake';

View file

@ -1,4 +1,5 @@
DROP TABLE IF EXISTS Tokens; DROP TABLE IF EXISTS SessionTokens;
DROP TABLE IF EXISTS AccountTokens;
DROP TABLE IF EXISTS Transactions; DROP TABLE IF EXISTS Transactions;
DROP TABLE IF EXISTS Users; DROP TABLE IF EXISTS Users;
DROP TABLE IF EXISTS Customers; DROP TABLE IF EXISTS Customers;

View file

@ -20,15 +20,20 @@ my $dbh = DBI->connect($config->{dsn},$config->{user},$config->{pass}) or die "C
$dbh->do("PRAGMA foreign_keys = ON"); $dbh->do("PRAGMA foreign_keys = ON");
$dbh->do("PRAGMA secure_delete = ON"); $dbh->do("PRAGMA secure_delete = ON");
my $sessionTimeSeconds = 60 * 60 * 24 * 7; #1 week.
my $sessionTokenJsonName = 'sessionToken';
my $sessionExpiresJsonName = 'sessionExpires';
Dwarn $config; Dwarn $config;
# shortcut for use in template # shortcut for use in template
helper db => sub { $dbh }; helper db => sub { $dbh };
any '/' => sub { any '/' => sub {
my $self = shift; my $self = shift;
$self->render(text => 'If you are seeing this, then the server is running.'); return $self->render(text => 'If you are seeing this, then the server is running.', success => Mojo::JSON->true);
}; };
post '/upload' => sub { post '/upload' => sub {
@ -117,7 +122,7 @@ post '/register' => sub {
}, },
status => 400,); #Malformed request status => 400,); #Malformed request
} }
elsif ( ! ($username =~ m/^[A-Za-z0-9]+$/)){ elsif ( ! ($self->valid_username($username))){
$self->app->log->debug('Path Error: file:' . __FILE__ . ', line: ' . __LINE__); $self->app->log->debug('Path Error: file:' . __FILE__ . ', line: ' . __LINE__);
return $self->render( json => { return $self->render( json => {
success => Mojo::JSON->false, success => Mojo::JSON->false,
@ -143,7 +148,7 @@ post '/register' => sub {
}, },
status => 400,); #Malformed request status => 400,); #Malformed request
} }
elsif ( ! Email::Valid->address($email)){ elsif ( ! $self->valid_email($email)){
$self->app->log->debug('Path Error: file:' . __FILE__ . ', line: ' . __LINE__); $self->app->log->debug('Path Error: file:' . __FILE__ . ', line: ' . __LINE__);
return $self->render( json => { return $self->render( json => {
success => Mojo::JSON->false, success => Mojo::JSON->false,
@ -329,6 +334,150 @@ post '/edit' => sub {
}; };
hook before_dispatch => sub {
my $self = shift;
$self->remove_all_expired_sessions();
#See if logged in.
my $sessionToken = $self->get_session_token();
#0 = no session, npn-0 is has updated session
my $hasBeenExtended = $self->extend_session($sessionToken);
my $path = $self->req->url->to_abs->path;
#Has valid session
if ($hasBeenExtended) {
#If logged in and requestine the login page redirect to the main page.
if ($path eq '/login') {
#Force expire and redirect.
$self->res->code(303);
$self->redirect_to('/');
}
}
#Has expired or did not exist in the first place and the path is not login
elsif ($path ne '/login' && $path ne '/register') {
$self->res->code(303);
$self->redirect_to('/login');
}
};
#FIXME placeholders
#Because of "before_dispatch" this will never be accessed unless the user is not logged in.
get '/login' => sub {
my $self = shift;
$self->render( text => 'This will be the login page.' );
};
#TODO set session cookie and add it to the database.
#FIXME This suffers from replay attacks, consider a challenge response. Would TLS solve this, most likely.
#SessionToken
#Because of "before_dispatch" this will never be accessed unless the user is not logged in.
post '/login' => sub {
my $self = shift;
my $json = $self->req->json;
$self->app->log->debug( "\n\nStart of login");
$self->app->log->debug( "JSON: " . Dumper $json );
if ( ! defined $json ){
$self->app->log->debug('Path Error: file:' . __FILE__ . ', line: ' . __LINE__);
return $self->render( json => {
success => Mojo::JSON->false,
message => 'No json sent.',
},
status => 400,); #Malformed request
}
my $email = $json->{email};
if ( ! defined $email ){
$self->app->log->debug('Path Error: file:' . __FILE__ . ', line: ' . __LINE__);
return $self->render( json => {
success => Mojo::JSON->false,
message => 'No email sent.',
},
status => 400,); #Malformed request
}
elsif ( ! $self->valid_email($email) ) {
$self->app->log->debug('Path Error: file:' . __FILE__ . ', line: ' . __LINE__);
return $self->render( json => {
success => Mojo::JSON->false,
message => 'email is invalid.',
},
status => 400,); #Malformed request
}
my $password = $json->{password};
if ( ! defined $password ){
$self->app->log->debug('Path Error: file:' . __FILE__ . ', line: ' . __LINE__);
return $self->render( json => {
success => Mojo::JSON->false,
message => 'No password sent.',
},
status => 400,); #Malformed request
}
#FIXME There is a timing attack here determining if an email exists or not.
if ($self->does_email_exist($email) && $self->check_password_email($email, $password)) {
#Match.
$self->app->log->debug('Path Success: file:' . __FILE__ . ', line: ' . __LINE__);
my $userId = $self->get_userid_foreign_key($email);
#Generates and stores
my $hash = $self->generate_session($userId);
$self->app->log->debug('session dump:' . Dumper ($hash));
return $self->render( json => {
success => Mojo::JSON->true,
$sessionTokenJsonName => $hash->{$sessionTokenJsonName},
$sessionExpiresJsonName => $hash->{$sessionExpiresJsonName},
});
}
else{
#Mismatch
$self->app->log->debug('Path Error: file:' . __FILE__ . ', line: ' . __LINE__);
return $self->render( json => {
success => Mojo::JSON->false,
message => 'Email or password is invalid.',
},
status => 401,); #Unauthorized request
}
};
post '/logout' => sub {
my $self = shift;
my $json = $self->req->json;
$self->app->log->debug( "\n\nStart of logout");
$self->app->log->debug( "JSON: " . Dumper $json );
#If the session token exists.
if ($self->expire_current_session()) {
$self->app->log->debug('Path Success: file:' . __FILE__ . ', line: ' . __LINE__);
return $self->render( json => {
success => Mojo::JSON->true,
message => 'you were successfully logged out.',
});
}
#Due to the "before_dispatch" hook, this most likely will not be called. i.e. race conditions.
#FIXME untested.
#An invalid token was presented, most likely because it has expired.
else {
$self->app->log->debug('Path Error: file:' . __FILE__ . ', line: ' . __LINE__);
return $self->render( json => {
success => Mojo::JSON->false,
message => 'the session has expired or did not exist in the first place.',
},
status => 401,); #Unauthorized request
}
};
post '/fetchuser' => sub { post '/fetchuser' => sub {
my $self = shift; my $self = shift;
@ -355,6 +504,17 @@ post '/fetchuser' => sub {
}); });
}; };
helper valid_username => sub {
my ($self, $username) = @_;
return ($username =~ m/^[A-Za-z0-9]+$/);
};
helper valid_email => sub {
my ($self, $email) = @_;
return (Email::Valid->address($email));
};
helper get_account_by_username => sub { helper get_account_by_username => sub {
my ( $self, $username ) = @_; my ( $self, $username ) = @_;
@ -365,11 +525,125 @@ helper get_account_by_username => sub {
); );
}; };
helper get_session_token => sub {
my $self = shift;
#See if logged in.
my $sessionToken = undef;
my $json = $self->req->json;
if (defined $json) {
$sessionToken = $json->{$sessionTokenJsonName};
}
if ( ! defined $sessionToken || $sessionToken eq "" ) {
$sessionToken = $self->session->{$sessionTokenJsonName};
}
if (defined $sessionToken && $sessionToken eq "" ) {
$sessionToken = undef;
}
return $sessionToken;
};
#This assumes the user has no current session on that device.
helper generate_session => sub {
my ($self, $userId) = @_;
my $sessionToken = $self->generate_session_token();
my $expireDateTime = $self->session_token_expiry_date_time();
my $insertStatement = $self->db->prepare('INSERT INTO SessionTokens (SessionTokenName, UserIdAssignedTo_FK, ExpireDateTime) VALUES (?, ?, ?)');
my $rowsAdded = $insertStatement->execute($sessionToken, $userId, $expireDateTime);
$self->session(expires => $expireDateTime);
$self->session->{$sessionTokenJsonName} = $sessionToken;
return {$sessionTokenJsonName => $sessionToken, $sessionExpiresJsonName => $expireDateTime};
};
helper generate_session_token => sub {
my $self = shift;
return Data::UUID->new->create_str();
};
helper expire_all_sessions => sub {
my $self = shift;
my $rowsDeleted = $self->db->prepare("DELETE FROM SessionTokens")->execute();
return $rowsDeleted;
};
helper session_token_expiry_date_time => sub {
my $self = shift;
return time() + $sessionTimeSeconds;
};
helper remove_all_expired_sessions => sub {
my $self = shift;
my $timeDateNow = time();
my $removeStatement = $self->db->prepare('DELETE FROM SessionTokens WHERE ExpireDateTime < ?');
my $rowsRemoved = $removeStatement->execute($timeDateNow);
return $rowsRemoved;
};
#1 = session update, 0 = there was no session or it expired.
#We assume the token has a valid structure.
helper extend_session => sub {
my ( $self, $sessionToken ) = @_;
my $timeDateExpire = $self->session_token_expiry_date_time();
my $updateStatement = $self->db->prepare('UPDATE SessionTokens SET ExpireDateTime = ? WHERE SessionTokenName = ?');
my $rowsChanges = $updateStatement->execute($timeDateExpire, $sessionToken);
#Has been updated.
if ($rowsChanges != 0) {
$self->session(expires => $timeDateExpire);
return 1;
}
else {
$self->session(expires => 1);
return 0;
}
};
helper get_session_expiry => sub {
my ( $self, $sessionToken ) = @_;
my ( $expireTime ) = $self->db->selectrow_array("SELECT ExpireDateTime FROM SessionTokens WHERE SessionTokenName = ?", undef, ($sessionToken));
return $expireTime;
};
#True for session was expire, false there was no session to expire.
helper expire_current_session => sub {
my $self = shift;
my $sessionToken = $self->get_session_token();
my $removeStatement = $self->db->prepare('DELETE FROM SessionTokens WHERE SessionTokenName = ?');
my $rowsRemoved = $removeStatement->execute($sessionToken);
$self->session(expires => 1);
$self->session->{$sessionTokenJsonName} = $sessionToken;
return $rowsRemoved != 0;
};
#Return true if and only if the token exists and has not been used. #Return true if and only if the token exists and has not been used.
helper is_token_unused => sub { helper is_token_unused => sub {
my ( $self, $token ) = @_; my ( $self, $token ) = @_;
my ( $out ) = $self->db->selectrow_array("SELECT COUNT(TokenId) FROM Tokens WHERE TokenName = ? AND Used = 0", undef, ($token)); my ( $out ) = $self->db->selectrow_array("SELECT COUNT(AccountTokenId) FROM AccountTokens WHERE AccountTokenName = ? AND Used = 0", undef, ($token));
return $out != 0; return $out != 0;
@ -387,12 +661,19 @@ helper get_age_foreign_key => sub {
return $out; return $out;
}; };
helper get_userid_foreign_key => sub {
my ( $self, $email ) = @_;
my ( $out ) = $self->db->selectrow_array("SELECT UserId FROM Users WHERE Email = ?", undef, ($email));
return $out;
};
helper does_username_exist => sub { helper does_username_exist => sub {
my ( $self, $username ) = @_; my ( $self, $username ) = @_;
my ($out) = $self->db->selectrow_array("SELECT COUNT(UserName) FROM Customers WHERE UserName = ?", {}, ($username)); my ($out) = $self->db->selectrow_array("SELECT COUNT(UserName) FROM Customers WHERE UserName = ?", {}, ($username));
#print "-". Dumper($out) ."-";
return $out != 0; return $out != 0;
}; };
@ -400,18 +681,16 @@ helper does_username_exist => sub {
helper does_email_exist => sub { helper does_email_exist => sub {
my ( $self, $email ) = @_; my ( $self, $email ) = @_;
return defined ($self->db->selectrow_hashref( my ($out) = $self->db->selectrow_array("SELECT COUNT(Email) FROM Users WHERE Email = ?", {}, ($email));
"SELECT Email FROM Users WHERE Email = ?",
{}, return $out != 0;
$email,
));
}; };
helper set_token_as_used => sub { helper set_token_as_used => sub {
my ( $self, $token ) = @_; my ( $self, $token ) = @_;
#Return true if and only if the token exists and has not been used. #Return true if and only if the token exists and has not been used.
my $statement = $self->db->prepare("UPDATE Tokens SET Used = 1 WHERE TokenName = ? AND Used = 0 "); my $statement = $self->db->prepare("UPDATE AccountTokens SET Used = 1 WHERE AccountTokenName = ? AND Used = 0 ");
my $rows = $statement->execute($token); my $rows = $statement->execute($token);
#print '-set_token_as_used-'.(Dumper($rows))."-\n"; #print '-set_token_as_used-'.(Dumper($rows))."-\n";
@ -433,14 +712,10 @@ helper generate_hashed_password => sub {
helper check_password_email => sub{ helper check_password_email => sub{
my ( $self, $email, $password) = @_; my ( $self, $email, $password) = @_;
my $statement = $self->db->prepare("SELECT HashedPassword FROM Users WHERE Email = ?"); my ($hashedPassword) = $self->db->selectrow_array("SELECT HashedPassword FROM Users WHERE Email = ?", undef, ($email));
my $result -> execute($email);
my ($hashedPassword) = $result->fetchrow_array;
my $ppr = Authen::Passphrase::BlowfishCrypt->from_crypt($hashedPassword); my $ppr = Authen::Passphrase::BlowfishCrypt->from_crypt($hashedPassword);
return $ppr->match($password); return $ppr->match($password);
}; };
app->start; app->start;

View file

@ -45,8 +45,16 @@ CREATE TABLE Transactions (
FOREIGN KEY (SellerOrganisationId_FK) REFERENCES Organisations (OrganisationalId) FOREIGN KEY (SellerOrganisationId_FK) REFERENCES Organisations (OrganisationalId)
); );
CREATE TABLE Tokens ( CREATE TABLE AccountTokens (
TokenId INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, AccountTokenId INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL,
TokenName TEXT UNIQUE NOT NULL, AccountTokenName TEXT UNIQUE NOT NULL,
Used INTEGER NOT NULL DEFAULT 0 Used INTEGER NOT NULL DEFAULT 0
); );
CREATE TABLE SessionTokens (
SessionTokenId INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL,
SessionTokenName TEXT UNIQUE NOT NULL,
UserIdAssignedTo_FK INTEGER NOT NULL,
ExpireDateTime INTEGER NOT NULL,
FOREIGN KEY (UserIdAssignedTo_FK) REFERENCES Users (UserId)
);

View file

@ -5,6 +5,6 @@ use FindBin;
require "$FindBin::Bin/../foodloopserver.pl"; require "$FindBin::Bin/../foodloopserver.pl";
my $t = Test::Mojo->new; my $t = Test::Mojo->new;
$t->get_ok('/')->status_is(200)->content_like(qr/server/); $t->get_ok('/login')->status_is(200)->content_like(qr/login page/);
done_testing(); done_testing();

311
t/login.t Normal file
View file

@ -0,0 +1,311 @@
use Test::More;
use Test::Mojo;
use Mojo::JSON;
use Time::Fake;
use FindBin;
$ENV{MOJO_MODE} = 'development';
$ENV{MOJO_LOG_LEVEL} = 'debug';
require "$FindBin::Bin/../foodloopserver.pl";
my $t = Test::Mojo->new;
my $dbh = $t->app->db;
#Dump all pf the test tables and start again.
my $sqlDeployment = Mojo::File->new("$FindBin::Bin/../dropschema.sql")->slurp;
for (split ';', $sqlDeployment){
$dbh->do($_) or die $dbh->errstr;
}
my $sqlDeployment = Mojo::File->new("$FindBin::Bin/../schema.sql")->slurp;
for (split ';', $sqlDeployment){
$dbh->do($_) or die $dbh->errstr;
}
my $accountToken = 'a';
my $tokenStatement = $dbh->prepare('INSERT INTO AccountTokens (AccountTokenName) VALUES (?)');
$tokenStatement->execute($accountToken);
my $sessionTimeSeconds = 60 * 60 * 24 * 7; #1 week.
my $sessionTokenJsonName = 'sessionToken';
my $sessionExpiresJsonName = 'sessionExpires';
#This depends on "register.t" working
#Valid customer, this also tests that redirects are disabled for register.
print "test 1 - Initial create user account\n";
my $email = 'rufus@shinra.energy';
my $password = 'MakoGold';
my $testJson = {
'usertype' => 'customer',
'token' => $accountToken,
'username' => 'RufusShinra',
'email' => $email,
'postcode' => 'LA1 1AA',
'password' => $password,
'age' => '20-35'
};
$t->post_ok('/register' => json => $testJson)
->status_is(200)
->json_is('/success', Mojo::JSON->true);
#Test login, this also checks that redirects are disabled for login when logged out.
print "test 2 - Login (cookies)\n";
$testJson = {
'email' => $email,
'password' => $password,
};
$t->post_ok('/login' => json => $testJson)
->status_is(200)
->json_is('/success', Mojo::JSON->true)
->json_has("/$sessionTokenJsonName")
->json_has("/$sessionExpiresJsonName");
print "test 3 - Login, no redirect on login paths (cookies)\n";
#No redirect, as you're logged in.
$t->get_ok('/')
->status_is(200);
my $location_is = sub {
my ($t, $value, $desc) = @_;
$desc ||= "Location: $value";
local $Test::Builder::Level = $Test::Builder::Level + 1;
return $t->success(is($t->tx->res->headers->location, $value, $desc));
};
print "test 4 - Login, redirect to root as already logged in (cookies)\n";
#Check for redirect to root when logged in.
$t->get_ok('/login')
->status_is(303)
->$location_is('/');
#Does login/logout work with a cookie based session.
print "test 5 - Logout (cookies)\n";
$t->post_ok('/logout')
->status_is(200)
->json_is('/success', Mojo::JSON->true)
->content_like(qr/you were successfully logged out/i);
$t->reset_session;
#Login.
print "test 6 - Login (json)\n";
$testJson = {
'email' => $email,
'password' => $password,
};
$t->post_ok('/login' => json => $testJson)
->status_is(200)
->json_is('/success', Mojo::JSON->true)
->json_has("/$sessionTokenJsonName")
->json_has("/$sessionExpiresJsonName");
my $sessionJsonTest = $t->tx->res->json;
my $expires = $sessionJsonTest->{$sessionExpiresJsonName};
my $sessionToken = $sessionJsonTest->{$sessionTokenJsonName};
#Reset the current state so you are still logged in but there are no cookies.
$t->reset_session;
#Redirect, as no cookies are set
print "test 7 - Login, no cookies or json redirect to login\n";
$t->get_ok('/')
->status_is(303)
->$location_is('/login');
print "test 8 - Login, no redirect on login paths (json)\n";
$t->get_ok('/' => json => {$sessionTokenJsonName => $sessionToken})
->status_is(200);
#No token send so redirect
print "test 9 - Logout, no cookies or json\n";
$t->post_ok('/logout')
->status_is(303)
->$location_is('/login');
#Token sent logout
print "test 10 - Logout, (json)\n";
$t->post_ok('/logout' => json => {$sessionTokenJsonName => $sessionToken})
->status_is(200);
#Send logged out expired token,
print "test 11 - Logout,expired session redirect (json)\n";
$t->post_ok('/logout' => json => {$sessionTokenJsonName => $sessionToken})
->status_is(303)
->$location_is('/login');
$t->reset_session;
#TODO it's difficult to test cookies as they automatically get removed.
#Login.
print "test 12 - Login test with fake time (json)\n";
$testJson = {
'email' => $email,
'password' => $password,
};
$t->post_ok('/login' => json => $testJson)
->status_is(200)
->json_is('/success', Mojo::JSON->true)
->json_has("/$sessionTokenJsonName")
->json_has("/$sessionExpiresJsonName");
$sessionJsonTest = $t->tx->res->json;
$expires = $sessionJsonTest->{$sessionExpiresJsonName};
$sessionToken = $sessionJsonTest->{$sessionTokenJsonName};
#Clear cookies
$t->reset_session;
#Offset time
Time::Fake->offset("+".($sessionTimeSeconds * 2)."s");
#Send time expired token,
print "test 13 - Fake time expired session redirect (json)\n";
$t->post_ok('/logout' => json => {$sessionTokenJsonName => $sessionToken})
->status_is(303)
->$location_is('/login');
Time::Fake->reset();
$t->reset_session;
#Attempt to logout without any session
# This is different from the one above as it's has no state.
print "test 14 - Logout, no session\n";
$t->post_ok('/logout')
->status_is(303)
->$location_is('/login');
#Clear the session state
$t->reset_session;
#Not logged in, redirect to login.
print "test 15 - Not logged in, get request redirect to login\n";
$t->get_ok('/')
->status_is(303)
->$location_is('/login');
$t->reset_session;
#Not logged in, redirect to login.
print "test 16 - Not logged in, get request one redirection is ok.\n";
$t->ua->max_redirects(1);
$t->get_ok('/')
->status_is(200);
$t->ua->max_redirects(0);
$t->reset_session;
#Not logged in, redirect to login.
print "test 17 - Not logged in, post request redirect to login\n";
$t->post_ok('/')
->status_is(303)
->$location_is('/login');
$t->reset_session;
#Not logged in, redirect to login.
print "test 18 - Not logged in, post request one redirection is ok.\n";
$t->ua->max_redirects(1);
$t->post_ok('/')
->status_is(200);
$t->ua->max_redirects(0);
$t->reset_session;
#Here on is just input params checking, no session testing.
#Test no JSON sent.
print "test 19 - No JSON sent.\n";
$t->post_ok('/login')
->status_is(400)
->json_is('/success', Mojo::JSON->false)
->content_like(qr/No json sent/i);
$t->reset_session;
#Test no email sent
print "test 20 - Email missing\n";
$testJson = {
'password' => $password,
};
$t->post_ok('/login' => json => $testJson)
->status_is(400)
->json_is('/success', Mojo::JSON->false)
->content_like(qr/No email sent/i);
$t->reset_session;
#Invalid email
print "test 21 - Invalid email\n";
$testJson = {
'email' => ($email . '@'),
'password' => $password,
};
$t->post_ok('/login' => json => $testJson)
->status_is(400)
->json_is('/success', Mojo::JSON->false)
->content_like(qr/email is invalid/i);
$t->reset_session;
#Test no password sent
print "test 22 - No password sent.\n";
$testJson = {
'email' => $email,
};
$t->post_ok('/login' => json => $testJson)
->status_is(400)
->json_is('/success', Mojo::JSON->false)
->content_like(qr/No password sent/i);
$t->reset_session;
#Email does not exist
print "test 23 - Email does not exist in the database\n";
$testJson = {
'email' => 'heidegger@shinra.energy',
'password' => $password,
};
$t->post_ok('/login' => json => $testJson)
->status_is(401)
->json_is('/success', Mojo::JSON->false)
->content_like(qr/Email or password is invalid/i);
$t->reset_session;
#Password is wrong
print "test 24 - Password is wrong\n";
$testJson = {
'email' => $email,
'password' => ($password . 'MoreText'),
};
$t->post_ok('/login' => json => $testJson)
->status_is(401)
->json_is('/success', Mojo::JSON->false)
->content_like(qr/Email or password is invalid/i);
$t->reset_session;
#$testJson = {
# 'email' => $email,
# 'password' => $password,
#};
#$t->post_ok('/login' => json => $testJson)
# ->status_is(200)
# ->json_is('/success', Mojo::JSON->true);
#TODO expire session.
done_testing();

View file

@ -28,7 +28,7 @@ for (split ';', $sqlDeployment){
my @names = ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'); my @names = ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z');
my @emails = ('a@a.com', 'b@a.com', 'c@a.com', 'd@a.com', 'e@a.com', 'f@a.com', 'g@a.com', 'h@a.com', 'i@a.com', 'j@a.com', 'k@a.com', 'l@a.com', 'm@a.com', 'n@a.com', 'o@a.com', 'p@a.com', 'q@a.com', 'r@a.com', 's@a.com', 't@a.com', 'u@a.com', 'v@a.com', 'w@a.com', 'x@a.com', 'y@a.com', 'z@a.com'); my @emails = ('a@a.com', 'b@a.com', 'c@a.com', 'd@a.com', 'e@a.com', 'f@a.com', 'g@a.com', 'h@a.com', 'i@a.com', 'j@a.com', 'k@a.com', 'l@a.com', 'm@a.com', 'n@a.com', 'o@a.com', 'p@a.com', 'q@a.com', 'r@a.com', 's@a.com', 't@a.com', 'u@a.com', 'v@a.com', 'w@a.com', 'x@a.com', 'y@a.com', 'z@a.com');
my @tokens = ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'); my @tokens = ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z');
my $tokenStatement = $dbh->prepare('INSERT INTO Tokens (TokenName) VALUES (?)'); my $tokenStatement = $dbh->prepare('INSERT INTO AccountTokens (AccountTokenName) VALUES (?)');
foreach (@tokens){ foreach (@tokens){
my $rowsAdded = $tokenStatement->execute($_); my $rowsAdded = $tokenStatement->execute($_);
} }