Security-Seite: Reichweiten-/Access-Control-Check (nur Booleans+Anzahl, keine Werte) - Profil-Privinfelder, Foto-IDOR, LV-Plan, Directory, anonyme iCal, Klassenliste

This commit is contained in:
Nicolas Gruber
2026-10-22 10:04:25 +02:00
parent 5b036024ec
commit 3af3c26304
6 changed files with 174 additions and 0 deletions
+26
View File
@@ -2,6 +2,7 @@
import hashlib
import json
import os
import random
import threading
import time
import uuid
@@ -454,6 +455,31 @@ def person_page(request: Request, uid: str):
})
@app.get("/security", response_class=HTMLResponse)
def security_page(request: Request):
return templates.TemplateResponse(request, "security.html", {
"request": request, "own_uid": OWN_UID,
})
@app.get("/api/security/probe")
def api_security_probe(uid: str = Query("")):
"""Access-Control-Report: nur Booleans/Anzahl - keine Personenwerte."""
meta = _meta()
label = current_semester(meta["semesters"])
s = next((x for x in meta["semesters"] if x["label"] == label), meta["semesters"][0])
target = uid.strip()
if not target:
pool = [b["uid"] for b in client.benutzer_all()
if b["uid"] != OWN_UID and b["uid"].isdigit()]
if not pool:
return JSONResponse({"error": "kein Ziel-Person aus Directory"}, status_code=502)
target = random.choice(pool)
if target == OWN_UID:
return JSONResponse({"error": "Eigenes Profil ist kein fremder Zugriff"}, status_code=400)
checks = client.privacy_probe(target, OWN_UID, s)
return {"target": target, "semester": label, "checks": checks}
@app.get("/api/person_id")
def api_person_id(uid: str = Query(...)):
return {"uid": uid, "person_id": client.person_id_for(uid)}