From c53a31c4051a567e61b6a83cdb86477706c9afb5 Mon Sep 17 00:00:00 2001 From: split Date: Tue, 25 Jun 2024 12:48:35 -0700 Subject: [PATCH] allow PATCH /account/:id with application/x-www-form-urlencoded, limit on codes --- src/server/lib/codes.ts | 17 +++++++++++++++-- src/server/routes/api/v1/account/index.ts | 18 ++++++++++++------ 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/server/lib/codes.ts b/src/server/lib/codes.ts index 10f675f..573d21e 100644 --- a/src/server/lib/codes.ts +++ b/src/server/lib/codes.ts @@ -4,12 +4,14 @@ import crypto from "node:crypto" export type Intent = "verifyEmail" | "recoverAccount" | "identityProof" export const Intents = { - verifyEmail: {}, + verifyEmail: { + limit: 2 + }, recoverAccount: {}, identityProof: { codeGenerator: crypto.randomUUID } -} as Record string}> +} as Record string, limit?: number}> export function isIntent(intent: string): intent is Intent { return intent in Intents @@ -72,4 +74,15 @@ export class Code { check(forUser: string) { return forUser === this.for } +} + +export function code(...params: ConstructorParameters): { success: true, code: Code } | { success: false, error: string } { + const [intent, forUser] = params + const {limit = 100} = Intents[intent] + const {length: codeCount} = codes[intent].byUser.get(forUser) || []; + + if (codeCount >= limit) + return { success: false, error: `Too many active codes for intent ${intent} (${limit})` } + else + return { success: true, code: new Code(...params) } } \ No newline at end of file diff --git a/src/server/routes/api/v1/account/index.ts b/src/server/routes/api/v1/account/index.ts index c255763..5d78b7b 100644 --- a/src/server/routes/api/v1/account/index.ts +++ b/src/server/routes/api/v1/account/index.ts @@ -111,12 +111,12 @@ const validators: { // send verification email - if ( - (CodeMgr.codes.verifyEmail.byUser.get(target.id)?.length || 0) >= 2 - ) - return [429, "you have too many active codes"] + const tryCode = CodeMgr.code("verifyEmail", target.id, params.email) - let code = new CodeMgr.Code("verifyEmail", target.id, params.email) + if (!tryCode.success) + return [429, tryCode.error] + + const { code } = tryCode sendMail( params.email, @@ -302,7 +302,13 @@ export default function (files: Files) { router.patch( "/:user", - scheme(UserUpdateScheme), + scheme( + UserUpdateScheme, + (c) => + c.req.header("content-type") == "application/x-www-form-urlencoded" + ? c.req.param() + : c.req.json() + ), assertAPI( ctx => Object.keys(ctx.get("parsedScheme"))