Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@accounts/server

Package Overview
Dependencies
Maintainers
5
Versions
204
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@accounts/server - npm Package Compare versions

Comparing version 0.0.8-alpha.840bab8d to 0.0.8-alpha.f59b6667

lib-es6/AccountsServer.js

1693

lib/index.js

@@ -1,28 +0,1687 @@

'use strict';
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory(require("babel-polyfill"), require("lodash"), require("jsonwebtoken"), require("@accounts/common"), require("bcryptjs"), require("crypto"), require("emailjs"));
else if(typeof define === 'function' && define.amd)
define(["babel-polyfill", "lodash", "jsonwebtoken", "@accounts/common", "bcryptjs", "crypto", "emailjs"], factory);
else if(typeof exports === 'object')
exports["@accounts/server"] = factory(require("babel-polyfill"), require("lodash"), require("jsonwebtoken"), require("@accounts/common"), require("bcryptjs"), require("crypto"), require("emailjs"));
else
root["@accounts/server"] = factory(root["babel-polyfill"], root["lodash"], root["jsonwebtoken"], root["@accounts/common"], root["bcryptjs"], root["crypto"], root["emailjs"]);
})(this, function(__WEBPACK_EXTERNAL_MODULE_1__, __WEBPACK_EXTERNAL_MODULE_3__, __WEBPACK_EXTERNAL_MODULE_4__, __WEBPACK_EXTERNAL_MODULE_5__, __WEBPACK_EXTERNAL_MODULE_8__, __WEBPACK_EXTERNAL_MODULE_10__, __WEBPACK_EXTERNAL_MODULE_12__) {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.config = exports.encryption = exports.AccountsServer = undefined;
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
var _AccountsServer = require('./AccountsServer');
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
var _AccountsServer2 = _interopRequireDefault(_AccountsServer);
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
var _encryption = require('./encryption');
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
var encryption = _interopRequireWildcard(_encryption);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
var _config = require('./config');
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
var _config2 = _interopRequireDefault(_config);
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
exports.default = _AccountsServer2.default; /* eslint-disable import/no-named-as-default */
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
exports.AccountsServer = _AccountsServer.AccountsServer;
exports.encryption = encryption;
exports.config = _config2.default;
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.config = exports.encryption = exports.AccountsServer = undefined;
__webpack_require__(1);
var _AccountsServer = __webpack_require__(2);
var _AccountsServer2 = _interopRequireDefault(_AccountsServer);
var _encryption = __webpack_require__(7);
var encryption = _interopRequireWildcard(_encryption);
var _config = __webpack_require__(6);
var _config2 = _interopRequireDefault(_config);
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/* eslint-disable import/no-named-as-default */
exports.default = _AccountsServer2.default;
exports.AccountsServer = _AccountsServer.AccountsServer;
exports.encryption = encryption;
exports.config = _config2.default;
/***/ },
/* 1 */
/***/ function(module, exports) {
module.exports = require("babel-polyfill");
/***/ },
/* 2 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.AccountsServer = undefined;
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
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; }; }();
var _lodash = __webpack_require__(3);
var _jsonwebtoken = __webpack_require__(4);
var _jsonwebtoken2 = _interopRequireDefault(_jsonwebtoken);
var _common = __webpack_require__(5);
var _config2 = __webpack_require__(6);
var _config3 = _interopRequireDefault(_config2);
var _encryption = __webpack_require__(7);
var _tokens = __webpack_require__(9);
var _email = __webpack_require__(11);
var _email2 = _interopRequireDefault(_email);
var _emailTemplates = __webpack_require__(13);
var _emailTemplates2 = _interopRequireDefault(_emailTemplates);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var AccountsServer = exports.AccountsServer = function () {
function AccountsServer() {
_classCallCheck(this, AccountsServer);
}
_createClass(AccountsServer, [{
key: 'config',
/**
* @description Configure AccountsServer.
* @param {Object} options - Options for AccountsServer.
* @param {Object} db - DBInterface for AccountsServer.
* @returns {Object} - Return the options.
*/
value: function config(options, db) {
this._options = _extends({}, _config3.default, options);
if (!db) {
throw new _common.AccountsError('A database driver is required');
}
this.db = db;
if (options.sendMail) {
this.email = { sendMail: options.sendMail };
} else {
this.email = new _email2.default(_config3.default.email);
}
this.emailTemplates = _emailTemplates2.default;
}
/**
* @description Return the AccountsServer options.
* @returns {Object} - Return the options.
*/
}, {
key: 'options',
value: function options() {
return this._options;
}
/**
* @description Login the user with his password.
* @param {Object} user - User to login.
* @param {string} password - Password of user to login.
* @param {string} ip - User ip.
* @param {string} userAgent - User user agent.
* @returns {Promise<Object>} - LoginReturnType.
*/
// eslint-disable-next-line max-len
}, {
key: 'loginWithPassword',
value: function () {
var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(user, password, ip, userAgent) {
var foundUser, sessionId, _createTokens, accessToken, refreshToken;
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
if (!(!user || !password)) {
_context.next = 2;
break;
}
throw new _common.AccountsError('Unrecognized options for login request', user, 400);
case 2:
if (!(!(0, _lodash.isString)(user) && !(0, _lodash.isPlainObject)(user) || !(0, _lodash.isString)(password))) {
_context.next = 4;
break;
}
throw new _common.AccountsError('Match failed', user, 400);
case 4:
foundUser = void 0;
if (!this._options.passwordAuthenticator) {
_context.next = 17;
break;
}
_context.prev = 6;
_context.next = 9;
return this._externalPasswordAuthenticator(this._options.passwordAuthenticator, user, password);
case 9:
foundUser = _context.sent;
_context.next = 15;
break;
case 12:
_context.prev = 12;
_context.t0 = _context['catch'](6);
throw new _common.AccountsError(_context.t0, user, 403);
case 15:
_context.next = 20;
break;
case 17:
_context.next = 19;
return this._defaultPasswordAuthenticator(user, password);
case 19:
foundUser = _context.sent;
case 20:
if (foundUser) {
_context.next = 22;
break;
}
throw new _common.AccountsError('User not found', user, 403);
case 22:
_context.next = 24;
return this.db.createSession(foundUser.id, ip, userAgent);
case 24:
sessionId = _context.sent;
_createTokens = this.createTokens(sessionId), accessToken = _createTokens.accessToken, refreshToken = _createTokens.refreshToken;
return _context.abrupt('return', {
sessionId: sessionId,
user: foundUser,
tokens: {
refreshToken: refreshToken,
accessToken: accessToken
}
});
case 27:
case 'end':
return _context.stop();
}
}
}, _callee, this, [[6, 12]]);
}));
function loginWithPassword(_x, _x2, _x3, _x4) {
return _ref.apply(this, arguments);
}
return loginWithPassword;
}()
// eslint-disable-next-line max-len
}, {
key: '_externalPasswordAuthenticator',
value: function () {
var _ref2 = _asyncToGenerator(regeneratorRuntime.mark(function _callee2(authFn, user, password) {
return regeneratorRuntime.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
return _context2.abrupt('return', authFn(user, password));
case 1:
case 'end':
return _context2.stop();
}
}
}, _callee2, this);
}));
function _externalPasswordAuthenticator(_x5, _x6, _x7) {
return _ref2.apply(this, arguments);
}
return _externalPasswordAuthenticator;
}()
}, {
key: '_defaultPasswordAuthenticator',
value: function () {
var _ref3 = _asyncToGenerator(regeneratorRuntime.mark(function _callee3(user, password) {
var _ref4, username, email, id, foundUser, hash, isPasswordValid;
return regeneratorRuntime.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
_ref4 = (0, _lodash.isString)(user) ? (0, _common.toUsernameAndEmail)({ user: user }) : (0, _common.toUsernameAndEmail)(_extends({}, user)), username = _ref4.username, email = _ref4.email, id = _ref4.id;
foundUser = void 0;
if (!id) {
_context3.next = 8;
break;
}
_context3.next = 5;
return this.db.findUserById(id);
case 5:
foundUser = _context3.sent;
_context3.next = 18;
break;
case 8:
if (!username) {
_context3.next = 14;
break;
}
_context3.next = 11;
return this.db.findUserByUsername(username);
case 11:
foundUser = _context3.sent;
_context3.next = 18;
break;
case 14:
if (!email) {
_context3.next = 18;
break;
}
_context3.next = 17;
return this.db.findUserByEmail(email);
case 17:
foundUser = _context3.sent;
case 18:
if (foundUser) {
_context3.next = 20;
break;
}
throw new _common.AccountsError('User not found', user, 403);
case 20:
_context3.next = 22;
return this.db.findPasswordHash(foundUser.id);
case 22:
hash = _context3.sent;
if (hash) {
_context3.next = 25;
break;
}
throw new _common.AccountsError('User has no password set', user, 403);
case 25:
_context3.next = 27;
return (0, _encryption.verifyPassword)(password, hash);
case 27:
isPasswordValid = _context3.sent;
if (isPasswordValid) {
_context3.next = 30;
break;
}
throw new _common.AccountsError('Incorrect password', user, 403);
case 30:
return _context3.abrupt('return', foundUser);
case 31:
case 'end':
return _context3.stop();
}
}
}, _callee3, this);
}));
function _defaultPasswordAuthenticator(_x8, _x9) {
return _ref3.apply(this, arguments);
}
return _defaultPasswordAuthenticator;
}()
/**
* @description Create a new user.
* @param {Object} user - The user object.
* @returns {Promise<string>} - Return the id of user created.
*/
}, {
key: 'createUser',
value: function () {
var _ref5 = _asyncToGenerator(regeneratorRuntime.mark(function _callee4(user) {
var userId;
return regeneratorRuntime.wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
if (!(!_common.validators.validateUsername(user.username) && !_common.validators.validateEmail(user.email))) {
_context4.next = 2;
break;
}
throw new _common.AccountsError('Username or Email is required', {
username: user && user.username,
email: user && user.email
});
case 2:
_context4.t0 = user.username;
if (!_context4.t0) {
_context4.next = 7;
break;
}
_context4.next = 6;
return this.db.findUserByUsername(user.username);
case 6:
_context4.t0 = _context4.sent;
case 7:
if (!_context4.t0) {
_context4.next = 9;
break;
}
throw new _common.AccountsError('Username already exists', { username: user.username });
case 9:
_context4.t1 = user.email;
if (!_context4.t1) {
_context4.next = 14;
break;
}
_context4.next = 13;
return this.db.findUserByEmail(user.email);
case 13:
_context4.t1 = _context4.sent;
case 14:
if (!_context4.t1) {
_context4.next = 16;
break;
}
throw new _common.AccountsError('Email already exists', { email: user.email });
case 16:
_context4.next = 18;
return this.db.createUser({
username: user.username,
email: user.email && user.email.toLowerCase(),
password: user.password,
profile: user.profile
});
case 18:
userId = _context4.sent;
return _context4.abrupt('return', userId);
case 20:
case 'end':
return _context4.stop();
}
}
}, _callee4, this);
}));
function createUser(_x10) {
return _ref5.apply(this, arguments);
}
return createUser;
}()
/**
* @description Refresh a user token.
* @param {string} accessToken - User access token.
* @param {string} refreshToken - User refresh token.
* @param {string} ip - User ip.
* @param {string} userAgent - User user agent.
* @returns {Promise<Object>} - LoginReturnType.
*/
// eslint-disable-next-line max-len
}, {
key: 'refreshTokens',
value: function () {
var _ref6 = _asyncToGenerator(regeneratorRuntime.mark(function _callee5(accessToken, refreshToken, ip, userAgent) {
var sessionId, decodedAccessToken, session, user, tokens;
return regeneratorRuntime.wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
case 0:
if (!(!(0, _lodash.isString)(accessToken) || !(0, _lodash.isString)(refreshToken))) {
_context5.next = 2;
break;
}
throw new _common.AccountsError('An accessToken and refreshToken are required');
case 2:
sessionId = void 0;
_context5.prev = 3;
_jsonwebtoken2.default.verify(refreshToken, this._options.tokenSecret);
decodedAccessToken = _jsonwebtoken2.default.verify(accessToken, this._options.tokenSecret, {
ignoreExpiration: true
});
sessionId = decodedAccessToken.data.sessionId;
_context5.next = 12;
break;
case 9:
_context5.prev = 9;
_context5.t0 = _context5['catch'](3);
throw new _common.AccountsError('Tokens are not valid');
case 12:
_context5.next = 14;
return this.db.findSessionById(sessionId);
case 14:
session = _context5.sent;
if (session) {
_context5.next = 17;
break;
}
throw new _common.AccountsError('Session not found');
case 17:
if (!session.valid) {
_context5.next = 29;
break;
}
_context5.next = 20;
return this.db.findUserById(session.userId);
case 20:
user = _context5.sent;
if (user) {
_context5.next = 23;
break;
}
throw new _common.AccountsError('User not found', { id: session.userId });
case 23:
tokens = this.createTokens(sessionId);
_context5.next = 26;
return this.db.updateSession(sessionId, ip, userAgent);
case 26:
return _context5.abrupt('return', {
sessionId: sessionId,
user: user,
tokens: tokens
});
case 29:
throw new _common.AccountsError('Session is no longer valid', { id: session.userId });
case 30:
case 'end':
return _context5.stop();
}
}
}, _callee5, this, [[3, 9]]);
}));
function refreshTokens(_x11, _x12, _x13, _x14) {
return _ref6.apply(this, arguments);
}
return refreshTokens;
}()
/**
* @description Refresh a user token.
* @param {string} sessionId - User session id.
* @returns {Promise<Object>} - Return a new accessToken and refreshToken.
*/
}, {
key: 'createTokens',
value: function createTokens(sessionId) {
var _options = this._options,
tokenSecret = _options.tokenSecret,
tokenConfigs = _options.tokenConfigs;
var accessToken = (0, _tokens.generateAccessToken)({
data: {
sessionId: sessionId
},
secret: tokenSecret,
config: tokenConfigs.accessToken
});
var refreshToken = (0, _tokens.generateRefreshToken)({
secret: tokenSecret,
config: tokenConfigs.refreshToken
});
return { accessToken: accessToken, refreshToken: refreshToken };
}
/**
* @description Logout a user and invalidate his session.
* @param {string} accessToken - User access token.
* @returns {Promise<void>} - Return a promise.
*/
}, {
key: 'logout',
value: function () {
var _ref7 = _asyncToGenerator(regeneratorRuntime.mark(function _callee6(accessToken) {
var session, user;
return regeneratorRuntime.wrap(function _callee6$(_context6) {
while (1) {
switch (_context6.prev = _context6.next) {
case 0:
_context6.next = 2;
return this.findSessionByAccessToken(accessToken);
case 2:
session = _context6.sent;
if (!session.valid) {
_context6.next = 13;
break;
}
_context6.next = 6;
return this.db.findUserById(session.userId);
case 6:
user = _context6.sent;
if (user) {
_context6.next = 9;
break;
}
throw new _common.AccountsError('User not found', { id: session.userId });
case 9:
_context6.next = 11;
return this.db.invalidateSession(session.sessionId);
case 11:
_context6.next = 14;
break;
case 13:
throw new _common.AccountsError('Session is no longer valid', { id: session.userId });
case 14:
case 'end':
return _context6.stop();
}
}
}, _callee6, this);
}));
function logout(_x15) {
return _ref7.apply(this, arguments);
}
return logout;
}()
}, {
key: 'resumeSession',
value: function () {
var _ref8 = _asyncToGenerator(regeneratorRuntime.mark(function _callee7(accessToken) {
var session, user;
return regeneratorRuntime.wrap(function _callee7$(_context7) {
while (1) {
switch (_context7.prev = _context7.next) {
case 0:
_context7.next = 2;
return this.findSessionByAccessToken(accessToken);
case 2:
session = _context7.sent;
if (!session.valid) {
_context7.next = 19;
break;
}
_context7.next = 6;
return this.db.findUserById(session.userId);
case 6:
user = _context7.sent;
if (user) {
_context7.next = 9;
break;
}
throw new _common.AccountsError('User not found', { id: session.userId });
case 9:
if (!this._options.resumeSessionValidator) {
_context7.next = 18;
break;
}
_context7.prev = 10;
_context7.next = 13;
return this._options.resumeSessionValidator(user, session);
case 13:
_context7.next = 18;
break;
case 15:
_context7.prev = 15;
_context7.t0 = _context7['catch'](10);
throw new _common.AccountsError(_context7.t0, { id: session.userId }, 403);
case 18:
return _context7.abrupt('return', user);
case 19:
return _context7.abrupt('return', null);
case 20:
case 'end':
return _context7.stop();
}
}
}, _callee7, this, [[10, 15]]);
}));
function resumeSession(_x16) {
return _ref8.apply(this, arguments);
}
return resumeSession;
}()
}, {
key: 'findSessionByAccessToken',
value: function () {
var _ref9 = _asyncToGenerator(regeneratorRuntime.mark(function _callee8(accessToken) {
var sessionId, decodedAccessToken, session;
return regeneratorRuntime.wrap(function _callee8$(_context8) {
while (1) {
switch (_context8.prev = _context8.next) {
case 0:
if ((0, _lodash.isString)(accessToken)) {
_context8.next = 2;
break;
}
throw new _common.AccountsError('An accessToken is required');
case 2:
sessionId = void 0;
_context8.prev = 3;
decodedAccessToken = _jsonwebtoken2.default.verify(accessToken, this._options.tokenSecret);
sessionId = decodedAccessToken.data.sessionId;
_context8.next = 11;
break;
case 8:
_context8.prev = 8;
_context8.t0 = _context8['catch'](3);
throw new _common.AccountsError('Tokens are not valid');
case 11:
_context8.next = 13;
return this.db.findSessionById(sessionId);
case 13:
session = _context8.sent;
if (session) {
_context8.next = 16;
break;
}
throw new _common.AccountsError('Session not found');
case 16:
return _context8.abrupt('return', session);
case 17:
case 'end':
return _context8.stop();
}
}
}, _callee8, this, [[3, 8]]);
}));
function findSessionByAccessToken(_x17) {
return _ref9.apply(this, arguments);
}
return findSessionByAccessToken;
}()
/**
* @description Find a user by one of his emails.
* @param {string} email - User email.
* @returns {Promise<Object>} - Return a user or null if not found.
*/
}, {
key: 'findUserByEmail',
value: function findUserByEmail(email) {
return this.db.findUserByEmail(email);
}
/**
* @description Find a user by his username.
* @param {string} username - User username.
* @returns {Promise<Object>} - Return a user or null if not found.
*/
}, {
key: 'findUserByUsername',
value: function findUserByUsername(username) {
return this.db.findUserByUsername(username);
}
/**
* @description Find a user by his id.
* @param {string} userId - User id.
* @returns {Promise<Object>} - Return a user or null if not found.
*/
}, {
key: 'findUserById',
value: function findUserById(userId) {
return this.db.findUserById(userId);
}
/**
* @description Add an email address for a user.
* Use this instead of directly updating the database.
* @param {string} userId - User id.
* @param {string} newEmail - A new email address for the user.
* @param {boolean} [verified] - Whether the new email address should be marked as verified.
* Defaults to false.
* @returns {Promise<void>} - Return a Promise.
*/
}, {
key: 'addEmail',
value: function addEmail(userId, newEmail, verified) {
return this.db.addEmail(userId, newEmail, verified);
}
/**
* @description Remove an email address for a user.
* Use this instead of directly updating the database.
* @param {string} userId - User id.
* @param {string} email - The email address to remove.
* @returns {Promise<void>} - Return a Promise.
*/
}, {
key: 'removeEmail',
value: function removeEmail(userId, email) {
return this.db.removeEmail(userId, email);
}
/**
* @description Marks the user's email address as verified.
* @param {string} token - The token retrieved from the verification URL.
* @returns {Promise<void>} - Return a Promise.
*/
}, {
key: 'verifyEmail',
value: function () {
var _ref10 = _asyncToGenerator(regeneratorRuntime.mark(function _callee9(token) {
var user, verificationTokens, tokenRecord, emailRecord;
return regeneratorRuntime.wrap(function _callee9$(_context9) {
while (1) {
switch (_context9.prev = _context9.next) {
case 0:
_context9.next = 2;
return this.db.findUserByEmailVerificationToken(token);
case 2:
user = _context9.sent;
if (user) {
_context9.next = 5;
break;
}
throw new _common.AccountsError('Verify email link expired');
case 5:
verificationTokens = (0, _lodash.get)(user, ['services', 'email', 'verificationTokens'], []);
tokenRecord = (0, _lodash.find)(verificationTokens, function (t) {
return t.token === token;
});
if (tokenRecord) {
_context9.next = 9;
break;
}
throw new _common.AccountsError('Verify email link expired');
case 9:
// TODO check time for expiry date
emailRecord = (0, _lodash.find)(user.emails, function (e) {
return e.address === tokenRecord.address;
});
if (emailRecord) {
_context9.next = 12;
break;
}
throw new _common.AccountsError('Verify email link is for unknown address');
case 12:
_context9.next = 14;
return this.db.verifyEmail(user.id, emailRecord.address);
case 14:
case 'end':
return _context9.stop();
}
}
}, _callee9, this);
}));
function verifyEmail(_x18) {
return _ref10.apply(this, arguments);
}
return verifyEmail;
}()
/**
* @description Reset the password for a user using a token received in email.
* @param {string} token - The token retrieved from the reset password URL.
* @param {string} newPassword - A new password for the user.
* @returns {Promise<void>} - Return a Promise.
*/
}, {
key: 'resetPassword',
value: function () {
var _ref11 = _asyncToGenerator(regeneratorRuntime.mark(function _callee10(token, newPassword) {
var user, resetTokens, resetTokenRecord, emails;
return regeneratorRuntime.wrap(function _callee10$(_context10) {
while (1) {
switch (_context10.prev = _context10.next) {
case 0:
_context10.next = 2;
return this.db.findUserByResetPasswordToken(token);
case 2:
user = _context10.sent;
if (user) {
_context10.next = 5;
break;
}
throw new _common.AccountsError('Reset password link expired');
case 5:
resetTokens = (0, _lodash.get)(user, ['services', 'password', 'resetTokens']);
resetTokenRecord = (0, _lodash.find)(resetTokens, function (t) {
return t.token === token;
});
if (resetTokenRecord) {
_context10.next = 9;
break;
}
throw new _common.AccountsError('Reset password link expired');
case 9:
// TODO check time for expiry date
emails = user.emails || [];
if ((0, _lodash.includes)(emails.map(function (email) {
return email.address;
}), resetTokenRecord.email)) {
_context10.next = 12;
break;
}
throw new _common.AccountsError('Token has invalid email address');
case 12:
_context10.next = 14;
return this.db.setResetPasssword(user.id, resetTokenRecord.email, newPassword, token);
case 14:
// Changing the password should invalidate existing sessions
this.db.invalidateAllSessions(user.id);
case 15:
case 'end':
return _context10.stop();
}
}
}, _callee10, this);
}));
function resetPassword(_x19, _x20) {
return _ref11.apply(this, arguments);
}
return resetPassword;
}()
/**
* @description Change the password for a user.
* @param {string} userId - User id.
* @param {string} newPassword - A new password for the user.
* @returns {Promise<void>} - Return a Promise.
*/
}, {
key: 'setPassword',
value: function setPassword(userId, newPassword) {
return this.db.setPasssword(userId, newPassword);
}
/**
* @description Change the profile for a user.
* @param {string} userId - User id.
* @param {Object} profile - The new user profile.
* @returns {Promise<void>} - Return a Promise.
*/
}, {
key: 'setProfile',
value: function () {
var _ref12 = _asyncToGenerator(regeneratorRuntime.mark(function _callee11(userId, profile) {
var user;
return regeneratorRuntime.wrap(function _callee11$(_context11) {
while (1) {
switch (_context11.prev = _context11.next) {
case 0:
_context11.next = 2;
return this.db.findUserById(userId);
case 2:
user = _context11.sent;
if (user) {
_context11.next = 5;
break;
}
throw new _common.AccountsError('User not found', { id: userId });
case 5:
_context11.next = 7;
return this.db.setProfile(userId, profile);
case 7:
case 'end':
return _context11.stop();
}
}
}, _callee11, this);
}));
function setProfile(_x21, _x22) {
return _ref12.apply(this, arguments);
}
return setProfile;
}()
/**
* @description Update the profile for a user,
* the new profile will be added to the existing one.
* @param {string} userId - User id.
* @param {Object} profile - User profile to add.
* @returns {Promise<Object>} - Return a Promise.
*/
}, {
key: 'updateProfile',
value: function () {
var _ref13 = _asyncToGenerator(regeneratorRuntime.mark(function _callee12(userId, profile) {
var user, res;
return regeneratorRuntime.wrap(function _callee12$(_context12) {
while (1) {
switch (_context12.prev = _context12.next) {
case 0:
_context12.next = 2;
return this.db.findUserById(userId);
case 2:
user = _context12.sent;
if (user) {
_context12.next = 5;
break;
}
throw new _common.AccountsError('User not found', { id: userId });
case 5:
_context12.next = 7;
return this.db.setProfile(userId, _extends({}, user.profile, profile));
case 7:
res = _context12.sent;
return _context12.abrupt('return', res);
case 9:
case 'end':
return _context12.stop();
}
}
}, _callee12, this);
}));
function updateProfile(_x23, _x24) {
return _ref13.apply(this, arguments);
}
return updateProfile;
}()
/**
* @description Send an email with a link the user can use verify their email address.
* @param {string} userId - The id of the user to send email to.
* @param {string} [address] - Which address of the user's to send the email to.
* This address must be in the user's emails list.
* Defaults to the first unverified email in the list.
* @returns {Promise<void>} - Return a Promise.
*/
}, {
key: 'sendVerificationEmail',
value: function () {
var _ref14 = _asyncToGenerator(regeneratorRuntime.mark(function _callee13(userId, address) {
var user, email, emails, token, verifyEmailUrl;
return regeneratorRuntime.wrap(function _callee13$(_context13) {
while (1) {
switch (_context13.prev = _context13.next) {
case 0:
_context13.next = 2;
return this.db.findUserById(userId);
case 2:
user = _context13.sent;
if (user) {
_context13.next = 5;
break;
}
throw new _common.AccountsError('User not found', { id: userId });
case 5:
// If no address provided find the first unverified email
if (!address) {
email = (0, _lodash.find)(user.emails, function (e) {
return !e.verified;
});
address = email && email.address; // eslint-disable-line no-param-reassign
}
// Make sure the address is valid
emails = user.emails || [];
if (!(!address || !(0, _lodash.includes)(emails.map(function (email) {
return email.address;
}), address))) {
_context13.next = 9;
break;
}
throw new _common.AccountsError('No such email address for user');
case 9:
token = (0, _tokens.generateRandomToken)();
_context13.next = 12;
return this.db.addEmailVerificationToken(userId, address, token);
case 12:
verifyEmailUrl = this._options.siteUrl + '/verify-email/' + token;
_context13.next = 15;
return this.email.sendMail({
from: this.emailTemplates.verifyEmail.from ? this.emailTemplates.verifyEmail.from : this.emailTemplates.from,
to: address,
subject: this.emailTemplates.verifyEmail.subject(user),
text: this.emailTemplates.verifyEmail.text(user, verifyEmailUrl)
});
case 15:
case 'end':
return _context13.stop();
}
}
}, _callee13, this);
}));
function sendVerificationEmail(_x25, _x26) {
return _ref14.apply(this, arguments);
}
return sendVerificationEmail;
}()
/**
* @description Send an email with a link the user can use to reset their password.
* @param {string} userId - The id of the user to send email to.
* @param {string} [address] - Which address of the user's to send the email to.
* This address must be in the user's emails list.
* Defaults to the first email in the list.
* @returns {Promise<void>} - Return a Promise.
*/
}, {
key: 'sendResetPasswordEmail',
value: function () {
var _ref15 = _asyncToGenerator(regeneratorRuntime.mark(function _callee14(userId, address) {
var user, token, resetPasswordUrl;
return regeneratorRuntime.wrap(function _callee14$(_context14) {
while (1) {
switch (_context14.prev = _context14.next) {
case 0:
_context14.next = 2;
return this.db.findUserById(userId);
case 2:
user = _context14.sent;
if (user) {
_context14.next = 5;
break;
}
throw new _common.AccountsError('User not found', { id: userId });
case 5:
address = this._getFirstUserEmail(user, address); // eslint-disable-line no-param-reassign
token = (0, _tokens.generateRandomToken)();
_context14.next = 9;
return this.db.addResetPasswordToken(userId, address, token);
case 9:
resetPasswordUrl = this._options.siteUrl + '/reset-password/' + token;
_context14.next = 12;
return this.email.sendMail({
from: this.emailTemplates.resetPassword.from ? this.emailTemplates.resetPassword.from : this.emailTemplates.from,
to: address,
subject: this.emailTemplates.resetPassword.subject(user),
text: this.emailTemplates.resetPassword.text(user, resetPasswordUrl)
});
case 12:
case 'end':
return _context14.stop();
}
}
}, _callee14, this);
}));
function sendResetPasswordEmail(_x27, _x28) {
return _ref15.apply(this, arguments);
}
return sendResetPasswordEmail;
}()
/**
* @description Send an email with a link the user can use to set their initial password.
* @param {string} userId - The id of the user to send email to.
* @param {string} [address] - Which address of the user's to send the email to.
* This address must be in the user's emails list.
* Defaults to the first email in the list.
* @returns {Promise<void>} - Return a Promise.
*/
}, {
key: 'sendEnrollmentEmail',
value: function () {
var _ref16 = _asyncToGenerator(regeneratorRuntime.mark(function _callee15(userId, address) {
var user, token, enrollAccountUrl;
return regeneratorRuntime.wrap(function _callee15$(_context15) {
while (1) {
switch (_context15.prev = _context15.next) {
case 0:
_context15.next = 2;
return this.db.findUserById(userId);
case 2:
user = _context15.sent;
if (user) {
_context15.next = 5;
break;
}
throw new _common.AccountsError('User not found', { id: userId });
case 5:
address = this._getFirstUserEmail(user, address); // eslint-disable-line no-param-reassign
token = (0, _tokens.generateRandomToken)();
_context15.next = 9;
return this.db.addResetPasswordToken(userId, address, token, 'enroll');
case 9:
enrollAccountUrl = this._options.siteUrl + '/enroll-account/' + token;
_context15.next = 12;
return this.email.sendMail({
from: this.emailTemplates.enrollAccount.from ? this.emailTemplates.enrollAccount.from : this.emailTemplates.from,
to: address,
subject: this.emailTemplates.enrollAccount.subject(user),
text: this.emailTemplates.enrollAccount.text(user, enrollAccountUrl)
});
case 12:
case 'end':
return _context15.stop();
}
}
}, _callee15, this);
}));
function sendEnrollmentEmail(_x29, _x30) {
return _ref16.apply(this, arguments);
}
return sendEnrollmentEmail;
}()
}, {
key: '_getFirstUserEmail',
value: function _getFirstUserEmail(user, address) {
// Pick the first email if we weren't passed an email
if (!address && user.emails && user.emails[0]) {
address = user.emails[0].address; // eslint-disable-line no-param-reassign
}
// Make sure the address is valid
var emails = user.emails || [];
if (!address || !(0, _lodash.includes)(emails.map(function (email) {
return email.address;
}), address)) {
throw new _common.AccountsError('No such email address for user');
}
return address;
}
}]);
return AccountsServer;
}();
exports.default = new AccountsServer();
/***/ },
/* 3 */
/***/ function(module, exports) {
module.exports = require("lodash");
/***/ },
/* 4 */
/***/ function(module, exports) {
module.exports = require("jsonwebtoken");
/***/ },
/* 5 */
/***/ function(module, exports) {
module.exports = require("@accounts/common");
/***/ },
/* 6 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _common = __webpack_require__(5);
exports.default = _extends({}, _common.config, {
tokenSecret: 'terrible secret',
tokenConfigs: {
accessToken: {
expiresIn: '90m'
},
refreshToken: {
expiresIn: '1d'
}
}
});
/***/ },
/* 7 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.verifyPassword = exports.hashPassword = undefined;
var _bcryptjs = __webpack_require__(8);
var _bcryptjs2 = _interopRequireDefault(_bcryptjs);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
var hashPassword = function () {
var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(password) {
var salt, hash;
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return _bcryptjs2.default.genSalt(10);
case 2:
salt = _context.sent;
_context.next = 5;
return _bcryptjs2.default.hash(password, salt);
case 5:
hash = _context.sent;
return _context.abrupt('return', hash);
case 7:
case 'end':
return _context.stop();
}
}
}, _callee, undefined);
}));
return function hashPassword(_x) {
return _ref.apply(this, arguments);
};
}();
exports.hashPassword = hashPassword;
var verifyPassword = function () {
var _ref2 = _asyncToGenerator(regeneratorRuntime.mark(function _callee2(password, hash) {
return regeneratorRuntime.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
return _context2.abrupt('return', _bcryptjs2.default.compare(password, hash));
case 1:
case 'end':
return _context2.stop();
}
}
}, _callee2, undefined);
}));
return function verifyPassword(_x2, _x3) {
return _ref2.apply(this, arguments);
};
}();
exports.verifyPassword = verifyPassword;
/***/ },
/* 8 */
/***/ function(module, exports) {
module.exports = require("bcryptjs");
/***/ },
/* 9 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.generateRefreshToken = exports.generateAccessToken = exports.generateRandomToken = undefined;
var _jsonwebtoken = __webpack_require__(4);
var _jsonwebtoken2 = _interopRequireDefault(_jsonwebtoken);
var _crypto = __webpack_require__(10);
var _crypto2 = _interopRequireDefault(_crypto);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var generateRandomToken = exports.generateRandomToken = function generateRandomToken() {
var length = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 43;
return _crypto2.default.randomBytes(length).toString('hex');
};
var generateAccessToken = exports.generateAccessToken = function generateAccessToken(_ref) {
var secret = _ref.secret,
data = _ref.data,
config = _ref.config;
return _jsonwebtoken2.default.sign({
data: data
}, secret, config);
};
var generateRefreshToken = exports.generateRefreshToken = function generateRefreshToken(_ref2) {
var secret = _ref2.secret,
data = _ref2.data,
config = _ref2.config;
return _jsonwebtoken2.default.sign({
data: data
}, secret, config);
};
/***/ },
/* 10 */
/***/ function(module, exports) {
module.exports = require("crypto");
/***/ },
/* 11 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
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; }; }();
var _emailjs = __webpack_require__(12);
var _emailjs2 = _interopRequireDefault(_emailjs);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Email = function () {
function Email(emailConfig) {
_classCallCheck(this, Email);
if (emailConfig) {
this.server = _emailjs2.default.server.connect(emailConfig);
}
}
_createClass(Email, [{
key: 'sendMail',
value: function sendMail(mail) {
var _this = this;
return new Promise(function (resolve, reject) {
// eslint-disable-line flowtype/require-parameter-type
// If no configuration for email just warn the user
if (!_this.server) {
console.log('No configuration for email, you must set an email configuration');
resolve();
return;
}
_this.server.send(mail, function (err, message) {
if (err) return reject(err);
return resolve(message);
});
});
}
}]);
return Email;
}();
exports.default = Email;
/***/ },
/* 12 */
/***/ function(module, exports) {
module.exports = require("emailjs");
/***/ },
/* 13 */
/***/ function(module, exports) {
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = {
from: 'js-accounts <no-reply@js-accounts.com>',
verifyEmail: {
subject: function subject() {
return 'Verify your account email';
},
text: function text(user, url) {
return 'To verify your account email please click on this link: ' + url;
}
},
resetPassword: {
subject: function subject() {
return 'Reset your password';
},
text: function text(user, url) {
return 'To reset your password please click on this link: ' + url;
}
},
enrollAccount: {
subject: function subject() {
return 'Set your password';
},
text: function text(user, url) {
return 'To set your password please click on this link: ' + url;
}
}
};
/***/ }
/******/ ])
});
;

12

package.json
{
"name": "@accounts/server",
"version": "0.0.8-alpha.840bab8d",
"version": "0.0.8-alpha.f59b6667",
"description": "Fullstack authentication and accounts-management",
"main": "lib/index.js",
"jsnext:main": "lib-es6/index.js",
"publishConfig": {

@@ -11,3 +12,5 @@ "access": "public"

"start": "webpack -p --config --progress --watch",
"compile": "babel ./src --out-dir ./lib",
"compile": "npm run compile:es6 && npm run compile:umd",
"compile:es6": "babel ./src --out-dir ./lib-es6",
"compile:umd": "webpack",
"postcompile": "npm run flow:prepublish",

@@ -19,3 +22,3 @@ "prepublish": "npm run compile",

"flow:check": "flow check",
"flow:prepublish": "for i in `ls ./src/*.js`; do cp $i `echo $i | sed \"s/src/lib/g\" | sed \"s/js/js\\.flow/g\"`; done",
"flow:prepublish": "for i in `ls ./src/*.js`; do cp $i `echo $i | sed \"s/src/lib-es6/g\" | sed \"s/js/js\\.flow/g\"`; done",
"coverage": "npm run testonly -- --coverage",

@@ -48,3 +51,4 @@ "coveralls": "cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage"

"dependencies": {
"@accounts/common": "^0.0.8-alpha.840bab8d",
"@accounts/common": "^0.0.8-alpha.f59b6667",
"babel-polyfill": "^6.23.0",
"bcryptjs": "^2.4.0",

@@ -51,0 +55,0 @@ "crypto": "^0.0.3",

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc