S1 (hoch): Die OIDC-Rueckkehr verknuepft eine Identitaet mit einem bestehenden Konto nur bei bestaetigter E-Mail — geprueft wurde das auch, nur war die Bestaetigung als `email_verified !== false` berechnet. Damit galt auch ein fehlender Claim als bestaetigt, und genau den schicken manche Anbieter gar nicht. Jetzt zaehlt allein ein ausdrueckliches `true`. S2 (hoch): `isAuthEnabled()` verlangte den Wert "true"; alles andere hiess "aus". Eine vergessene Variable ergab eine Anwendung, in der jeder Besucher alles darf, und nichts sah danach aus. Umgedreht: Abgeschaltet wird nur, wer ausdruecklich "false" setzt. Die Vorgaben in Compose und .env.example stehen auf true, und der Container warnt beim Start mehrzeilig, solange die Anmeldung aus ist. S5 (mittel): Der OIDC-Bootstrap las `user.count()` und legte danach an — zwei gleichzeitige erste Anmeldungen konnten beide Administrator werden. Jetzt in einer serialisierbaren Transaktion, wie die lokale Ersteinrichtung es laengst tut. S6 (niedrig): Die Herkunftspruefung verglich nur den Host, nicht das Schema. Das Schema kommt jetzt aus BASE_URL — die eine Angabe zum Ursprung, ueber die der Aufrufer nicht mitbestimmt. S3, S4 und S7 bleiben offen und stehen begruendet in docs/sicherheit.md. Bei S3 wurde der naheliegende Ausweg geprueft und verworfen: Waehrend der Sperre weiter Passwoerter zu pruefen kostet 128 MiB je Versuch und tauschte eine Sperre gegen ein Konto gegen eine gegen alle. Refs #20
62 lines
2.3 KiB
YAML
62 lines
2.3 KiB
YAML
services:
|
|
db:
|
|
image: postgres:18-alpine
|
|
restart: unless-stopped
|
|
environment:
|
|
POSTGRES_USER: ${POSTGRES_USER:-qrcode}
|
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD fehlt — bitte .env aus .env.example anlegen}
|
|
POSTGRES_DB: ${POSTGRES_DB:-qrcode}
|
|
volumes:
|
|
# Ab PostgreSQL 18 liegt das Datenverzeichnis in einem Unterordner mit
|
|
# Versionsnummer — der Mountpunkt ist deshalb /var/lib/postgresql und
|
|
# nicht mehr /var/lib/postgresql/data.
|
|
- db-data:/var/lib/postgresql
|
|
healthcheck:
|
|
# Die App startet erst, wenn die Datenbank wirklich Anfragen annimmt.
|
|
test:
|
|
["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-qrcode} -d ${POSTGRES_DB:-qrcode}"]
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 12
|
|
start_period: 10s
|
|
|
|
app:
|
|
build:
|
|
context: .
|
|
restart: unless-stopped
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
environment:
|
|
# Achtung beim Ergänzen: Compose liest die .env nur, um Platzhalter wie
|
|
# ${BASE_URL} zu ersetzen. In den Container gelangt ausschließlich, was
|
|
# hier aufgeführt ist — eine neue Variable in der .env allein bleibt
|
|
# wirkungslos.
|
|
#
|
|
# Öffentliche Adresse der App — landet in jedem dynamischen QR-Code.
|
|
BASE_URL: ${BASE_URL:-http://localhost:3000}
|
|
DATABASE_URL: ${DATABASE_URL}
|
|
# Anmeldung mit Benutzern, Gruppen und Rollen.
|
|
# Ohne Angabe: an. Abgeschaltet wird nur, wer ausdruecklich
|
|
# AUTH_ENABLED=false setzt — siehe .env.example.
|
|
AUTH_ENABLED: ${AUTH_ENABLED:-true}
|
|
MAX_UPLOAD_MB: ${MAX_UPLOAD_MB:-10}
|
|
SESSION_IDLE_DAYS: ${SESSION_IDLE_DAYS:-30}
|
|
SESSION_MAX_DAYS: ${SESSION_MAX_DAYS:-90}
|
|
OIDC_ENABLED: ${OIDC_ENABLED:-false}
|
|
OIDC_ISSUER: ${OIDC_ISSUER:-}
|
|
OIDC_CLIENT_ID: ${OIDC_CLIENT_ID:-}
|
|
OIDC_CLIENT_SECRET: ${OIDC_CLIENT_SECRET:-}
|
|
OIDC_BUTTON_LABEL: ${OIDC_BUTTON_LABEL:-Mit Authentik anmelden}
|
|
OIDC_SCOPES: ${OIDC_SCOPES:-openid email profile}
|
|
OIDC_ONLY: ${OIDC_ONLY:-false}
|
|
OIDC_DEFAULT_ROLE: ${OIDC_DEFAULT_ROLE:-VIEWER}
|
|
OIDC_ADMIN_GROUP: ${OIDC_ADMIN_GROUP:-}
|
|
OIDC_GROUPS_CLAIM: ${OIDC_GROUPS_CLAIM:-groups}
|
|
ports:
|
|
# Direktes Port-Mapping, bewusst ohne Reverse Proxy.
|
|
- "${APP_PORT:-3000}:3000"
|
|
|
|
volumes:
|
|
db-data:
|