Privater Bereich /api/privat fuer Behoerdenfotos (d4rk-rp-planung#227 H1)

Polizeifotos aus dem Spiel duerfen nicht unter /f/ liegen, wo jeder sie mit
der Adresse bekommt. Neu:

- eigener Ordner DATA_DIR/privat neben files/ (fuer /f/ und /t/ durch
  Bauart unerreichbar), eigene Tabelle privat_media, eigene Vorschauen
- PUT/GET /api/privat/datei/<pfad>, ?vorschau=1; kein Ueberschreiben (409),
  kein Loeschweg; Cache-Control private, no-store
- Token-Fessel "privat": ein privater Token kommt an keinen oeffentlichen
  Weg (upload, Fivemanage, Liste), ein oeffentlicher an keinen privaten
- Dashboard: Kaestchen "nur privater Bereich" beim Anlegen und Bearbeiten,
  Marke in der Liste
- checkPathUnter: dieselbe Pfadregel fuer beide Ablagen
- tools/sichern.ps1 packt privat/ mit und zaehlt Dateien gegen Eintraege

Geprueft mit tools/privat-pruefen.mjs gegen einen Wegwerf-Container des
Abbilds: 21/21, mit Kontrollen (oeffentliches Bild MUSS unter /f/ kommen).
Dashboard gemessen (kopfloser Edge): 7/7.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
D4rkst3randClaude Opus 5.5 committed 2026-10-16 21:36:16 +02:00
1 parent c8080fb2eb
commit 6630def7b2
14 files changed
+641 -15

No files matched your search

+57
View File
@@ -463,6 +463,63 @@ Papierkorb. Die tägliche Sicherung hilft nur bis zum letzten Lauf.
---
## Der private Bereich: /api/privat
Seit dem 16.10.2026 (d4rk-rp-planung#227). Er ist für Bilder, die **nicht
öffentlich** sein dürfen, z. B. Fotos der Behörden aus dem Spiel. Alles unter
`/f/` ist für jeden lesbar, der die Adresse kennt; hier nicht.
```
PUT /api/privat/datei/<pfad> ablegen
GET /api/privat/datei/<pfad> lesen
GET /api/privat/datei/<pfad>?vorschau=1 Vorschau, 320 px WebP (404, wenn keine)
```
**Nur mit einem Token, der die Fessel „nur privater Bereich“ trägt**
(Dashboard → Token, Spalte `privat`):
| Token | `/api/privat` | `/api/upload`, Fivemanage-Wege, Liste, exists |
|---|---|---|
| privat | ✅ | **403**: „Dieser Token gilt nur für den privaten Bereich …“ |
| öffentlich | **403** | ✅ |
Ein Polizeifoto kann so nicht aus Versehen öffentlich landen.
**Ablegen:** Der Rumpf ist roh oder Base64 (`X-Encoding: base64`, eine
Data-URL wird abgeschnitten). Die Art steht in `X-Mime`. Es gelten dieselben
Fesseln wie öffentlich: Präfix (auch beim **Lesen**), größte Datei,
Kontingent, Arten, Kantenlänge, Ablauf.
**Kein Überschreiben:** Derselbe Pfad ein zweites Mal gibt **409**. Es gibt
**keinen Löschweg**: ein Beweisfoto wird nicht ausgetauscht, der Verbraucher
storniert bei sich.
**Antwort beim Ablegen:**
```json
{ "path": "fotos/police/2026-10/1.webp", "size": 222118, "sha256": "…", "mime": "image/webp", "vorschau": true }
```
Die Antwort enthält **keine `url`**. Es gibt keine öffentliche Adresse.
**Lesen:** Die Antwort trägt `Cache-Control: private, no-store` und
`X-Content-Type-Options: nosniff`.
**Wo es liegt:**
- Dateien in `DATA_DIR/privat`, Einträge in der Tabelle `privat_media`.
- `/f/` und `/t/` lösen nur unter `files/` bzw. `thumbs/` auf und kommen nie
dorthin. Keine Liste, keine Freigabe und keine Galerie liest die Tabelle.
- Die Vorschauen liegen in `DATA_DIR/privat-vorschau`.
- `tools/sichern.ps1` packt `privat/` mit ein und zählt Dateien gegen
Einträge.
**Prüfung:** `node tools/privat-pruefen.mjs <bild.webp>` gegen einen
Wegwerf-Container des Abbilds `d4rk-media:h1-test`. Gemessen am 16.10.2026:
21/21, mit Kontrollen (ein öffentliches Bild MUSS unter `/f/` kommen).
---
## Die Wege des Dashboards
Diese brauchen eine **Sitzung** und keinen Token — sie sind für die Oberfläche