From 60df92b23d90c48ee0694cad79fe5e6f69dae7ef Mon Sep 17 00:00:00 2001 From: Schalli Date: Tue, 7 Jul 2026 15:43:10 +0200 Subject: [PATCH] docs(quick-260707-lgh): Favoriten-Widget Icon-Proxy fuer CORP-Seiten Co-Authored-By: Claude Sonnet 5 --- .planning/STATE.md | 5 ++-- .../260707-lgh-SUMMARY.md | 25 +++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 .planning/quick/260707-lgh-favoriten-widget-icon-proxy-fuer-cross-o/260707-lgh-SUMMARY.md diff --git a/.planning/STATE.md b/.planning/STATE.md index f923847..c0eb620 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -148,6 +148,7 @@ None yet. | 260630-gbh | User Settings: Passwort ändern (nur non-LDAP) + Profilbild setzen | 2026-06-30 | merge | [260630-gbh-user-settings-passwort-ndern-nur-non-lda](.planning/quick/260630-gbh-user-settings-passwort-ndern-nur-non-lda/) | | 260701-abc | Fix i18n: marketplace.accessDenied + calendar form hardcoded EN strings | 2026-07-01 | e5b76b7 | [260701-abc-i18n-missing-keys](.planning/quick/260701-abc-i18n-missing-keys/) | | 260707-csw | LDAP AD Anbindung: Zugangsdaten aus XWiki vorbefuellen und Import-Filter fuer Benutzer/Gruppen | 2026-07-07 | a5c500d | [260707-csw-ldap-ad-anbindung-zugangsdaten-aus-xwiki](.planning/quick/260707-csw-ldap-ad-anbindung-zugangsdaten-aus-xwiki/) | +| 260707-lgh | Favoriten-Widget: Icon-Proxy fuer Cross-Origin-Resource-Policy-Seiten (claude.ai) | 2026-07-07 | f06a2ff | [260707-lgh-favoriten-widget-icon-proxy-fuer-cross-o](.planning/quick/260707-lgh-favoriten-widget-icon-proxy-fuer-cross-o/) | ## Deferred Items @@ -159,7 +160,7 @@ Items acknowledged and carried forward from previous milestone close: ## Session Continuity -Last session: 2026-07-07T07:58:00.000Z +Last session: 2026-07-07T13:42:00.000Z Stopped at: context exhaustion at 77% (2026-07-02) Resume file: .planning/phases/08-dashboard-widgets-vollimplementierung/08-CONTEXT.md -Last activity: 2026-07-07 - Completed quick task 260707-csw: LDAP AD Anbindung: Zugangsdaten aus XWiki vorbefuellen und Import-Filter fuer Benutzer/Gruppen +Last activity: 2026-07-07 - Completed quick task 260707-lgh: Favoriten-Widget Icon-Proxy fuer Cross-Origin-Resource-Policy-Seiten diff --git a/.planning/quick/260707-lgh-favoriten-widget-icon-proxy-fuer-cross-o/260707-lgh-SUMMARY.md b/.planning/quick/260707-lgh-favoriten-widget-icon-proxy-fuer-cross-o/260707-lgh-SUMMARY.md new file mode 100644 index 0000000..7e9a4c5 --- /dev/null +++ b/.planning/quick/260707-lgh-favoriten-widget-icon-proxy-fuer-cross-o/260707-lgh-SUMMARY.md @@ -0,0 +1,25 @@ +--- +status: complete +--- + +# Quick Task 260707-lgh: Favoriten-Widget Icon-Proxy fuer Cross-Origin-Resource-Policy-Seiten + +## What shipped + +1. **`icon-discovery.service.ts`** — extracted the shared SSRF-guarded redirect loop into `fetchWithRedirectGuard` (exported `isPublicHttpUrl`), added `fetchIconBytes()`: image-content-type gate, 1MB cap, dedicated timeout. `discoverFavoriteIconUrl` unchanged. 10 new vitest specs, all passing. +2. **`favorites.service.ts` / `favorites.controller.ts`** — `getIconBytes(id, userId)` (same userId-only ownership check as update/remove; 404 on mismatch/no-icon), new `GET /favorites/:id/icon` streaming endpoint (Cache-Control 86400s, 502 on upstream failure). +3. **`favorites-widget.tsx`** — icon `` now points at `/api-proxy/favorites/:id/icon` (same pattern as the existing avatar image proxy) instead of hotlinking the external URL directly. + +## Bugs caught and fixed during manual testing (not in original plan) + +- **Cloudflare WAF blocking the byte-fetch itself.** After wiring the proxy, chatgpt.com's icon returned 502. Root cause isolated via direct `fetch()` comparison inside the API container: the `tessera/1.0` User-Agent was blocked (403) reproducibly (3/3), while a realistic Chrome UA succeeded (3/3) — a bare `image/*` Accept header alone was a red herring from an earlier (cache-hit-masked) test. Fixed by parameterizing `fetchWithRedirectGuard`'s User-Agent and overriding it only for `fetchIconBytes` (browser-realistic UA + full image Accept list); the HTML-discovery path keeps its original `tessera/1.0` UA unchanged, per the plan's no-regression constraint. + +## Verification performed + +- `vitest run icon-discovery.service.spec.ts` — 10/10 passing. +- API + web `type-check`, API `build` — all green. +- Live end-to-end via Playwright against the running dev stack: both `ChatGPT` and `Claude` favorites now render their real logos (screenshot-confirmed) instead of the letter fallback; network tab shows both `/api-proxy/favorites/:id/icon` requests returning 200 from Tessera's own origin. + +## Known limitations + +- The realistic-browser-UA workaround is a pragmatic fix for one observed WAF behavior (Cloudflare on chatgpt.com); other sites' bot-mitigation could still reject the request for other reasons (rate limits, TLS fingerprinting, etc.) — those will still degrade gracefully to the letter fallback (502 -> `onError` hides the ``), just without a logo.