UNPKG

periodicjs.ext.asyncadmin

Version:

An authentication extension for periodicjs that uses passport to authenticate user sessions.

424 lines (371 loc) 11.7 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>JSDoc: Source: controller/token_controller.js</title> <script src="scripts/prettify/prettify.js"> </script> <script src="scripts/prettify/lang-css.js"> </script> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> </head> <body> <div id="main"> <h1 class="page-title">Source: controller/token_controller.js</h1> <section> <article> <pre class="prettyprint source"><code>'use strict'; var async = require('async'), appSettings, appenvironment, bcrypt = require('bcrypt'), CoreController, CoreUtilities, ControllerHelper = require('periodicjs.core.controller'), CoreMailer = require('periodicjs.core.mailer'), Utilities = require('periodicjs.core.utilities'), jwt = require('jsonwebtoken'), loginExtSettings, logger, mongoose, User, path = require('path'), passport; // Utility Functions var waterfall = function (array, cb) { async.waterfall(array, cb); }; var encode = function (data) { return jwt.sign(data, loginExtSettings.token.secret); }; var decode = function (data, cb) { jwt.verify(data, loginExtSettings.token.secret, {}, function (err, decoded_token) { if (err) { console.log('Error from JWT.verify', err.name); console.log('Error from JWT.verify', err.message); cb(err); } else { cb(null, decoded_token); } }); }; var hasExpired = function (token_expires_millis) { var now = new Date(); var diff = (now.getTime() - token_expires_millis); return diff > 0; }; var invalidateUserToken = function (req, res, next, cb) { var token = req.controllerData.token; User.findOne({ 'attributes.reset_token': token }, function (err, usr) { if (err) { console.log('error finding the user for invalidate token fn'); cb(err, null); } else { usr.attributes.reset_token = ''; usr.attributes.reset_token_link = ''; usr.attributes.reset_token_expires_millis = 0; cb(false, req, res, next, usr); } }); }; var resetPassword = function (req, res, next, user, cb) { var err; //console.log('loginExtSettings', loginExtSettings); if (req.body.password) { if (req.body.password !== req.body.passwordconfirm) { err = new Error('Passwords do not match'); req.flash('error', err); cb(err, null); } else if (req.body.password === undefined || req.body.password.length &lt; loginExtSettings.new_user_validation.length_of_password) { err = new Error('Password is too short'); req.flash('error', err); cb(err, null); } else { var salt = bcrypt.genSaltSync(10), hash = bcrypt.hashSync(req.body.password, salt); user.password = hash; cb(null, user, req); } } }; /** * description The save user function has two special fn calls on the model to mark the properties on it as changed/modified this gets around some werid edge cases when its being updated in memory but not save in mongo * */ function saveUser(user, req, cb) { user.markModified('attributes'); user.markModified('password'); user.save(function (err, usr) { if (err) { cb(err, null); } cb(null, usr, req); }); } var getUser = function (req, res, next, cb) { User.findOne({ email: req.body.email }, function (err, user) { if (err) { cb(err, null); } else if (user) { cb(false, user, req); } else { req.flash('error', 'No user with that email found!'); cb(new Error('No user with that email found.'), null); } }); }; var generateToken = function (user, req, cb) { //Generate reset token and URL link; also, create expiry for reset token //make sure attributes exists || create it via merge var salt = bcrypt.genSaltSync(10); var now = new Date(); var expires = new Date(now.getTime() + (loginExtSettings.token.resetTokenExpiresMinutes * 60 * 1000)).getTime(); user.attributes = {}; user.attributes.reset_token = encode({ email: user.email, apikey: user.apikey }); user.attributes.reset_token_link = CoreUtilities.makeNiceName(bcrypt.hashSync(user.attributes.reset_token, salt)); user.attributes.reset_token_expires_millis = expires; //TODO: Look into why mongoose properties //are not being saved during async fn calls user.markModified('attributes'); user.save(function (err) { if (err) { cb(err, null); } cb(null, user, req); }); }; // create a func for the mail options var emailForgotPasswordLink = function (user, req, cb) { CoreController.getPluginViewDefaultTemplate({ viewname: 'email/user/forgot_password_link', themefileext: appSettings.templatefileextension }, function (err, templatepath) { if (err) { cb(err); } else { // console.log('user for forgot password', user); if (templatepath === 'email/user/forgot_password_link') { templatepath = path.resolve(process.cwd(), 'node_modules/periodicjs.ext.login/views', templatepath + '.' + appSettings.templatefileextension); } CoreMailer.sendEmail({ appenvironment: appenvironment, to: user.email, replyTo: appSettings.adminnotificationemail, subject: appSettings.name + ' - Reset your password', emailtemplatefilepath: templatepath, emailtemplatedata: { user: user, appname: appSettings.name, hostname: req.headers.host } }, cb); } } ); // cb(null, options); }; var emailResetPasswordNotification = function (user, req, cb) { CoreController.getPluginViewDefaultTemplate({ viewname: 'email/user/reset_password_notification', themefileext: appSettings.templatefileextension }, function (err, templatepath) { if (err) { cb(err); } else { // console.log('user for forgot password', user); if (templatepath === 'email/user/reset_password_notification') { templatepath = path.resolve(process.cwd(), 'node_modules/periodicjs.ext.login/views', templatepath + '.' + appSettings.templatefileextension); } CoreMailer.sendEmail({ appenvironment: appenvironment, to: user.email, replyTo: appSettings.adminnotificationemail, subject: appSettings.name + ' - Password reset notification', emailtemplatefilepath: templatepath, emailtemplatedata: { user: user, appname: appSettings.name, hostname: req.headers.host } }, cb); } } ); // cb(null, options); }; //Post to auth/forgot with the users email var forgot = function (req, res, next) { var arr = [ function (cb) { cb(null, req, res, next); }, getUser, generateToken, emailForgotPasswordLink ]; waterfall(arr, function (err /*, results*/ ) { if (err) { req.flash('error', err.message); res.redirect('/auth/forgot'); } else { req.flash('info', 'Password reset instructions were sent to your email address'); res.redirect(loginExtSettings.settings.authLoginPath); } }); }; var get_token = function (req, res, next) { req.controllerData = (req.controllerData) ? req.controllerData : {}; User.findOne({ 'attributes.reset_token_link': req.params.token }, function (err, user_with_token) { if (err) { req.flash('error', err.message); res.redirect(loginExtSettings.settings.authLoginPath); } else if (!user_with_token || !user_with_token.attributes.reset_token) { req.flash('error', 'invalid reset token'); res.redirect(loginExtSettings.settings.authLoginPath); } else if (hasExpired(user_with_token.attributes.reset_token_expires_millis)) { req.flash('error', 'Password reset token is has expired.'); res.redirect(loginExtSettings.settings.authLoginPath); } else { req.controllerData.token = user_with_token.attributes.reset_token; next(); } }); }; //GET if the user token is vaild show the change password page var reset = function (req, res) { var token = req.controllerData.token, // current_user, decode_token; decode(token, function (err, decode) { if (err) { CoreController.handleDocumentQueryErrorResponse({ err: err, res: res, req: req, errorflash: err.message }); } else { decode_token = decode; //Find the User by their token User.findOne({ 'attributes.reset_token': token }, function (err, found_user) { if (err || !found_user) { req.flash('error', 'Password reset token is invalid.'); res.redirect(loginExtSettings.settings.authLoginPath); } // current_user = found_user; //Check to make sure token hasn't expired //Check to make sure token is valid and sign by us else if (found_user.email !== decode_token.email && found_user.api_key !== decode_token.api_key) { req.flash('error', 'This token is not valid please try again'); res.redirect(loginExtSettings.settings.authLoginPath); } else { CoreController.getPluginViewDefaultTemplate({ viewname: 'user/reset', themefileext: appSettings.templatefileextension, extname: 'periodicjs.ext.login' }, function (err, templatepath) { CoreController.handleDocumentQueryRender({ res: res, req: req, renderView: templatepath, responseData: { pagedata: { title: 'Reset Password', current_user: found_user }, user: req.user } }); }); } }); } }); }; //POST change the users old password to the new password in the form var token = function (req, res, next) { var user_token = req.controllerData.token; waterfall([ function (cb) { cb(null, req, res, next); }, invalidateUserToken, resetPassword, saveUser, emailResetPasswordNotification ], function (err /*, results*/ ) { if (err) { req.flash('error', err.message); res.redirect('/auth/reset/' + user_token); } else { req.flash('success', 'Password Sucessfully Changed!'); res.redirect(loginExtSettings.settings.authLoginPath); } }); }; var tokenController = function (resources, passportResources) { appSettings = resources.settings; CoreController = new ControllerHelper(resources); CoreUtilities = new Utilities(resources); loginExtSettings = passportResources.loginExtSettings; logger = resources.logger; mongoose = resources.mongoose; passport = passportResources.passport; User = mongoose.model('User'); appenvironment = appSettings.application.environment; return { forgot: forgot, reset: reset, get_token: get_token, token: token }; }; module.exports = tokenController; </code></pre> </article> </section> </div> <nav> <h2><a href="index.html">Index</a></h2><h3>Modules</h3><ul><li><a href="module-authController.html">authController</a></li><li><a href="module-userloginController.html">userloginController</a></li><li><a href="login.html">login</a></li></ul><h3>Global</h3><ul><li><a href="global.html#facebook">facebook</a></li><li><a href="global.html#facebookcallback">facebookcallback</a></li><li><a href="global.html#instagram">instagram</a></li><li><a href="global.html#instagramcallback">instagramcallback</a></li><li><a href="global.html#saveUser">saveUser</a></li><li><a href="global.html#twitter">twitter</a></li><li><a href="global.html#twittercallback">twittercallback</a></li><li><a href="global.html#usePassport">usePassport</a></li></ul> </nav> <br clear="both"> <footer> Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.2.2</a> on Thu Jan 29 2015 21:18:44 GMT-0500 (EST) </footer> <script> prettyPrint(); </script> <script src="scripts/linenumber.js"> </script> </body> </html>