Add missing admin action files and navigation links

- Add 11 missing server action files: badges, bulk-users, catalog, catalog-bc, catalog-items, import-badges, import-furni, multi-account-detect, permissions, rooms, soundtracks
- Add missing admin navigation links: tickets, sounds, translations, import, radio sub-pages
- Add translation keys for all new navigation items
This commit is contained in:
openhands committed 2026-07-11 12:01:05 +02:00
1 parent 7e1ae17a3b
commit 41be6835bf
347 files changed
+28378 -6091

No files matched your search

+16 -4
View File
@@ -19,14 +19,20 @@ async function sessionUserId(): Promise<number> {
function generateRecoveryCodes(): string[] {
const codes: string[] = [];
for (let i = 0; i < 8; i++) {
codes.push(randomBytes(4).toString("hex").toUpperCase().replace(/(.{4})/, "$1-"));
codes.push(
randomBytes(4)
.toString("hex")
.toUpperCase()
.replace(/(.{4})/, "$1-"),
);
}
return codes;
}
/** Verify a TOTP code OR a recovery code. Returns the updated recovery codes (minus used one) if a recovery code was used, or null on failure. */
async function verifyTwoFactorCode(
userId: number, code: string,
userId: number,
code: string,
): Promise<{ ok: boolean; updatedRecoveryCodes?: string | null }> {
const user = await prisma.user.findUnique({
where: { id: userId },
@@ -38,12 +44,18 @@ async function verifyTwoFactorCode(
try {
const secret = new LaravelEncrypter(env.APP_KEY as string).decrypt(user.twoFactorSecret);
if (verifyTotp(code, secret)) return { ok: true };
} catch { /* fall through to recovery */ }
} catch {
/* fall through to recovery */
}
// Try recovery codes
if (user.twoFactorRecoveryCodes) {
let codes: string[];
try { codes = JSON.parse(user.twoFactorRecoveryCodes) as string[]; } catch { codes = []; }
try {
codes = JSON.parse(user.twoFactorRecoveryCodes) as string[];
} catch {
codes = [];
}
const idx = codes.indexOf(code);
if (idx !== -1) {
codes.splice(idx, 1);