var passport = require('passport'); var LocalStrategy = require('passport-local'); var crypto = require('crypto'); const router = require('express').Router() const config = require("../config.js"); const keys = require("../.Keys.js"); /* Configure password authentication strategy. * * The `LocalStrategy` authenticates users by verifying a username and password. * The strategy parses the username and password from the request and calls the * `verify` function. * * The `verify` function queries the database for the user record and verifies * the password by hashing the password supplied by the user and comparing it to * the hashed password stored in the database. If the comparison succeeds, the * user is authenticated; otherwise, not. */ const { UserDb }= require('../services/userDb'); passport.use(new LocalStrategy({ usernameField: 'email', passwordField: 'password' },async function verify(email, password, cb) { try { const userDb = await UserDb.init(); const user = await userDb.getByEmail(email); if (!user) { return cb(null, false, { message: 'Incorrect username or password.' }); } crypto.pbkdf2(password, user.salt, 310000, 32, 'sha256', async function(err, hashedPassword) { if (err) { return cb(err); } if (!crypto.timingSafeEqual(Buffer.from(user.hashed_password, 'hex'), Buffer.from(hashedPassword, 'hex'))) { return cb(null, false, { message: 'Incorrect username or password.' }); } return cb(null, user); }); } catch (err) { return cb(err); } })); /* Configure session management. * * When a login session is established, information about the user will be * stored in the session. This information is supplied by the `serializeUser` * function, which is yielding the user ID and username. * * As the user interacts with the app, subsequent requests will be authenticated * by verifying the session. The same user information that was serialized at * session establishment will be restored when the session is authenticated by * the `deserializeUser` function. * * Since every request to the app needs the user ID and username, in order to * fetch todo records and render the user element in the navigation bar, that * information is stored in the session. */ passport.serializeUser(function(user, cb) { process.nextTick(function() { cb(null, { id: user._id, username: user.email }); }); }); passport.deserializeUser(function(user, cb) { process.nextTick(function() { return cb(null, user); }); }); // JWT var jwt = require('jsonwebtoken'); var JwtStrategy = require('passport-jwt').Strategy, ExtractJwt = require('passport-jwt').ExtractJwt; var opts = {} opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken(); opts.secretOrKey = keys.jwt; opts.issuer = config.jwtOptions.issuer; opts.audience = config.jwtOptions.audience; passport.use(new JwtStrategy(opts, async function(jwt_payload, done) { const userDb = await UserDb.init(); try { const user = await userDb.get(jwt_payload.sub); if (user) { return done(null, user); } else { return done(null, false); // or you could create a new account } } catch (err) { return done(err, false); } })); router.post('/authenticate', async function(req, res) { passport.authenticate('local', async function(err, user, info) { if (err) { return res.status(500).json({message: err.message}); } if (!user) { return res.status(401).json({message: 'Incorrect email or password.'}); } // User found, generate a JWT for the user var token = jwt.sign({ sub: user._id, email: user.email }, opts.secretOrKey, { issuer: opts.issuer, audience: opts.audience, expiresIn: 86400 * 30 // 30 days }); res.json({ token: token }); //return res.status(500).json({message: 'Incorrect email or password.'}) })(req, res); }); module.exports = router;