All files / src reset-password.js

95.35% Statements 41/43
73.33% Branches 11/15
100% Functions 5/5
95.35% Lines 41/43

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 1051x 1x 1x 1x 1x 1x 1x 1x 1x   1x   1x           48x   48x       11x 11x   9x       57x 57x 57x     57x 48x 48x 9x 9x             57x 57x   42x 42x   4x           38x       13x             42x 42x   13x 4x       4x   9x             9x           29x               29x 29x    
const errors = require('@feathersjs/errors');
const makeDebug = require('debug');
const comparePasswords = require('./helpers/compare-passwords');
const deconstructId = require('./helpers/deconstruct-id');
const ensureObjPropsValid = require('./helpers/ensure-obj-props-valid');
const ensureValuesAreStrings = require('./helpers/ensure-values-are-strings');
const getUserData = require('./helpers/get-user-data');
const hashPassword = require('./helpers/hash-password');
const notifier = require('./helpers/notifier');
 
const debug = makeDebug('authLocalMgnt:resetPassword');
 
module.exports = {
  resetPwdWithLongToken,
  resetPwdWithShortToken
};
 
async function resetPwdWithLongToken (options, resetToken, password, field, notifierOptions = {}) {
  ensureValuesAreStrings(resetToken, password);
 
  return resetPassword(options, { resetToken }, { resetToken }, password, field, notifierOptions);
}
 
async function resetPwdWithShortToken (options, resetShortToken, identifyUser, password, field, notifierOptions = {}) {
  ensureValuesAreStrings(resetShortToken, password);
  ensureObjPropsValid(identifyUser, options.identifyUserProps);
 
  return resetPassword(options, identifyUser, { resetShortToken }, password, field, notifierOptions);
}
 
async function resetPassword (options, query, tokens, password, field, notifierOptions = {}) {
  debug('resetPassword', query, tokens, password);
  const usersService = options.app.service(options.service);
  const usersServiceIdName = usersService.id;
  let users;
 
  if (tokens.resetToken) {
    let id = deconstructId(tokens.resetToken);
    users = await usersService.get(id);
  } else Eif (tokens.resetShortToken) {
    users = await usersService.find({ query });
  } else {
    throw new errors.BadRequest('resetToken and resetShortToken are missing. (authLocalMgnt)', {
      errors: { $className: 'missingToken' }
    });
  }
 
  const checkProps = options.skipIsVerifiedCheck ? ['resetNotExpired'] : ['resetNotExpired', 'isVerified'];
  const user1 = getUserData(users, checkProps);
 
  const tokenChecks = Object.keys(tokens).map(async key => {
    if (options.reuseResetToken) {
      // Comparing token directly as reused resetToken is not hashed
      Iif (tokens[key] !== user1[key]) {
        throw new errors.BadRequest('Reset Token is incorrect. (authLocalMgnt)', {
          errors: {$className: 'incorrectToken'}
        });
      }
    } else {
      return comparePasswords(
        tokens[key],
        user1[key],
        () =>
          new errors.BadRequest('Reset Token is incorrect. (authLocalMgnt)', {
            errors: {$className: 'incorrectToken'}
          })
      );
    }
  });
 
  try {
    await Promise.all(tokenChecks);
  } catch (err) {
    if (user1.resetAttempts > 0) {
      await usersService.patch(user1[usersServiceIdName], {
        resetAttempts: user1.resetAttempts - 1
      });
 
      throw err;
    } else {
      await usersService.patch(user1[usersServiceIdName], {
        resetToken: null,
        resetAttempts: null,
        resetShortToken: null,
        resetExpires: null
      });
 
      throw new errors.BadRequest('Invalid token. Get for a new one. (authLocalMgnt)', {
        errors: { $className: 'invalidToken' }
      });
    }
  }
 
  const user2 = await usersService.patch(user1[usersServiceIdName], {
    password: await hashPassword(options.app, password, field),
    resetExpires: null,
    resetAttempts: null,
    resetToken: null,
    resetShortToken: null
  });
 
  const user3 = await notifier(options.notifier, 'resetPwd', user2, notifierOptions);
  return options.sanitizeUserForClient(user3);
}