Interner Zugang auffindbar + Owner kann eigenen Code selbst aendern

- Footer hat jetzt einen eigenen Block "Intern" mit Links zum
  Bewerbungs-Postfach und zu Zugaenge & Rollen (vorher nur ein
  winziger Link ganz unten)
- Postfach-Login verlinkt auf die Zugaenge-Seite
- Neue Tabelle app_settings + Endpunkt /admin/owner/set-code:
  der Hauptadministrator kann seinen Code selbst aendern, mit
  Bestaetigung des aktuellen Codes; gespeichert wird nur der Hash
- Neuer Tab "Mein Zugang" in zugaenge.html (nur fuer den Owner)

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-07-31 02:19:36 +02:00
co-authored by Claude Opus 5
parent 0e1f2fbdc4
commit 597988a9a2
8 changed files with 140 additions and 5 deletions
+40 -1
View File
@@ -3,9 +3,48 @@
===================================================================== */
import { verifyCode, createSession, endSession, isLockedOut, recordFailedAttempt, clearAttempts, clientKey } from "../lib/auth.js";
import { logAction } from "../lib/audit.js";
import { nowIso } from "../lib/crypto.js";
import { nowIso, sha256Hex } from "../lib/crypto.js";
import { json } from "../lib/http.js";
/**
* Der Hauptadministrator ändert seinen eigenen Zugangscode.
* Nur mit gültiger Owner-Session UND erneuter Eingabe des aktuellen Codes.
* Gespeichert wird ausschließlich der SHA-256-Hash — nie der Klartext.
*/
export async function setOwnerCode(request, env, session) {
if (!session || !session.isOwner) {
return json({ ok: false, error: "Das darf nur der Hauptadministrator." }, 403);
}
const body = await request.json().catch(() => ({}));
const currentCode = String(body.currentCode || "");
const newCode = String(body.newCode || "");
const check = await verifyCode(env, currentCode);
if (!check.ok || !check.isOwner) {
await logAction(env, "owner", "owner.code_change_failed", null, null);
return json({ ok: false, error: "Der aktuelle Code stimmt nicht." }, 403);
}
if (newCode.length < 10) {
return json({ ok: false, error: "Der neue Code muss mindestens 10 Zeichen haben." }, 400);
}
if (newCode === currentCode) {
return json({ ok: false, error: "Der neue Code muss sich vom alten unterscheiden." }, 400);
}
const hash = await sha256Hex(newCode);
await env.DB.prepare(
`INSERT INTO app_settings (key, value, updated_at) VALUES ('owner_code_hash', ?, ?)
ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at`
)
.bind(hash, nowIso())
.run();
await logAction(env, "owner", "owner.code_changed", null, null);
return json({ ok: true });
}
export async function login(request, env) {
const body = await request.json().catch(() => ({}));
const code = String(body.code || "");