diff --git a/src/modules/ssr-front-end/login/login.controller.ts b/src/modules/ssr-front-end/login/login.controller.ts index 292abaa..4173dba 100644 --- a/src/modules/ssr-front-end/login/login.controller.ts +++ b/src/modules/ssr-front-end/login/login.controller.ts @@ -25,6 +25,13 @@ import { UserService } from 'src/modules/objects/user/user.service'; import { FormUtilityService } from 'src/modules/utility/services/form-utility.service'; import { TokenService } from 'src/modules/utility/services/token.service'; +interface VerifyChallenge { + type: 'verify'; + id: string; + user: string; + remember: boolean; +} + @Controller('/login') export class LoginController { constructor( @@ -80,7 +87,12 @@ export class LoginController { await this.audit.auditRequest(req, AuditAction.LOGIN, req.session.id, user); if (await this.totpService.userHasTOTP(user)) { - const challenge = { type: 'verify', user: user.uuid, remember }; + const challenge: VerifyChallenge = { + type: 'verify', + id: req.session.id, + user: user.uuid, + remember, + }; const encrypted = await this.token.encryptChallenge(challenge); res.redirect( `login/verify?challenge=${encrypted}${ @@ -141,12 +153,15 @@ export class LoginController { throw new Error('No challenge'); } - const decrypted = await this.token.decryptChallenge<{ - type: 'verify'; - user: string; - remember: boolean; - }>(query.challenge); - if (!decrypted || decrypted.type !== 'verify' || !decrypted.user) { + const decrypted = await this.token.decryptChallenge( + query.challenge, + ); + if ( + !decrypted || + decrypted.type !== 'verify' || + decrypted.id !== req.session.id || + !decrypted.user + ) { throw new Error('Bad challenge'); } diff --git a/src/modules/ssr-front-end/two-factor/two-factor.controller.ts b/src/modules/ssr-front-end/two-factor/two-factor.controller.ts index f8ee049..52fd2c5 100644 --- a/src/modules/ssr-front-end/two-factor/two-factor.controller.ts +++ b/src/modules/ssr-front-end/two-factor/two-factor.controller.ts @@ -9,6 +9,7 @@ import { QRCodeService } from 'src/modules/utility/services/qr-code.service'; import { TokenService } from 'src/modules/utility/services/token.service'; interface ChallengeType { + id: string; secret: string; type: 'totp'; user: string; @@ -36,14 +37,23 @@ export class TwoFactorController { const challenge = await this.token.decryptChallenge( challengeString, ); - if (challenge.type === 'totp' && challenge.user === req.user.uuid) { + if ( + challenge.type === 'totp' && + challenge.user === req.user.uuid && + challenge.id === req.session.id + ) { secret = challenge.secret; } } if (!secret) { secret = this.totp.createTOTPSecret(); - const challenge = { type: 'totp', secret, user: req.user.uuid }; + const challenge = { + type: 'totp', + secret, + id: req.session.id, + user: req.user.uuid, + }; const encrypted = await this.token.encryptChallenge(challenge); const cleanURL = req.originalUrl.replace(/\?(.*)$/, ''); res.redirect(`${cleanURL}?challenge=${encrypted}`); @@ -85,6 +95,7 @@ export class TwoFactorController { if ( challenge.type !== 'totp' || challenge.user !== req.user.uuid || + challenge.id !== req.session.id || !secret ) { throw new Error('Invalid request');