"use server"; import { redirect } from "next/navigation"; import { completeSignIn, endSession, safeNext, signIn } from "@/lib/auth"; import { requestPasswordReset, resetPassword, sendVerificationEmailLater } from "@/lib/emails"; import { MAIL_ENABLED } from "@/lib/mail"; import { SIGNUPS_ENABLED } from "@/lib/signups"; import { createUser, UserError, validatePassword } from "@/lib/users"; import type { FormState } from "./types"; export async function signupAction(_prev: FormState, formData: FormData): Promise { if (!SIGNUPS_ENABLED) return { error: "Sign-ups are closed." }; const password = String(formData.get("password") ?? ""); try { const user = await createUser({ username: String(formData.get("username") ?? ""), email: String(formData.get("email") ?? ""), password, name: String(formData.get("name") ?? ""), }); sendVerificationEmailLater(user); await signIn(user.email, password); } catch (e) { if (e instanceof UserError) return { error: e.message }; throw e; } redirect(safeNext(formData.get("next"))); } export async function loginAction(_prev: FormState, formData: FormData): Promise { const result = await signIn(String(formData.get("login") ?? ""), String(formData.get("password") ?? "")); if (!result) return { error: "Incorrect username or password." }; const next = safeNext(formData.get("next")); if (result.needsCode) redirect(next === "/" ? "/login/two-factor" : `/login/two-factor?next=${encodeURIComponent(next)}`); redirect(next); } export async function twoFactorLoginAction(_prev: FormState, formData: FormData): Promise { const next = safeNext(formData.get("next")); const result = await completeSignIn(String(formData.get("code") ?? "")); if (result === "invalid") return { error: "That code didn't match. Try the newest code from your app." }; if (result === "locked") return { error: "Too many wrong codes. Wait 15 minutes, then try again." }; if (result === "expired") redirect(`/login?expired=1${next !== "/" ? `&next=${encodeURIComponent(next)}` : ""}`); redirect(next); } export async function forgotPasswordAction(_prev: FormState, formData: FormData): Promise { if (!MAIL_ENABLED) return { error: "This server can't send email. Ask the person who runs it to reset your password." }; const login = String(formData.get("login") ?? "").trim(); if (!login) return { error: "Enter your username or email address." }; await requestPasswordReset(login); return { success: "If that's an account here, we've sent a link to choose a new password to its email address. It works for one hour." }; } export async function resetPasswordAction(_prev: FormState, formData: FormData): Promise { const password = String(formData.get("password") ?? ""); if (password !== formData.get("confirm")) return { error: "The passwords don't match." }; const problem = validatePassword(password); if (problem) return { error: problem }; if (!(await resetPassword(String(formData.get("token") ?? ""), password))) { return { error: "This link has expired or was already used. Ask for a new one." }; } redirect("/login?reset=1"); } export async function logoutAction() { await endSession(); redirect("/"); }