From 0ea12eaafce45b14d4f3f585acad0c3f55372513 Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Tue, 6 May 2025 08:37:56 +0200 Subject: [PATCH] enable password on invite or reset --- src/command/management/user/userCommand.ts | 1 + .../management/user/userCommandHandler.ts | 1 + src/controller/authController.ts | 3 ++- src/controller/inviteController.ts | 26 ++++++++++++------- src/controller/resetController.ts | 26 ++++++++++++------- src/helpers/settingsHelper.ts | 16 +++++++----- src/routes/invite.ts | 10 ++++--- src/routes/reset.ts | 10 ++++--- 8 files changed, 61 insertions(+), 32 deletions(-) diff --git a/src/command/management/user/userCommand.ts b/src/command/management/user/userCommand.ts index 66bab37..cb19989 100644 --- a/src/command/management/user/userCommand.ts +++ b/src/command/management/user/userCommand.ts @@ -7,6 +7,7 @@ export interface CreateUserCommand { lastname: string; secret: string; isOwner: boolean; + routine: LoginRoutineEnum; } export interface UpdateUserCommand { diff --git a/src/command/management/user/userCommandHandler.ts b/src/command/management/user/userCommandHandler.ts index 0f89ef5..daa5535 100644 --- a/src/command/management/user/userCommandHandler.ts +++ b/src/command/management/user/userCommandHandler.ts @@ -31,6 +31,7 @@ export default abstract class UserCommandHandler { lastname: createUser.lastname, secret: createUser.secret, isOwner: createUser.isOwner, + routine: createUser.routine, }) .execute() .then((result) => { diff --git a/src/controller/authController.ts b/src/controller/authController.ts index 77a6717..6302a3c 100644 --- a/src/controller/authController.ts +++ b/src/controller/authController.ts @@ -41,6 +41,8 @@ export async function login(req: Request, res: Response): Promise { let { id } = await UserService.getByUsername(username); let { secret, routine } = await UserService.getUserSecretAndRoutine(id); + console.log(secret, passedSecret); + let valid = false; if (routine == LoginRoutineEnum.totp) { valid = speakeasy.totp.verify({ @@ -50,7 +52,6 @@ export async function login(req: Request, res: Response): Promise { window: 2, }); } else { - console.log(passedSecret, secret, passedSecret == secret); valid = passedSecret == secret; } diff --git a/src/controller/inviteController.ts b/src/controller/inviteController.ts index a183cbc..9492e10 100644 --- a/src/controller/inviteController.ts +++ b/src/controller/inviteController.ts @@ -16,6 +16,7 @@ import UserService from "../service/management/userService"; import CustomRequestException from "../exceptions/customRequestException"; import InviteFactory from "../factory/admin/management/invite"; import SettingHelper from "../helpers/settingsHelper"; +import { LoginRoutineEnum } from "../enums/loginRoutineEnum"; /** * @description get all invites @@ -112,20 +113,26 @@ export async function verifyInvite(req: Request, res: Response): Promise { */ export async function finishInvite(req: Request, res: Response, grantAdmin: boolean = false): Promise { let mail = req.body.mail; + let routine = req.body.routine; let token = req.body.token; - let totp = req.body.totp; + let passedSecret = req.body.secret; let { secret, username, firstname, lastname } = await InviteService.getByMailAndToken(mail, token); - let valid = speakeasy.totp.verify({ - secret: secret, - encoding: "base32", - token: totp, - window: 2, - }); + let valid = false; + if (routine == LoginRoutineEnum.totp) { + valid = speakeasy.totp.verify({ + secret: secret, + encoding: "base32", + token: passedSecret, + window: 2, + }); + } else { + valid = passedSecret != ""; + } if (!valid) { - throw new UnauthorizedRequestException("Token not valid or expired"); + throw new UnauthorizedRequestException("Credentials not valid or expired"); } let createUser: CreateUserCommand = { @@ -133,8 +140,9 @@ export async function finishInvite(req: Request, res: Response, grantAdmin: bool firstname: firstname, lastname: lastname, mail: mail, - secret: secret, + secret: routine == LoginRoutineEnum.totp ? secret : passedSecret, isOwner: grantAdmin, + routine, }; let id = await UserCommandHandler.create(createUser); diff --git a/src/controller/resetController.ts b/src/controller/resetController.ts index 1a12b3f..7ffafe5 100644 --- a/src/controller/resetController.ts +++ b/src/controller/resetController.ts @@ -81,28 +81,34 @@ export async function verifyReset(req: Request, res: Response): Promise { */ export async function finishReset(req: Request, res: Response): Promise { let mail = req.body.mail; + let routine = req.body.routine; let token = req.body.token; - let totp = req.body.totp; + let passedSecret = req.body.secret; let { secret, username } = await ResetService.getByMailAndToken(mail, token); - let valid = speakeasy.totp.verify({ - secret: secret, - encoding: "base32", - token: totp, - window: 2, - }); + let valid = false; + if (routine == LoginRoutineEnum.totp) { + valid = speakeasy.totp.verify({ + secret: secret, + encoding: "base32", + token: passedSecret, + window: 2, + }); + } else { + valid = passedSecret != ""; + } if (!valid) { - throw new UnauthorizedRequestException("Token not valid or expired"); + throw new UnauthorizedRequestException("Credentials not valid or expired"); } let { id } = await UserService.getByUsername(username); let updateUserSecret: UpdateUserSecretCommand = { id, - secret, - routine: LoginRoutineEnum.totp, + secret: routine == LoginRoutineEnum.totp ? secret : passedSecret, + routine, }; await UserCommandHandler.updateSecret(updateUserSecret); diff --git a/src/helpers/settingsHelper.ts b/src/helpers/settingsHelper.ts index b90cd07..526e10a 100644 --- a/src/helpers/settingsHelper.ts +++ b/src/helpers/settingsHelper.ts @@ -56,12 +56,17 @@ export default abstract class SettingHelper { return rawValue as unknown as SettingValueMapping[K]; } + let processedValue = rawValue; + if (typeof settingType.type === "string" && settingType.type.includes("/crypt")) { + processedValue = CodingHelper.decrypt(APPLICATION_SECRET, processedValue); + } + const baseType = typeof settingType.type === "string" ? (settingType.type.split("/")[0] as SettingTypeAtom) : (settingType.type as SettingTypeAtom); - return this.converters[baseType].fromString(rawValue) as unknown as SettingValueMapping[K]; + return this.converters[baseType].fromString(processedValue) as unknown as SettingValueMapping[K]; } /** @@ -81,11 +86,11 @@ export default abstract class SettingHelper { const settingType = settingsType[key]; this.validateSetting(key, stringValue); - const oldValue = this.getSetting(key); - let finalValue = stringValue; + const oldValue = cloneDeep(this.settings[key]); + let newValue = stringValue; if (typeof settingType.type === "string" && settingType.type.includes("/crypt")) { - finalValue = CodingHelper.encrypt(APPLICATION_SECRET, stringValue); + newValue = CodingHelper.encrypt(APPLICATION_SECRET, stringValue); } this.settings[key] = stringValue; @@ -94,10 +99,9 @@ export default abstract class SettingHelper { await SettingCommandHandler.create({ topic, key: settingKey, - value: finalValue, + value: newValue, }); - const newValue = this.getSetting(key); this.notifyListeners(key, newValue, oldValue); } diff --git a/src/routes/invite.ts b/src/routes/invite.ts index 5d8794e..ebb4ddd 100644 --- a/src/routes/invite.ts +++ b/src/routes/invite.ts @@ -8,8 +8,12 @@ router.post("/verify", ParamaterPassCheckHelper.requiredIncludedMiddleware(["mai await verifyInvite(req, res); }); -router.put("/", ParamaterPassCheckHelper.requiredIncludedMiddleware(["mail", "token", "totp"]), async (req, res) => { - await finishInvite(req, res); -}); +router.put( + "/", + ParamaterPassCheckHelper.requiredIncludedMiddleware(["mail", "token", "secret", "routine "]), + async (req, res) => { + await finishInvite(req, res); + } +); export default router; diff --git a/src/routes/reset.ts b/src/routes/reset.ts index acb1516..31df6c4 100644 --- a/src/routes/reset.ts +++ b/src/routes/reset.ts @@ -12,8 +12,12 @@ router.post("/", ParamaterPassCheckHelper.requiredIncludedMiddleware(["username" await startReset(req, res); }); -router.put("/", ParamaterPassCheckHelper.requiredIncludedMiddleware(["mail", "token", "totp"]), async (req, res) => { - await finishReset(req, res); -}); +router.put( + "/", + ParamaterPassCheckHelper.requiredIncludedMiddleware(["mail", "token", "secret", "routine"]), + async (req, res) => { + await finishReset(req, res); + } +); export default router;