352 lines
11 KiB
JavaScript
352 lines
11 KiB
JavaScript
/**
|
|
* @module flitter-auth/deploy/controllers/Auth
|
|
*/
|
|
|
|
const validator = require('validator')
|
|
const bcrypt = require('bcrypt')
|
|
const uuid = require('uuid/v4')
|
|
|
|
/**
|
|
* Controller for the auth and user functionality for Flitter-auth.
|
|
* @class
|
|
*/
|
|
class Auth {
|
|
|
|
/**
|
|
* Create an authenticated session.
|
|
* @param {Express/Request} req - the incoming Express request
|
|
* @param {module:flitter-auth/deploy/models/User~User} user - the user for which a session should be created
|
|
*/
|
|
create_auth_session(req, user){
|
|
req.session.auth = {
|
|
authenticated: true,
|
|
uuid: user.uuid,
|
|
user
|
|
}
|
|
|
|
req.session.auth.user.password = ""
|
|
}
|
|
|
|
/**
|
|
* Destroy the authenticated session.
|
|
* @param {Express/Request} req - the incoming Express request
|
|
*/
|
|
destroy_auth_session(req){
|
|
req.session.auth = {}
|
|
}
|
|
|
|
/**
|
|
* Serve the registration page.
|
|
* @param {Express/Request} req - the incoming Express request
|
|
* @param {Express/Response} res - the corresponding Express response
|
|
*/
|
|
register_get(req, res){
|
|
|
|
/*
|
|
* Check for auth_form errors in the session.
|
|
* If they exist, pass them along to the view.
|
|
*/
|
|
let submission_data = { error: false, data: {} }
|
|
if ( req.session && 'auth_form' in req.session && 'errors' in req.session.auth_form ){
|
|
submission_data = req.session.auth_form
|
|
delete req.session.auth_form
|
|
}
|
|
|
|
/*
|
|
* Return the registration view with the errors.
|
|
*/
|
|
_flitter.view(res, 'auth/register', { submission_data })
|
|
}
|
|
|
|
/**
|
|
* Handle the registration and create a new user.
|
|
* @param {Express/Request} req - the incoming Express request
|
|
* @param {Express/Response} res - the corresponding Express response
|
|
*/
|
|
register_post(req, res){
|
|
|
|
let username, password
|
|
|
|
/*
|
|
* Creates a session variable with the auth_form errors.
|
|
*/
|
|
const create_error_session = (field, message) => {
|
|
let auth_form = {
|
|
error: true,
|
|
errors: {
|
|
|
|
},
|
|
data: {
|
|
'username': req.body.username
|
|
}
|
|
}
|
|
|
|
auth_form.errors[field] = message
|
|
req.session.auth_form = auth_form
|
|
}
|
|
|
|
/*
|
|
* Fail if username isn't provided.
|
|
*/
|
|
if ( !( 'username' in req.body ) ){
|
|
req.session.auth_form = {
|
|
error: true,
|
|
errors: { 'username': 'Username is required.' }
|
|
}
|
|
|
|
return res.redirect('/auth/register')
|
|
}
|
|
|
|
/*
|
|
* Fail if the password or password verification aren't provided.
|
|
*/
|
|
if ( !( 'password' in req.body ) || !( 'password_verify' in req.body ) ){
|
|
req.session.auth_form = {
|
|
error: true,
|
|
errors: { 'password': 'Password and verification are required.' }
|
|
}
|
|
|
|
return res.redirect('/auth/register')
|
|
}
|
|
|
|
/*
|
|
* Validate that the username is alphanumeric.
|
|
*/
|
|
if ( !validator.isAlphanumeric( req.body.username ) ) {
|
|
|
|
/*
|
|
* Create an auth_form error in the session and
|
|
* redirect back to the registration form.
|
|
*/
|
|
create_error_session('username', 'Username must be alpha-numeric.')
|
|
return res.redirect('/auth/register')
|
|
}
|
|
|
|
/*
|
|
* Get the User model.
|
|
*/
|
|
const User = _flitter.model('User')
|
|
|
|
/*
|
|
* Check if the username is already in the
|
|
* database. If so, redirect with an error.
|
|
*/
|
|
User.find({ username: req.body.username }, (err, users) => {
|
|
if ( users.length ){
|
|
|
|
/*
|
|
* Create an auth_form error in the session and
|
|
* redirect back to the registration form.
|
|
*/
|
|
create_error_session('username', 'Username is already taken.')
|
|
return res.redirect('/auth/register')
|
|
}
|
|
username = req.body.username
|
|
|
|
/*
|
|
* Check if the password meets the minimum length requirement.
|
|
*/
|
|
if ( !validator.isLength(req.body.password, {min:8}) ){
|
|
|
|
/*
|
|
* Create an auth_form error in the session and
|
|
* redirect back to the registration form.
|
|
*/
|
|
create_error_session('password', 'Password must be at least 8 characters.')
|
|
return res.redirect('/auth/register')
|
|
}
|
|
|
|
/*
|
|
* Check that the password matches the password_verify field.
|
|
*/
|
|
if ( !validator.equals(req.body.password, req.body.password_verify) ){
|
|
|
|
/*
|
|
* Create an auth_form error in the session and
|
|
* redirect back to the registration form.
|
|
*/
|
|
create_error_session('password', 'Passwords don\'t match.')
|
|
return res.redirect('/auth/register')
|
|
}
|
|
password = req.body.password
|
|
|
|
/*
|
|
* Create the password hash.
|
|
*/
|
|
bcrypt.hash(password, 10, (err, hash) => {
|
|
/*
|
|
* Instantiate a new user object.
|
|
*/
|
|
const unique_id = uuid()
|
|
const user = new User({
|
|
username,
|
|
password: hash,
|
|
data: JSON.stringify({}),
|
|
uuid: unique_id
|
|
})
|
|
|
|
/*
|
|
* Store the new user in the database.
|
|
*/
|
|
user.save().then(()=>{
|
|
_flitter.controller('Auth').create_auth_session(req, user)
|
|
return _flitter.view(res, 'auth/register_success')
|
|
})
|
|
})
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Log the user out and destroy the authenticated session.
|
|
* @param {Express/Request} req - the incoming Express request
|
|
* @param {Express/Response} res - the corresponding Express response
|
|
*/
|
|
logout( req, res ){
|
|
if ( req.session ){
|
|
_flitter.controller('Auth').destroy_auth_session(req)
|
|
}
|
|
|
|
return _flitter.view(res, 'auth/logged_out')
|
|
}
|
|
|
|
/**
|
|
* Serve the login view.
|
|
* @param {Express/Request} req - the incoming Express request
|
|
* @param {Express/Response} res - the corresponding Express response
|
|
*/
|
|
login_get( req, res ){
|
|
|
|
/*
|
|
* Check for auth_form errors in the session.
|
|
* If they exist, pass them along to the view.
|
|
*/
|
|
let submission_data = { error: false, data: {} }
|
|
if ( req.session && 'auth_form' in req.session && 'errors' in req.session.auth_form ){
|
|
submission_data = req.session.auth_form
|
|
delete req.session.auth_form
|
|
}
|
|
|
|
/*
|
|
* Return the login view with the errors.
|
|
*/
|
|
return _flitter.view(res, 'auth/login', { submission_data })
|
|
}
|
|
|
|
/**
|
|
* Process a login request.
|
|
* If it is successful, create a user session and carry on.
|
|
* @param {Express/Request} req - the incoming Express request
|
|
* @param {Express/Response} res - the corresponding Express response
|
|
*/
|
|
login_post( req, res ){
|
|
const create_error_session = (field, message) => {
|
|
let auth_form = {
|
|
error: true,
|
|
errors: {
|
|
|
|
},
|
|
data: {
|
|
'username': req.body.username
|
|
}
|
|
}
|
|
|
|
auth_form.errors[field] = message
|
|
req.session.auth_form = auth_form
|
|
}
|
|
|
|
/*
|
|
* Fail if username isn't provided.
|
|
*/
|
|
if ( !( 'username' in req.body ) ){
|
|
req.session.auth_form = {
|
|
error: true,
|
|
errors: { 'username': 'Username is required.' }
|
|
}
|
|
|
|
return res.redirect('/auth/login')
|
|
}
|
|
|
|
/*
|
|
* Fail if the password isn't provided.
|
|
*/
|
|
if ( !( 'password' in req.body ) ){
|
|
req.session.auth_form = {
|
|
error: true,
|
|
errors: { 'password': 'Password is required.' }
|
|
}
|
|
|
|
return res.redirect('/auth/login')
|
|
}
|
|
|
|
/*
|
|
* Make sure the username is still alphanum.
|
|
* Just a sanity check to prevent code injection.
|
|
*/
|
|
if ( !validator.isAlphanumeric( req.body.username ) ){
|
|
create_error_session('username', "Invalid username.")
|
|
return res.redirect('/auth/login')
|
|
}
|
|
|
|
const User = _flitter.model('User')
|
|
User.findOne({username: req.body.username}, (err, user) => {
|
|
|
|
/*
|
|
* If no user with the username is found, return
|
|
* an error back.
|
|
*/
|
|
if ( !user ){
|
|
create_error_session('username', 'Invalid username.')
|
|
return res.redirect('/auth/login')
|
|
}
|
|
|
|
/*
|
|
* Check the provided password against the stored hash.
|
|
*/
|
|
bcrypt.compare( req.body.password, user.password, (err, match) => {
|
|
|
|
/*
|
|
* Return an error if the password fails the hash.
|
|
*/
|
|
if ( !match ){
|
|
create_error_session('password', 'Invalid password.')
|
|
return res.redirect('/auth/login')
|
|
}
|
|
else {
|
|
|
|
/*
|
|
* Create an authenticated session.
|
|
*/
|
|
_flitter.controller('Auth').create_auth_session(req, user)
|
|
|
|
/*
|
|
* If a destination was provided, redirect there.
|
|
*/
|
|
if ( req.session.destination ){
|
|
const redirect_to = req.session.destination
|
|
delete req.session.destination
|
|
return res.redirect(redirect_to)
|
|
}
|
|
|
|
/*
|
|
* Otherwise, redirect to the provided sample dash.
|
|
*/
|
|
else {
|
|
return res.redirect('/auth/dash')
|
|
}
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Return the dash view.
|
|
* By default, this is pretty simple. It's designed to be replaced by your app.
|
|
* @param {Express/Request} req - the incoming Express request
|
|
* @param {Express/Response} res - the corresponding Express response
|
|
*/
|
|
dash_get(req, res){
|
|
return _flitter.view(res, 'auth/dash', { user: req.session.auth.user })
|
|
}
|
|
}
|
|
|
|
module.exports = Auth |