Add 2FA, email + password reset, and batch-7 pages

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).
This commit is contained in:
2026-06-28 14:25:19 +02:00
parent 486ce51559
commit e668fa85ec
24 changed files with 1223 additions and 34 deletions
+11
View File
@@ -1,3 +1,4 @@
import Link from "next/link";
import { redirect } from "next/navigation";
import { updateMotto } from "@/actions/user-settings";
import { avatarImageUrl } from "@/lib/format";
@@ -81,6 +82,16 @@ export default async function SettingsPage() {
Updates instantly in-game if you are online.
</p>
</div>
<div className="card" style={{ maxWidth: 520, marginTop: "1.5rem" }}>
<h3 style={{ marginTop: 0 }}>Security</h3>
<p className="muted" style={{ marginTop: 0 }}>
Protect your account with two-factor authentication.
</p>
<Link href="/settings/2fa" className="btn btn-outline">
Two-factor authentication
</Link>
</div>
</main>
);
}