Big Bang
This commit is contained in:
352
app/controllers/Auth.controller.js
Normal file
352
app/controllers/Auth.controller.js
Normal file
@@ -0,0 +1,352 @@
|
||||
/**
|
||||
* @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
|
||||
24
app/controllers/Home.controller.js
Normal file
24
app/controllers/Home.controller.js
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Home Controller
|
||||
* -------------------------------------------------------------
|
||||
* Controller for the main homepage of this Flitter app. Methods here
|
||||
* are used as handlers for routes specified in the route files.
|
||||
*/
|
||||
class Home {
|
||||
|
||||
/*
|
||||
* Serve the main welcome page.
|
||||
*/
|
||||
welcome(req, res){
|
||||
|
||||
/*
|
||||
* Return the welcome view.
|
||||
* It must be passed the response.
|
||||
* View parameters can be passed as an optional third
|
||||
* argument to the view() method.
|
||||
*/
|
||||
return _flitter.view(res, 'welcome')
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Home
|
||||
58
app/controllers/api/v1.controller.js
Normal file
58
app/controllers/api/v1.controller.js
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* v1 Controller
|
||||
* -------------------------------------------------------------
|
||||
* Put some description here!
|
||||
*/
|
||||
const Out = _flitter.model('v1:Out')
|
||||
const Project = _flitter.model('v1:Project')
|
||||
class v1 {
|
||||
|
||||
/*
|
||||
* Serve the main page.
|
||||
*/
|
||||
main(req, res){
|
||||
|
||||
/*
|
||||
* Return the main view.
|
||||
* It must be passed the response.
|
||||
* View parameters can be passed as an optional third
|
||||
* argument to the view() method.
|
||||
*/
|
||||
return view(res, 'view_name')
|
||||
}
|
||||
|
||||
async new_out( req, res, next ){
|
||||
console.log(req.body)
|
||||
const project = await Project.findOne({ uuid: req.params.key })
|
||||
|
||||
if ( !project ){
|
||||
return res.status(404).send({
|
||||
success: false,
|
||||
error: 'Project not found with specified key.'
|
||||
})
|
||||
}
|
||||
|
||||
if ( !req.body.data ){
|
||||
return res.status(400).send({
|
||||
success: false,
|
||||
error: 'Missing data.'
|
||||
})
|
||||
}
|
||||
|
||||
const data = JSON.parse(req.body.data)
|
||||
|
||||
const out = new Out({
|
||||
brief: data.brief,
|
||||
data: JSON.stringify(data.data),
|
||||
project_id: project.id
|
||||
})
|
||||
|
||||
await out.save()
|
||||
|
||||
return res.send({
|
||||
success: true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = exports = v1
|
||||
73
app/controllers/dash/v1.controller.js
Normal file
73
app/controllers/dash/v1.controller.js
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* v1 Controller
|
||||
* -------------------------------------------------------------
|
||||
* Put some description here!
|
||||
*/
|
||||
const Project = _flitter.model('v1:Project')
|
||||
const Out = _flitter.model('v1:Out')
|
||||
class v1 {
|
||||
|
||||
/*
|
||||
* Serve the main page.
|
||||
*/
|
||||
async main(req, res){
|
||||
|
||||
const projects = await Project.find({ archived: false, user_id: req.session.auth.uuid })
|
||||
|
||||
/*
|
||||
* Return the main view.
|
||||
* It must be passed the response.
|
||||
* View parameters can be passed as an optional third
|
||||
* argument to the view() method.
|
||||
*/
|
||||
return _flitter.view(res, 'dash_v1:main', { projects })
|
||||
}
|
||||
|
||||
new_project_show(req, res, next){
|
||||
return _flitter.view(res, 'dash_v1:project', {})
|
||||
}
|
||||
|
||||
async new_project_do(req, res, next){
|
||||
if ( !req.body.name ){
|
||||
return view(res, 'dash_v1:project', {errors: ['Project name is required.']})
|
||||
}
|
||||
|
||||
const project = new Project({
|
||||
name: req.body.name,
|
||||
user_id: req.session.auth.uuid,
|
||||
data: JSON.stringify({
|
||||
created: Date.now(),
|
||||
modified: Date.now()
|
||||
}),
|
||||
shared_user_ids: [],
|
||||
})
|
||||
|
||||
await project.save()
|
||||
|
||||
return res.redirect('/dash/v1')
|
||||
}
|
||||
|
||||
async project_view(req, res, next){
|
||||
const project = await Project.findById(req.params.id)
|
||||
const outs = await Out.find({ project_id: project.id }).sort('-created')
|
||||
|
||||
if ( !project ){
|
||||
_flitter.error(res, 404, 'Project not found.')
|
||||
}
|
||||
|
||||
return _flitter.view(res, 'dash_v1:view', { project, outs })
|
||||
}
|
||||
|
||||
async out_view(req, res, next){
|
||||
const out = await Out.findById(req.params.id)
|
||||
|
||||
console.log(out.data)
|
||||
|
||||
const pretty = JSON.stringify(JSON.parse(out.data), null, 4)
|
||||
|
||||
// TODO permission access check
|
||||
return _flitter.view(res, 'dash_v1:out', {out, prettyd:pretty});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = exports = v1
|
||||
Reference in New Issue
Block a user