mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-17 22:57:21 +01:00
* start migrating to bcrypt * added method to convert the password to bcrypt when logging in, added method to compare password without knowing the hashing algorhytm, remove default * travis: try to upgrade to container based infrastructure * travis: add deps to build bcrypt.js * travis: add deps to build bcrypt.js * travis: add deps to build bcrypt.js * travis: add deps to build bcrypt.js * use bcryptjs until bcrypt can be installed on travis, see https://github.com/kelektiv/node.bcrypt.js/issues/476 * correct sha1 unit tests * try different mongodb repo * try without mognodb services * try again with bcrypt * disable request logging in travis * migrate missing routes * simplify code * remove bcryptjs * fix typo * fix typo * fix typo in comment * add unit tests for new passwords utility emthods * travis: back to old infrastructure, containers often have timeouts * add integration test for passwordHashMethod * update shrinkwrap * clarify code and add comments * add integration tests * fix linting * fix integration tests
66 lines
2.5 KiB
JavaScript
66 lines
2.5 KiB
JavaScript
// Utilities for working with passwords
|
|
import crypto from 'crypto';
|
|
import bcrypt from 'bcrypt';
|
|
|
|
const BCRYPT_SALT_ROUNDS = 10;
|
|
|
|
// Hash a plain text password
|
|
export function bcryptHash (passwordToHash) {
|
|
return bcrypt.hash(passwordToHash, BCRYPT_SALT_ROUNDS); // returns a promise
|
|
}
|
|
|
|
// Check if a plain text password matches a hash
|
|
export function bcryptCompare (passwordToCheck, hashedPassword) {
|
|
return bcrypt.compare(passwordToCheck, hashedPassword); // returns a promise
|
|
}
|
|
|
|
// Return the encrypted version of a password (using sha1) given a salt
|
|
// Used for legacy passwords that have not yet been migrated to bcrypt
|
|
export function sha1Encrypt (password, salt) {
|
|
return crypto
|
|
.createHmac('sha1', salt)
|
|
.update(password)
|
|
.digest('hex');
|
|
}
|
|
|
|
// Create a salt, default length is 10
|
|
export function sha1MakeSalt (len = 10) {
|
|
return crypto
|
|
.randomBytes(Math.ceil(len / 2))
|
|
.toString('hex')
|
|
.substring(0, len);
|
|
}
|
|
|
|
// Compare the password for an user
|
|
// Works with bcrypt and sha1 indipendently
|
|
// An async function is used so that a promise is always returned
|
|
// even for comparing sha1 hashed passwords that use a sync method
|
|
export async function compare (user, passwordToCheck) {
|
|
if (!user || !passwordToCheck) throw new Error('user and passwordToCheck are required parameters.');
|
|
|
|
let passwordHashMethod = user.auth.local.passwordHashMethod;
|
|
let passwordHash = user.auth.local.hashed_password;
|
|
let passwordSalt = user.auth.local.salt; // Only used for SHA1
|
|
|
|
if (passwordHashMethod === 'bcrypt') {
|
|
return await bcryptCompare(passwordToCheck, passwordHash);
|
|
// default to sha1 if the user has a salt but no passwordHashMethod
|
|
} else if (passwordHashMethod === 'sha1' || !passwordHashMethod && passwordSalt) {
|
|
return passwordHash === sha1Encrypt(passwordToCheck, passwordSalt);
|
|
} else {
|
|
throw new Error('Invalid password hash method.');
|
|
}
|
|
}
|
|
|
|
// Convert an user to use bcrypt from sha1 for password hashing
|
|
// needs to save the user separately.
|
|
// NOTE: before calling this method it should be verified that the supplied plain text password
|
|
// is indeed hashed with sha1 and is valid
|
|
export async function convertToBcrypt (user, plainTextPassword) {
|
|
if (!user || !plainTextPassword) throw new Error('user and plainTextPassword are required parameters.');
|
|
|
|
user.auth.local.salt = undefined;
|
|
user.auth.local.passwordHashMethod = 'bcrypt';
|
|
user.auth.local.hashed_password = await bcryptHash(plainTextPassword); // eslint-disable-line camelcase
|
|
}
|