UNPKG

vbauth

Version:

This module provides SSO (Single Sign-On) support for vBulletin accounts and your Node.js powered website.

1,146 lines (948 loc) 36.4 kB
'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /* eslint no-underscore-dangle: ["off"] */ /* eslint class-methods-use-this: "error"*/ var crypto = require('crypto'); var moment = require('moment'); var _debug = require('debug'); var mysql = require('mysql'); var parallel = require('async/parallel'); var series = require('async/series'); var colors = require('colors/safe'); var debug = _debug('vbauth'); debug('Initializing vbauth'); var __DEV__ = process.env.NODE_ENV !== 'production'; // e-mail confirmed / not banned users var _isUser = function _isUser(userinfo) { return userinfo.usergroupid > 1 && userinfo.usergroupid !== 8 && // banned userinfo.usergroupid !== 3 && // awaiting email confirmation userinfo.usergroupid !== 4 // awaiting moderation ; }; // admins var _isAdmin = function _isAdmin(userinfo) { return userinfo.usergroupid === 6; }; // admins, moderators and super moderators var _isModerator = function _isModerator(userinfo) { return userinfo.usergroupid >= 5 && userinfo.usergroupid <= 7; }; var VBAuth = function () { function VBAuth(database, options) { var _this = this; _classCallCheck(this, VBAuth); if (typeof options.cookieSalt !== 'string' || options.cookieSalt.length === 0) { console.error(colors.red('A cookieSalt must be specified in VBAuth.options! You can find your cookie salt at \'includes/functions.php\' of your vBulletin install folder.\nIf you don\'t specify the correct cookie salt "remember-me cookies" won\'t work')); } if (!database) { throw new Error('You must pass the database information on vbauth initialization'); } else if ({}.hasOwnProperty.call(database, 'connectionLimit') && {}.hasOwnProperty.call(database, 'host') && {}.hasOwnProperty.call(database, 'user') && {}.hasOwnProperty.call(database, 'password') && {}.hasOwnProperty.call(database, 'database')) { this.database = mysql.createPool(database); } else if (!{}.hasOwnProperty.call(database, 'config')) { throw new Error('Invalid MySQL info passed on vbauth initialization'); } else { // an actual mysql pool was passed this.database = database; } this.options = Object.assign({ // Used to salt the remember me password before setting the cookie. // The cookieSalt is located at the file 'includes/functions.php' of your vBulletin install cookieSalt: '', // Cookie prefix used by vBulletin. Defaults to 'bb_'. cookiePrefix: 'bb_', // How long it takes for a session to timeout. cookieTimeout: 900, // Cookie domain. cookieDomain: '', // Default path, for activity refresh. Set a url, or null. null defaults to req.path defaultPath: 'http://my.domain.com', // The strike system will block the user from trying to log in after 5 wrong tries useStrikeSystem: true, // Should it refresh activity or not? If not, it will simply attach the userinfo to the // request object, and will not make any writes or updates in to the Forum database refreshActivity: true, // Use Secure cookies for remember me. Secure cookies only gets stored if transmitted // via TLS/SSL (https sites) secureCookies: false, // Use a redis cache for faster session look-up? // If so, you must pass a redis-client instance to this redisCache: false, // Query user subscriptions? subscriptions: true, // Subscription id to query subscriptionId: 1, // The subnet mask which reflects the level of checking you wish to run // against IP addresses when a session is being fetched. // To check this, go to: // vBulletin Options -> // Server Settings and Optimization Options -> // Session IP Octet Length Check // 255.255.255.255 = 0 // 255.255.255.0 = 1 // 255.255.0.0 = 2 sessionIpOctetLength: 1, // CSRF-Token Key csrfTokenKey: '1234567891123456789112345678911234567891' }, options); this.defaultUserObject = { userid: 0, username: 'unregistered', usergroupid: 1, membergroupids: '', email: '', posts: 0 }; if (this.options.subscriptions) { this.defaultUserObject.subscriptionexpirydate = 0; this.defaultUserObject.subscriptionstatus = 0; } this.isUser = options.isUser || _isUser; this.isModerator = options.isModerator || _isModerator; this.isAdmin = options.isAdmin || _isAdmin; if (typeof this.options.refreshActivity === 'function') { this.refreshActivity = this.options.refreshActivity; } else if (this.options.refreshActivity === true) { this.refreshActivity = function () { return true; }; } else { this.refreshActivity = function () { return false; }; } if (this.options.csrfTokenKey && this.options.csrfTokenKey.length > 0) { this.hmac = true; } // enable query logging if (debug.enabled) { (function () { var originalQuery = _this.database.query; _this.database.query = function () { for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } if (args.length === 3) { debug(mysql.format(args[0], args[1])); } else if (args.length === 2) { debug(args[0]); } originalQuery.apply(_this.database, args); }; })(); } } // Removes ipv6 from ip _createClass(VBAuth, [{ key: '_getCsrfToken', value: function _getCsrfToken(sessionHash) { return crypto.createHmac('sha256', this.options.csrfTokenKey).update(sessionHash).digest('hex'); } // Unique id based on user ip and user agent }, { key: '_fetchIdHash', value: function _fetchIdHash(req) { var ip = VBAuth._getIpv4(req.ip); var ipSubStr = VBAuth._getSubstrIp(ip, this.options.sessionIpOctetLength); var userAgent = req.header('user-agent'); return crypto.createHash('md5').update(userAgent + ipSubStr).digest('hex'); } }, { key: '_mysqlCreateSession', value: function _mysqlCreateSession(userid, ip, idHash, sessionHash, url, userAgent, req) { var _this2 = this; return new Promise(function (resolve, reject) { if (!_this2.refreshActivity(req)) { resolve(sessionHash); return; } var query = mysql.format('INSERT INTO session' + ' (userid, sessionhash, host, idhash, lastactivity, location, useragent, loggedin)' + ' VALUES (?, ?, ?, ?, ?, ?, ?, ?)', [userid, sessionHash, ip, idHash, moment().unix(), url, userAgent, userid > 0]); _this2.database.query(query, function (err) { if (err) { reject(err); return; } resolve(sessionHash); }); }); } }, { key: '_redisCreateSession', value: function _redisCreateSession(userid, ip, idHash, sessionHash, url, userAgent) { var _this3 = this; return new Promise(function (resolve, reject) { if (!_this3.options.redisCache) { resolve(); return; } var key = 'vbsession:' + sessionHash; debug('Storing vbsession in redis-cache'); var multi = _this3.options.redisCache.multi(); multi.hmset(key, { userid: userid, sessionhash: sessionHash, host: ip, idhash: idHash, lastactivity: moment().unix(), location: url, useragent: userAgent, loggedin: userid > 0 }); multi.expire(key, Math.floor(_this3.options.cookieTimeout * 0.25)); multi.exec(function (err) { if (err) { reject(err); return; } resolve(); }); }); } // Create a new session in the database for the user }, { key: 'createSession', value: function createSession(req, res, userid /* , loginType*/) { var ip = VBAuth._getIpv4(req.ip); var idHash = this._fetchIdHash(req); var url = this.options.defaultPath ? this.options.defaultPath : req.path; var userAgent = req.header('user-agent').slice(0, 100); var hash = moment().valueOf().toString() + userid + ip; hash = crypto.createHash('md5').update(hash).digest('hex'); // Sets cookie to the response res.cookie(this.options.cookiePrefix + 'sessionhash', hash, { domain: this.options.cookieDomain, httpOnly: true }); // Lets also set the csrf token here if (this.hmac) { req.csrfToken = this._getCsrfToken(hash); req.sessionHash = hash; } // Use Redis cache, if available this._redisCreateSession(userid, ip, idHash, hash, url, userAgent); // Returns a promise return this._mysqlCreateSession(userid, ip, idHash, hash, url, userAgent, req); } }, { key: '_mysqlUpdateUserActivity', value: function _mysqlUpdateUserActivity(userid, sessionHash, lastUrl, req) { var _this4 = this; return new Promise(function (resolve, reject) { if (!_this4.refreshActivity(req)) { resolve(true); return; } var query = mysql.format('UPDATE session SET \n lastactivity = ?,\n location = ?,\n userid = ?,\n loggedin = ? \n WHERE sessionhash = ?', [moment().unix(), lastUrl, userid, userid > 0, sessionHash]); _this4.database.query(query, function (err, result) { if (err) { reject(err); return; } resolve(result.affectedRows > 0); }); }); } }, { key: '_redisUpdateUserActivity', value: function _redisUpdateUserActivity(userid, sessionHash, lastUrl) { var _this5 = this; return new Promise(function (resolve, reject) { var key = 'vbsession:' + sessionHash; if (!_this5.options.redisCache) { resolve(false); // redis not available return; } debug('Checking vbsession existance in redis-cache'); _this5.options.redisCache.exists(key, function (err, exists) { if (err) { reject(err); return; } if (!exists) { resolve(false); // not updated return; } debug('Updating vbsession in redis-cache'); var multi = _this5.options.redisCache.multi(); multi.hmset(key, { lastactivity: moment().unix(), location: lastUrl, userid: userid, loggedin: userid > 0 }); multi.expire(key, Math.floor(_this5.options.cookieTimeout * 0.25)); multi.exec(function (err2) { if (err2) { reject(err2); return; } resolve(true); }); }); }); } // Refreshes the user activity in the database, according to its session }, { key: 'updateUserActivity', value: function updateUserActivity(lastUrl, userid, sessionHash, req) { var _this6 = this; if (!sessionHash || sessionHash.length === 0) { return Promise.resolve(false); } return this._redisUpdateUserActivity(userid, sessionHash, lastUrl).then(function (updated) { if (!updated) { return _this6._mysqlUpdateUserActivity(userid, sessionHash, lastUrl, req); } return Promise.resolve(updated); }); } // Deletes a session }, { key: 'deleteSession', value: function deleteSession(sessionhash, redisOnly, req) { var _this7 = this; return new Promise(function (resolve, reject) { if (typeof sessionhash !== 'string') { resolve(true); return; } parallel([function (cb) { if (redisOnly || !_this7.refreshActivity(req)) { return cb(null, true); } var query = mysql.format('DELETE FROM session WHERE sessionhash = ?', [sessionhash]); return _this7.database.query(query, function (err) { return cb(err, true); }); }, function (cb) { if (!_this7.options.redisCache) { return cb(null, true); } debug('Deleting vbsession in redis-cache'); return _this7.options.redisCache.del('vbsession:' + sessionhash, function (err) { return cb(err, true); }); }], function (err) { if (err) { reject(err); return; } resolve(true); }); }); } // Returns the userinfo if the username/password are valid, or null if it's not valid }, { key: 'isValidLogin', value: function isValidLogin(username, password) { var _this8 = this; return new Promise(function (resolve, reject) { var query = mysql.format('SELECT userid, password FROM user WHERE ' + 'username = ? AND ' + '(password = md5(concat(?, salt)) OR password = md5(concat(md5(?), salt)))', [username, password, password]); _this8.database.query(query, function (err, rows) { if (err) { reject(err); return; } resolve(rows[0]); }); }); } // Returns true if the cookie userid/password is valid, false otherwise }, { key: 'checkRememberMeCredentials', value: function checkRememberMeCredentials(userid, password) { var _this9 = this; return new Promise(function (resolve, reject) { var query = mysql.format('SELECT userid FROM user' + ' WHERE userid = ? AND md5(concat(password, ?)) = ?', [userid, _this9.options.cookieSalt, password]); _this9.database.query(query, function (err, rows) { if (err) { reject(err); return; } resolve(rows.length > 0); }); }); } }, { key: '_redisStoreUserInfo', value: function _redisStoreUserInfo(userinfo) { var _this10 = this; return new Promise(function (resolve, reject) { if (!_this10.options.redisCache) { resolve(true); return; } var key = 'vbuser:' + userinfo.userid; debug('Storing vbuser in redis-cache'); var multi = _this10.options.redisCache.multi(); multi.hmset(key, userinfo); multi.expire(key, Math.floor(_this10.options.cookieTimeout * 0.25)); multi.exec(function (err) { if (err) { reject(err); return; } resolve(true); }); }); } }, { key: '_redisGetUserInfo', value: function _redisGetUserInfo(userid) { var _this11 = this; return new Promise(function (resolve, reject) { if (!_this11.options.redisCache) { resolve(null); return; } var key = 'vbuser:' + userid; debug('Fetching vbuser from redis-cache'); _this11.options.redisCache.hgetall(key, function (err, results) { if (err) { return reject(err); } if (!results) { return resolve(null); } var ret = results; ret.userid = parseInt(results.userid, 10); ret.usergroupid = parseInt(results.usergroupid, 10); ret.posts = parseInt(results.posts, 10); if (_this11.options.subscriptions) { ret.subscriptionstatus = parseInt(results.subscriptionstatus, 10) || 0; ret.subscriptionexpirydate = parseInt(results.subscriptionexpirydate, 10) || 0; } else { delete ret.subscriptionstatus; delete ret.subscriptionexpirydate; } return resolve(ret); }); }); } }, { key: '_mysqlGetUserInfo', value: function _mysqlGetUserInfo(userid) { var _this12 = this; return new Promise(function (resolve, reject) { var subscriptionFields = ''; var subscriptionJoin = ''; if (_this12.options.subscriptions) { subscriptionFields = ', IFNULL(b.status, 0) AS subscriptionstatus,' + ' IFNULL(b.expirydate, 0) AS subscriptionexpirydate'; subscriptionJoin = 'LEFT JOIN subscriptionlog AS b' + (' ON a.userid = b.userid AND b.subscriptionid = ' + mysql.escape(_this12.options.subscriptionId)); } var query = 'SELECT a.userid, a.username, ' + ' a.usergroupid, a.membergroupids,' + (' a.email, a.posts' + subscriptionFields) + (' FROM user AS a ' + subscriptionJoin) + (' WHERE a.userid = ' + mysql.escape(userid)); _this12.database.query(query, function (err, rows) { if (err) { reject(err); return; } var userinfo = rows[0]; if (!userinfo) { console.warn('User does not exist:', userid); resolve(null); return; } _this12._redisStoreUserInfo(userinfo); resolve(userinfo); }); }); } // Get user info }, { key: 'getUserInfo', value: function getUserInfo(userid) { var _this13 = this; // Avoid performing this query if the user is not authenticated if (!userid || userid === 0) { return Promise.resolve(Object.assign({}, this.defaultUserObject)); } return this._redisGetUserInfo(userid).then(function (userinfo) { if (!userinfo) { return _this13._mysqlGetUserInfo(userid); } return Promise.resolve(userinfo); }); } }, { key: '_mysqlGetActiveSession', value: function _mysqlGetActiveSession(sessionHash, idHash) { var _this14 = this; return new Promise(function (resolve, reject) { var query = mysql.format('SELECT a.* FROM session AS a' + ' WHERE sessionhash = ? AND idhash = ? AND lastactivity > ?', [sessionHash, idHash, moment().unix() - _this14.options.cookieTimeout]); _this14.database.query(query, function (err, rows) { if (err) { reject(err); return; } var sessionData = rows[0]; if (!sessionData) { console.warn('Session expired:', sessionHash); resolve(null); return; } _this14._redisCreateSession(sessionData.userid, sessionData.host, idHash, sessionHash, sessionData.location, sessionData.useragent); resolve(sessionData); }); }); } }, { key: '_redisGetActiveSession', value: function _redisGetActiveSession(sessionHash, idHash) { var _this15 = this; return new Promise(function (resolve, reject) { if (!_this15.options.redisCache) { resolve(null); return; } debug('Fetching vbsession from redis-cache'); var key = 'vbsession:' + sessionHash; _this15.options.redisCache.hgetall(key, function (err, results) { if (err) { reject(err); return; } if (!results || results.idhash !== idHash) { debug('vbsession expired from redis-cache!'); resolve(null); } else { resolve(results); } }); }); } // Returns the currently active session, or null if there isn't any }, { key: 'getActiveSession', value: function getActiveSession(sessionHash, idHash) { var _this16 = this; return new Promise(function (resolve, reject) { if (!sessionHash || sessionHash.length === 0) { resolve(null); return; } _this16._redisGetActiveSession(sessionHash, idHash).then(function (session) { if (!session) { return _this16._mysqlGetActiveSession(sessionHash, idHash); } return Promise.resolve(session); }).then(function (session) { return resolve(session); }).catch(function (err) { return reject(err); }); }); } // Just for code reusing }, { key: 'updateOrCreateSession', value: function updateOrCreateSession(req, res, sessionHash, userid) { var _this17 = this; /* eslint no-param-reassign: ["error", { "props": false }] */ return new Promise(function (resolve, reject) { // Append user info to request object req.vbuser = { userid: userid }; var url = _this17.options.defaultPath ? _this17.options.defaultPath : req.path; // call those in parallel var callArray = [function (cb) { return _this17.getUserInfo(userid).then(function (userinfo) { return cb(null, userinfo); }).catch(function (err) { return cb(err); }); }, function (cb) { return ( // this will return right away if sessionHash is null, or empty _this17.updateUserActivity(url, userid, sessionHash, req).then(function (updated) { if (!updated) { // if for some reason his old session wasn't in the db, then just make him a new one // this should never happen, but just in case... return _this17.createSession(req, res, userid); } return Promise.resolve(sessionHash); }).then(function (hash) { return cb(null, hash); }).catch(function (err) { return cb(err); }) ); }]; // After the tasks have been done, we may get back to where we were... parallel(callArray, function (err, results) { if (err) { reject(err); return; } req.vbuser = results[0]; if (_this17.hmac && !req.csrfToken) { req.csrfToken = _this17._getCsrfToken(sessionHash); req.sessionHash = sessionHash; } resolve(results[1]); }); }); } // Increases the amount of login tries in the database }, { key: 'execStrikeUser', value: function execStrikeUser(username, userip) { var _this18 = this; return new Promise(function (resolve, reject) { if (!_this18.options.useStrikeSystem) { resolve(null); return; } var query = mysql.format('INSERT INTO strikes ' + '(striketime, strikeip, username) ' + 'VALUES ' + '(?, ?, ?)', [moment().unix(), userip, username]); _this18.database.query(query, function (err) { if (err) { reject(err); return; } resolve(null); }); }); } // Removes his login strikes after a successful login }, { key: 'execUnstrikeUser', value: function execUnstrikeUser(username, userip) { var _this19 = this; return new Promise(function (resolve, reject) { if (!_this19.options.useStrikeSystem) { resolve(null); return; } var query = mysql.format('DELETE FROM strikes WHERE strikeip = ? AND username = ?', [userip, username]); _this19.database.query(query, function (err) { if (err) { reject(err); return; } resolve(null); }); }); } // Checks whether the user can try logging in or not // If he already typed the password wrongly 5 times // in the last 15 minutes he will not be allowed to try again }, { key: 'verifyStrikeStatus', value: function verifyStrikeStatus(username, userip) { var _this20 = this; return new Promise(function (resolve, reject) { if (!_this20.options.useStrikeSystem) { resolve(0); return; } var deleteQuery = mysql.format('DELETE FROM strikes WHERE striketime < ?', [moment().unix() - 3600]); var selectQuery = mysql.format('SELECT COUNT(*) AS strikes, MAX(striketime) AS lasttime ' + 'FROM strikes ' + 'WHERE strikeip = ?', [userip]); series([function (cb) { return _this20.database.query(deleteQuery, cb); }, function (cb) { return _this20.database.query(selectQuery, cb); }], function (err, results) { if (err) { reject(err); return; } var strikeResults = results[1][0][0]; if (strikeResults.strikes >= 5 && strikeResults.lasttime > moment().unix() - 900) { // they've got it wrong 5 times or greater for any username at the moment // the user is still not giving up so lets keep increasing this marker _this20.execStrikeUser(username, userip).catch(function (err2) { return console.warn(err2); }); resolve(strikeResults.strikes + 1); return; } resolve(strikeResults.strikes); }); }); } // Authenticates the session, and injects vbuser information // in to the request object (req) }, { key: 'authenticateSession', value: function authenticateSession(req, res) { var _this21 = this; debug('Calling authenticateSession()'); // userid and password are set when you login using remember-me var userid = parseInt(req.cookies[this.options.cookiePrefix + 'userid'], 10) || 0; var password = req.cookies[this.options.cookiePrefix + 'password']; // sessionhash is set everywhere when navigating on vbulletin var sessionHash = req.cookies[this.options.cookiePrefix + 'sessionhash']; // queried sessionObj var sessionObj = null; return this.getActiveSession(sessionHash, this._fetchIdHash(req)).then(function (session) { // Check if we have remember-me set if (userid && password && (!session || session.userid !== userid)) { return _this21.checkRememberMeCredentials(userid, password); } // store session we just queried in sessionObj sessionObj = session; // doesn't have a remember me return Promise.resolve(true); }).then(function (validRememberMe) { if (!validRememberMe) { // Remember me password was wrong. Lets clear it out! var cookieOption = { domain: _this21.options.cookieDomain }; res.clearCookie(_this21.options.cookiePrefix + 'userid', cookieOption); res.clearCookie(_this21.options.cookiePrefix + 'password', cookieOption); userid = 0; } // update session, or create, if user doesn't have any userid = sessionObj ? parseInt(sessionObj.userid, 10) : userid; return _this21.updateOrCreateSession(req, res, sessionHash, userid); }); } // Logs the user in }, { key: '_login', value: function _login(username, pass, rememberme, loginType, req, res) { var _this22 = this; var ip = VBAuth._getIpv4(req.ip); var sessionHash = req.cookies[this.options.cookiePrefix + 'sessionhash']; var userid = 0; return new Promise(function (resolve, reject) { if (!username || !pass || username.length === 0 || pass.length === 0) { resolve('failed, login and password are required'); return; } _this22.verifyStrikeStatus(username, ip).then(function (strikes) { if (strikes >= 5) { throw new Error('too many tries'); } return _this22.isValidLogin(username, pass); }).then(function (authinfo) { if (!authinfo) { _this22.execStrikeUser(username, ip).catch(function (err) { return console.warn(err); }); throw new Error('wrong login or password'); } userid = authinfo.userid; _this22.execUnstrikeUser(username, ip); if (rememberme) { // set remember me cookies var hash = authinfo.password + _this22.options.cookieSalt; hash = crypto.createHash('md5').update(hash).digest('hex'); var cookieAge = 365 * 24 * 60 * 60 * 1000; var cookieOptions = { maxAge: cookieAge, domain: _this22.options.cookieDomain, secure: _this22.options.secureCookies, httpOnly: true }; res.cookie(_this22.options.cookiePrefix + 'userid', userid, cookieOptions); res.cookie(_this22.options.cookiePrefix + 'password', hash, cookieOptions); } return _this22.createSession(req, res, userid, loginType); }).then(function () { // We just gave him a new session, lets delete his old one, if he had one... if (sessionHash && sessionHash.length > 0) { _this22.deleteSession(sessionHash, false, req); } return _this22.getUserInfo(userid); }).then(function (userinfo) { req.vbuser = userinfo; if (_this22.hmac && !req.csrfToken) { req.csrfToken = _this22._getCsrfToken(sessionHash); req.sessionHash = sessionHash; } resolve('success'); }).catch(function (err) { if (err.message === 'too many tries' || err.message === 'wrong login or password') { resolve('failed, ' + err.message); return; } reject(err); }); }); } // Logs you out }, { key: 'logoutSession', value: function logoutSession(req, res) { var _this23 = this; return new Promise(function (resolve, reject) { // Will log you out from the currently set cookie var sessionhash = req.cookies[_this23.options.cookiePrefix + 'sessionhash']; // Clear redisCache after vBulletin logout, requires a hook if (req.body && req.body.redisOnly) { _this23.deleteSession(sessionhash, true, req).then(function () { return resolve(); }).catch(function (err) { return reject(err); }); return; } // Logs out from the current cookie session _this23.deleteSession(sessionhash, false, req).then(function () { req.vbuser = Object.assign({}, _this23.defaultUserObject); if (req.csrfToken) { delete req.csrfToken; delete req.sessionHash; } var cookieOptions = { domain: _this23.options.cookieDomain }; res.clearCookie(_this23.options.cookiePrefix + 'sessionhash', cookieOptions); res.clearCookie(_this23.options.cookiePrefix + 'userid', cookieOptions); res.clearCookie(_this23.options.cookiePrefix + 'password', cookieOptions); res.clearCookie(_this23.options.cookiePrefix + 'imloggedin', cookieOptions); resolve('success'); }).catch(function (err) { return reject(err); }); }); } // Middleware wrapper to make mustBe user, moderator, or admin... }, { key: '_mustBeMiddleware', value: function _mustBeMiddleware(req, res, next, func) { var errorMsg = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 'Invalid request'; var errorCode = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 400; var tmp = function tmp(userinfo) { if (func(userinfo)) { next(); } else { var err = new Error(errorMsg); err.status = errorCode; next(err); } }; // This will make sure the session won't get re-authenticated // if you had already attached a session() middleware. if (!req.vbuser) { this.authenticateSession(req, res).then(function () { tmp(req.vbuser); }).catch(function (err) { if (__DEV__) { next(err); return; } console.warn(err); next(new Error('Database error')); }); } else { tmp(req.vbuser); } } /* ******* * * Exports * * ******* */ }, { key: 'session', value: function session() { var _this24 = this; return function (req, res, next) { if (!req.cookies) { next(new Error('cookie-parser middleware is required for vbauth to work')); return; } _this24.authenticateSession(req, res).then(function () { return next(); }).catch(function (err) { if (__DEV__) { next(err); return; } console.warn(err); next(new Error('Database error')); }); }; } }, { key: 'logout', value: function logout() { var _this25 = this; return function (req, res, next) { _this25.logoutSession(req, res).then(function (result) { if (result === 'success') { // logged out, give the user a new empty session // this will prevent session() from trying to query existing session delete req.cookies[_this25.options.cookiePrefix + 'sessionhash']; // make new session _this25.session()(req, res, next); } else { // only deleted from redis-cache, no need to give user a new session next(); } }).catch(function (err) { if (__DEV__) { next(err); return; } console.warn(err); next(new Error('Database error')); }); }; } }, { key: 'login', value: function login(username, pass, rememberme, loginType, req, res) { var _this26 = this; return new Promise(function (resolve, reject) { _this26._login(username, pass, rememberme, loginType, req, res).then(function (result) { return resolve(result); }).catch(function (err) { if (__DEV__) { reject(err); return; } console.warn(err); reject(new Error('Database error')); }); }); } }, { key: 'mustBeUser', value: function mustBeUser() { var _this27 = this; return function (req, res, next) { _this27._mustBeMiddleware(req, res, next, _this27.isUser); }; } }, { key: 'mustBeAdmin', value: function mustBeAdmin() { var _this28 = this; return function (req, res, next) { _this28._mustBeMiddleware(req, res, next, _this28.isAdmin, 'Page not found', 404); }; } }, { key: 'mustBeModerator', value: function mustBeModerator() { var _this29 = this; return function (req, res, next) { _this29._mustBeMiddleware(req, res, next, _this29.isModerator, 'Page not found', 404); }; } }, { key: 'mustBe', value: function mustBe(func) { var _this30 = this; return function (req, res, next) { _this30._mustBeMiddleware(req, res, next, func, 'Page not found', 404); }; } }], [{ key: '_getIpv4', value: function _getIpv4(ip) { /* eslint no-param-reassign: "off"*/ var tmpIp = ip || ''; return tmpIp.slice(tmpIp.lastIndexOf(':') + 1); } // Cuts off the the last sessions of an ip address }, { key: '_getSubstrIp', value: function _getSubstrIp(ip, octectLength, defaultOctectLength) { var length = octectLength; if (octectLength === undefined || octectLength > 3) { length = defaultOctectLength; } var arr = ip.split('.').slice(0, 4 - length); return arr.join('.'); } }]); return VBAuth; }(); module.exports = VBAuth;