mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #3234 from overleaf/sk-fix-password-validation-email
Overhaul password validation GitOrigin-RevId: a591c4e192e30a0ac053eab6f80627543a8a92fe
This commit is contained in:
parent
85d37f8990
commit
e9f7a17093
13 changed files with 127 additions and 91 deletions
|
@ -3,7 +3,6 @@ const { User } = require('../../models/User')
|
||||||
const { db, ObjectId } = require('../../infrastructure/mongodb')
|
const { db, ObjectId } = require('../../infrastructure/mongodb')
|
||||||
const bcrypt = require('bcrypt')
|
const bcrypt = require('bcrypt')
|
||||||
const EmailHelper = require('../Helpers/EmailHelper')
|
const EmailHelper = require('../Helpers/EmailHelper')
|
||||||
const V1Handler = require('../V1/V1Handler')
|
|
||||||
const {
|
const {
|
||||||
InvalidEmailError,
|
InvalidEmailError,
|
||||||
InvalidPasswordError
|
InvalidPasswordError
|
||||||
|
@ -66,8 +65,8 @@ const AuthenticationManager = {
|
||||||
|
|
||||||
// validates a password based on a similar set of rules to `complexPassword.js` on the frontend
|
// validates a password based on a similar set of rules to `complexPassword.js` on the frontend
|
||||||
// note that `passfield.js` enforces more rules than this, but these are the most commonly set.
|
// note that `passfield.js` enforces more rules than this, but these are the most commonly set.
|
||||||
// returns null on success, or an error string.
|
// returns null on success, or an error object.
|
||||||
validatePassword(password) {
|
validatePassword(password, email) {
|
||||||
if (password == null) {
|
if (password == null) {
|
||||||
return new InvalidPasswordError({
|
return new InvalidPasswordError({
|
||||||
message: 'password not set',
|
message: 'password not set',
|
||||||
|
@ -113,11 +112,23 @@ const AuthenticationManager = {
|
||||||
info: { code: 'invalid_character' }
|
info: { code: 'invalid_character' }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if (typeof email === 'string' && email !== '') {
|
||||||
|
const startOfEmail = email.split('@')[0]
|
||||||
|
if (
|
||||||
|
password.indexOf(email) !== -1 ||
|
||||||
|
password.indexOf(startOfEmail) !== -1
|
||||||
|
) {
|
||||||
|
return new InvalidPasswordError({
|
||||||
|
message: 'password contains part of email address',
|
||||||
|
info: { code: 'contains_email' }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
return null
|
return null
|
||||||
},
|
},
|
||||||
|
|
||||||
setUserPassword(userId, password, callback) {
|
setUserPassword(user, password, callback) {
|
||||||
AuthenticationManager.setUserPasswordInV2(userId, password, callback)
|
AuthenticationManager.setUserPasswordInV2(user, password, callback)
|
||||||
},
|
},
|
||||||
|
|
||||||
checkRounds(user, hashedPassword, password, callback) {
|
checkRounds(user, hashedPassword, password, callback) {
|
||||||
|
@ -128,7 +139,7 @@ const AuthenticationManager = {
|
||||||
// check current number of rounds and rehash if necessary
|
// check current number of rounds and rehash if necessary
|
||||||
const currentRounds = bcrypt.getRounds(hashedPassword)
|
const currentRounds = bcrypt.getRounds(hashedPassword)
|
||||||
if (currentRounds < BCRYPT_ROUNDS) {
|
if (currentRounds < BCRYPT_ROUNDS) {
|
||||||
AuthenticationManager.setUserPassword(user._id, password, callback)
|
AuthenticationManager.setUserPassword(user, password, callback)
|
||||||
} else {
|
} else {
|
||||||
callback()
|
callback()
|
||||||
}
|
}
|
||||||
|
@ -143,8 +154,11 @@ const AuthenticationManager = {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
setUserPasswordInV2(userId, password, callback) {
|
setUserPasswordInV2(user, password, callback) {
|
||||||
const validationError = this.validatePassword(password)
|
if (!user || !user.email || !user._id) {
|
||||||
|
return callback(new Error('invalid user object'))
|
||||||
|
}
|
||||||
|
const validationError = this.validatePassword(password, user.email)
|
||||||
if (validationError) {
|
if (validationError) {
|
||||||
return callback(validationError)
|
return callback(validationError)
|
||||||
}
|
}
|
||||||
|
@ -154,7 +168,7 @@ const AuthenticationManager = {
|
||||||
}
|
}
|
||||||
db.users.updateOne(
|
db.users.updateOne(
|
||||||
{
|
{
|
||||||
_id: ObjectId(userId.toString())
|
_id: ObjectId(user._id.toString())
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
$set: {
|
$set: {
|
||||||
|
@ -174,20 +188,6 @@ const AuthenticationManager = {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
setUserPasswordInV1(v1UserId, password, callback) {
|
|
||||||
const validationError = this.validatePassword(password)
|
|
||||||
if (validationError) {
|
|
||||||
return callback(validationError.message)
|
|
||||||
}
|
|
||||||
|
|
||||||
V1Handler.doPasswordReset(v1UserId, password, function(error, reset) {
|
|
||||||
if (error) {
|
|
||||||
return callback(error)
|
|
||||||
}
|
|
||||||
callback(error, reset)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
_passwordCharactersAreValid(password) {
|
_passwordCharactersAreValid(password) {
|
||||||
let digits, letters, lettersUp, symbols
|
let digits, letters, lettersUp, symbols
|
||||||
if (
|
if (
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
const PasswordResetHandler = require('./PasswordResetHandler')
|
const PasswordResetHandler = require('./PasswordResetHandler')
|
||||||
const RateLimiter = require('../../infrastructure/RateLimiter')
|
const RateLimiter = require('../../infrastructure/RateLimiter')
|
||||||
const AuthenticationController = require('../Authentication/AuthenticationController')
|
const AuthenticationController = require('../Authentication/AuthenticationController')
|
||||||
const AuthenticationManager = require('../Authentication/AuthenticationManager')
|
|
||||||
const UserGetter = require('../User/UserGetter')
|
const UserGetter = require('../User/UserGetter')
|
||||||
const UserUpdater = require('../User/UserUpdater')
|
const UserUpdater = require('../User/UserUpdater')
|
||||||
const UserSessionsManager = require('../User/UserSessionsManager')
|
const UserSessionsManager = require('../User/UserSessionsManager')
|
||||||
|
@ -15,9 +14,6 @@ async function setNewUserPassword(req, res, next) {
|
||||||
return res.sendStatus(400)
|
return res.sendStatus(400)
|
||||||
}
|
}
|
||||||
passwordResetToken = passwordResetToken.trim()
|
passwordResetToken = passwordResetToken.trim()
|
||||||
if (AuthenticationManager.validatePassword(password) != null) {
|
|
||||||
return res.sendStatus(400)
|
|
||||||
}
|
|
||||||
delete req.session.resetToken
|
delete req.session.resetToken
|
||||||
|
|
||||||
const initiatorId = AuthenticationController.getLoggedInUserId(req)
|
const initiatorId = AuthenticationController.getLoggedInUserId(req)
|
||||||
|
|
|
@ -54,7 +54,7 @@ function getUserForPasswordResetToken(token, callback) {
|
||||||
}
|
}
|
||||||
UserGetter.getUserByMainEmail(
|
UserGetter.getUserByMainEmail(
|
||||||
data.email,
|
data.email,
|
||||||
{ _id: 1, 'overleaf.id': 1 },
|
{ _id: 1, 'overleaf.id': 1, email: 1 },
|
||||||
(err, user) => {
|
(err, user) => {
|
||||||
if (err != null) {
|
if (err != null) {
|
||||||
callback(err)
|
callback(err)
|
||||||
|
@ -93,6 +93,11 @@ async function setNewUserPassword(token, password, auditLog) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const reset = await AuthenticationManager.promises.setUserPassword(
|
||||||
|
user,
|
||||||
|
password
|
||||||
|
)
|
||||||
|
|
||||||
await UserAuditLogHandler.promises.addEntry(
|
await UserAuditLogHandler.promises.addEntry(
|
||||||
user._id,
|
user._id,
|
||||||
'reset-password',
|
'reset-password',
|
||||||
|
@ -100,11 +105,6 @@ async function setNewUserPassword(token, password, auditLog) {
|
||||||
auditLog.ip
|
auditLog.ip
|
||||||
)
|
)
|
||||||
|
|
||||||
const reset = await AuthenticationManager.promises.setUserPassword(
|
|
||||||
user._id,
|
|
||||||
password
|
|
||||||
)
|
|
||||||
|
|
||||||
return { found: true, reset, userId: user._id }
|
return { found: true, reset, userId: user._id }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,13 +85,19 @@ async function changePassword(req, res, next) {
|
||||||
req.i18n.translate('password_change_passwords_do_not_match')
|
req.i18n.translate('password_change_passwords_do_not_match')
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
const validationError = AuthenticationManager.validatePassword(
|
|
||||||
req.body.newPassword1
|
|
||||||
)
|
|
||||||
if (validationError != null) {
|
|
||||||
return HttpErrorHandler.badRequest(req, res, validationError.message)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
await AuthenticationManager.promises.setUserPassword(
|
||||||
|
user,
|
||||||
|
req.body.newPassword1
|
||||||
|
)
|
||||||
|
} catch (error) {
|
||||||
|
if (error.name === 'InvalidPasswordError') {
|
||||||
|
return HttpErrorHandler.badRequest(req, res, error.message)
|
||||||
|
} else {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
await UserAuditLogHandler.promises.addEntry(
|
await UserAuditLogHandler.promises.addEntry(
|
||||||
user._id,
|
user._id,
|
||||||
'update-password',
|
'update-password',
|
||||||
|
@ -99,11 +105,6 @@ async function changePassword(req, res, next) {
|
||||||
req.ip
|
req.ip
|
||||||
)
|
)
|
||||||
|
|
||||||
await AuthenticationManager.promises.setUserPassword(
|
|
||||||
user._id,
|
|
||||||
req.body.newPassword1
|
|
||||||
)
|
|
||||||
|
|
||||||
// no need to wait, errors are logged and not passed back
|
// no need to wait, errors are logged and not passed back
|
||||||
_sendSecurityAlertPasswordChanged(user)
|
_sendSecurityAlertPasswordChanged(user)
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,8 @@ const UserRegistrationHandler = {
|
||||||
_registrationRequestIsValid(body, callback) {
|
_registrationRequestIsValid(body, callback) {
|
||||||
const invalidEmail = AuthenticationManager.validateEmail(body.email || '')
|
const invalidEmail = AuthenticationManager.validateEmail(body.email || '')
|
||||||
const invalidPassword = AuthenticationManager.validatePassword(
|
const invalidPassword = AuthenticationManager.validatePassword(
|
||||||
body.password || ''
|
body.password || '',
|
||||||
|
body.email
|
||||||
)
|
)
|
||||||
if (invalidEmail != null || invalidPassword != null) {
|
if (invalidEmail != null || invalidPassword != null) {
|
||||||
return false
|
return false
|
||||||
|
@ -71,7 +72,7 @@ const UserRegistrationHandler = {
|
||||||
),
|
),
|
||||||
cb =>
|
cb =>
|
||||||
AuthenticationManager.setUserPassword(
|
AuthenticationManager.setUserPassword(
|
||||||
user._id,
|
user,
|
||||||
userDetails.password,
|
userDetails.password,
|
||||||
cb
|
cb
|
||||||
),
|
),
|
||||||
|
|
|
@ -283,4 +283,5 @@ block content
|
||||||
span(ng-show="state.inflight") #{translate("deleting")}…
|
span(ng-show="state.inflight") #{translate("deleting")}…
|
||||||
|
|
||||||
script(type='text/javascript').
|
script(type='text/javascript').
|
||||||
|
window.usersEmail = !{StringHelper.stringifyJsonForScript(user.email)};
|
||||||
window.passwordStrengthOptions = !{StringHelper.stringifyJsonForScript(settings.passwordStrengthOptions || {})}
|
window.passwordStrengthOptions = !{StringHelper.stringifyJsonForScript(settings.passwordStrengthOptions || {})}
|
||||||
|
|
|
@ -194,6 +194,7 @@ export default App.controller('UserAffiliationsController', function(
|
||||||
email.default = false
|
email.default = false
|
||||||
}
|
}
|
||||||
userEmail.default = true
|
userEmail.default = true
|
||||||
|
window.usersEmail = userEmail.email
|
||||||
})
|
})
|
||||||
|
|
||||||
$scope.removeUserEmail = function(userEmail) {
|
$scope.removeUserEmail = function(userEmail) {
|
||||||
|
|
|
@ -20,7 +20,7 @@ class User {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
this.email = this.emails[0].email
|
this.email = this.emails[0].email
|
||||||
this.password = `acceptance-test-${count}-password`
|
this.password = `a-terrible-secret-${count}`
|
||||||
count++
|
count++
|
||||||
this.jar = request.jar()
|
this.jar = request.jar()
|
||||||
this.request = request.defaults({
|
this.request = request.defaults({
|
||||||
|
@ -111,21 +111,17 @@ class User {
|
||||||
return callback(error)
|
return callback(error)
|
||||||
}
|
}
|
||||||
this.setExtraAttributes(user)
|
this.setExtraAttributes(user)
|
||||||
AuthenticationManager.setUserPasswordInV2(
|
AuthenticationManager.setUserPasswordInV2(user, this.password, error => {
|
||||||
user._id,
|
if (error != null) {
|
||||||
this.password,
|
return callback(error)
|
||||||
error => {
|
}
|
||||||
|
this.mongoUpdate({ $set: { emails: this.emails } }, error => {
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
return callback(error)
|
return callback(error)
|
||||||
}
|
}
|
||||||
this.mongoUpdate({ $set: { emails: this.emails } }, error => {
|
callback(null, this.password)
|
||||||
if (error != null) {
|
})
|
||||||
return callback(error)
|
})
|
||||||
}
|
|
||||||
callback(null, this.password)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,6 @@ describe('AuthenticationManager', function() {
|
||||||
},
|
},
|
||||||
bcrypt: (this.bcrypt = {}),
|
bcrypt: (this.bcrypt = {}),
|
||||||
'settings-sharelatex': this.settings,
|
'settings-sharelatex': this.settings,
|
||||||
'../V1/V1Handler': (this.V1Handler = {}),
|
|
||||||
'../User/UserGetter': (this.UserGetter = {}),
|
'../User/UserGetter': (this.UserGetter = {}),
|
||||||
'./AuthenticationErrors': AuthenticationErrors
|
'./AuthenticationErrors': AuthenticationErrors
|
||||||
}
|
}
|
||||||
|
@ -99,6 +98,8 @@ describe('AuthenticationManager', function() {
|
||||||
_id: '5c8791477192a80b5e76ca7e',
|
_id: '5c8791477192a80b5e76ca7e',
|
||||||
email: (this.email = 'USER@sharelatex.com')
|
email: (this.email = 'USER@sharelatex.com')
|
||||||
}
|
}
|
||||||
|
this.db.users.updateOne = sinon
|
||||||
|
this.User.findOne = sinon.stub().callsArgWith(2, null, this.user)
|
||||||
this.db.users.updateOne = sinon
|
this.db.users.updateOne = sinon
|
||||||
.stub()
|
.stub()
|
||||||
.callsArgWith(2, null, { modifiedCount: 1 })
|
.callsArgWith(2, null, { modifiedCount: 1 })
|
||||||
|
@ -106,7 +107,7 @@ describe('AuthenticationManager', function() {
|
||||||
|
|
||||||
it('should not produce an error', function(done) {
|
it('should not produce an error', function(done) {
|
||||||
this.AuthenticationManager.setUserPasswordInV2(
|
this.AuthenticationManager.setUserPasswordInV2(
|
||||||
this.user._id,
|
this.user,
|
||||||
'testpassword',
|
'testpassword',
|
||||||
(err, updated) => {
|
(err, updated) => {
|
||||||
expect(err).to.not.exist
|
expect(err).to.not.exist
|
||||||
|
@ -118,7 +119,7 @@ describe('AuthenticationManager', function() {
|
||||||
|
|
||||||
it('should set the hashed password', function(done) {
|
it('should set the hashed password', function(done) {
|
||||||
this.AuthenticationManager.setUserPasswordInV2(
|
this.AuthenticationManager.setUserPasswordInV2(
|
||||||
this.user._id,
|
this.user,
|
||||||
'testpassword',
|
'testpassword',
|
||||||
err => {
|
err => {
|
||||||
expect(err).to.not.exist
|
expect(err).to.not.exist
|
||||||
|
@ -224,7 +225,7 @@ describe('AuthenticationManager', function() {
|
||||||
|
|
||||||
it('should set the users password (with a higher number of rounds)', function() {
|
it('should set the users password (with a higher number of rounds)', function() {
|
||||||
this.AuthenticationManager.setUserPassword
|
this.AuthenticationManager.setUserPassword
|
||||||
.calledWith('user-id', this.unencryptedPassword)
|
.calledWith(this.user, this.unencryptedPassword)
|
||||||
.should.equal(true)
|
.should.equal(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -258,7 +259,7 @@ describe('AuthenticationManager', function() {
|
||||||
|
|
||||||
it('should not set the users password (with a higher number of rounds)', function() {
|
it('should not set the users password (with a higher number of rounds)', function() {
|
||||||
this.AuthenticationManager.setUserPassword
|
this.AuthenticationManager.setUserPassword
|
||||||
.calledWith('user-id', this.unencryptedPassword)
|
.calledWith(this.user, this.unencryptedPassword)
|
||||||
.should.equal(false)
|
.should.equal(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -525,11 +526,16 @@ describe('AuthenticationManager', function() {
|
||||||
describe('setUserPassword', function() {
|
describe('setUserPassword', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
this.user_id = ObjectId()
|
this.user_id = ObjectId()
|
||||||
|
this.user = {
|
||||||
|
_id: this.user_id,
|
||||||
|
email: 'user@example.com'
|
||||||
|
}
|
||||||
this.password = 'banana'
|
this.password = 'banana'
|
||||||
this.hashedPassword = 'asdkjfa;osiuvandf'
|
this.hashedPassword = 'asdkjfa;osiuvandf'
|
||||||
this.salt = 'saltaasdfasdfasdf'
|
this.salt = 'saltaasdfasdfasdf'
|
||||||
this.bcrypt.genSalt = sinon.stub().callsArgWith(2, null, this.salt)
|
this.bcrypt.genSalt = sinon.stub().callsArgWith(2, null, this.salt)
|
||||||
this.bcrypt.hash = sinon.stub().callsArgWith(2, null, this.hashedPassword)
|
this.bcrypt.hash = sinon.stub().callsArgWith(2, null, this.hashedPassword)
|
||||||
|
this.User.findOne = sinon.stub().callsArgWith(2, null, this.user)
|
||||||
this.db.users.updateOne = sinon.stub().callsArg(2)
|
this.db.users.updateOne = sinon.stub().callsArg(2)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -545,7 +551,7 @@ describe('AuthenticationManager', function() {
|
||||||
|
|
||||||
it('should return and error', function(done) {
|
it('should return and error', function(done) {
|
||||||
this.AuthenticationManager.setUserPassword(
|
this.AuthenticationManager.setUserPassword(
|
||||||
this.user_id,
|
this.user,
|
||||||
this.password,
|
this.password,
|
||||||
err => {
|
err => {
|
||||||
expect(err).to.exist
|
expect(err).to.exist
|
||||||
|
@ -556,7 +562,7 @@ describe('AuthenticationManager', function() {
|
||||||
|
|
||||||
it('should not start the bcrypt process', function(done) {
|
it('should not start the bcrypt process', function(done) {
|
||||||
this.AuthenticationManager.setUserPassword(
|
this.AuthenticationManager.setUserPassword(
|
||||||
this.user_id,
|
this.user,
|
||||||
this.password,
|
this.password,
|
||||||
() => {
|
() => {
|
||||||
this.bcrypt.genSalt.called.should.equal(false)
|
this.bcrypt.genSalt.called.should.equal(false)
|
||||||
|
@ -567,6 +573,42 @@ describe('AuthenticationManager', function() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('contains full email', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
this.password = `some${this.user.email}password`
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should reject the password', function(done) {
|
||||||
|
this.AuthenticationManager.setUserPassword(
|
||||||
|
this.user,
|
||||||
|
this.password,
|
||||||
|
err => {
|
||||||
|
expect(err).to.exist
|
||||||
|
expect(err.name).to.equal('InvalidPasswordError')
|
||||||
|
done()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('contains first part of email', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
this.password = `some${this.user.email.split('@')[0]}password`
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should reject the password', function(done) {
|
||||||
|
this.AuthenticationManager.setUserPassword(
|
||||||
|
this.user,
|
||||||
|
this.password,
|
||||||
|
err => {
|
||||||
|
expect(err).to.exist
|
||||||
|
expect(err.name).to.equal('InvalidPasswordError')
|
||||||
|
done()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('too short', function() {
|
describe('too short', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
this.settings.passwordStrengthOptions = {
|
this.settings.passwordStrengthOptions = {
|
||||||
|
@ -580,7 +622,7 @@ describe('AuthenticationManager', function() {
|
||||||
|
|
||||||
it('should return and error', function(done) {
|
it('should return and error', function(done) {
|
||||||
this.AuthenticationManager.setUserPassword(
|
this.AuthenticationManager.setUserPassword(
|
||||||
this.user_id,
|
this.user,
|
||||||
this.password,
|
this.password,
|
||||||
err => {
|
err => {
|
||||||
expect(err).to.exist
|
expect(err).to.exist
|
||||||
|
@ -591,7 +633,7 @@ describe('AuthenticationManager', function() {
|
||||||
|
|
||||||
it('should not start the bcrypt process', function(done) {
|
it('should not start the bcrypt process', function(done) {
|
||||||
this.AuthenticationManager.setUserPassword(
|
this.AuthenticationManager.setUserPassword(
|
||||||
this.user_id,
|
this.user,
|
||||||
this.password,
|
this.password,
|
||||||
() => {
|
() => {
|
||||||
this.bcrypt.genSalt.called.should.equal(false)
|
this.bcrypt.genSalt.called.should.equal(false)
|
||||||
|
@ -606,7 +648,7 @@ describe('AuthenticationManager', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
this.UserGetter.getUser = sinon.stub().yields(null, { overleaf: null })
|
this.UserGetter.getUser = sinon.stub().yields(null, { overleaf: null })
|
||||||
this.AuthenticationManager.setUserPassword(
|
this.AuthenticationManager.setUserPassword(
|
||||||
this.user_id,
|
this.user,
|
||||||
this.password,
|
this.password,
|
||||||
this.callback
|
this.callback
|
||||||
)
|
)
|
||||||
|
|
|
@ -44,9 +44,6 @@ describe('PasswordResetController', function() {
|
||||||
revokeAllUserSessions: sinon.stub().resolves()
|
revokeAllUserSessions: sinon.stub().resolves()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.AuthenticationManager = {
|
|
||||||
validatePassword: sinon.stub()
|
|
||||||
}
|
|
||||||
this.UserUpdater = {
|
this.UserUpdater = {
|
||||||
promises: {
|
promises: {
|
||||||
removeReconfirmFlag: sinon.stub().resolves()
|
removeReconfirmFlag: sinon.stub().resolves()
|
||||||
|
@ -70,7 +67,6 @@ describe('PasswordResetController', function() {
|
||||||
getLoggedInUserId: sinon.stub(),
|
getLoggedInUserId: sinon.stub(),
|
||||||
finishLogin: sinon.stub()
|
finishLogin: sinon.stub()
|
||||||
}),
|
}),
|
||||||
'../Authentication/AuthenticationManager': this.AuthenticationManager,
|
|
||||||
'../User/UserGetter': (this.UserGetter = {
|
'../User/UserGetter': (this.UserGetter = {
|
||||||
promises: {
|
promises: {
|
||||||
getUser: sinon.stub()
|
getUser: sinon.stub()
|
||||||
|
@ -248,13 +244,13 @@ describe('PasswordResetController', function() {
|
||||||
|
|
||||||
it('should return 400 (Bad Request) if the password is invalid', function(done) {
|
it('should return 400 (Bad Request) if the password is invalid', function(done) {
|
||||||
this.req.body.password = 'correct horse battery staple'
|
this.req.body.password = 'correct horse battery staple'
|
||||||
this.AuthenticationManager.validatePassword = sinon
|
const err = new Error('bad')
|
||||||
.stub()
|
err.name = 'InvalidPasswordError'
|
||||||
.returns({ message: 'password contains invalid characters' })
|
this.PasswordResetHandler.promises.setNewUserPassword.rejects(err)
|
||||||
this.res.sendStatus = code => {
|
this.res.sendStatus = code => {
|
||||||
code.should.equal(400)
|
code.should.equal(400)
|
||||||
this.PasswordResetHandler.promises.setNewUserPassword.called.should.equal(
|
this.PasswordResetHandler.promises.setNewUserPassword.called.should.equal(
|
||||||
false
|
true
|
||||||
)
|
)
|
||||||
done()
|
done()
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,6 @@ describe('PasswordResetHandler', function() {
|
||||||
}
|
}
|
||||||
this.EmailHandler = { sendEmail: sinon.stub() }
|
this.EmailHandler = { sendEmail: sinon.stub() }
|
||||||
this.AuthenticationManager = {
|
this.AuthenticationManager = {
|
||||||
setUserPasswordInV1: sinon.stub(),
|
|
||||||
setUserPasswordInV2: sinon.stub(),
|
setUserPasswordInV2: sinon.stub(),
|
||||||
promises: {
|
promises: {
|
||||||
setUserPassword: sinon.stub().resolves()
|
setUserPassword: sinon.stub().resolves()
|
||||||
|
@ -227,7 +226,7 @@ describe('PasswordResetHandler', function() {
|
||||||
email: this.email
|
email: this.email
|
||||||
})
|
})
|
||||||
this.AuthenticationManager.promises.setUserPassword
|
this.AuthenticationManager.promises.setUserPassword
|
||||||
.withArgs(this.user._id, this.password)
|
.withArgs(this.user, this.password)
|
||||||
.resolves(true)
|
.resolves(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -355,18 +354,18 @@ describe('PasswordResetHandler', function() {
|
||||||
new Error('oops')
|
new Error('oops')
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
it('should return the error and not update the password', function(done) {
|
it('should return the error', function(done) {
|
||||||
this.PasswordResetHandler.setNewUserPassword(
|
this.PasswordResetHandler.setNewUserPassword(
|
||||||
this.token,
|
this.token,
|
||||||
this.password,
|
this.password,
|
||||||
this.auditLog,
|
this.auditLog,
|
||||||
(error, result) => {
|
(error, _result) => {
|
||||||
expect(error).to.exist
|
expect(error).to.exist
|
||||||
expect(
|
expect(
|
||||||
this.UserAuditLogHandler.promises.addEntry.callCount
|
this.UserAuditLogHandler.promises.addEntry.callCount
|
||||||
).to.equal(1)
|
).to.equal(1)
|
||||||
expect(this.AuthenticationManager.promises.setUserPassword).to
|
expect(this.AuthenticationManager.promises.setUserPassword).to
|
||||||
.not.have.been.called
|
.have.been.called
|
||||||
done()
|
done()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -386,7 +385,7 @@ describe('PasswordResetHandler', function() {
|
||||||
email: this.email
|
email: this.email
|
||||||
})
|
})
|
||||||
this.AuthenticationManager.promises.setUserPassword
|
this.AuthenticationManager.promises.setUserPassword
|
||||||
.withArgs(this.user._id, this.password)
|
.withArgs(this.user, this.password)
|
||||||
.resolves(true)
|
.resolves(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -664,7 +664,7 @@ describe('UserController', function() {
|
||||||
it('should set the new password if they do match', function(done) {
|
it('should set the new password if they do match', function(done) {
|
||||||
this.res.json.callsFake(() => {
|
this.res.json.callsFake(() => {
|
||||||
this.AuthenticationManager.promises.setUserPassword.should.have.been.calledWith(
|
this.AuthenticationManager.promises.setUserPassword.should.have.been.calledWith(
|
||||||
this.user._id,
|
this.user,
|
||||||
'newpass'
|
'newpass'
|
||||||
)
|
)
|
||||||
done()
|
done()
|
||||||
|
@ -749,9 +749,12 @@ describe('UserController', function() {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('it should not set the new password if it is invalid', function(done) {
|
it('it should not set the new password if it is invalid', function(done) {
|
||||||
this.AuthenticationManager.validatePassword = sinon
|
// this.AuthenticationManager.validatePassword = sinon
|
||||||
.stub()
|
// .stub()
|
||||||
.returns({ message: 'validation-error' })
|
// .returns({ message: 'validation-error' })
|
||||||
|
const err = new Error('bad')
|
||||||
|
err.name = 'InvalidPasswordError'
|
||||||
|
this.AuthenticationManager.promises.setUserPassword.rejects(err)
|
||||||
this.AuthenticationManager.promises.authenticate.resolves({})
|
this.AuthenticationManager.promises.authenticate.resolves({})
|
||||||
this.req.body = {
|
this.req.body = {
|
||||||
newPassword1: 'newpass',
|
newPassword1: 'newpass',
|
||||||
|
@ -761,10 +764,10 @@ describe('UserController', function() {
|
||||||
expect(this.HttpErrorHandler.badRequest).to.have.been.calledWith(
|
expect(this.HttpErrorHandler.badRequest).to.have.been.calledWith(
|
||||||
this.req,
|
this.req,
|
||||||
this.res,
|
this.res,
|
||||||
'validation-error'
|
err.message
|
||||||
)
|
)
|
||||||
this.AuthenticationManager.promises.setUserPassword.callCount.should.equal(
|
this.AuthenticationManager.promises.setUserPassword.callCount.should.equal(
|
||||||
0
|
1
|
||||||
)
|
)
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
|
@ -784,7 +787,7 @@ describe('UserController', function() {
|
||||||
this.UserController.changePassword(this.req, this.res, error => {
|
this.UserController.changePassword(this.req, this.res, error => {
|
||||||
expect(error).to.be.instanceof(Error)
|
expect(error).to.be.instanceof(Error)
|
||||||
this.AuthenticationManager.promises.setUserPassword.callCount.should.equal(
|
this.AuthenticationManager.promises.setUserPassword.callCount.should.equal(
|
||||||
0
|
1
|
||||||
)
|
)
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
|
|
|
@ -208,7 +208,7 @@ describe('UserRegistrationHandler', function() {
|
||||||
it('should set the password', function(done) {
|
it('should set the password', function(done) {
|
||||||
return this.handler.registerNewUser(this.passingRequest, err => {
|
return this.handler.registerNewUser(this.passingRequest, err => {
|
||||||
this.AuthenticationManager.setUserPassword
|
this.AuthenticationManager.setUserPassword
|
||||||
.calledWith(this.user._id, this.passingRequest.password)
|
.calledWith(this.user, this.passingRequest.password)
|
||||||
.should.equal(true)
|
.should.equal(true)
|
||||||
return done()
|
return done()
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue