UNPKG

strider

Version:

Brilliant continuous deployment platform

298 lines 9.76 kB
const crypto = require('crypto'); const BluebirdPromise = require('bluebird'); const passport = require('passport'); const LocalStrategy = require('passport-local').Strategy; const utils = require('./utils'); const mailer = require('./email'); require('./config'); require('./logging'); const User = require('./models').User; const randomBytes = BluebirdPromise.promisify(crypto.randomBytes); function setupPasswordAuth() { passport.use(new LocalStrategy({ usernameField: 'email', }, function (username, password, done) { console.log('username: %s', username); User.authenticate(username, password, function (err, user) { if (err || !user) { console.log('no user'); return done(null, false, { message: 'Incorrect username.' }); } return done(null, user); }); })); } function registerRoutes(app) { app.get('/register', function (req, res, next) { if (req.query.ember) { return next(); } return res.redirect('/register?ember=true'); }); app.post('/register', function (req, res) { const errors = []; if (!req.body.inviteCode) errors.push('No invite code specified'); if (!req.body.email) errors.push('Missing email'); if (!req.body.password) errors.push('Missing password'); if (errors.length) { return res.status(400).json({ errors: errors }); } User.registerWithInvite(req.body.invite_code, req.body.email, req.body.password, function (err, user) { if (err) { return res.status(400).json({ errors: [err], }); } // Registered success: req.login(user, function () { res.redirect('/'); }); }); }); app.get('/login', function (req, res, next) { if (req.user) { return res.redirect('/'); } // Pass to Ember if not an error from old login if (!req.query.failed && !req.query.ember) { return res.redirect('/login?ember=true'); } else if (!req.query.failed && req.query.ember) { return next(); } const failed = Boolean(req.query.failed); const errors = []; if (failed) { errors.push('Authentication failed, please supply a valid email/password.'); } return res.render('login.html', { errors: errors, }); }); } function setup(app) { app.registerAuthStrategy = function (strategy) { passport.use(strategy); }; app.authenticate = function () { console.log('AUTHENTICATE', arguments); const res = passport.authenticate.apply(passport, arguments); console.log('!!!', res); return function (req) { console.log('>>>> AUTHENTICATE', req._passport, req._passport.instance._strategies.github); res.apply(this, arguments); }; }; setupPasswordAuth(); // serialize user on login passport.serializeUser(function (user, done) { done(null, user.id); }); // deserialize user on logout passport.deserializeUser(function (id, done) { User.findById(id, function (err, user) { done(err, user); }); }); app.use(passport.initialize()); app.use(passport.session()); app.use(basicAuth); // Middleware to setup view parameters with user app.use(function (req, res, next) { if (req.user) { req.user.gravatar = utils.gravatar(req.user.email); } res.locals.currentUser = req.user || null; next(); }); registerRoutes(app); } function basicAuth(req, res, next) { const auth = req.get('authorization'); if (!auth) return next(); const parts = auth.split(' '); if (parts.length !== 2 || parts[0].toLowerCase() !== 'basic') return next(); let plain; try { plain = new Buffer(parts[1], 'base64').toString().split(':'); } catch (e) { console.error('Invalid base64 in auth header'); return next(); } if (plain.length < 2) { console.error('Invalid auth header'); return next(); } User.authenticate(plain[0], plain.slice(1).join(':'), function (err, user) { if (err || !user) { console.log('basic auth: user not found'); return res.status(401).send('Invalid username/password in basic auth'); } req.user = user; return next(); }); } const _authenticate = (cb) => passport.authenticate('local', cb); function logout(req, res) { req.logout(); res.redirect('/login?ember=true'); } function forgot(req, res) { const email = req.body.email.toLowerCase(); User.findOne({ email: { $regex: new RegExp(email, 'i') } }, function (error, user) { if (error) { return res.status(400).json({ errors: ['An error occured while attempting to reset your password.'], }); } if (user) { randomBytes(20) .then(function (buffer) { return buffer.toString('hex'); }) .then(function (token) { user.resetPasswordToken = token; user.resetPasswordExpires = Date.now() + 3600000; // 1 hour return new BluebirdPromise(function (resolve, reject) { user.save(function (err, u) { if (err) { reject(err); } else { resolve(u); } }); }); }) .then(function (user) { mailer.sendPasswordReset(user); res.json({ ok: true, message: 'Please check your email for the password reset url. Thank you!', }); }) .catch(function (error) { res.status(500).json({ errors: ['Password reset error: ' + error] }); }); } else { res .status(404) .json({ errors: ['We could not find a user with that email.'] }); } }); } function reset(req, res, next) { if (req.query.ember) { return next(); } const token = req.params.token; User.findOne({ resetPasswordToken: token, resetPasswordExpires: { $gt: Date.now() }, }, function (err, user) { if (!user) { return res.status(400).json({ errors: ['Password reset token is invalid or has expired.'], }); } res.render('reset.html', { token: token, user: user, }); }); } function resetPost(req, res) { const password = req.body.password; const confirmation = req.body.passwordConfirmation; if (password === confirmation) { User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() }, }, function (err, user) { if (!user) { req.flash('error', 'Password reset token is invalid or has expired.'); return res.redirect('back'); } user.password = password; user.resetPasswordToken = undefined; user.resetPasswordExpires = undefined; user.save(function (err) { if (err) { req.flash('error', "Couldn't save changes with new password."); return res.redirect('/'); } req.login(user, function (err) { if (err) { req.flash('error', "You'r user authentication was not successful."); } res.redirect('/'); }); }); }); } else { res.redirect(req.header('Referer')); } } // Require a logged in session function requireUser(req, res, next) { if (req.user) { next(); } else { req.session.return_to = req.url; res.redirect('/login?ember=true'); } } function requireUserOr401(req, res, next) { if (req.user) { next(); } else { res.status(401).send('not authorized'); } } // Require admin privileges function requireAdminOr401(req, res, next) { if (!req.user || !req.user['account_level'] || req.user.account_level < 1) { res.status(401).send('not authorized'); } else { next(); } } // Require the logged-in user to have admin access to the repository in the // URI path. // E.g. http://striderapp.com/beyondfog/strider/latest_build function requireProjectAdmin(req, res, next) { if (!req.project) return res.status(404).send('Project not loaded'); if (!req.user) return res.status(401).send('No user'); const isAdmin = req.user.account_level && req.user.account_level > 0; const notAuthed = (!req.accessLevel || req.accessLevel < 2) && !isAdmin; if (notAuthed) return res.status(401).send('Not authorized for configuring this project'); next(); } module.exports = { setup: setup, authenticate: _authenticate, logout: logout, forgot: forgot, reset: reset, resetPost: resetPost, // Auth middleware requireUser: requireUser, requireUserOr401: requireUserOr401, requireAdminOr401: requireAdminOr401, requireProjectAdmin: requireProjectAdmin, }; //# sourceMappingURL=auth.js.map