Set up basic registration (but not login, yet)
This commit is contained in:
parent
7c78886191
commit
744c916fde
|
@ -0,0 +1,9 @@
|
||||||
|
# CharmBoard-specific
|
||||||
|
charmboard.conf
|
||||||
|
|
||||||
|
# Mojolicious examples to be nuked later
|
||||||
|
t/basic.t
|
||||||
|
|
||||||
|
# SQLite
|
||||||
|
*.db
|
||||||
|
*.db-*
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"cSpell.enableFiletypes": [
|
||||||
|
"mojolicious",
|
||||||
|
"perl"
|
||||||
|
],
|
||||||
|
"cSpell.words": [
|
||||||
|
"Acmlm",
|
||||||
|
"Authen",
|
||||||
|
"CharmBoard",
|
||||||
|
"Facepunch",
|
||||||
|
"pgsql",
|
||||||
|
"resultset",
|
||||||
|
"signup"
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
# CharmBoard installation instructions
|
||||||
|
|
||||||
|
Please keep in mind that CharmBoard is alpha software, and as such should not be used in a production environment and will likely be unstable or insecure.
|
||||||
|
|
||||||
|
## Preparation
|
||||||
|
|
||||||
|
### Database types
|
||||||
|
|
||||||
|
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.)<br />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.<br />Harder to set up than SQLite as it requires the separate database server software to be set up alongside CharmBoard. |
|
||||||
|
|
||||||
|
### Installing dependencies
|
||||||
|
|
||||||
|
(filler filler filler)
|
||||||
|
|
||||||
|
**NOTE:** If you use a RHEL-related Linux distro (RHEL, Rocky Linux, Fedora, et al) you might need to install `DBIx::Class` using either `yum` or `dnf` instead of with `cpan`, or it may not be recognized by your Perl install. The package name is `perl-DBIx-Class`.
|
14
README.md
14
README.md
|
@ -1,2 +1,16 @@
|
||||||
# CharmBoard
|
# 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.
|
||||||
|
|
||||||
|
## 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`
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Please see `INSTALLING.md`
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
boardName => '', # this doesn't do anything yet
|
||||||
|
|
||||||
|
database => {
|
||||||
|
type => '', # 'sqlite', 'mysql', or 'pgsql'
|
||||||
|
name => '',
|
||||||
|
user => '',
|
||||||
|
pass => ''
|
||||||
|
},
|
||||||
|
|
||||||
|
passCrypt => {
|
||||||
|
pepper => '' # generate this with `tools/pepper.pl` for now
|
||||||
|
},
|
||||||
|
|
||||||
|
secrets => ['']
|
||||||
|
};
|
|
@ -0,0 +1,48 @@
|
||||||
|
--
|
||||||
|
-- File generated with SQLiteStudio v3.4.4 on Fri. May 5 22:21:17 2023
|
||||||
|
--
|
||||||
|
-- Text encoding used: UTF-8
|
||||||
|
--
|
||||||
|
PRAGMA foreign_keys = off;
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
-- Table: categories
|
||||||
|
DROP TABLE IF EXISTS categories;
|
||||||
|
CREATE TABLE IF NOT EXISTS "categories" (
|
||||||
|
"cat_id" INTEGER NOT NULL UNIQUE,
|
||||||
|
"cat_name" TEXT,
|
||||||
|
"cat_desc" 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")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 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: threads
|
||||||
|
DROP TABLE IF EXISTS threads;
|
||||||
|
CREATE TABLE IF NOT EXISTS threads (thread_id INTEGER NOT NULL, thread_title TEXT NOT NULL, thread_cat 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);
|
||||||
|
|
||||||
|
COMMIT TRANSACTION;
|
||||||
|
PRAGMA foreign_keys = on;
|
|
@ -0,0 +1,86 @@
|
||||||
|
package CharmBoard;
|
||||||
|
use experimental 'smartmatch';
|
||||||
|
use Mojo::Base 'Mojolicious', -signatures;
|
||||||
|
use CharmBoard::Schema;
|
||||||
|
|
||||||
|
# This method will run once at server start
|
||||||
|
sub startup ($app) {
|
||||||
|
|
||||||
|
$app = shift;
|
||||||
|
|
||||||
|
$app->plugin('TagHelpers');
|
||||||
|
$app->plugin('Renderer::WithoutCache'); # for dev env only
|
||||||
|
|
||||||
|
$app->renderer->cache->max_keys(0); # for dev env only
|
||||||
|
|
||||||
|
$app->defaults(layout => 'default');
|
||||||
|
|
||||||
|
# Load configuration from config file
|
||||||
|
my $config = $app->plugin('Config' => {
|
||||||
|
file => 'charmboard.conf'
|
||||||
|
});
|
||||||
|
|
||||||
|
# Configure the application
|
||||||
|
## Import Mojolicious secrets (cookie encryption)
|
||||||
|
$app->secrets($config->{secrets});
|
||||||
|
## Import password pepper value
|
||||||
|
my $pepper = $config->{passCrypt}->{pepper};
|
||||||
|
$app->helper( pepper => sub { $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') {
|
||||||
|
$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.
|
||||||
|
If you're sure you've set it to something supported, maybe double check your spelling?\n
|
||||||
|
Valid options: 'sqlite', 'mysql'"
|
||||||
|
};
|
||||||
|
|
||||||
|
my $schema = CharmBoard::Schema->connect(
|
||||||
|
$dsn,
|
||||||
|
$config->{database}->{user},
|
||||||
|
$config->{database}->{pass},
|
||||||
|
{
|
||||||
|
$dbUnicode => 1
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$app->helper( schema => sub { $schema } );
|
||||||
|
|
||||||
|
# Router
|
||||||
|
my $r = $app->routes;
|
||||||
|
|
||||||
|
# Controller routes
|
||||||
|
## Index page
|
||||||
|
$r->get('/')->to(
|
||||||
|
controller => 'Controller::Main',
|
||||||
|
action => 'index'
|
||||||
|
);
|
||||||
|
## Registration page
|
||||||
|
$r->get('/register')->to(
|
||||||
|
controller => 'Controller::Auth',
|
||||||
|
action => 'register'
|
||||||
|
);
|
||||||
|
$r->post('/register')->to(
|
||||||
|
controller => 'Controller::Auth',
|
||||||
|
action => 'registration_do'
|
||||||
|
);
|
||||||
|
## Login page
|
||||||
|
$r->get('/login')->to(
|
||||||
|
controller => 'Controller::Auth',
|
||||||
|
action => 'login'
|
||||||
|
);
|
||||||
|
$r->post('/login')->to(
|
||||||
|
controller => 'Controller::Auth',
|
||||||
|
action => 'login_do'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
|
@ -0,0 +1,73 @@
|
||||||
|
package CharmBoard::Controller::Auth;
|
||||||
|
use Mojo::Base 'Mojolicious::Controller', -signatures;
|
||||||
|
use CharmBoard::Crypt::Password;
|
||||||
|
|
||||||
|
# initial registration page
|
||||||
|
sub register ($app) {
|
||||||
|
$app->render(
|
||||||
|
template => 'register',
|
||||||
|
error => $app->flash('error'),
|
||||||
|
message => $app->flash('message')
|
||||||
|
)};
|
||||||
|
|
||||||
|
# process submitted registration form
|
||||||
|
sub registration_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');
|
||||||
|
};
|
||||||
|
|
||||||
|
# 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');
|
||||||
|
};
|
||||||
|
|
||||||
|
# check to make sure username and/or email isn't already in use;
|
||||||
|
# if not, continue with registration
|
||||||
|
my $userCheck = $app->schema->resultset('User')->search({username => $username})->single;
|
||||||
|
my $emailCheck = $app->schema->resultset('User')->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 {
|
||||||
|
$password = $app->pepper . ':' . $password;
|
||||||
|
my ($hash, $salt) = pass_gen($password);
|
||||||
|
$app->schema->resultset('User')->create({
|
||||||
|
username => $username,
|
||||||
|
email => $email,
|
||||||
|
password => $hash,
|
||||||
|
salt => $salt,
|
||||||
|
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')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
|
@ -0,0 +1,8 @@
|
||||||
|
package CharmBoard::Controller::Main;
|
||||||
|
use Mojo::Base 'Mojolicious::Controller', -signatures;
|
||||||
|
|
||||||
|
sub index ($app) {
|
||||||
|
$app->render(template => 'index');
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
|
@ -0,0 +1,21 @@
|
||||||
|
package CharmBoard::Crypt::Password;
|
||||||
|
use Authen::Passphrase::Argon2;
|
||||||
|
|
||||||
|
use Exporter qw(import);
|
||||||
|
|
||||||
|
our @EXPORT = qw/ pass_gen /;
|
||||||
|
|
||||||
|
sub pass_gen ($) {
|
||||||
|
my $argon2 = Authen::Passphrase::Argon2->new(
|
||||||
|
salt_random => 1,
|
||||||
|
passphrase => $_[0],
|
||||||
|
cost => 3,
|
||||||
|
factor => '16M',
|
||||||
|
parallelism => 1,
|
||||||
|
size => 32
|
||||||
|
);
|
||||||
|
|
||||||
|
return ($argon2->salt_hex, $argon2->as_hex);
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
|
@ -0,0 +1,6 @@
|
||||||
|
package CharmBoard::Schema;
|
||||||
|
use base qw/DBIx::Class::Schema/;
|
||||||
|
|
||||||
|
__PACKAGE__->load_namespaces();
|
||||||
|
|
||||||
|
1;
|
|
@ -0,0 +1,21 @@
|
||||||
|
package CharmBoard::Schema::Result::Categories;
|
||||||
|
use base qw/DBIx::Class::Core/;
|
||||||
|
|
||||||
|
__PACKAGE__->table('categories');
|
||||||
|
__PACKAGE__->add_columns(
|
||||||
|
cat_id => {
|
||||||
|
data_type => 'integer',
|
||||||
|
is_auto_increment => 1,
|
||||||
|
is_nullable => 1
|
||||||
|
},
|
||||||
|
cat_name => {
|
||||||
|
data_type => 'text',
|
||||||
|
is_nullable => 0
|
||||||
|
},
|
||||||
|
cat_desc => {
|
||||||
|
data_type => 'text',
|
||||||
|
is_nullable => 1
|
||||||
|
});
|
||||||
|
__PACKAGE__->set_primary_key('cat_id');
|
||||||
|
|
||||||
|
1
|
|
@ -0,0 +1,28 @@
|
||||||
|
package CharmBoard::Schema::Result::Posts;
|
||||||
|
use base qw/DBIx::Class::Core/;
|
||||||
|
|
||||||
|
__PACKAGE__->table('posts');
|
||||||
|
__PACKAGE__->add_columns(
|
||||||
|
post_id => {
|
||||||
|
data_type => 'integer',
|
||||||
|
is_auto_increment => 1,
|
||||||
|
is_nullable => 0
|
||||||
|
},
|
||||||
|
user_id => {
|
||||||
|
data_type => 'integer',
|
||||||
|
is_auto_increment => 1,
|
||||||
|
is_nullable => 0
|
||||||
|
},
|
||||||
|
thread_id => {
|
||||||
|
data_type => 'integer',
|
||||||
|
is_auto_increment => 1,
|
||||||
|
is_nullable => 0
|
||||||
|
},
|
||||||
|
post_date => {
|
||||||
|
data_type => 'integer',
|
||||||
|
is_auto_increment => 1,
|
||||||
|
is_nullable => 0
|
||||||
|
});
|
||||||
|
__PACKAGE__->set_primary_key('post_id');
|
||||||
|
|
||||||
|
1
|
|
@ -0,0 +1,20 @@
|
||||||
|
package CharmBoard::Schema::Result::Session;
|
||||||
|
use base qw/DBIx::Class::Core/;
|
||||||
|
|
||||||
|
__PACKAGE__->table('session');
|
||||||
|
__PACKAGE__->add_columns(
|
||||||
|
user_id => {
|
||||||
|
data_type => 'integer',
|
||||||
|
is_nullable => 0,
|
||||||
|
},
|
||||||
|
session_id => {
|
||||||
|
data_type => 'text',
|
||||||
|
is_nullable => 0
|
||||||
|
},
|
||||||
|
session_expiry => {
|
||||||
|
data_type => 'integer',
|
||||||
|
is_nullable => 0
|
||||||
|
});
|
||||||
|
__PACKAGE__->set_primary_key('user_id');
|
||||||
|
|
||||||
|
1
|
|
@ -0,0 +1,21 @@
|
||||||
|
package CharmBoard::Schema::Result::Threads;
|
||||||
|
use base qw/DBIx::Class::Core/;
|
||||||
|
|
||||||
|
__PACKAGE__->table('threads');
|
||||||
|
__PACKAGE__->add_columns(
|
||||||
|
thread_id => {
|
||||||
|
data_type => 'integer',
|
||||||
|
is_auto_increment => 1,
|
||||||
|
is_nullable => 0
|
||||||
|
},
|
||||||
|
thread_title => {
|
||||||
|
data_type => 'text',
|
||||||
|
is_nullable => 0
|
||||||
|
},
|
||||||
|
thread_cat => {
|
||||||
|
data_type => 'integer',
|
||||||
|
is_nullable => 1
|
||||||
|
});
|
||||||
|
__PACKAGE__->set_primary_key('thread_id');
|
||||||
|
|
||||||
|
1
|
|
@ -0,0 +1,34 @@
|
||||||
|
package CharmBoard::Schema::Result::User;
|
||||||
|
use base qw/DBIx::Class::Core/;
|
||||||
|
|
||||||
|
__PACKAGE__->table('users');
|
||||||
|
__PACKAGE__->add_columns(
|
||||||
|
user_id => {
|
||||||
|
data_type => 'integer',
|
||||||
|
is_numeric => 1,
|
||||||
|
is_nullable => 0,
|
||||||
|
is_auto_increment => 1
|
||||||
|
},
|
||||||
|
username => {
|
||||||
|
data_type => 'text',
|
||||||
|
is_nullable => 0
|
||||||
|
},
|
||||||
|
email => {
|
||||||
|
data_type => 'text'
|
||||||
|
},
|
||||||
|
password => {
|
||||||
|
data_type => 'text',
|
||||||
|
is_nullable => 0
|
||||||
|
},
|
||||||
|
salt => {
|
||||||
|
data_type => 'text',
|
||||||
|
is_nullable => 0
|
||||||
|
},
|
||||||
|
signup_date => {
|
||||||
|
data_type => 'integer',
|
||||||
|
is_numeric => 1,
|
||||||
|
is_nullable => 0
|
||||||
|
});
|
||||||
|
__PACKAGE__->set_primary_key('user_id');
|
||||||
|
|
||||||
|
1
|
|
@ -0,0 +1,13 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use utf8;
|
||||||
|
use experimental 'smartmatch';
|
||||||
|
|
||||||
|
use Mojo::File qw(curfile);
|
||||||
|
use lib curfile->dirname->sibling('lib')->to_string;
|
||||||
|
use Mojolicious::Commands;
|
||||||
|
|
||||||
|
# Start command line interface for application
|
||||||
|
Mojolicious::Commands->start_app('CharmBoard');
|
|
@ -0,0 +1,3 @@
|
||||||
|
% layout 'default', title => 'CharmBoard';
|
||||||
|
|
||||||
|
index page
|
|
@ -0,0 +1,2 @@
|
||||||
|
<hr />
|
||||||
|
<i>footer placeholder</i>
|
|
@ -0,0 +1,2 @@
|
||||||
|
<a href="/"><h2>CharmBoard</h2></a>
|
||||||
|
<a href="/login">login</a> | <a href="/register">register</a><br /><br />
|
|
@ -0,0 +1,12 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title><%= title %></title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
%= include 'layouts/_header'
|
||||||
|
<%= content %>
|
||||||
|
%= include 'layouts/_footer'
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,19 @@
|
||||||
|
% layout 'default', title => 'CharmBoard - Login';
|
||||||
|
% if ($error) {
|
||||||
|
<p style="color: red"><%= $error %></p>
|
||||||
|
%};
|
||||||
|
% if ($message) {
|
||||||
|
<p style="color: blue"><%= $message %></p>
|
||||||
|
%};
|
||||||
|
<form method="post" action='/login'>
|
||||||
|
username: <input
|
||||||
|
id="username"
|
||||||
|
name="username"
|
||||||
|
/><br />
|
||||||
|
password: <input
|
||||||
|
id="password"
|
||||||
|
name="password"
|
||||||
|
type="password"
|
||||||
|
/><br />
|
||||||
|
<input type="submit" value="login" />
|
||||||
|
</form>
|
|
@ -0,0 +1,30 @@
|
||||||
|
% layout 'default', title => 'CharmBoard - Registration';
|
||||||
|
% if ($error) {
|
||||||
|
<p style="color: red"><%= $error %></p>
|
||||||
|
%};
|
||||||
|
% if ($message) {
|
||||||
|
<p style="color: blue"><%= $message %></p>
|
||||||
|
%};
|
||||||
|
<p>fields marked with <span style="color: red">*</span> are required</p>
|
||||||
|
<form method="post" action='/register'>
|
||||||
|
username: <input
|
||||||
|
id="username"
|
||||||
|
name="username"
|
||||||
|
/><span style="color: red"> *</span><br />
|
||||||
|
email: <input
|
||||||
|
id="email"
|
||||||
|
name="email"
|
||||||
|
type="email"
|
||||||
|
/><span style="color: red"> *</span><br />
|
||||||
|
password: <input
|
||||||
|
id="password"
|
||||||
|
name="password"
|
||||||
|
type="password"
|
||||||
|
/><span style="color: red"> *</span><br />
|
||||||
|
confirm password: <input
|
||||||
|
id="confirm-password"
|
||||||
|
name="confirm-password"
|
||||||
|
type="password"
|
||||||
|
/><span style="color: red"> *</span><br />
|
||||||
|
<input type="submit" value="register account" />
|
||||||
|
</form>
|
|
@ -0,0 +1,25 @@
|
||||||
|
#!/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);
|
Loading…
Reference in New Issue