diff --git a/.vscode/settings.json b/.vscode/settings.json
index a4d38eb..0b963d1 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -8,8 +8,13 @@
"Authen",
"CharmBoard",
"Facepunch",
+ "passchk",
+ "passgen",
"pgsql",
"resultset",
- "signup"
+ "signup",
+ "subf",
+ "subforum",
+ "subforums"
]
}
\ No newline at end of file
diff --git a/INSTALLING.md b/INSTALLING.md
index 32d5642..6bd9550 100644
--- a/INSTALLING.md
+++ b/INSTALLING.md
@@ -4,13 +4,13 @@ Please keep in mind that CharmBoard is alpha software, and as such should not be
## Preparation
-### Database types
+### Selecting a database type
CharmBoard supports two different types of databases. Below is a table listing off each type, as well as an explanation of the differences for people who are unsure which to pick.
| Name | config value | DBD package | Information |
|-|-|-|-|
-| SQLite | `sqlite` | `DBD:SQLite` | Good for small installs (private forum with one friend group, etc.)
Easy to set up as the database is contained in a standalone file. |
+| SQLite | `sqlite` | `DBD:SQLite` | Good for small installs (i.e. a private forum with one friend group, etc.)
Easy to set up as the database is contained in a standalone file. |
| MySQL | `mysql` | `DBD:mysql` | Has better performance on larger databases than SQLite does.
Harder to set up than SQLite as it requires the separate database server software to be set up alongside CharmBoard. |
### Installing dependencies
diff --git a/README.md b/README.md
index 4e0f6b7..e79b4d4 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,17 @@
# CharmBoard
-CharmBoard is forum software written in Perl, inspired by AcmlmBoard/its derivatives, the original Facepunch forums, and Knockout.chat. It's intended to be a more "fun" alternative to the bigger forum software suites available today.
+CharmBoard is forum software written in Perl, inspired by AcmlmBoard/its derivatives, the original Facepunch forums, and Knockout.chat. It's intended to be a more "fun" alternative to the bigger forum software suites available today. Though largely, it's just intended as a sort of pet project of mine for now and a way to learn Perl + Mojolicious, and some other modules I've been wanting to learn.
## Requirements
-- Perl 5 (TODO: specific version reqs)
- - `Mojolicious` ([website](https://www.mojolicious.org/), [metacpan](https://metacpan.org/pod/Mojolicious))
- - `DBI`
- - `DBIx::Class`
- - one of two `DBD` database drivers — see `INSTALLING.md` for detailed information
- - `Authen::Passphrase::Argon2`
+- Perl5 v5.20.0 or higher
+- `Mojolicious` ([website](https://www.mojolicious.org/), [metacpan](https://metacpan.org/pod/Mojolicious))
+ - `Mojolicious::Plugin::Renderer::WithoutCache` — only needed in dev environment
+- `DBI`
+ - `DBIx::Class`
+ - one of two `DBD` database drivers — see `INSTALLING.md` for detailed information
+- `Authen::Passphrase::Argon2`
+- `Math::Random::Secure`
## Installation
diff --git a/charmboard.example.conf b/charmboard.example.conf
index 4c7ed0f..c827b77 100644
--- a/charmboard.example.conf
+++ b/charmboard.example.conf
@@ -1,16 +1,18 @@
{
- boardName => '', # this doesn't do anything yet
+ board_name => '', # this doesn't do anything yet
database => {
- type => '', # 'sqlite', 'mysql', or 'pgsql'
+ type => '', # 'sqlite' or 'mysql'
name => '',
user => '',
pass => ''
},
- passCrypt => {
+ pass_crypt => {
pepper => '' # generate this with `tools/pepper.pl` for now
},
+ environment => '', # only use 'dev' for now
+
secrets => ['']
};
\ No newline at end of file
diff --git a/database.sql b/database.sql
index 6209daa..0579130 100644
--- a/database.sql
+++ b/database.sql
@@ -1,5 +1,5 @@
--
--- File generated with SQLiteStudio v3.4.4 on Sat. May 6 00:01:26 2023
+-- File generated with SQLiteStudio v3.4.4 on Sun. May 7 00:02:05 2023
--
-- Text encoding used: UTF-8
--
@@ -8,40 +8,104 @@ BEGIN TRANSACTION;
-- Table: categories
DROP TABLE IF EXISTS categories;
-CREATE TABLE IF NOT EXISTS categories (cat_id INTEGER NOT NULL UNIQUE, cat_name TEXT, PRIMARY KEY (cat_id AUTOINCREMENT));
+
+CREATE TABLE IF NOT EXISTS categories (
+ cat_id INTEGER NOT NULL ON CONFLICT ROLLBACK
+ UNIQUE ON CONFLICT ROLLBACK,
+ cat_name TEXT,
+ PRIMARY KEY (
+ cat_id AUTOINCREMENT
+ )
+);
+
-- Table: posts
DROP TABLE IF EXISTS posts;
-CREATE TABLE IF NOT EXISTS "posts" (
- "post_id" INTEGER NOT NULL UNIQUE,
- "user_id" INTEGER NOT NULL,
- "thread_id" INTEGER NOT NULL,
- "post_date" INTEGER NOT NULL,
- PRIMARY KEY("post_id" AUTOINCREMENT),
- FOREIGN KEY("user_id") REFERENCES "users"("user_id"),
- FOREIGN KEY("thread_id") REFERENCES "threads"("thread_id")
+
+CREATE TABLE IF NOT EXISTS posts (
+ post_id INTEGER NOT NULL ON CONFLICT ROLLBACK
+ UNIQUE ON CONFLICT ROLLBACK,
+ user_id INTEGER NOT NULL ON CONFLICT ROLLBACK,
+ thread_id INTEGER NOT NULL ON CONFLICT ROLLBACK,
+ post_date INTEGER NOT NULL ON CONFLICT ROLLBACK,
+ PRIMARY KEY (
+ post_id AUTOINCREMENT
+ ),
+ FOREIGN KEY (
+ user_id
+ )
+ REFERENCES users (user_id),
+ FOREIGN KEY (
+ thread_id
+ )
+ REFERENCES threads (thread_id)
);
--- Table: session
-DROP TABLE IF EXISTS session;
-CREATE TABLE IF NOT EXISTS "session" (
- "user_id" INTEGER NOT NULL UNIQUE,
- "session_id" TEXT NOT NULL,
- "session_expiry" INTEGER,
- PRIMARY KEY("user_id")
+
+-- Table: sessions
+DROP TABLE IF EXISTS sessions;
+
+CREATE TABLE IF NOT EXISTS sessions (
+ user_id INTEGER PRIMARY KEY
+ REFERENCES users (user_id)
+ UNIQUE
+ NOT NULL,
+ session_key TEXT NOT NULL
+ UNIQUE,
+ session_expiry NUMERIC NOT NULL,
+ is_ip_bound INTEGER (1, 1) NOT NULL
+ DEFAULT (0),
+ bound_ip TEXT
);
+
-- Table: subforums
DROP TABLE IF EXISTS subforums;
-CREATE TABLE IF NOT EXISTS subforums (subf_id INTEGER PRIMARY KEY UNIQUE NOT NULL, subf_cat INTEGER REFERENCES categories (cat_id) UNIQUE NOT NULL, subf_name TEXT NOT NULL, subf_desc);
+
+CREATE TABLE IF NOT EXISTS subforums (
+ subf_id INTEGER PRIMARY KEY
+ UNIQUE ON CONFLICT ROLLBACK
+ NOT NULL ON CONFLICT ROLLBACK,
+ subf_cat INTEGER REFERENCES categories (cat_id)
+ UNIQUE ON CONFLICT ROLLBACK
+ NOT NULL ON CONFLICT ROLLBACK,
+ subf_name TEXT NOT NULL ON CONFLICT ROLLBACK,
+ subf_desc
+);
+
-- Table: threads
DROP TABLE IF EXISTS threads;
-CREATE TABLE IF NOT EXISTS threads (thread_id INTEGER NOT NULL, thread_title TEXT NOT NULL, thread_subf INTEGER REFERENCES categories (cat_id), PRIMARY KEY (thread_id AUTOINCREMENT));
+
+CREATE TABLE IF NOT EXISTS threads (
+ thread_id INTEGER NOT NULL ON CONFLICT ROLLBACK,
+ thread_title TEXT NOT NULL ON CONFLICT ROLLBACK,
+ thread_subf INTEGER REFERENCES categories (cat_id),
+ PRIMARY KEY (
+ thread_id AUTOINCREMENT
+ )
+);
+
-- Table: users
DROP TABLE IF EXISTS users;
-CREATE TABLE IF NOT EXISTS users (user_id INTEGER NOT NULL UNIQUE, username TEXT NOT NULL UNIQUE ON CONFLICT ABORT, email TEXT UNIQUE NOT NULL, password INTEGER NOT NULL, salt TEXT NOT NULL, signup_date INTEGER NOT NULL, PRIMARY KEY (user_id AUTOINCREMENT) ON CONFLICT FAIL);
+
+CREATE TABLE IF NOT EXISTS users (
+ user_id INTEGER NOT NULL ON CONFLICT ROLLBACK
+ UNIQUE ON CONFLICT ROLLBACK,
+ username TEXT NOT NULL ON CONFLICT ROLLBACK
+ UNIQUE ON CONFLICT ROLLBACK,
+ email TEXT UNIQUE ON CONFLICT ROLLBACK
+ NOT NULL ON CONFLICT ROLLBACK,
+ password TEXT NOT NULL ON CONFLICT ROLLBACK,
+ salt TEXT NOT NULL ON CONFLICT ROLLBACK,
+ signup_date REAL NOT NULL,
+ PRIMARY KEY (
+ user_id AUTOINCREMENT
+ )
+ ON CONFLICT ABORT
+);
+
COMMIT TRANSACTION;
PRAGMA foreign_keys = on;
diff --git a/lib/CharmBoard.pm b/lib/CharmBoard.pm
index 2ce2e7f..733f225 100644
--- a/lib/CharmBoard.pm
+++ b/lib/CharmBoard.pm
@@ -3,84 +3,65 @@ use experimental 'smartmatch';
use Mojo::Base 'Mojolicious', -signatures;
use CharmBoard::Schema;
-# This method will run once at server start
+# this method will run once at server start
sub startup ($app) {
-
- $app = shift;
-
+ # load plugins that require no additional conf
$app->plugin('TagHelpers');
- $app->plugin('Renderer::WithoutCache'); # for dev env only
- $app->renderer->cache->max_keys(0); # for dev env only
+ # load configuration from config file
+ my $config = $app->plugin('Config' => {file => 'charmboard.conf'});
- $app->defaults(layout => 'default');
-
- # Load configuration from config file
- my $config = $app->plugin('Config' => {
- file => 'charmboard.conf'
- });
+ # load dev env only stuff, if applicable
+ if ( $config->{environment} eq 'dev' ) {
+ $app->plugin('Renderer::WithoutCache');
+ $app->renderer->cache->max_keys(0)};
- # Configure the application
- ## Import Mojolicious secrets (cookie encryption)
+ # import Mojolicious secrets
$app->secrets($config->{secrets});
- ## Import password pepper value
- my $pepper = $config->{passCrypt}->{pepper};
- $app->helper( pepper => sub { $pepper } );
- ## Database setup
- my ($dsn, $dbUnicode);
+ # import password pepper value
+ $app->helper(pepper => sub {$config->{pass_crypt}->{pepper}});
+
+ ## database setup
+ my ($dsn, $dbUnicode);
if ($app->config->{database}->{type} ~~ 'sqlite') {
$dsn = "dbi:SQLite:" . $config->{database}->{name};
- $dbUnicode = "sqlite_unicode";
- } elsif ($app->config->{database}->{type} ~~ 'mysql') {
+ $dbUnicode = "sqlite_unicode"}
+ elsif ($app->config->{database}->{type} ~~ 'mysql') {
$dsn = "dbi:mysql:" . $config->{database}->{name};
- $dbUnicode = "mysql_enable_utf";
- } elsif ($app->config->{database}->{type} ~~ 'pgsql') {
- $dsn = "dbi:Pg:" . $config->{database}->{name};
- $dbUnicode = "pg_enable_utf8";
- } else { die "\nUnknown, unsupported, or empty database type in charmboard.conf.
+ $dbUnicode = "mysql_enable_utf"}
+ else {die "\nUnknown, unsupported, or empty database type in charmboard.conf.
If you're sure you've set it to something supported, maybe double check your spelling?\n
- Valid options: 'sqlite', 'mysql'"
- };
-
+ Valid options: 'sqlite', 'mysql'"};
my $schema = CharmBoard::Schema->connect(
$dsn,
$config->{database}->{user},
$config->{database}->{pass},
- {
- $dbUnicode => 1
- }
- );
+ {$dbUnicode => 1});
+ $app->helper(schema => sub {$schema});
- $app->helper( schema => sub { $schema } );
-
- # Router
+ # router
my $r = $app->routes;
- # Controller routes
- ## Index page
+ # controller routes
+ ## index page
$r->get('/')->to(
controller => 'Controller::Main',
- action => 'index'
- );
- ## Registration page
+ action => 'index');
+ ## registration page
$r->get('/register')->to(
controller => 'Controller::Auth',
- action => 'register'
- );
+ action => 'register');
$r->post('/register')->to(
controller => 'Controller::Auth',
- action => 'registration_do'
- );
- ## Login page
+ action => 'register_do');
+ ## login page
$r->get('/login')->to(
controller => 'Controller::Auth',
- action => 'login'
- );
+ action => 'login');
$r->post('/login')->to(
controller => 'Controller::Auth',
- action => 'login_do'
- )
+ action => 'login_do');
}
1;
diff --git a/lib/CharmBoard/Controller/Auth.pm b/lib/CharmBoard/Controller/Auth.pm
index db24b0f..cd00ac1 100644
--- a/lib/CharmBoard/Controller/Auth.pm
+++ b/lib/CharmBoard/Controller/Auth.pm
@@ -1,6 +1,8 @@
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) {
@@ -11,63 +13,80 @@ sub register ($app) {
)};
# process submitted registration form
-sub registration_do ($app) {
+# TODO: implement email validation here at some point
+sub register_do ($app) {
my $username = $app->param('username');
my $email = $app->param('email');
my $password = $app->param('password');
my $confirmPassword = $app->param('confirm-password');
# check to make sure all required fields are filled
- if ( ! $username || ! $password || ! $confirmPassword ) {
- $app->flash( error => 'All fields required.' );
- $app->redirect_to('register');
- };
+ if (! $username || ! $password || ! $confirmPassword) {
+ $app->flash(error => 'All fields required.');
+ $app->redirect_to('register')};
# check to make sure both passwords match
# TODO: add check on frontend for this for people with JS enabled
- if ( $confirmPassword ne $password ) {
- $app->flash( error => 'Passwords do not match.' );
- $app->redirect_to('register');
- };
+ if ($confirmPassword ne $password) {
+ $app->flash(error => 'Passwords do not match.');
+ $app->redirect_to('register')};
# check to make sure username and/or email isn't already in use;
# if not, continue with registration
+ ## search for input username and email in database
my $userCheck = $app->schema->resultset('Users')->search({username => $username})->single;
my $emailCheck = $app->schema->resultset('Users')->search({email => $email})->single;
- if ( $userCheck || $emailCheck ) {
- 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 {
+
+ if ($userCheck || $emailCheck) {
+ 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;
- my ($hash, $salt) = pass_gen($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,
email => $email,
password => $hash,
salt => $salt,
- signup_date => time
- });
- $app->flash( message => 'User registered successfully!' );
- $app->redirect_to('register');
- }};
+ signup_date => time });
+ $app->flash(message => 'User registered successfully!');
+ $app->redirect_to('register')}};
sub login ($app) {
$app->render(
template => 'login',
error => $app->flash('error'),
- message => $app->flash('message')
- );
+ message => $app->flash('message'))};
+
+sub login_do ($app) {
+ my $username = $app->param('username');
+ my $password = $app->param('password');
+ $password = $app->pepper . ':' . $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);
+ if ($passCheckStatus) {
+ $app->flash(message => 'Password correct, but auth isn\'t implemented yet');
+ $app->redirect_to('login')
+ } else {
+ $app->flash(error => 'Password incorrect');
+ $app->redirect_to('login')}}
+ else {
+ $app->flash(error => 'User ' . $username . ' does not exist.');
+ $app->redirect_to('login')};
+
}
1;
\ No newline at end of file
diff --git a/lib/CharmBoard/Controller/Main.pm b/lib/CharmBoard/Controller/Main.pm
index 5234ee7..cc3cc65 100644
--- a/lib/CharmBoard/Controller/Main.pm
+++ b/lib/CharmBoard/Controller/Main.pm
@@ -2,7 +2,6 @@ package CharmBoard::Controller::Main;
use Mojo::Base 'Mojolicious::Controller', -signatures;
sub index ($app) {
- $app->render(template => 'index');
-}
+ $app->render(template => 'index')}
1;
\ No newline at end of file
diff --git a/lib/CharmBoard/Crypt/Password.pm b/lib/CharmBoard/Crypt/Password.pm
index 5c2934a..72300b8 100644
--- a/lib/CharmBoard/Crypt/Password.pm
+++ b/lib/CharmBoard/Crypt/Password.pm
@@ -2,20 +2,35 @@ package CharmBoard::Crypt::Password;
use Authen::Passphrase::Argon2;
use Exporter qw(import);
+our @EXPORT = qw(passgen passchk);
-our @EXPORT = qw(pass_gen);
-
-sub pass_gen ($) {
+# subroutine to generate password salt + hashed pw on pass creation
+# outputs the salt and then the hashed pw, so when assigning vars
+# from this sub's output, do it like this:
+# `my ($salt, $hash) = passgen($password);`
+sub passgen ($) {
my $argon2 = Authen::Passphrase::Argon2->new(
salt_random => 1,
- passphrase => $_[0],
- cost => 3,
- factor => '16M',
+ passphrase => $_[0],
+ cost => 3,
+ factor => '32M',
parallelism => 1,
- size => 32
- );
+ size => 16 );
- return ($argon2->salt_hex, $argon2->as_hex);
-}
+ return ($argon2->salt, $argon2->as_crypt)};
+
+# 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,
+ factor => '32M',
+ parallelism => 1,
+ size => 16 );
+
+ return ($argon2->match($_[2]))}
1;
\ No newline at end of file
diff --git a/lib/CharmBoard/Crypt/Seasoning.pm b/lib/CharmBoard/Crypt/Seasoning.pm
new file mode 100644
index 0000000..b2c7e2c
--- /dev/null
+++ b/lib/CharmBoard/Crypt/Seasoning.pm
@@ -0,0 +1,20 @@
+package CharmBoard::Crypt::Seasoning;
+use Math::Random::Secure qw(irand);
+
+use Exporter qw(import);
+our @EXPORT = qw(seasoning);
+
+sub seasoning ($) {
+ my @spices = qw(0 1 2 3 4 5 6 7 8 9 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 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 $blend;
+ while (length($blend) < $_[0]) {
+ # gen num to choose char for $blend
+ $blend = $blend . $spices[irand(@spices)]};
+
+ return ($blend); }
+
+1;
\ No newline at end of file
diff --git a/lib/CharmBoard/Schema/Result/Categories.pm b/lib/CharmBoard/Schema/Result/Categories.pm
index 894e43f..e39134a 100644
--- a/lib/CharmBoard/Schema/Result/Categories.pm
+++ b/lib/CharmBoard/Schema/Result/Categories.pm
@@ -6,12 +6,10 @@ __PACKAGE__->add_columns(
cat_id => {
data_type => 'integer',
is_auto_increment => 1,
- is_nullable => 0,
- },
+ is_nullable => 0, },
cat_name => {
data_type => 'text',
- is_nullable => 0,
- });
+ is_nullable => 0, });
__PACKAGE__->set_primary_key('cat_id');
1
\ No newline at end of file
diff --git a/lib/CharmBoard/Schema/Result/Posts.pm b/lib/CharmBoard/Schema/Result/Posts.pm
index 47a6143..e74a958 100644
--- a/lib/CharmBoard/Schema/Result/Posts.pm
+++ b/lib/CharmBoard/Schema/Result/Posts.pm
@@ -6,33 +6,27 @@ __PACKAGE__->add_columns(
post_id => {
data_type => 'integer',
is_auto_increment => 1,
- is_nullable => 0,
- },
+ is_nullable => 0, },
user_id => {
data_type => 'integer',
- is_auto_increment => 1,
- is_nullable => 0,
- },
+ is_auto_increment => 0,
+ is_nullable => 0, },
thread_id => {
data_type => 'integer',
is_auto_increment => 1,
- is_nullable => 0,
- },
+ is_nullable => 0, },
post_date => {
data_type => 'integer',
- is_auto_increment => 1,
- is_nullable => 0,
- });
+ is_auto_increment => 0,
+ is_nullable => 0, });
__PACKAGE__->set_primary_key('post_id');
__PACKAGE__->belongs_to(
user_id =>
'CharmBoard::Schema::Result::Users',
- 'user_id'
-);
+ 'user_id' );
__PACKAGE__->belongs_to(
thread_id =>
'CharmBoard::Schema::Result::Threads',
- 'thread_id'
-);
+ 'thread_id' );
1
\ No newline at end of file
diff --git a/lib/CharmBoard/Schema/Result/Session.pm b/lib/CharmBoard/Schema/Result/Session.pm
index 77adedb..8361c6e 100644
--- a/lib/CharmBoard/Schema/Result/Session.pm
+++ b/lib/CharmBoard/Schema/Result/Session.pm
@@ -1,25 +1,32 @@
package CharmBoard::Schema::Result::Session;
use base qw(DBIx::Class::Core);
-__PACKAGE__->table('session');
+__PACKAGE__->table('sessions');
__PACKAGE__->add_columns(
user_id => {
- data_type => 'integer',
- is_nullable => 0,
- },
- session_id => {
- data_type => 'text',
- is_nullable => 0,
- },
+ data_type => 'integer',
+ is_auto_increment => 0,
+ is_nullable => 0, },
+ session_key => {
+ data_type => 'text',
+ is_auto_increment => 0,
+ is_nullable => 0, },
session_expiry => {
- data_type => 'integer',
- is_nullable => 0,
- });
+ data_type => 'numeric',
+ is_auto_increment => 0,
+ is_nullable => 0, },
+ is_ip_bound => {
+ data_type => 'integer',
+ is_auto_increment => 0,
+ is_nullable => 0, },
+ bound_ip => {
+ 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',
- 'user_id'
-);
+ 'user_id');
1
\ No newline at end of file
diff --git a/lib/CharmBoard/Schema/Result/Subforums.pm b/lib/CharmBoard/Schema/Result/Subforums.pm
index 182f4f1..167e4c4 100644
--- a/lib/CharmBoard/Schema/Result/Subforums.pm
+++ b/lib/CharmBoard/Schema/Result/Subforums.pm
@@ -6,25 +6,23 @@ __PACKAGE__->add_columns(
subf_id => {
data_type => 'integer',
is_auto_increment => 1,
- is_nullable => 0,
- },
+ is_nullable => 0, },
subf_cat => {
data_type => 'integer',
- is_nullable => 0,
- },
+ is_auto_increment => 0,
+ is_nullable => 0, },
subf_name => {
data_type => 'text',
- is_nullable => 0,
- },
+ is_auto_increment => 0,
+ is_nullable => 0, },
subf_desc => {
data_type => 'text',
- is_nullable => 1,
- });
+ is_auto_increment => 0,
+ is_nullable => 1, });
__PACKAGE__->set_primary_key('subf_id');
__PACKAGE__->belongs_to(
subf_cat =>
'CharmBoard::Schema::Result::Categories',
- {'foreign.cat_id' => 'self.subf_cat'}
-);
+ {'foreign.cat_id' => 'self.subf_cat'});
1
\ No newline at end of file
diff --git a/lib/CharmBoard/Schema/Result/Threads.pm b/lib/CharmBoard/Schema/Result/Threads.pm
index 9a577a3..8162eca 100644
--- a/lib/CharmBoard/Schema/Result/Threads.pm
+++ b/lib/CharmBoard/Schema/Result/Threads.pm
@@ -6,21 +6,17 @@ __PACKAGE__->add_columns(
thread_id => {
data_type => 'integer',
is_auto_increment => 1,
- is_nullable => 0,
- },
+ is_nullable => 0, },
thread_title => {
data_type => 'text',
- is_nullable => 0,
- },
+ is_nullable => 0, },
thread_subf => {
data_type => 'integer',
- is_nullable => 1,
- });
+ is_nullable => 1, });
__PACKAGE__->set_primary_key('thread_id');
__PACKAGE__->belongs_to(
thread_subf =>
'CharmBoard::Schema::Result::Subforums',
- {'foreign.subf_id' => 'self.thread_subf'}
-);
+ {'foreign.subf_id' => 'self.thread_subf'});
1
\ No newline at end of file
diff --git a/lib/CharmBoard/Schema/Result/Users.pm b/lib/CharmBoard/Schema/Result/Users.pm
index 35eb272..09c262a 100644
--- a/lib/CharmBoard/Schema/Result/Users.pm
+++ b/lib/CharmBoard/Schema/Result/Users.pm
@@ -7,28 +7,23 @@ __PACKAGE__->add_columns(
data_type => 'integer',
is_numeric => 1,
is_nullable => 0,
- is_auto_increment => 1
- },
+ is_auto_increment => 1, },
username => {
data_type => 'text',
- is_nullable => 0
- },
- email => {
- data_type => 'text'
- },
+ is_nullable => 0, },
+ email => {
+ data_type => 'text',
+ is_nullable => 0, },
password => {
data_type => 'text',
- is_nullable => 0
- },
+ is_nullable => 0, },
salt => {
data_type => 'text',
- is_nullable => 0
- },
+ is_nullable => 0, },
signup_date => {
- data_type => 'integer',
+ data_type => 'real',
is_numeric => 1,
- is_nullable => 0
- });
+ is_nullable => 0, });
__PACKAGE__->set_primary_key('user_id');
1
\ No newline at end of file
diff --git a/tools/pepper.pl b/tools/pepper.pl
deleted file mode 100755
index cf99325..0000000
--- a/tools/pepper.pl
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/usr/bin/env perl
-use warnings;
-use strict;
-use Math::Random::Secure qw( irand );
-
-my @chars = qw( 0 1 2 3 4 5 6 7 8 9
- 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 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 $pepper = '';
-while ( length($pepper) < 25 ) {
- # gen and discard numbers to flush out dupe chance
- irand(255); irand(255); irand(255); irand(255);
- irand(255); irand(255); irand(255); irand(255);
- # gen num for pepper
- $pepper = $pepper . $chars[irand(@chars)];
-}
-
-print("Your pepper value is:\n");
-print($pepper);
\ No newline at end of file