From 72fd330ae68d46c2d9c2e1f02c4b62724e7f2617 Mon Sep 17 00:00:00 2001 From: D4rkst3r Date: Wed, 12 Aug 2026 00:43:29 +0200 Subject: [PATCH] feat: der Dienst nennt sich selbst -- und Cloudflare bricht die WebP-Auslieferung DER NAME KAM VIERMAL FEST AUS DEM QUELLTEXT: Kopfzeile, Anmeldeseite, Fusszeile einer Freigabe, Tab-Titel -- und zwar als "d4rk_media", was der Name des Repositorys ist und nicht der des Dienstes. Wer ihn aendern wollte, musste vier Stellen finden und eine davon uebersehen. Er kommt jetzt vom Server, aus der Einstellung marke.name -- DERSELBEN, die schon in der Fusszeile der Discord-Meldungen steht ("D4RKST3R // MEDIA"). Ein zweiter Name fuer die Oberflaeche waere ein zweiter, der beim naechsten Mal anders lautet als der erste. Ausgeliefert wird er ueber /api/dash/auth/config (oeffentlich, die Anmeldeseite hat noch keine Sitzung) und in der Freigabe-Antwort (die Seite ist oeffentlich und holt sonst nichts, was ihn kennen koennte). Angezeigt wird " Media" -- die Marke allein waere falsch, sie steht ueber allem, was hier laeuft. EINE STELLE BLEIBT ABSICHTLICH: der Schluessel im Speicher des Browsers (merker.ts) heisst weiter "d4rk_media.". Wer ihn umbenennt, wirft still alle gemerkten Ansichtseinstellungen weg, und niemand versteht, warum die Galerie ploetzlich wieder bei 60 Kacheln steht. Steht als Kommentar daneben. --- UND DER NEUE NAME HAENGT HINTER CLOUDFLARE, was die WebP-Auslieferung bricht. NPM ist sauber, sogar besser als vorgeschlagen: beide Namen auf DEMSELBEN Host, die drei ^~-Bloecke gelten damit fuer beide. Der DNS-Eintrag geht aber ueber Cloudflare (188.114.97.3, Server: cloudflare), waehrend fivemanage direkt auf 88.218.224.10 zeigt. Gemessen, dieselbe Datei: fivemanage (direkt) ohne Accept -> image/png 12295 B richtig mit Accept -> image/webp 2270 B richtig media (Cloudflare) 1. mit Accept -> image/webp 2270 B MISS 2. mit Accept -> image/webp 2270 B HIT 3. OHNE Accept -> image/webp 2270 B HIT FALSCH Und andersherum genauso -- wer zuerst kommt, praegt den Zwischenspeicher fuer alle. Es sind unsere eigenen Bytes (2270 = unsere WebP-Fassung), also kein Polish, sondern ein Cache-Schluessel ohne Accept. Vary: Accept wird an den Client durchgereicht, aber nicht zum Unterscheiden benutzt. Fuer ein Lua-Skript heisst das: items/foo.png liefert WebP-Bytes unter einem .png-Namen, und das faellt erst auf, wenn irgendwo ein Bild nicht laedt. PUBLIC_URL ist deshalb NICHT umgestellt. Genau davor stand die Warnung im letzten Commit, und sie war keine Vorsicht, sondern eine Vorhersage. Co-Authored-By: Claude Opus 5 --- ROADMAP.md | 36 ++++++++++++++++++++++ server/src/routes/dash.ts | 10 +++++- server/src/routes/freigabe.ts | 4 +++ server/src/settings.ts | 10 ++++++ server/ui/index.html | 2 +- server/ui/src/App.tsx | 4 ++- server/ui/src/api.ts | 2 +- server/ui/src/marke.ts | 52 ++++++++++++++++++++++++++++++++ server/ui/src/merker.ts | 5 +++ server/ui/src/pages/Anmelden.tsx | 9 ++++-- server/ui/src/pages/Freigabe.tsx | 5 +-- 11 files changed, 131 insertions(+), 8 deletions(-) create mode 100644 server/ui/src/marke.ts diff --git a/ROADMAP.md b/ROADMAP.md index 7f152c5..6781572 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -960,6 +960,42 @@ einfügen.** Ein neuer Host bringt seine eigene `assets.conf` mit. **3. Sagen.** Dann setze ich `PUBLIC_URL` um und ziehe Dokumentation, Fotostudio, Handy und die Watchdog-Einträge nach. +#### ⚠️ DNS und NPM stehen — aber der Name hängt hinter Cloudflare + +Am 12.08.2026 eingerichtet. NPM ist dabei sogar besser gelöst als vorgeschlagen: +**beide Namen auf demselben Host** (`server_name fivemanage.d4rkst3r.de +media.d4rkst3r.de;`), die drei `^~`-Blöcke gelten damit für beide. + +Der DNS-Eintrag geht aber über Cloudflare, und **das bricht die +WebP-Auslieferung.** Gemessen, dieselbe Datei, dieselbe Sekunde: + +``` +fivemanage (direkt) ohne Accept -> image/png 12295 B richtig + mit Accept -> image/webp 2270 B richtig + +media (Cloudflare) 1. mit Accept -> image/webp 2270 B MISS + 2. mit Accept -> image/webp 2270 B HIT + 3. OHNE Accept -> image/webp 2270 B HIT ← FALSCH +``` + +Und andersherum genauso: wer zuerst kommt, prägt den Zwischenspeicher für alle. +Es sind **unsere eigenen Bytes** (2270 B = unsere WebP-Fassung), also kein +Cloudflare-Polish, sondern ein **Cache-Schlüssel ohne `Accept`**. `Vary: Accept` +wird an den Client durchgereicht, aber nicht zum Unterscheiden benutzt — +Cloudflare variiert standardmäßig nur über `Accept-Encoding`. + +Für ein Lua-Skript heißt das: `items/foo.png` liefert WebP-Bytes unter einem +`.png`-Namen, und das fällt erst auf, wenn irgendwo ein Bild nicht lädt. + +**Deshalb ist `PUBLIC_URL` noch nicht umgestellt.** Zwei Wege heraus: + +1. **Graue Wolke** für `media` — Cloudflare-Proxy aus, DNS-only, wie bei + `fivemanage`. Der Ursprung ist ohnehin nicht verborgen (`fivemanage` zeigt + direkt darauf), Cloudflare bringt hier also nichts, was den Bruch aufwöge. +2. Cloudflare behalten und dort eine **Cache Rule** anlegen, die `/f/*` und + `/t/*` vom Zwischenspeicher ausnimmt. Funktioniert, ist aber eine dritte + Stelle, an der dieselbe Regel gepflegt werden will. + Gegenprüfen lässt sich beides mit dem, was schon da ist: ```powershell diff --git a/server/src/routes/dash.ts b/server/src/routes/dash.ts index e182a19..c74ef8c 100644 --- a/server/src/routes/dash.ts +++ b/server/src/routes/dash.ts @@ -39,6 +39,7 @@ import { mkdir, readdir, readFile, rm, rmdir, stat } from 'node:fs/promises' import { join } from 'node:path' import { DISCORD_KEYS, + MARKE_KEY, SICHERUNG_KEYS, ausDatenbank, discordConfig, @@ -265,7 +266,14 @@ dashRoutes.get('/auth/me', (c) => { * Nur ein Ja/Nein: ob der Discord-Knopf ueberhaupt sinnvoll ist. Weder * Client-ID noch Server-ID gehen hier heraus — die braucht das Formular * nicht, und was nicht herausgeht, kann auch nicht abgeschrieben werden. */ -dashRoutes.get('/auth/config', (c) => c.json({ discord: discordConfig().bereit })) +dashRoutes.get('/auth/config', (c) => + c.json({ + discord: discordConfig().bereit, + // Der Name gehoert MIT hier hinein, obwohl es eine Anmeldeauskunft ist: + // die Anmeldeseite braucht ihn, und die hat noch keine Sitzung. Ohne + // das muesste sie ihn erraten oder fest eingebaut mitbringen. + marke: getSetting(MARKE_KEY) || 'D4RKST3R', + })) // Der Discord-Weg selbst. MUSS vor der Wache stehen: wer sich anmelden will, // ist noch nicht angemeldet. diff --git a/server/src/routes/freigabe.ts b/server/src/routes/freigabe.ts index faf9fa9..a8706a6 100644 --- a/server/src/routes/freigabe.ts +++ b/server/src/routes/freigabe.ts @@ -18,6 +18,7 @@ import { randomBytes } from 'node:crypto' import { Hono } from 'hono' import { db, now, type Freigabe, type Media } from '../db.js' import { config } from '../config.js' +import { getSetting, MARKE_KEY } from '../settings.js' import { publicUrlFor } from '../storage.js' export const freigabeRoutes = new Hono() @@ -63,6 +64,9 @@ freigabeRoutes.get('/:schluessel', (c) => { .all(`${maskiert}/%`) as Pick[] return c.json({ + // Auch hier der Name aus derselben Einstellung -- die Freigabeseite ist + // oeffentlich und holt sonst nichts, was ihn kennen koennte. + marke: getSetting(MARKE_KEY) || 'D4RKST3R', titel: eintrag.titel || eintrag.ordner, ordner: eintrag.ordner, // Der Praefix, den die Oberflaeche abschneidet -- damit dort diff --git a/server/src/settings.ts b/server/src/settings.ts index 9f66b2d..5662221 100644 --- a/server/src/settings.ts +++ b/server/src/settings.ts @@ -58,6 +58,16 @@ export function ausDatenbank(key: string): boolean { // Als JSON in EINER Zeile der Einstellungstabelle. Eine eigene Tabelle fuer // eine Handvoll Zeilen waere eine Wanderung mehr, die niemand braucht. +/** Wie der Dienst sich nennt. + * + * DIESELBE Einstellung, die auch in der Fusszeile der Discord-Meldungen steht + * (`D4RKST3R // MEDIA`). Ein zweiter Name fuer die Oberflaeche waere ein + * zweiter, der beim naechsten Mal anders lautet als der erste -- und dann + * heisst dasselbe Ding an zwei Stellen verschieden. + * + * Der Standard steht in meldung.ts; hier wird er nur weitergereicht. */ +export const MARKE_KEY = 'marke.name' + export const VORLAGEN_KEY = 'vorlagen' export type Vorlage = { name: string; muster: string } diff --git a/server/ui/index.html b/server/ui/index.html index de8cb4b..7d9a0ee 100644 --- a/server/ui/index.html +++ b/server/ui/index.html @@ -3,7 +3,7 @@ - d4rk_media + D4RKST3R Media diff --git a/server/ui/src/App.tsx b/server/ui/src/App.tsx index aa2d020..6fbf940 100644 --- a/server/ui/src/App.tsx +++ b/server/ui/src/App.tsx @@ -25,6 +25,7 @@ import { Freigabe } from './pages/Freigabe' import { Meldungen } from './components/Meldungen' import { gehZu, usePfad } from './router' import { Kontomenue } from './components/Kontomenue' +import { dienstName, useMarke } from './marke' /** Die Breite des Inhalts — an EINER Stelle. * @@ -59,6 +60,7 @@ export function App() { const checking = useStore((s) => s.checking) const checkSession = useStore((s) => s.checkSession) const pfad = usePfad() + const marke = useMarke() useEffect(() => { void checkSession() @@ -114,7 +116,7 @@ export function App() { className="flex items-center gap-2 font-semibold" > - d4rk_media + {dienstName(marke)}