feat: release per URL registrieren (gitea-asset) - /api/v1/releases/from-url

- Admin-Endpoint laedt die ZIP einmal von einer URL (z.B. Gitea-Release-Asset),
  speichert sie lokal; Kunden-Download bleibt token-/lizenzgeschuetzt.
- Guards: Produkt/Version/URL-Pruefung, GITEA_BASE_URL-Restriktion, DNS-SSRF-Schutz,
  optional GITEA_TOKEN fuer private Repos, ZIP-Signatur + 50MB-Limit.
- env-Beispiele + README + Tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
s4luorth
2026-06-07 15:51:19 +02:00
parent 576ad1f74a
commit e691b675cd
4 changed files with 102 additions and 0 deletions

View File

@@ -79,8 +79,21 @@ Optional: `email`, `note`, `expires_at` (ISO date; omit for lifetime).
| GET | `/api/v1/products` | list products |
| POST | `/api/v1/products` | add a product |
| POST | `/api/v1/releases?product=&version=` | upload a plugin ZIP (raw body) |
| POST | `/api/v1/releases/from-url` | fetch a ZIP from a URL (e.g. Gitea release asset) |
| GET | `/api/v1/releases/:product` | list releases |
**Register a release from a Gitea release asset** (no file upload — just JSON):
```bash
curl -X POST https://hub.lucas-orth.de/api/v1/releases/from-url \
-H "X-Admin-Token: $ADMIN_API_TOKEN" -H "Content-Type: application/json" \
-d '{"product":"gdpr-content-blocker","version":"1.1.0","zip_url":"https://gitea.lucas-orth.de/lucas.orth/GDPR-Content-Blocker/releases/download/v1.1.0/gdpr-content-blocker.zip"}'
```
The backend downloads the ZIP once and stores it locally, so the customer download
stays license-gated. The asset must be a **built plugin ZIP** (top-level
`gdpr-content-blocker/` folder) attached to the Gitea release — the auto-generated
"Source code" archive of the monorepo will NOT work. Set `GITEA_BASE_URL` to
restrict fetches to your Gitea, and `GITEA_TOKEN` for private repos.
**Upload a new plugin version** (raw `.zip` as the body — no multipart):
```bash
curl -X POST "https://hub.lucas-orth.de/api/v1/releases?product=gdpr-content-blocker&version=1.1.0" \