const low = require('lowdb') const FileSync = require('lowdb/adapters/FileSync'); const adapter = new FileSync('./appdata/users.json'); const db = low(adapter); db.defaults( { users: [] } ).write(); /************************* * Authentication module ************************/ var bcrypt = require('bcrypt'); const saltRounds = 10; var jwt = require('jsonwebtoken'); const JWT_EXPIRATION = (60 * 60); // one hour const { uuid } = require('uuidv4'); const SERVER_SECRET = uuid(); exports.passport = require('passport'); var BasicStrategy = require('passport-http').BasicStrategy; /*************************************** * Register user with hashed password **************************************/ exports.registerUser = function(req, res) { console.log('got here'); var userid = req.body.userid; var username = req.body.username; var plaintextPassword = req.body.password; bcrypt.hash(plaintextPassword, saltRounds) .then(function(hash) { // check if user exists if (db.get('users').find({uid: userid}).value()) { // user id is taken! res.status(409).send('UID is already taken!'); } else if (db.get('users').find({name: username}).value()) { // user name is taken! res.status(409).send('User name is already taken!'); } else { // add to db db.get('users').push({ name: username, uid: userid, passhash: hash }).write(); } }) .then(function(result) { res.send('registered'); }) .catch(function(err) { if( err.code == 'ER_DUP_ENTRY' ) { res.status(409).send('UserId already taken'); } else { console.log('failed TO register User'); // res.writeHead(500, {'Content-Type':'text/plain'}); res.end(err); } }); } /*************************************** * Login methods **************************************/ /************************************************* * This gets called when passport.authenticate() * gets called. * * This checks that the credentials are valid. * If so, passes the user info to the next middleware. ************************************************/ exports.passport.use(new BasicStrategy( function(userid, plainTextPassword, done) { // console.log('BasicStrategy: verifying credentials'); const user = db.get('users').find({uid: userid}).value(); if (user) { var hashedPwd = user.passhash; return bcrypt.compare(plainTextPassword, hashedPwd); } else { return false; } } )); /************************************************************* * This is a wrapper for auth.passport.authenticate(). * We use this to change WWW-Authenticate header so * the browser doesn't pop-up challenge dialog box by default. * Browser's will pop-up up dialog when status is 401 and * "WWW-Authenticate:Basic..." *************************************************************/ exports.authenticateViaPassport = function(req, res, next) { exports.passport.authenticate('basic',{session:false}, function(err, user, info) { if(!user){ res.set('WWW-Authenticate', 'x'+info); // change to xBasic res.status(401).send('Invalid Authentication'); } else { req.user = user; next(); } } )(req, res, next); }; /********************************** * Generating/Signing a JWT token * And attaches the user info into * the payload to be sent on every * request. *********************************/ exports.generateJWT = function(req, res, next) { var payload = { exp: Math.floor(Date.now() / 1000) + JWT_EXPIRATION , user: req.user, // , role: role }; req.token = jwt.sign(payload, SERVER_SECRET); next(); } exports.returnAuthResponse = function(req, res) { res.status(200).json({ user: req.user, token: req.token }); } /*************************************** * Authorization: middleware that checks the * JWT token for validity before allowing * the user to access anything. * * It also passes the user object to the next * middleware through res.locals **************************************/ exports.ensureAuthenticatedElseError = function(req, res, next) { var token = getToken(req.query); if( token ) { try { var payload = jwt.verify(token, SERVER_SECRET); // console.log('payload: ' + JSON.stringify(payload)); // check if user still exists in database if you'd like res.locals.user = payload.user; next(); } catch(err) { res.status(401).send('Invalid Authentication'); } } else { res.status(401).send('Missing Authorization header'); } } function getToken(queryParams) { if (queryParams && queryParams.jwt) { var parted = queryParams.jwt.split(' '); if (parted.length === 2) { return parted[1]; } else { return null; } } else { return null; } };