mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Code cleanup; add tests
This commit is contained in:
@@ -52,6 +52,10 @@ var hashPassword = function (password) {
|
||||
return bcryptHash(password, Accounts._bcryptRounds);
|
||||
};
|
||||
|
||||
// Extract the number of rounds used in the specified bcrypt hash.
|
||||
const getRoundsFromBcryptHash =
|
||||
hash => hash ? Number(hash.substring(4, 6)) : null;
|
||||
|
||||
// Check whether the provided password matches the bcrypt'ed password in
|
||||
// the database user record. `password` can be a string (in which case
|
||||
// it will be run through SHA256 before bcrypt) or an object with
|
||||
@@ -63,21 +67,19 @@ Accounts._checkPassword = function (user, password) {
|
||||
userId: user._id
|
||||
};
|
||||
|
||||
password = getPasswordString(password);
|
||||
const formattedPassword = getPasswordString(password);
|
||||
const hash = user.services.password.bcrypt;
|
||||
const hashRounds = getRoundsFromBcryptHash(hash);
|
||||
|
||||
if (! bcryptCompare(password, user.services.password.bcrypt)) {
|
||||
if (! bcryptCompare(formattedPassword, hash)) {
|
||||
result.error = handleError("Incorrect password", false);
|
||||
} else if (
|
||||
user.services.password.bcrypt &&
|
||||
Accounts._bcryptRounds >
|
||||
Number(user.services.password.bcrypt.substring(4, 6))
|
||||
) {
|
||||
// password checks out, but user bcrypt may need update
|
||||
} else if (hash && Accounts._bcryptRounds != hashRounds) {
|
||||
// The password checks out, but the user's bcrypt hash needs to be updated.
|
||||
Meteor.defer(() => {
|
||||
Meteor.users.update({ _id: user._id }, {
|
||||
$set: {
|
||||
'services.password.bcrypt':
|
||||
bcryptHash(password, Accounts._bcryptRounds)
|
||||
$set: {
|
||||
'services.password.bcrypt':
|
||||
bcryptHash(formattedPassword, Accounts._bcryptRounds)
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -92,7 +94,7 @@ var checkPassword = Accounts._checkPassword;
|
||||
///
|
||||
const handleError = (msg, throwError = true) => {
|
||||
const error = new Meteor.Error(
|
||||
403,
|
||||
403,
|
||||
Accounts._options.ambiguousErrorMessages
|
||||
? "Something went wrong. Please check your credentials."
|
||||
: msg
|
||||
|
||||
@@ -1886,4 +1886,51 @@ if (Meteor.isServer) (function () {
|
||||
]);
|
||||
});
|
||||
|
||||
Tinytest.addAsync(
|
||||
'passwords - allow custom bcrypt rounds',
|
||||
function (test, done) {
|
||||
function getUserHashRounds(user) {
|
||||
return Number(user.services.password.bcrypt.substring(4, 6));
|
||||
}
|
||||
|
||||
// Verify that a bcrypt hash generated for a new account uses the
|
||||
// default number of rounds.
|
||||
let username = Random.id();
|
||||
const password = 'abc123';
|
||||
const userId1 = Accounts.createUser({ username, password });
|
||||
let user1 = Meteor.users.findOne(userId1);
|
||||
let rounds = getUserHashRounds(user1);
|
||||
test.equal(rounds, Accounts._bcryptRounds);
|
||||
|
||||
// When a custom number of bcrypt rounds is set via Accounts.config,
|
||||
// and an account was already created using the default number of rounds,
|
||||
// make sure that a new hash is created (and stored) using the new number
|
||||
// of rounds, the next time the password is checked.
|
||||
const defaultRounds = Accounts._bcryptRounds;
|
||||
const customRounds = 11;
|
||||
Accounts._bcryptRounds = customRounds;
|
||||
Accounts._checkPassword(user1, password);
|
||||
Meteor.setTimeout(() => {
|
||||
user1 = Meteor.users.findOne(userId1);
|
||||
rounds = getUserHashRounds(user1);
|
||||
test.equal(rounds, customRounds);
|
||||
Accounts._options.bcryptRounds = null;
|
||||
|
||||
// When a custom number of bcrypt rounds is set, make sure it's
|
||||
// used for new bcrypt password hashes.
|
||||
username = Random.id();
|
||||
const userId2 = Accounts.createUser({ username, password });
|
||||
const user2 = Meteor.users.findOne(userId2);
|
||||
rounds = getUserHashRounds(user2);
|
||||
test.equal(rounds, customRounds);
|
||||
|
||||
// Cleanup
|
||||
Accounts._bcryptRounds = defaultRounds;
|
||||
Meteor.users.remove(userId1);
|
||||
Meteor.users.remove(userId2);
|
||||
done();
|
||||
}, 5000);
|
||||
}
|
||||
);
|
||||
|
||||
}) ();
|
||||
|
||||
Reference in New Issue
Block a user