Merge pull request #15728 from overleaf/td-lg-expire-password-tokens

Expire user password reset tokens when user changes their password

GitOrigin-RevId: 2d303eba947c224e71ebe60083abc7a8ff5207a5
This commit is contained in:
Tim Down 2023-11-21 14:14:57 +00:00 committed by Copybot
parent fa0ea24f53
commit 2807a35e24
4 changed files with 63 additions and 0 deletions

View file

@ -112,6 +112,25 @@ const OneTimeTokenHandler = {
}
)
},
expireAllTokensForUser(userId, use, callback) {
const now = new Date()
db.tokens.updateMany(
{
use,
'data.user_id': userId.toString(),
usedAt: { $exists: false },
},
{
$set: {
usedAt: now,
},
},
error => {
callback(error)
}
)
},
}
OneTimeTokenHandler.promises = promisifyAll(OneTimeTokenHandler)

View file

@ -22,6 +22,7 @@ const {
acceptsJson,
} = require('../../infrastructure/RequestContentTypeDetection')
const Modules = require('../../infrastructure/Modules')
const OneTimeTokenHandler = require('../Security/OneTimeTokenHandler')
async function _sendSecurityAlertClearedSessions(user) {
const emailOptions = {
@ -131,6 +132,11 @@ async function changePassword(req, res, next) {
req.sessionID,
])
await OneTimeTokenHandler.promises.expireAllTokensForUser(
userId.toString(),
'password'
)
return res.json({
message: {
type: 'success',

View file

@ -0,0 +1,22 @@
/* eslint-disable no-unused-vars */
const Helpers = require('./lib/helpers')
exports.tags = ['server-ce', 'server-pro', 'saas']
const index = {
key: {
'data.user_id': 1,
},
name: 'data.user_id_1',
}
exports.migrate = async client => {
const { db } = client
await Helpers.addIndexesToCollection(db.tokens, [index])
}
exports.rollback = async client => {
const { db } = client
await Helpers.dropIndexesFromCollection(db.tokens, [index])
}

View file

@ -129,6 +129,10 @@ describe('UserController', function () {
promises: { sendEmail: sinon.stub().resolves() },
}
this.OneTimeTokenHandler = {
promises: { expireAllTokensForUser: sinon.stub().resolves() },
}
this.UserController = SandboxedModule.require(modulePath, {
requires: {
'../Helpers/UrlHelper': this.UrlHelper,
@ -149,6 +153,7 @@ describe('UserController', function () {
'@overleaf/settings': this.settings,
'@overleaf/o-error': OError,
'../Email/EmailHandler': this.EmailHandler,
'../Security/OneTimeTokenHandler': this.OneTimeTokenHandler,
'../../infrastructure/RequestContentTypeDetection':
this.RequestContentTypeDetection,
},
@ -739,6 +744,17 @@ describe('UserController', function () {
})
this.UserController.changePassword(this.req, this.res)
})
it('should expire password reset tokens', function (done) {
this.res.json.callsFake(() => {
this.OneTimeTokenHandler.promises.expireAllTokensForUser.should.have.been.calledWith(
this.user._id,
'password'
)
done()
})
this.UserController.changePassword(this.req, this.res)
})
})
describe('errors', function () {