113 lines
3.9 KiB
JavaScript
113 lines
3.9 KiB
JavaScript
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; |