chore: Screenshot-Instanz mit eingerichteten Meldewegen

Die Wegwerf-Instanz bekommt je Lauf ein frisch erzeugtes VAPID-Paar und
einen Mailhost, den es nie geben wird. Damit zeigen die Bilder den
eingerichteten Normalfall statt zweier Warnhinweise — und im Verzeichnis
bleibt kein privater Schluessel liegen.

Kein Push-Geraet mehr in den Demo-Daten: Seine Schluessel liegen
verschluesselt, und der Versand entfernt jedes Geraet, dessen Schluessel
er nicht lesen kann. Der erfundene Eintrag waere beim ersten Lauf wieder
verschwunden.

Dass der Browser im Bild "blockiert" meldet, laesst sich nicht abstellen:
Chromium im Kopflosbetrieb antwortet auf Notification.permission immer so.
Das Handbuch sagt es jetzt dazu.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Florian Wilde
2026-09-11 13:34:40 +02:00
co-authored by Claude Opus 5
parent 7bef4351ec
commit 35ecb2fa78
4 changed files with 25 additions and 15 deletions
+11
View File
@@ -57,5 +57,16 @@ services:
WEBAUTHN_RP_NAME: Planer WEBAUTHN_RP_NAME: Planer
WEBAUTHN_ORIGIN: http://127.0.0.1:${SCREENSHOT_APP_PORT:-3200} WEBAUTHN_ORIGIN: http://127.0.0.1:${SCREENSHOT_APP_PORT:-3200}
DEMO_MODUS: 'true' DEMO_MODUS: 'true'
# Damit die Karte "Benachrichtigungen" den Normalfall zeigt und nicht
# den Hinweis, dass nichts eingerichtet ist. Das Schluesselpaar erzeugt
# scripts/screenshots.ts fuer jeden Lauf neu – es steht bewusst nirgends
# im Verzeichnis.
VAPID_OEFFENTLICH: ${SCREENSHOT_VAPID_OEFFENTLICH:-}
VAPID_PRIVAT: ${SCREENSHOT_VAPID_PRIVAT:-}
VAPID_KONTAKT: mailto:planer@planer.invalid
# Ein Host, den es nie geben wird: die Oberflaeche zeigt E-Mail als
# moeglich, hinaus geht trotzdem nichts.
SMTP_HOST: smtp.planer.invalid
SMTP_ABSENDER: Planer <planer@planer.invalid>
ports: ports:
- '${SCREENSHOT_APP_PORT:-3200}:3000' - '${SCREENSHOT_APP_PORT:-3200}:3000'
+3
View File
@@ -6,6 +6,9 @@ Wichtige. Was du hier einschaltest, kommt. Alles andere nicht.
![Benachrichtigungen in den Einstellungen](../bilder/benachrichtigungen-hell-schreibtisch.png) ![Benachrichtigungen in den Einstellungen](../bilder/benachrichtigungen-hell-schreibtisch.png)
_Der Browser auf dem Bild hat Benachrichtigungen blockiert — so sieht die
Karte aus, wenn die Erlaubnis fehlt. Wie du sie erteilst, steht weiter unten._
Du findest die Einstellung unter **Einstellungen → Benachrichtigungen**. Du findest die Einstellung unter **Einstellungen → Benachrichtigungen**.
## Die zwei Wege ## Die zwei Wege
+4 -15
View File
@@ -437,21 +437,10 @@ async function main(): Promise<void> {
}, },
}) })
await db.pushGeraet.deleteMany({ where: { benutzerId: benutzer.id } }) // Kein Push-Gerät in den Demo-Daten: Seine Schlüssel liegen
await db.pushGeraet.create({ // verschlüsselt, und der Versand entfernt jedes Gerät, dessen Schlüssel er
data: { // nicht lesen kann. Ein erfundener Eintrag verschwände beim ersten Lauf
benutzerId: benutzer.id, // wieder — die Bilder zeigen deshalb den Zustand vor der ersten Anmeldung.
// Erfunden und unerreichbar. Die Schlüsselfelder halten sonst
// verschlüsselte Werte; hier stehen Platzhalter, weil aus der
// Demo-Instanz ohnehin nichts hinausgeht.
endpunkt: 'https://push.invalid/demo-arbeitsplatz',
p256dh: 'demo',
auth: 'demo',
bezeichnung: 'Firefox auf Windows',
erstelltAm: new Date(Date.UTC(2026, 1, 3, 8, 20)),
zuletztBenutzt: new Date(Date.UTC(2026, 2, 17, 6, 5)),
},
})
console.log(`Demo-Daten stehen bereit. Anmeldung: ${DEMO_EMAIL}`) console.log(`Demo-Daten stehen bereit. Anmeldung: ${DEMO_EMAIL}`)
} }
+7
View File
@@ -14,6 +14,7 @@
*/ */
import { spawnSync } from 'node:child_process' import { spawnSync } from 'node:child_process'
import { fileURLToPath } from 'node:url' import { fileURLToPath } from 'node:url'
import webpush from 'web-push'
const WURZEL = fileURLToPath(new URL('..', import.meta.url)) const WURZEL = fileURLToPath(new URL('..', import.meta.url))
const PROJEKT = 'planer-screenshots' const PROJEKT = 'planer-screenshots'
@@ -22,10 +23,16 @@ const COMPOSE_DATEI = 'docker-compose.screenshots.yml'
const APP_PORT = process.env.SCREENSHOT_APP_PORT ?? '3200' const APP_PORT = process.env.SCREENSHOT_APP_PORT ?? '3200'
const DB_PORT = process.env.SCREENSHOT_DB_PORT ?? '5455' const DB_PORT = process.env.SCREENSHOT_DB_PORT ?? '5455'
// Frisches Paar je Lauf: Die Bilder sollen die eingerichtete Anwendung
// zeigen, ohne dass irgendwo ein privater Schluessel liegen bleibt.
const VAPID = webpush.generateVAPIDKeys()
const UMGEBUNG = { const UMGEBUNG = {
...process.env, ...process.env,
SCREENSHOT_APP_PORT: APP_PORT, SCREENSHOT_APP_PORT: APP_PORT,
SCREENSHOT_DB_PORT: DB_PORT, SCREENSHOT_DB_PORT: DB_PORT,
SCREENSHOT_VAPID_OEFFENTLICH: VAPID.publicKey,
SCREENSHOT_VAPID_PRIVAT: VAPID.privateKey,
} }
function meldung(text: string): void { function meldung(text: string): void {