example-sveltekit-email-pas.../src/routes/2fa/reset/+page.server.ts
pilcrowOnPaper 25cc397095 init
2024-10-03 18:50:34 +09:00

73 lines
1.7 KiB
TypeScript

import { recoveryCodeBucket, resetUser2FAWithRecoveryCode } from "$lib/server/2fa";
import { fail, redirect } from "@sveltejs/kit";
import type { Actions, RequestEvent } from "./$types";
export const actions: Actions = {
default: action
};
export async function load(event: RequestEvent) {
if (event.locals.user === null || event.locals.session === null) {
return redirect(302, "/login");
}
if (!event.locals.user.emailVerified) {
return redirect(302, "/verify-email");
}
if (!event.locals.user.registered2FA) {
return redirect(302, "/2fa/setup");
}
if (event.locals.session.twoFactorVerified) {
return redirect(302, "/");
}
return {};
}
async function action(event: RequestEvent) {
if (event.locals.session === null || event.locals.user === null) {
return fail(401, {
message: "Not authenticated"
});
}
if (!event.locals.user.emailVerified) {
return fail(403, {
message: "Forbidden"
});
}
if (!event.locals.user.registered2FA) {
return fail(403, {
message: "Forbidden"
});
}
if (!recoveryCodeBucket.check(event.locals.user.id, 1)) {
return fail(429, {
message: "Too many requests"
});
}
const formData = await event.request.formData();
const code = formData.get("code");
if (typeof code !== "string") {
return fail(400, {
message: "Invalid or missing fields"
});
}
if (code === "") {
return fail(400, {
message: "Please enter your code"
});
}
if (!recoveryCodeBucket.consume(event.locals.user.id, 1)) {
return fail(429, {
message: "Too many requests"
});
}
const valid = resetUser2FAWithRecoveryCode(event.locals.user.id, code);
if (!valid) {
return fail(400, {
message: "Invalid recovery code"
});
}
recoveryCodeBucket.reset(event.locals.user.id);
return redirect(302, "/2fa/setup");
}