Auth (hand-built on the auth core): - 2FA: User model gains two_factor_secret/recovery_codes/confirmed_at (+ idempotent MariaDB migration). authorize() requires a valid TOTP code when 2FA is confirmed (secret decrypted via Laravel APP_KEY, fail-closed). Two-step login (precheckLogin reveals the code field). /settings/2fa enable/confirm/disable flow. - Password reset: nodemailer email service; PasswordReset model + migration; /forgot (request, generic response) + /reset (token sha256 + 1h TTL, sets argon2id hash). Login links to forgot. Batch 7 (parallel agents): /admin/commandocentrum (RCON controls + emulator_errors), social write actions (friend request + guild forum new thread), /help/[category], /badges (public). env: APP_KEY, APP_URL, SMTP_*. Nav extended. Verified: tsc exit 0, vitest 48/48, next build exit 0 (64 page routes).
39 lines
1.4 KiB
TypeScript
39 lines
1.4 KiB
TypeScript
import Link from "next/link";
|
|
import { resetPassword } from "@/actions/password-reset";
|
|
|
|
export default async function ResetPage({
|
|
searchParams,
|
|
}: {
|
|
searchParams: Promise<{ email?: string; token?: string; error?: string }>;
|
|
}) {
|
|
const { email = "", token = "", error } = await searchParams;
|
|
|
|
return (
|
|
<main style={{ maxWidth: 400, margin: "2rem auto" }}>
|
|
<div className="card" style={{ padding: "1.75rem" }}>
|
|
<h1 style={{ marginTop: 0, textAlign: "center" }}>Set a new password</h1>
|
|
<form action={resetPassword} style={{ display: "grid", gap: "0.7rem", marginTop: "1rem" }}>
|
|
<input type="hidden" name="email" value={email} />
|
|
<input type="hidden" name="token" value={token} />
|
|
<input
|
|
name="password"
|
|
type="password"
|
|
placeholder="New password (min 6 chars)"
|
|
autoComplete="new-password"
|
|
required
|
|
/>
|
|
<button type="submit" className="btn btn-primary">
|
|
Reset password
|
|
</button>
|
|
</form>
|
|
{error ? (
|
|
<p style={{ color: "var(--color-danger)", textAlign: "center", marginBottom: 0 }}>{error}</p>
|
|
) : null}
|
|
<p className="muted" style={{ textAlign: "center", marginBottom: 0, marginTop: "1rem" }}>
|
|
<Link href="/login">Back to login</Link>
|
|
</p>
|
|
</div>
|
|
</main>
|
|
);
|
|
}
|