diff --git a/src/routes/cloudron.js b/src/routes/cloudron.js index 8c91a11c8..6ce7c4309 100644 --- a/src/routes/cloudron.js +++ b/src/routes/cloudron.js @@ -35,6 +35,7 @@ const assert = require('assert'), HttpError = require('connect-lastmile').HttpError, HttpSuccess = require('connect-lastmile').HttpSuccess, safe = require('safetydance'), + speakeasy = require('speakeasy'), sysinfo = require('../sysinfo.js'), system = require('../system.js'), tokens = require('../tokens.js'), @@ -95,6 +96,13 @@ async function passwordReset(req, res, next) { if (error) return next(new HttpError(401, 'Invalid resetToken')); if (!userObject) return next(new HttpError(401, 'Invalid resetToken')); + if (userObject.twoFactorAuthenticationEnabled) { + if (typeof req.body.totpToken !== 'string') return next(new HttpError(401, 'A totpToken must be provided')); + + const verified = speakeasy.totp.verify({ secret: userObject.twoFactorAuthenticationSecret, encoding: 'base32', token: req.body.totpToken, window: 2 }); + if (!verified) return next(new HttpError(401, 'Invalid totpToken')); + } + // if you fix the duration here, the emails and UI have to be fixed as well if (Date.now() - userObject.resetTokenCreationTime > 7 * 24 * 60 * 60 * 1000) return next(new HttpError(401, 'Token expired')); if (!userObject.username) return next(new HttpError(409, 'No username set'));