Files
tessera-ctl/.planning/quick/261008-j9f-nextcloud-status-logo-per-http-adresse-h/261008-j9f-SUMMARY.md
T
2026-10-08 14:14:38 +02:00

119 lines
6.4 KiB
Markdown

---
phase: quick-261008-j9f
plan: 01
subsystem: nextcloud-status
tags: [ssrf, logo, validation, i18n, nextcloud-status]
requires: []
provides:
- "http logo address fetched once by Tessera and stored like an upload"
- "shared SSRF guard (apps/api/src/common/public-url-guard.ts)"
- "code-based form errors (API + web) for the cloud form"
affects: [favorites (re-export only), nextcloud-status]
tech-stack:
added: []
patterns: ["{ code, message } errors mapped to de/en texts in the web (as in Domains)"]
key-files:
created:
- apps/api/src/common/public-url-guard.ts
- apps/api/src/nextcloud-status/nextcloud-form-errors.ts
- apps/api/src/nextcloud-status/nextcloud-logo-fetch.ts
- apps/api/src/nextcloud-status/nextcloud-logo-fetch.spec.ts
- apps/api/src/nextcloud-status/dto/nextcloud-instance.dto.spec.ts
- apps/web/src/components/nextcloud-status/cloud-form-errors.ts
- apps/web/src/components/nextcloud-status/cloud-form-errors.test.ts
modified:
- apps/api/src/favorites/icon-discovery.service.ts
- apps/api/src/nextcloud-status/dto/nextcloud-instance.dto.ts
- apps/api/src/nextcloud-status/nextcloud-status.service.ts
- apps/api/src/nextcloud-status/nextcloud-status.service.spec.ts
- apps/web/src/lib/nextcloud-status-api.ts
- apps/web/src/app/(portal)/modules/nextcloud-status/components/CloudForm.tsx
- apps/web/src/app/(portal)/modules/nextcloud-status/components/CloudForm.test.tsx
- apps/web/src/messages/de.json
- apps/web/src/messages/en.json
- apps/web/src/messages/umlaut-dictionary.ts
- CHANGELOG.md
- docs/anleitung-anwender.md
- docs/anleitung-administration.md
decisions:
- "Only http addresses are downloaded; https stays a browser-loaded logoUrl (D-04)"
- "DTO keeps only type guards whose messages are error codes; length and URL rules live in validateInstanceInput / classifyLogoUrl so they arrive as { code, message }"
- "Web never renders server text; unknown errors fall back to the generic German save/delete text"
metrics:
tasks: 3
completed: 2026-10-08
status: complete
commits: 3
plan_head_before: 4ff43c225241133c759d729b31cfc324467e00d2
plan_head_after: 166a6fc9d15ae4289f47a0314e102b37ff2380f9
actuals:
tokens: 60000
tasks: 3
commits: 3
---
# Phase quick-261008-j9f Plan 01: Nextcloud-Status http logo address Summary
An http:// logo address in the Nextcloud cloud form is now downloaded once by Tessera (SSRF-guarded per hop, 8 s total deadline, 1 MiB streaming cap, magic-byte check) and stored in logoData/logoMime like an upload; every error of the form now appears in German (English with the English UI) via stable error codes.
## Commits
| Task | Commit | Description |
| ---- | ------ | ----------- |
| 1 (tracer, API) | 4432561 | shared SSRF guard, fetchLogoImage, error catalogue, DTO codes, service wiring + specs |
| 2 (web) | c30a82e | client pre-check, code -> de/en mapping, label "Bildadresse" + new hint, umlaut allowlist |
| 3 (docs) | 166a6fc | CHANGELOG (Geändert + Behoben), both manuals |
## Measurements
- Task 1 gate: nextcloud-status + favorites + rls-coverage/inventory: 18 files, 365 tests green; api tsc clean; favorites spec/service/controller byte-identical to 4ff43c2; tenantPrisma call sites still 14.
- New specs: nextcloud-logo-fetch.spec.ts 16 tests, dto spec 3 tests, service spec 32 tests, web cloud-form-errors.test.ts + extended CloudForm.test.tsx.
- Full suites: api 137 files / 2525 tests green; web 133 files / 1472 tests green; both `tsc --noEmit` clean.
- Biome: clean on all new/changed files (pre-existing findings in untouched favorites files left alone).
- de/en parity, 12 error keys, label/hint, old keys removed, no Mandant/Lizenz words: "web form ok".
- Umlaut allowlist addition: `Adressen` (correct German, in the new hint).
## Live probe (rebuilt local stack, admin)
```
POST instances logoUrl http://127.0.0.1/logo.png -> 400 {"code":"logoFetchInternal", ...German text}
POST instances logoUrl ftp://x -> 400 {"code":"logoUrlInvalid", ...}
POST instances customerName "" -> 400 {"code":"customerNameRequired", ...}
POST instances customerName 5 -> 400 {"message":["customerNameRequired"]} (DTO message = code)
POST instances logoUrl http://example.com/ -> 400 {"code":"logoFetchNotImage", ...}
POST instances logoUrl http://upload.wikimedia.org/...png (follows http->https redirect)
-> 201, hasUploadedLogo true, logoUrl null
GET instances/:id/logo -> 200 image/png
```
The 201 probe row was deleted again; no "Probe j9f" row remains.
## Deviations from Plan
None - plan executed as written. Notes:
- The user-visible old/new `Cloud nicht gefunden` message changed to the code-based `notFound` text on all cloud routes as the plan specified (not a deviation).
- A rejected file type in the upload picker clears the pending file and shows the error; a subsequent submit clears the error and saves without logo (same behaviour as the existing too-large case).
## Known Stubs
None.
## Threat Flags
None - the new outbound request surface (logo download) is exactly the one covered by T-j9f-01..05 in the plan's threat model.
## Browser steps for the orchestrator (dark mode)
1. Nextcloud-Status -> edit a cloud -> radio "Bildadresse" shows the new hint (https loaded by browser, http fetched once, internal via "Bild hochladen").
2. Enter a public http:// image address of a real website, save -> tile shows the logo; reopening the form shows "Bild hochladen" selected (stored like an upload). A working example: http://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png
3. http://192.168.x.x/logo.png -> German hint pointing to "Bild hochladen", nothing saved.
4. http address of an HTML page (e.g. http://example.com/) -> "Unter dieser Adresse liegt kein Bild ...".
5. Empty name, address without http(s) and an ftp:// logo address -> German texts without any request.
6. https logo address still works as before (browser loads it, logoUrl kept).
7. Switch the UI to English once and repeat (5) -> English texts.
8. Favorites: an existing favorite still shows its icon.
## Self-Check: PASSED
- Created files exist (public-url-guard.ts, nextcloud-form-errors.ts, nextcloud-logo-fetch.ts + spec, dto spec, cloud-form-errors.ts + test).
- Commits 4432561, c30a82e, 166a6fc exist on main (3 commits measured from plan_head_before).