diff --git a/src/lib/server/email-verification.ts b/src/lib/server/email-verification.ts index 3d6e4ea..3a7bd74 100644 --- a/src/lib/server/email-verification.ts +++ b/src/lib/server/email-verification.ts @@ -5,10 +5,11 @@ import { encodeBase32LowerCaseNoPadding } from "@oslojs/encoding"; import type { RequestEvent } from "@sveltejs/kit"; -export function getEmailVerificationRequest(id: string): EmailVerificationRequest | null { - const row = db.queryOne("SELECT id, user_id, code, email, expires_at FROM email_verification_request WHERE id = ?", [ - id - ]); +export function getUserEmailVerificationRequest(userId: number, id: string): EmailVerificationRequest | null { + const row = db.queryOne( + "SELECT id, user_id, code, email, expires_at FROM email_verification_request WHERE id = ? AND user_id = ?", + [id, userId] + ); if (row === null) { return row; } @@ -81,8 +82,8 @@ export function getUserEmailVerificationRequestFromRequest(event: RequestEvent): if (id === null) { return null; } - const request = getEmailVerificationRequest(id); - if (request !== null && request.userId !== event.locals.user.id) { + const request = getUserEmailVerificationRequest(event.locals.user.id, id); + if (request !== null) { deleteEmailVerificationRequestCookie(event); return null; } diff --git a/src/routes/2fa/passkey/+server.ts b/src/routes/2fa/passkey/+server.ts index 62f0585..9de6094 100644 --- a/src/routes/2fa/passkey/+server.ts +++ b/src/routes/2fa/passkey/+server.ts @@ -23,12 +23,11 @@ export async function POST(event: RequestEvent) { status: 401 }); } - if (!event.locals.user.emailVerified) { - return new Response("Forbidden", { - status: 403 - }); - } - if (!event.locals.user.registeredPasskey) { + if ( + !event.locals.user.emailVerified || + !event.locals.user.registeredPasskey || + event.locals.session.twoFactorVerified + ) { return new Response("Forbidden", { status: 403 }); diff --git a/src/routes/2fa/reset/+page.server.ts b/src/routes/2fa/reset/+page.server.ts index e342cb1..8622e99 100644 --- a/src/routes/2fa/reset/+page.server.ts +++ b/src/routes/2fa/reset/+page.server.ts @@ -29,12 +29,7 @@ async function action(event: RequestEvent) { message: "Not authenticated" }); } - if (!event.locals.user.emailVerified) { - return fail(403, { - message: "Forbidden" - }); - } - if (!event.locals.user.registered2FA) { + if (!event.locals.user.emailVerified || !event.locals.user.registered2FA || event.locals.session.twoFactorVerified) { return fail(403, { message: "Forbidden" }); diff --git a/src/routes/2fa/security-key/+server.ts b/src/routes/2fa/security-key/+server.ts index cbf9f8a..9ba5038 100644 --- a/src/routes/2fa/security-key/+server.ts +++ b/src/routes/2fa/security-key/+server.ts @@ -23,12 +23,11 @@ export async function POST(event: RequestEvent) { status: 401 }); } - if (!event.locals.user.emailVerified) { - return new Response("Forbidden", { - status: 403 - }); - } - if (!event.locals.user.registeredSecurityKey) { + if ( + !event.locals.user.emailVerified || + !event.locals.user.registeredSecurityKey || + event.locals.session.twoFactorVerified + ) { return new Response("Forbidden", { status: 403 }); diff --git a/src/routes/2fa/totp/+page.server.ts b/src/routes/2fa/totp/+page.server.ts index be230cf..f72dca3 100644 --- a/src/routes/2fa/totp/+page.server.ts +++ b/src/routes/2fa/totp/+page.server.ts @@ -33,12 +33,7 @@ async function action(event: RequestEvent) { message: "Not authenticated" }); } - if (!event.locals.user.emailVerified) { - return fail(403, { - message: "Forbidden" - }); - } - if (!event.locals.user.registered2FA) { + if (!event.locals.user.emailVerified || !event.locals.user.registeredTOTP || event.locals.session.twoFactorVerified) { return fail(403, { message: "Forbidden" }); diff --git a/src/routes/reset-password/2fa/+server.ts b/src/routes/reset-password/2fa/+server.ts index ccc6433..312a93a 100644 --- a/src/routes/reset-password/2fa/+server.ts +++ b/src/routes/reset-password/2fa/+server.ts @@ -1,4 +1,3 @@ -import { redirect } from "@sveltejs/kit"; import { getPasswordReset2FARedirect } from "$lib/server/2fa"; import { validatePasswordResetSessionRequest } from "$lib/server/password-reset"; diff --git a/src/routes/reset-password/2fa/passkey/+server.ts b/src/routes/reset-password/2fa/passkey/+server.ts index 00d7f1b..0a4e50d 100644 --- a/src/routes/reset-password/2fa/passkey/+server.ts +++ b/src/routes/reset-password/2fa/passkey/+server.ts @@ -24,12 +24,7 @@ export async function POST(event: RequestEvent) { status: 401 }); } - if (!user.emailVerified) { - return new Response("Forbidden", { - status: 403 - }); - } - if (!user.registeredPasskey) { + if (!user.emailVerified || !user.registeredPasskey || session.twoFactorVerified) { return new Response("Forbidden", { status: 403 }); diff --git a/src/routes/reset-password/2fa/recovery-code/+page.server.ts b/src/routes/reset-password/2fa/recovery-code/+page.server.ts index 3b1b01f..af79808 100644 --- a/src/routes/reset-password/2fa/recovery-code/+page.server.ts +++ b/src/routes/reset-password/2fa/recovery-code/+page.server.ts @@ -29,28 +29,23 @@ export const actions: Actions = { }; async function action(event: RequestEvent) { - const { session } = validatePasswordResetSessionRequest(event); + const { session, user } = validatePasswordResetSessionRequest(event); if (session === null) { return fail(401, { message: "Not authenticated" }); } - if (!session.emailVerified) { + if (!user.emailVerified || !user.registered2FA || session.twoFactorVerified) { return fail(403, { message: "Forbidden" }); } + if (!recoveryCodeBucket.check(session.userId, 1)) { return fail(429, { message: "Too many requests" }); } - if (session.twoFactorVerified) { - return fail(400, { - message: "Already verified" - }); - } - const formData = await event.request.formData(); const code = formData.get("code"); if (typeof code !== "string") { diff --git a/src/routes/reset-password/2fa/security-key/+server.ts b/src/routes/reset-password/2fa/security-key/+server.ts index b860bef..1f41435 100644 --- a/src/routes/reset-password/2fa/security-key/+server.ts +++ b/src/routes/reset-password/2fa/security-key/+server.ts @@ -24,12 +24,7 @@ export async function POST(event: RequestEvent) { status: 401 }); } - if (!user.emailVerified) { - return new Response("Forbidden", { - status: 403 - }); - } - if (!user.registeredSecurityKey) { + if (!user.emailVerified || !user.registeredSecurityKey || session.twoFactorVerified) { return new Response("Forbidden", { status: 403 }); diff --git a/src/routes/reset-password/2fa/totp/+page.server.ts b/src/routes/reset-password/2fa/totp/+page.server.ts index 52fc703..050e2c4 100644 --- a/src/routes/reset-password/2fa/totp/+page.server.ts +++ b/src/routes/reset-password/2fa/totp/+page.server.ts @@ -40,16 +40,16 @@ async function action(event: RequestEvent) { message: "Not authenticated" }); } + if (!user.emailVerified || !user.registeredTOTP || session.twoFactorVerified) { + return fail(403, { + message: "Forbidden" + }); + } if (!totpBucket.check(session.userId, 1)) { return fail(429, { message: "Too many requests" }); } - if (!user.registered2FA || session.twoFactorVerified || !session.emailVerified) { - return fail(403, { - message: "Forbidden" - }); - } const formData = await event.request.formData(); const code = formData.get("code"); diff --git a/src/routes/reset-password/verify-email/+page.server.ts b/src/routes/reset-password/verify-email/+page.server.ts index be9bd40..fa3e481 100644 --- a/src/routes/reset-password/verify-email/+page.server.ts +++ b/src/routes/reset-password/verify-email/+page.server.ts @@ -38,17 +38,17 @@ async function action(event: RequestEvent) { message: "Not authenticated" }); } + if (session.emailVerified) { + return fail(403, { + message: "Forbidden" + }); + } if (!bucket.check(session.userId, 1)) { return fail(429, { message: "Too many requests" }); } - if (session.emailVerified) { - return fail(400, { - message: "Already verified" - }); - } const formData = await event.request.formData(); const code = formData.get("code"); if (typeof code !== "string") { diff --git a/src/routes/verify-email/+page.server.ts b/src/routes/verify-email/+page.server.ts index 2fc7bd2..4cb7887 100644 --- a/src/routes/verify-email/+page.server.ts +++ b/src/routes/verify-email/+page.server.ts @@ -131,10 +131,6 @@ async function resendEmail(event: RequestEvent) { }); } - let verificationRequest = getUserEmailVerificationRequestFromRequest(event); - if (verificationRequest === null) { - return fail(401); - } if (!sendVerificationEmailBucket.consume(event.locals.user.id, 1)) { return fail(429, { resend: { @@ -142,7 +138,20 @@ async function resendEmail(event: RequestEvent) { } }); } - verificationRequest = createEmailVerificationRequest(verificationRequest.userId, verificationRequest.email); + + let verificationRequest = getUserEmailVerificationRequestFromRequest(event); + if (verificationRequest === null) { + if (event.locals.user.emailVerified) { + return fail(403, { + resend: { + message: "Forbidden" + } + }); + } + verificationRequest = createEmailVerificationRequest(event.locals.user.id, event.locals.user.email); + } else { + verificationRequest = createEmailVerificationRequest(event.locals.user.id, verificationRequest.email); + } sendVerificationEmail(verificationRequest.email, verificationRequest.code); setEmailVerificationRequestCookie(event, verificationRequest); return {