Skip to content

Instantly share code, notes, and snippets.

@jberger
Last active August 29, 2015 02:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jberger/2d77bdf4dbb239eafc20 to your computer and use it in GitHub Desktop.
Save jberger/2d77bdf4dbb239eafc20 to your computer and use it in GitHub Desktop.
use Mojolicious::Lite;
use DBM::Deep;
use Mojo::JWT;
plugin 'Bcrypt';
plugin 'Minion' => {File => 'minion.db'};
app->minion->add_task(send_email => sub {
my ($job, $address, $subject, $body) = @_;
require Email::Sender::Simple;
require Email::Simple;
require Email::Sender::Transport::Print;
my $email = Email::Simple->create(
header => [
To => $address,
From => 'me@nobody.com',
Subject => $subject,
],
body => $body,
);
my $transport = Email::Sender::Transport::Print->new;
Email::Sender::Simple->send($email, {transport => $transport});
});
helper email => sub { shift->minion->enqueue(send_email => [@_]) };
helper jwt => sub { Mojo::JWT->new(secret => shift->app->secrets->[0] || die) };
helper to_index => sub {
my ($c, $msg) = @_;
$c->flash(message => $msg) if $msg;
$c->redirect_to('index');
};
helper users => sub { DBM::Deep->new('users.db') };
any '/' => sub {
my $c = shift;
$c->render('logged_in') if $c->session('username');
} => 'index';
any '/logout' => sub { shift->session(expires => 1)->to_index };
post '/sign_in' => sub {
my $c = shift;
my $username = $c->param('username');
return $c->to_index("Username $username not found")
unless my $user = $c->users->{$username};
return $c->to_index("Username $username has not been confirmed")
unless $user->{confirmed};
return $c->to_index('Password not correct')
unless $c->bcrypt_validate($c->param('password'), $user->{password});
$c->session(username => $username)->to_index;
};
post '/sign_up' => sub {
my $c = shift;
my $username = $c->param('username');
return $c->to_index("Username $username is taken")
if $c->users->{$username};
return $c->to_index('Password cannot be blank')
unless my $password = $c->param('password');
return $c->to_index('Email cannot be blank')
unless my $email = $c->param('email');
$c->users->{$username} = {
email => $email,
password => $c->bcrypt($password),
confirmed => 0,
};
my $jwt = $c->jwt->claims({username => $username})->encode;
my $url = $c->url_for('confirm')->to_abs->query(jwt => $jwt);
$c->email($email, 'Confirm registration', "Please visit $url to confirm");
$c->to_index('registration complete, please confirm via email');
};
post '/forgot' => sub {
my $c = shift;
my $username = $c->param('username');
return $c->to_index("Username $username not found")
unless my $user = $c->users->{$username};
return $c->to_index("User $username has no email listed")
unless my $email = $user->{email};
my $jwt = $c->jwt->claims({username => $username})->encode;
my $url = $c->url_for('reset')->to_abs->query(jwt => $jwt);
$c->email($email, 'Password reset', "Please visit $url to reset password");
$c->to_index('password reset email sent, please follow email instructions');
};
get '/confirm' => sub {
my $c = shift;
my $username = $c->jwt->decode($c->param('jwt'))->{username};
$c->users->{$username}{confirmed} = 1;
$c->to_index('registration confirmed, please log in');
};
any '/reset' => sub {
my $c = shift;
my $username = $c->jwt->decode($c->param('jwt'))->{username};
return $c->render('reset', username => $username)
if $c->req->method eq 'GET';
return $c->to_index("Username $username not found")
unless my $user = $c->users->{$username};
return $c->to_index('Password cannot be blank')
unless my $password = $c->param('password');
$user->{password} = $c->bcrypt($password);
$c->to_index('password changed successfully, please login');
};
app->start;
__DATA__
@@ index.html.ep
<p>Hello Guest!</p>
<p><%= flash('message') || 'Sign in or sign up!' %></p>
%= form_for sign_in => begin
%= label_for username => 'Username'
%= text_field 'username'
%= label_for password => 'Password'
%= password_field 'password'
%= label_for email => 'Email'
%= email_field 'email', placeholder => 'new acct only'
<br>
%= submit_button 'Sign In'
%= submit_button 'Sign Up', formaction => url_for('sign_up')
%= submit_button 'Forgot Password', formaction => url_for('forgot')
% end
@@ logged_in.html.ep
<p>Welcome back <%= session 'username' %>!</p>
<p><%= link_to 'Log out' => 'logout' %>
@@ reset.html.ep
%= form_for reset => method => POST => begin
%= label_for password => "Reset password for $username"
%= password_field 'password'
%= hidden_field jwt => param 'jwt';
%= submit_button 'Change';
% end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment