From 3e177539d573677819aca4c82a670ab9ebfbadde Mon Sep 17 00:00:00 2001 From: Maidul Islam Date: Sun, 29 Jan 2023 15:48:25 -0800 Subject: [PATCH] Remove state from password controllers --- .../src/controllers/v1/passwordController.ts | 70 +++++++++++-------- 1 file changed, 41 insertions(+), 29 deletions(-) diff --git a/backend/src/controllers/v1/passwordController.ts b/backend/src/controllers/v1/passwordController.ts index 27d712a6b..d429cbf41 100644 --- a/backend/src/controllers/v1/passwordController.ts +++ b/backend/src/controllers/v1/passwordController.ts @@ -9,8 +9,8 @@ import { checkEmailVerification } from '../../helpers/signup'; import { createToken } from '../../helpers/auth'; import { sendMail } from '../../helpers/nodemailer'; import { JWT_SIGNUP_LIFETIME, JWT_SIGNUP_SECRET, SITE_URL } from '../../config'; - -const clientPublicKeys: any = {}; +import LoginSRPDetail from '../../models/LoginSRPDetail'; +import { BadRequestError } from '../../utils/errors'; /** * Password reset step 1: Send email verification link to email [email] @@ -32,7 +32,7 @@ export const emailPasswordReset = async (req: Request, res: Response) => { error: 'Failed to send email verification for password reset' }); } - + const token = crypto.randomBytes(16).toString('hex'); await Token.findOneAndUpdate( @@ -44,7 +44,7 @@ export const emailPasswordReset = async (req: Request, res: Response) => { }, { upsert: true, new: true } ); - + await sendMail({ template: 'passwordReset.handlebars', subjectLine: 'Infisical password reset', @@ -55,15 +55,15 @@ export const emailPasswordReset = async (req: Request, res: Response) => { callback_url: SITE_URL + '/password-reset' } }); - + } catch (err) { Sentry.setUser(null); Sentry.captureException(err); return res.status(400).send({ message: 'Failed to send email for account recovery' - }); + }); } - + return res.status(200).send({ message: `Sent an email for account recovery to ${email}` }); @@ -79,7 +79,7 @@ export const emailPasswordResetVerify = async (req: Request, res: Response) => { let user, token; try { const { email, code } = req.body; - + user = await User.findOne({ email }).select('+publicKey'); if (!user || !user?.publicKey) { // case: user doesn't exist with email [email] or @@ -93,7 +93,7 @@ export const emailPasswordResetVerify = async (req: Request, res: Response) => { email, code }); - + // generate temporary password-reset token token = createToken({ payload: { @@ -107,7 +107,7 @@ export const emailPasswordResetVerify = async (req: Request, res: Response) => { Sentry.captureException(err); return res.status(400).send({ message: 'Failed email verification for password reset' - }); + }); } return res.status(200).send({ @@ -130,7 +130,7 @@ export const srp1 = async (req: Request, res: Response) => { const user = await User.findOne({ email: req.user.email }).select('+salt +verifier'); - + if (!user) throw new Error('Failed to find user'); const server = new jsrp.server(); @@ -139,13 +139,15 @@ export const srp1 = async (req: Request, res: Response) => { salt: user.salt, verifier: user.verifier }, - () => { + async () => { // generate server-side public key const serverPublicKey = server.getPublicKey(); - clientPublicKeys[req.user.email] = { - clientPublicKey, - serverBInt: bigintConversion.bigintToBuf(server.bInt) - }; + + await LoginSRPDetail.findOneAndReplace({ email: req.user.email }, { + email: req.user.email, + clientPublicKey: clientPublicKey, + serverBInt: bigintConversion.bigintToBuf(server.bInt), + }, { upsert: true, returnNewDocument: false }) return res.status(200).send({ serverPublicKey, @@ -180,17 +182,21 @@ export const changePassword = async (req: Request, res: Response) => { if (!user) throw new Error('Failed to find user'); + const loginSRPDetailFromDB = await LoginSRPDetail.findOneAndDelete({ email: req.user.email }) + + if (!loginSRPDetailFromDB) { + return BadRequestError(Error("It looks like some details from the first login are not found. Please try login one again")) + } + const server = new jsrp.server(); server.init( { salt: user.salt, verifier: user.verifier, - b: clientPublicKeys[req.user.email].serverBInt + b: loginSRPDetailFromDB.serverBInt }, async () => { - server.setClientPublicKey( - clientPublicKeys[req.user.email].clientPublicKey - ); + server.setClientPublicKey(loginSRPDetailFromDB.clientPublicKey); // compare server and client shared keys if (server.checkClientProof(clientProof)) { @@ -249,16 +255,22 @@ export const createBackupPrivateKey = async (req: Request, res: Response) => { if (!user) throw new Error('Failed to find user'); + const loginSRPDetailFromDB = await LoginSRPDetail.findOneAndDelete({ email: req.user.email }) + + if (!loginSRPDetailFromDB) { + return BadRequestError(Error("It looks like some details from the first login are not found. Please try login one again")) + } + const server = new jsrp.server(); server.init( { salt: user.salt, verifier: user.verifier, - b: clientPublicKeys[req.user.email].serverBInt + b: loginSRPDetailFromDB.serverBInt }, async () => { server.setClientPublicKey( - clientPublicKeys[req.user.email].clientPublicKey + loginSRPDetailFromDB.clientPublicKey ); // compare server and client shared keys @@ -311,16 +323,16 @@ export const getBackupPrivateKey = async (req: Request, res: Response) => { backupPrivateKey = await BackupPrivateKey.findOne({ user: req.user._id }).select('+encryptedPrivateKey +iv +tag'); - + if (!backupPrivateKey) throw new Error('Failed to find backup private key'); } catch (err) { - Sentry.setUser({ email: req.user.email}); + Sentry.setUser({ email: req.user.email }); Sentry.captureException(err); return res.status(400).send({ message: 'Failed to get backup private key' }); } - + return res.status(200).send({ backupPrivateKey }); @@ -348,15 +360,15 @@ export const resetPassword = async (req: Request, res: Response) => { { new: true } - ); + ); } catch (err) { - Sentry.setUser({ email: req.user.email}); + Sentry.setUser({ email: req.user.email }); Sentry.captureException(err); return res.status(400).send({ message: 'Failed to get backup private key' - }); + }); } - + return res.status(200).send({ message: 'Successfully reset password' });