'use strict'; /** * Module dependencies. */ var _ = require('lodash'), errorHandler = require('../errors.server.controller'), mongoose = require('mongoose'), passport = require('passport'), async = require('async'), config = require('../../../config/config'), nodemailer = require('nodemailer'), crypto = require('crypto'), User = mongoose.model('User'); var smtpTransport = nodemailer.createTransport(config.mailer.options); /** * Reset password GET from email token */ exports.validateResetToken = function(req, res) { User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) { if (!user) { return res.redirect('/#!/password/reset/invalid'); } res.redirect('/#!/password/reset/' + req.params.token); }); }; /** * Send verification email */ var sendVerificationEmail = function(req, res, next) { // Init Variables var passwordDetails = req.body; async.waterfall([ // Generate random token function(done) { crypto.randomBytes(20, function(err, buffer) { var token = buffer.toString('hex'); done(err, token); }); }, function(token, done) { // For security measurement we remove the roles from the req.body object delete req.body.roles; // Init Variables var user = new User(req.body); user.resetPasswordToken = token; user.resetPasswordExpires = Date.now() + 3600000; // 1 hour // Add missing user fields user.provider = 'local'; user.displayName = user.firstName + ' ' + user.lastName; // Then save the user user.save(function(err) { done(err, token, user); }); }, function(token, user, done) { res.render('templates/verify-account-email', { name: user.displayName, url: 'http://' + req.headers.host + '/auth/activate/' + token, appName: config.app.title }, function(err, emailHTML) { done(err, emailHTML, user); }); }, // If valid email, send reset email using service function(emailHTML, user, done) { var mailOptions = { to: user.email, from: config.mailer.from, subject: 'Please verify your email', html: emailHTML }; smtpTransport.sendMail(mailOptions, function(err) { done(err, 'done'); }); } ], function(err) { if (err) return next(err); res.status(200).send('new user successfully registered'); }); }; /** * Signup */ exports.signup = function(req, res) { // For security measurement we remove the roles from the req.body object delete req.body.roles; // Init Variables var user = new User(req.body); var message = null; // Add missing user fields user.provider = 'local'; user.displayName = user.firstName + ' ' + user.lastName; // Then save the user user.save(function(err) { if (err) { return res.status(400).send({ message: errorHandler.getErrorMessage(err) }); } else { // Remove sensitive data before login user.password = undefined; user.salt = undefined; res.status(200).send('new user successfully registered'); // req.login(user, function(err) { // if (err) { // res.status(400).send(err); // } else { // res.status(200).send('new user successfully registered'); // } // }); } }); }; /** * Signin after passport authentication */ exports.signin = function(req, res, next) { passport.authenticate('local', function(err, user, info) { if (err || !user) { res.status(400).send(info); } else { // Remove sensitive data before login user.password = undefined; user.salt = undefined; req.login(user, function(err) { if (err) { return res.status(400).send({ message: errorHandler.getErrorMessage(err) }); } else { res.json(user); } }); } })(req, res, next); }; /** * Signout */ exports.signout = function(req, res) { req.logout(); res.status(200).send('user successfully logged out'); // res.redirect('/'); }; /** * OAuth callback */ exports.oauthCallback = function(strategy) { return function(req, res, next) { passport.authenticate(strategy, function(err, user, redirectURL) { if (err || !user) { return res.redirect('/#!/signin'); } req.login(user, function(err) { if (err) { return res.redirect('/#!/signin'); } return res.redirect(redirectURL || '/'); }); })(req, res, next); }; }; /** * Helper function to save or update a OAuth user profile */ exports.saveOAuthUserProfile = function(req, providerUserProfile, done) { if (!req.user) { // Define a search query fields var searchMainProviderIdentifierField = 'providerData.' + providerUserProfile.providerIdentifierField; var searchAdditionalProviderIdentifierField = 'additionalProvidersData.' + providerUserProfile.provider + '.' + providerUserProfile.providerIdentifierField; // Define main provider search query var mainProviderSearchQuery = {}; mainProviderSearchQuery.provider = providerUserProfile.provider; mainProviderSearchQuery[searchMainProviderIdentifierField] = providerUserProfile.providerData[providerUserProfile.providerIdentifierField]; // Define additional provider search query var additionalProviderSearchQuery = {}; additionalProviderSearchQuery[searchAdditionalProviderIdentifierField] = providerUserProfile.providerData[providerUserProfile.providerIdentifierField]; // Define a search query to find existing user with current provider profile var searchQuery = { $or: [mainProviderSearchQuery, additionalProviderSearchQuery] }; User.findOne(searchQuery, function(err, user) { if (err) { return done(err); } else { if (!user) { var possibleUsername = providerUserProfile.username || ((providerUserProfile.email) ? providerUserProfile.email.split('@')[0] : ''); User.findUniqueUsername(possibleUsername, null, function(availableUsername) { user = new User({ firstName: providerUserProfile.firstName, lastName: providerUserProfile.lastName, username: availableUsername, displayName: providerUserProfile.displayName, email: providerUserProfile.email, provider: providerUserProfile.provider, providerData: providerUserProfile.providerData }); // And save the user user.save(function(err) { return done(err, user); }); }); } else { return done(err, user); } } }); } else { // User is already logged in, join the provider data to the existing user var user = req.user; // Check if user exists, is not signed in using this provider, and doesn't have that provider data already configured if (user.provider !== providerUserProfile.provider && (!user.additionalProvidersData || !user.additionalProvidersData[providerUserProfile.provider])) { // Add the provider data to the additional provider data field if (!user.additionalProvidersData) user.additionalProvidersData = {}; user.additionalProvidersData[providerUserProfile.provider] = providerUserProfile.providerData; // Then tell mongoose that we've updated the additionalProvidersData field user.markModified('additionalProvidersData'); // And save the user user.save(function(err) { return done(err, user, '/#!/settings/accounts'); }); } else { return done(new Error('User is already connected using this provider'), user); } } }; /** * Remove OAuth provider */ exports.removeOAuthProvider = function(req, res, next) { var user = req.user; var provider = req.param('provider'); if (user && provider) { // Delete the additional provider if (user.additionalProvidersData[provider]) { delete user.additionalProvidersData[provider]; // Then tell mongoose that we've updated the additionalProvidersData field user.markModified('additionalProvidersData'); } user.save(function(err) { if (err) { return res.status(400).send({ message: errorHandler.getErrorMessage(err) }); } else { req.login(user, function(err) { if (err) { res.status(400).send(err); } else { res.json(user); } }); } }); } };