UNPKG

feathers-service-verify-reset

Version:

Adds user email verification and password reset capabilities to local feathers-authentication

228 lines (183 loc) 7.09 kB
/* global assert, describe, it */ /* eslint no-shadow: 0, no-var: 0, one-var: 0, one-var-declaration-per-line: 0, no-param-reassign: 0, no-unused-vars: 0 */ const assert = require('chai').assert; const bcrypt = require('bcryptjs'); const auth = require('feathers-authentication').hooks; const feathersStubs = require('./../test/helpers/feathersStubs'); const verifyResetService = require('../lib/index').service; const SpyOn = require('./../test/helpers/basicSpy'); // user DB const usersDb = [ { _id: 'a', email: 'a', plainPassword: 'aa', plainNewPassword: 'xx', isVerified: false }, { _id: 'b', email: 'b', plainPassword: 'bb', plainNewPassword: 'yy', isVerified: true }, ]; describe('passwordChange - setup', () => { it('encode passwords', function (done) { this.timeout(9000); Promise.all([ encrypt(feathersStubs.app(), usersDb[0].plainPassword) .then(password => { usersDb[0].password = password; }), encrypt(feathersStubs.app(), usersDb[1].plainPassword) .then(password => { usersDb[1].password = password; }), encrypt(feathersStubs.app(), usersDb[0].plainNewPassword) .then(password => { usersDb[0].newPassword = password; }), encrypt(feathersStubs.app(), usersDb[1].plainNewPassword) .then(password => { usersDb[1].newPassword = password; }), ]) .then(() => { done(); }) .catch(err => console.log('encode', err)); // eslint-disable-line no-console }); it('compare plain passwords to encrypted ones', function () { this.timeout(9000); assert.isOk(bcrypt.compareSync(usersDb[0].plainPassword, usersDb[0].password), '[0]'); assert.isOk(bcrypt.compareSync(usersDb[1].plainPassword, usersDb[1].password), '[1]'); assert.isOk(bcrypt.compareSync(usersDb[0].plainNewPassword, usersDb[0].newPassword), 'new [0]'); assert.isOk(bcrypt.compareSync(usersDb[1].plainNewPassword, usersDb[1].newPassword), 'new [1]'); }); }); // Tests ['_id', 'id'].forEach(idType => { ['paginated', 'non-paginated'].forEach(pagination => { describe(`passwordChange ${pagination} ${idType}`, () => { const ifNonPaginated = pagination === 'non-paginated'; describe('standard', () => { var db; var app; var users; var verifyReset; beforeEach(() => { db = clone(usersDb); app = feathersStubs.app(); users = feathersStubs.users(app, db, ifNonPaginated, idType); verifyResetService().call(app); // define and attach verifyReset service verifyReset = app.service('verifyReset'); // get handle to verifyReset }); it('updates verified user', function (done) { this.timeout(9000); const i = 1; const user = clone(db[i]); const paramsUser = clone(user); delete paramsUser.password; verifyReset.create({ action: 'password', value: { oldPassword: user.plainPassword, password: user.plainNewPassword }, }, { user: paramsUser }, (err, user) => { assert.strictEqual(err, null, 'err code set'); assert.strictEqual(user.isVerified, true, 'isVerified not true'); assert.isOk(bcrypt.compareSync(db[i].plainNewPassword, db[i].password), `[${i}]`); done(); }); }); it('updates unverified user', function (done) { this.timeout(9000); const i = 0; const user = clone(db[i]); const paramsUser = clone(user); delete paramsUser.password; verifyReset.create({ action: 'password', value: { oldPassword: user.plainPassword, password: user.plainNewPassword }, }, { user: paramsUser }, (err, user) => { assert.strictEqual(err, null, 'err code set'); assert.strictEqual(user.isVerified, false, 'isVerified not false'); assert.isOk(bcrypt.compareSync(db[i].plainNewPassword, db[i].password), `[${i}]`); done(); }); }); it('error on wrong password', function (done) { this.timeout(9000); const i = 0; const user = clone(db[i]); verifyReset.create({ action: 'password', value: { oldPassword: 'fdfgfghghj', password: user.plainNewPassword }, }, { user }, (err, user) => { assert.isString(err.message); assert.isNotFalse(err.message); done(); }); }); }); describe('with email', () => { var db; var app; var users; var spyEmailer; var verifyReset; beforeEach(() => { db = clone(usersDb); app = feathersStubs.app(); users = feathersStubs.users(app, db, ifNonPaginated, idType); spyEmailer = new SpyOn(emailer); verifyResetService({ emailer: spyEmailer.callWithCb }).call(app); // attach verifyReset verifyReset = app.service('verifyReset'); // get handle to verifyReset }); it('updates verified user', function (done) { this.timeout(9000); const i = 1; const user = clone(db[i]); const paramsUser = clone(user); delete paramsUser.password; verifyReset.create({ action: 'password', value: { oldPassword: user.plainPassword, password: user.plainNewPassword }, }, { user: paramsUser }, (err, user) => { assert.strictEqual(err, null, 'err code set'); assert.strictEqual(user.isVerified, true, 'isVerified not true'); assert.isOk(bcrypt.compareSync(db[i].plainNewPassword, db[i].password), `[${i}]`); assert.deepEqual(spyEmailer.result(), [ { args: [ 'passwordChange', sanitizeUserForEmail(db[i]), {}, '' ], result: [null] }, ]); done(); }); }); }); }); }); }); // Helpers function encrypt(app, password) { const hook = { type: 'before', data: { password }, params: { provider: null }, app: { get(str) { return app.get(str); }, }, }; return auth.hashPassword()(hook) .then(hook1 => hook1.data.password) .catch(err => console.log('encrypt', err)); // eslint-disable-line no-console } function emailer(action, user, notifierOptions, newEmail, cb) { cb(null); } function sanitizeUserForEmail(user) { const user1 = clone(user); delete user1.password; return user1; } function clone(obj) { return JSON.parse(JSON.stringify(obj)); }