fix auth issues
This commit is contained in:
parent
654b243ab8
commit
254d2bc5d5
@ -14,7 +14,8 @@
|
||||
"Bash(npx tsc:*)",
|
||||
"Bash(pnpm db:generate:*)",
|
||||
"Bash(DATABASE_URL=\"postgresql://fedjens@localhost:5432/eyrun_test\" JWT_SECRET=\"test-secret-that-is-at-least-32-characters-long\" pnpm db:migrate:*)",
|
||||
"Bash(ls:*)"
|
||||
"Bash(ls:*)",
|
||||
"Bash(curl:*)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
"@types/node": "^25.2.1",
|
||||
"@vitest/coverage-v8": "^4.0.18",
|
||||
"drizzle-kit": "^0.31.8",
|
||||
"pino-pretty": "^13.1.3",
|
||||
"tsx": "^4.21.0",
|
||||
"typescript": "^5.9.3",
|
||||
"vitest": "^4.0.18"
|
||||
|
||||
92
pnpm-lock.yaml
generated
92
pnpm-lock.yaml
generated
@ -48,6 +48,9 @@ importers:
|
||||
drizzle-kit:
|
||||
specifier: ^0.31.8
|
||||
version: 0.31.8
|
||||
pino-pretty:
|
||||
specifier: ^13.1.3
|
||||
version: 13.1.3
|
||||
tsx:
|
||||
specifier: ^4.21.0
|
||||
version: 4.21.0
|
||||
@ -801,10 +804,16 @@ packages:
|
||||
resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
colorette@2.0.20:
|
||||
resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
|
||||
|
||||
cookie@1.1.1:
|
||||
resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
dateformat@4.6.3:
|
||||
resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==}
|
||||
|
||||
debug@4.4.3:
|
||||
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
|
||||
engines: {node: '>=6.0'}
|
||||
@ -942,6 +951,9 @@ packages:
|
||||
resolution: {integrity: sha512-EuJWwlHPZ1LbADuKTClvHtwbaFn4rOD+dRAbWysqEOXRc2Uui0hJInNJrsdH0c+OhJA4nrCBdSkW4DD5YxAo6A==}
|
||||
engines: {node: '>=8.10.0'}
|
||||
|
||||
end-of-stream@1.4.5:
|
||||
resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==}
|
||||
|
||||
entities@4.5.0:
|
||||
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
|
||||
engines: {node: '>=0.12'}
|
||||
@ -976,6 +988,9 @@ packages:
|
||||
resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
fast-copy@4.0.2:
|
||||
resolution: {integrity: sha512-ybA6PDXIXOXivLJK/z9e+Otk7ve13I4ckBvGO5I2RRmBU1gMHLVDJYEuJYhGwez7YNlYji2M2DvVU+a9mSFDlw==}
|
||||
|
||||
fast-decode-uri-component@1.0.1:
|
||||
resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==}
|
||||
|
||||
@ -988,6 +1003,9 @@ packages:
|
||||
fast-querystring@1.1.2:
|
||||
resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==}
|
||||
|
||||
fast-safe-stringify@2.1.1:
|
||||
resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==}
|
||||
|
||||
fast-sha256@1.3.0:
|
||||
resolution: {integrity: sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==}
|
||||
|
||||
@ -1032,6 +1050,9 @@ packages:
|
||||
resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
|
||||
hasBin: true
|
||||
|
||||
help-me@5.0.0:
|
||||
resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==}
|
||||
|
||||
html-escaper@2.0.2:
|
||||
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
|
||||
|
||||
@ -1066,6 +1087,10 @@ packages:
|
||||
resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
joycon@3.1.1:
|
||||
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
js-tokens@10.0.0:
|
||||
resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==}
|
||||
|
||||
@ -1141,6 +1166,9 @@ packages:
|
||||
resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
minimist@1.2.8:
|
||||
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
|
||||
|
||||
ms@2.1.3:
|
||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||
|
||||
@ -1160,6 +1188,9 @@ packages:
|
||||
resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
||||
once@1.4.0:
|
||||
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
|
||||
|
||||
openapi-types@12.1.3:
|
||||
resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==}
|
||||
|
||||
@ -1182,6 +1213,10 @@ packages:
|
||||
pino-abstract-transport@3.0.0:
|
||||
resolution: {integrity: sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==}
|
||||
|
||||
pino-pretty@13.1.3:
|
||||
resolution: {integrity: sha512-ttXRkkOz6WWC95KeY9+xxWL6AtImwbyMHrL1mSwqwW9u+vLp/WIElvHvCSDg0xO/Dzrggz1zv3rN5ovTRVowKg==}
|
||||
hasBin: true
|
||||
|
||||
pino-std-serializers@7.1.0:
|
||||
resolution: {integrity: sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==}
|
||||
|
||||
@ -1203,6 +1238,9 @@ packages:
|
||||
process-warning@5.0.0:
|
||||
resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==}
|
||||
|
||||
pump@3.0.3:
|
||||
resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==}
|
||||
|
||||
punycode.js@2.3.1:
|
||||
resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
|
||||
engines: {node: '>=6'}
|
||||
@ -1303,6 +1341,10 @@ packages:
|
||||
std-env@3.10.0:
|
||||
resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==}
|
||||
|
||||
strip-json-comments@5.0.3:
|
||||
resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==}
|
||||
engines: {node: '>=14.16'}
|
||||
|
||||
supports-color@7.2.0:
|
||||
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
|
||||
engines: {node: '>=8'}
|
||||
@ -1436,6 +1478,9 @@ packages:
|
||||
engines: {node: '>=8'}
|
||||
hasBin: true
|
||||
|
||||
wrappy@1.0.2:
|
||||
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
||||
|
||||
yaml@2.8.2:
|
||||
resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==}
|
||||
engines: {node: '>= 14.6'}
|
||||
@ -1936,8 +1981,12 @@ snapshots:
|
||||
|
||||
chai@6.2.2: {}
|
||||
|
||||
colorette@2.0.20: {}
|
||||
|
||||
cookie@1.1.1: {}
|
||||
|
||||
dateformat@4.6.3: {}
|
||||
|
||||
debug@4.4.3:
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
@ -1985,6 +2034,10 @@ snapshots:
|
||||
|
||||
encoding-japanese@2.2.0: {}
|
||||
|
||||
end-of-stream@1.4.5:
|
||||
dependencies:
|
||||
once: 1.4.0
|
||||
|
||||
entities@4.5.0: {}
|
||||
|
||||
es-module-lexer@1.7.0: {}
|
||||
@ -2085,6 +2138,8 @@ snapshots:
|
||||
|
||||
expect-type@1.3.0: {}
|
||||
|
||||
fast-copy@4.0.2: {}
|
||||
|
||||
fast-decode-uri-component@1.0.1: {}
|
||||
|
||||
fast-deep-equal@3.1.3: {}
|
||||
@ -2102,6 +2157,8 @@ snapshots:
|
||||
dependencies:
|
||||
fast-decode-uri-component: 1.0.1
|
||||
|
||||
fast-safe-stringify@2.1.1: {}
|
||||
|
||||
fast-sha256@1.3.0: {}
|
||||
|
||||
fast-uri@3.1.0: {}
|
||||
@ -2151,6 +2208,8 @@ snapshots:
|
||||
|
||||
he@1.2.0: {}
|
||||
|
||||
help-me@5.0.0: {}
|
||||
|
||||
html-escaper@2.0.2: {}
|
||||
|
||||
html-to-text@9.0.5:
|
||||
@ -2191,6 +2250,8 @@ snapshots:
|
||||
html-escaper: 2.0.2
|
||||
istanbul-lib-report: 3.0.1
|
||||
|
||||
joycon@3.1.1: {}
|
||||
|
||||
js-tokens@10.0.0: {}
|
||||
|
||||
json-schema-ref-resolver@3.0.0:
|
||||
@ -2295,6 +2356,8 @@ snapshots:
|
||||
dependencies:
|
||||
semver: 7.7.4
|
||||
|
||||
minimist@1.2.8: {}
|
||||
|
||||
ms@2.1.3: {}
|
||||
|
||||
nanoid@3.3.11: {}
|
||||
@ -2305,6 +2368,10 @@ snapshots:
|
||||
|
||||
on-exit-leak-free@2.1.2: {}
|
||||
|
||||
once@1.4.0:
|
||||
dependencies:
|
||||
wrappy: 1.0.2
|
||||
|
||||
openapi-types@12.1.3: {}
|
||||
|
||||
parseley@0.12.1:
|
||||
@ -2324,6 +2391,22 @@ snapshots:
|
||||
dependencies:
|
||||
split2: 4.2.0
|
||||
|
||||
pino-pretty@13.1.3:
|
||||
dependencies:
|
||||
colorette: 2.0.20
|
||||
dateformat: 4.6.3
|
||||
fast-copy: 4.0.2
|
||||
fast-safe-stringify: 2.1.1
|
||||
help-me: 5.0.0
|
||||
joycon: 3.1.1
|
||||
minimist: 1.2.8
|
||||
on-exit-leak-free: 2.1.2
|
||||
pino-abstract-transport: 3.0.0
|
||||
pump: 3.0.3
|
||||
secure-json-parse: 4.1.0
|
||||
sonic-boom: 4.2.0
|
||||
strip-json-comments: 5.0.3
|
||||
|
||||
pino-std-serializers@7.1.0: {}
|
||||
|
||||
pino@10.3.0:
|
||||
@ -2352,6 +2435,11 @@ snapshots:
|
||||
|
||||
process-warning@5.0.0: {}
|
||||
|
||||
pump@3.0.3:
|
||||
dependencies:
|
||||
end-of-stream: 1.4.5
|
||||
once: 1.4.0
|
||||
|
||||
punycode.js@2.3.1: {}
|
||||
|
||||
quick-format-unescaped@4.0.4: {}
|
||||
@ -2450,6 +2538,8 @@ snapshots:
|
||||
|
||||
std-env@3.10.0: {}
|
||||
|
||||
strip-json-comments@5.0.3: {}
|
||||
|
||||
supports-color@7.2.0:
|
||||
dependencies:
|
||||
has-flag: 4.0.0
|
||||
@ -2549,6 +2639,8 @@ snapshots:
|
||||
siginfo: 2.0.0
|
||||
stackback: 0.0.2
|
||||
|
||||
wrappy@1.0.2: {}
|
||||
|
||||
yaml@2.8.2: {}
|
||||
|
||||
zod@4.3.6: {}
|
||||
|
||||
@ -10,7 +10,12 @@ import { registerRoutes } from "./routes/index.js";
|
||||
|
||||
export function buildApp() {
|
||||
const app = Fastify({
|
||||
logger: true,
|
||||
logger: {
|
||||
transport:
|
||||
process.env.NODE_ENV !== "production"
|
||||
? { target: "pino-pretty", options: { translateTime: "HH:MM:ss", ignore: "pid,hostname" } }
|
||||
: undefined,
|
||||
},
|
||||
});
|
||||
|
||||
app.addHook("onClose", async () => {
|
||||
|
||||
@ -7,9 +7,9 @@ import { otpCodes } from "../db/schema.js";
|
||||
|
||||
const resend = new Resend(config.RESEND_API_KEY);
|
||||
|
||||
const OTP_MAX_ATTEMPTS = 5;
|
||||
const OTP_MAX_ATTEMPTS = 10;
|
||||
const OTP_TTL_MINUTES = 10;
|
||||
const OTP_RATE_LIMIT_PER_HOUR = 3;
|
||||
const OTP_RATE_LIMIT_PER_HOUR = 10;
|
||||
|
||||
/** Rate-limit, generate, store, and send an OTP for the given email. */
|
||||
export async function requestOtp(email: string): Promise<void> {
|
||||
@ -26,6 +26,12 @@ export async function requestOtp(email: string): Promise<void> {
|
||||
const code = crypto.randomInt(100_000, 999_999).toString();
|
||||
const expiresAt = new Date(Date.now() + OTP_TTL_MINUTES * 60 * 1000);
|
||||
|
||||
// Invalidate any previous unused codes for this email
|
||||
await db
|
||||
.update(otpCodes)
|
||||
.set({ used: true })
|
||||
.where(and(eq(otpCodes.email, email), eq(otpCodes.used, false)));
|
||||
|
||||
await db.insert(otpCodes).values({ email, code, expiresAt });
|
||||
await sendOtp(email, code);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user