| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 | const _          = require('lodash');const error      = require('../lib/error');const userModel  = require('../models/user');const authModel  = require('../models/auth');const helpers    = require('../lib/helpers');const TokenModel = require('../models/token');const ERROR_MESSAGE_INVALID_AUTH = 'Invalid email or password';module.exports = {	/**	 * @param   {Object} data	 * @param   {String} data.identity	 * @param   {String} data.secret	 * @param   {String} [data.scope]	 * @param   {String} [data.expiry]	 * @param   {String} [issuer]	 * @returns {Promise}	 */	getTokenFromEmail: (data, issuer) => {		let Token = new TokenModel();		data.scope  = data.scope || 'user';		data.expiry = data.expiry || '1d';		return userModel			.query()			.where('email', data.identity.toLowerCase().trim())			.andWhere('is_deleted', 0)			.andWhere('is_disabled', 0)			.first()			.then((user) => {				if (user) {					// Get auth					return authModel						.query()						.where('user_id', '=', user.id)						.where('type', '=', 'password')						.first()						.then((auth) => {							if (auth) {								return auth.verifyPassword(data.secret)									.then((valid) => {										if (valid) {											if (data.scope !== 'user' && _.indexOf(user.roles, data.scope) === -1) {												// The scope requested doesn't exist as a role against the user,												// you shall not pass.												throw new error.AuthError('Invalid scope: ' + data.scope);											}											// Create a moment of the expiry expression											let expiry = helpers.parseDatePeriod(data.expiry);											if (expiry === null) {												throw new error.AuthError('Invalid expiry time: ' + data.expiry);											}											return Token.create({												iss:   issuer || 'api',												attrs: {													id: user.id												},												scope:     [data.scope],												expiresIn: data.expiry											})												.then((signed) => {													return {														token:   signed.token,														expires: expiry.toISOString()													};												});										} else {											throw new error.AuthError(ERROR_MESSAGE_INVALID_AUTH);										}									});							} else {								throw new error.AuthError(ERROR_MESSAGE_INVALID_AUTH);							}						});				} else {					throw new error.AuthError(ERROR_MESSAGE_INVALID_AUTH);				}			});	},	/**	 * @param {Access} access	 * @param {Object} [data]	 * @param {String} [data.expiry]	 * @param {String} [data.scope]   Only considered if existing token scope is admin	 * @returns {Promise}	 */	getFreshToken: (access, data) => {		let Token = new TokenModel();		data        = data || {};		data.expiry = data.expiry || '1d';		if (access && access.token.getUserId(0)) {			// Create a moment of the expiry expression			let expiry = helpers.parseDatePeriod(data.expiry);			if (expiry === null) {				throw new error.AuthError('Invalid expiry time: ' + data.expiry);			}			let token_attrs = {				id: access.token.getUserId(0)			};			// Only admins can request otherwise scoped tokens			let scope = access.token.get('scope');			if (data.scope && access.token.hasScope('admin')) {				scope = [data.scope];				if (data.scope === 'job-board' || data.scope === 'worker') {					token_attrs.id = 0;				}			}			return Token.create({				iss:       'api',				scope:     scope,				attrs:     token_attrs,				expiresIn: data.expiry			})				.then((signed) => {					return {						token:   signed.token,						expires: expiry.toISOString()					};				});		} else {			throw new error.AssertionFailedError('Existing token contained invalid user data');		}	},	/**	 * @param   {Object} user	 * @returns {Promise}	 */	getTokenFromUser: (user) => {		const expire = '1d';		const Token  = new TokenModel();		const expiry = helpers.parseDatePeriod(expire);		return Token.create({			iss:   'api',			attrs: {				id: user.id			},			scope:     ['user'],			expiresIn: expire		})			.then((signed) => {				return {					token:   signed.token,					expires: expiry.toISOString(),					user:    user				};			});	}};
 |