Presigned URLs wie Fivemanage v3, einmalig und gefesselt (d4rk-rp-planung#239)

d4rk_phone gab den Token an jeden Client, weil der Dienst keinen Weg ohne
Token kannte. Jetzt wie Fivemanage (docs.fivemanage.com, gelesen 19.10.2026;
sky_phone nutzt denselben Weg):

  GET  /api/v3/file/presigned-url[?expiresAt=]   mit Token  -> data.presignedUrl
  POST /api/v3/file/presigned-url/<schluessel>   OHNE Token -> data.url

Strenger: jeder Schluessel einmal (auch bei Ablehnung verbraucht), hoechstens
15 Minuten, Fesseln des ausstellenden Tokens beim Hochladen frisch gelesen,
private Tokens bekommen keinen. Im Arbeitsspeicher (Betreiber 19.10.2026),
nur der Hash.

tools/presign-pruefen.mjs gegen einen Wegwerf-Container: 19/19, mit
Kontrollen (v3/file mit Token geht, ohne bleibt 401).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
D4rkst3randClaude Opus 5.5 committed 2026-10-19 21:08:21 +02:00
1 parent a4e918be8a
commit f077ac155b
3 files changed
+271 -2

No files matched your search

+31 -2
View File
@@ -111,6 +111,8 @@ Dienstes** ein.
| `POST /api/video` | ✅ gleich | `video` | dito |
| `POST /api/audio` | ✅ gleich | `audio` | dito |
| `POST /api/v3/file` | ✅ gleich | `file`, `path?`, `filename?` | `{ "status": "ok", "data": { "id", "url" } }` |
| `GET /api/v3/file/presigned-url` | ✅ gleich, strenger | `?expiresAt=` (Unix-Sekunden) | `{ "status": "ok", "data": { "presignedUrl", "expiresAt" } }` |
| `POST /api/v3/file/presigned-url/<schlüssel>` | ✅ gleich, **ohne Token** | `file`, `path?`, `filename?` | wie `/api/v3/file` |
Der Schlüssel steht **nackt** im `Authorization`-Kopf, ohne `Bearer` — genau so
wie bei Fivemanage. `Bearer …` geht weiterhin auch.
@@ -136,8 +138,35 @@ Fivemanages ID auch hat.
**Was NICHT übernommen wird:** `metadata` wird angenommen und ignoriert (es gibt
hier keine Spielerdaten an einer Datei), `retentionExempt` ebenso — dieser
Dienst löscht nichts von selbst. Presigned URLs gibt es nicht: der Upload geht
direkt hierher.
Dienst löscht nichts von selbst.
### Presigned URLs — wenn die Bytes vom Spieler kommen
Seit 19.10.2026 (d4rk-rp-planung#239). **Der Token gehört nie in den Browser
eines Spielers.** Muss ein Bild, Ton oder Video aus der NUI hochgehen, holt der
**Server** mit seinem Token eine Adresse, und nur die geht an den Client:
```lua
-- Server: Adresse holen (Token nackt im Kopf, wie bei Fivemanage)
PerformHttpRequest('https://media.d4rkst3r.de/api/v3/file/presigned-url', cb, 'GET', '',
{ Authorization = GetConvar('mein_token', '') })
-- cb: data.presignedUrl an den Client geben
```
```js
// NUI: dorthin hochladen, OHNE Authorization
const f = new FormData(); f.append('file', blob, 'foto.webp')
const r = await fetch(presignedUrl, { method: 'POST', body: f }) // -> data.url
```
**Strenger als Fivemanage, mit Absicht** (gemessen mit `tools/presign-pruefen.mjs`, 19/19):
- jede Adresse gilt **genau einmal**, auch ein Versuch, der an einer Fessel scheitert, verbraucht sie;
- höchstens **15 Minuten**, auch wenn `expiresAt` mehr verlangt; ohne Angabe 15 Minuten;
- es gelten **die Fesseln des ausstellenden Tokens**, beim Hochladen frisch gelesen — wird der Token gelöscht oder gefesselt, gilt das sofort auch für seine offenen Adressen;
- ein **privater** Token bekommt keine (403).
Die Schlüssel liegen im Arbeitsspeicher; ein Neustart des Dienstes verwirft offene.
> Beide Formen sind **aus echtem Code abgelesen**, nicht geraten:
> [fivemanage/sdk](https://github.com/fivemanage/sdk) für v3 und