From 5f54fa3e580be736ea219d76603074e91c0d17cc Mon Sep 17 00:00:00 2001 From: Bernd Storath <32197462+kaaax0815@users.noreply.github.com> Date: Tue, 16 Jun 2026 14:12:00 +0200 Subject: [PATCH] improve totp security (#2668) improve security --- src/server/api/me/totp.post.ts | 14 ++++++++++++++ src/server/database/repositories/user/service.ts | 4 ++++ src/server/database/repositories/user/types.ts | 3 +++ 3 files changed, 21 insertions(+) diff --git a/src/server/api/me/totp.post.ts b/src/server/api/me/totp.post.ts index 53c87f8a..f3782828 100644 --- a/src/server/api/me/totp.post.ts +++ b/src/server/api/me/totp.post.ts @@ -23,6 +23,13 @@ export default definePermissionEventHandler( checkPermissions(user); if (body.type === 'setup') { + if (user.totpVerified) { + throw createError({ + statusCode: 409, + statusMessage: 'TOTP is already enabled', + }); + } + const key = new Secret({ size: 20 }); const totp = new TOTP({ @@ -50,6 +57,13 @@ export default definePermissionEventHandler( type: 'created', } as Response; } else if (body.type === 'delete') { + if (!user.totpVerified) { + throw createError({ + statusCode: 409, + statusMessage: 'TOTP is not enabled', + }); + } + await Database.users.deleteTotpKey(user.id, body.currentPassword); return { diff --git a/src/server/database/repositories/user/service.ts b/src/server/database/repositories/user/service.ts index e3526315..b84ed365 100644 --- a/src/server/database/repositories/user/service.ts +++ b/src/server/database/repositories/user/service.ts @@ -221,6 +221,10 @@ export class UserService { throw new Error('User not found'); } + if (txUser.totpVerified) { + throw new Error('TOTP is already verified'); + } + const totpKey = txUser.totpKey; if (!totpKey) { throw new Error('TOTP key is not set'); diff --git a/src/server/database/repositories/user/types.ts b/src/server/database/repositories/user/types.ts index bb5a7290..9a175a6a 100644 --- a/src/server/database/repositories/user/types.ts +++ b/src/server/database/repositories/user/types.ts @@ -18,7 +18,10 @@ const remember = z.boolean({ message: t('zod.user.remember') }); const totpCode = z .string({ message: t('zod.user.totpCode') }) + // min and max to improve error messages .min(6, t('zod.user.totpCode')) + .max(6, t('zod.user.totpCode')) + .regex(/^\d{6}$/, t('zod.user.totpCode')) .pipe(safeStringRefine); export const UserLoginSchema = z.object({