smueller 070e99303a Update dependencies in requirements.txt and enhance Docker build workflow
- Updated jinja2, python-multipart, python-jose, and cryptography to their latest versions for improved security and functionality.
- Modified the Docker build workflow to include specific vulnerability ignores for pip-audit, ensuring smoother dependency checks while addressing known issues.
2026-07-09 12:46:34 +02:00
2026-07-03 11:35:25 +02:00

TK Wiki Newsletter Admin

Produktionsnahes internes Tool zur Erstellung von Thomas-Krenn.AG Newslettern auf Basis der letzten Wiki-Änderungen.

Funktionen

  • Login und Benutzerverwaltung mit RBAC (admin, editor, reader)
  • Verpflichtender CSRF-Schutz auf allen POST-Formularen
  • Filter in der Web-UI:
    • Zeitraum in Tagen oder „Letzter Monat“
    • Artikel-Auswahl: alle, nur neue oder nur bearbeitete Artikel
    • Kategorie
  • Redaktioneller Feinschliff pro Ausgabe:
    • Redaktionsnotiz optionaler Hinweistext, der als eigene Box im Newsletter erscheint
    • Top-Highlights bis zu 3 Artikel per Titel hervorheben (erscheinen oben als Highlight-Box)
  • Datenquelle: MediaWiki API (recentchanges über wikiDE/api.php)
  • E-Mail-Layout im Thomas-Krenn Corporate Design:
    • Hero-Header mit Logo, Artikel-Karten mit „Zum Beitrag“-Button, Kontakt- und Adress-Footer
    • Neu-/Bearbeitet-Trennung, Zusammenfassungs-Kacheln, Outlook-taugliche Kopiervorschau
  • Export:
    • Plain Text (für Outlook)
    • Raw HTML
  • Optionaler SMTP-Versand:
    • UI-konfigurierbar (nur für Admins)
    • Verteilerlisten mit E-Mail-Validierung
    • Versand per BCC (Empfänger nicht im sichtbaren To:-Header)
    • flexibler Zeitplan (täglich / wöchentlich / monatlich) über einen Hintergrund-Scheduler
    • eigene Inhalts-Vorgaben für den geplanten Versand (Zeitraum, Artikel-Auswahl, Kategorie)
    • „Generieren“ verschickt nie manueller Versand nur per Button „Newsletter jetzt senden“
    • automatischer Versand nur mit zwei aktiven Häkchen: Zeitplan + Bestätigung „ohne manuelle Freigabe“
    • Versandprotokoll (nur für Editor/Admin sichtbar)
  • Docker/Compose Betrieb mit Container-Hardening, inkl. automatischem Image-Build & Push in die Gitea Container Registry (per Versions-Tag)

Start mit Docker

  1. Konfiguration anlegen:

    cp .env.example .env
    
  2. Wichtige Werte in .env setzen (siehe auch Konfiguration):

    Variable Lokal (Entwicklung) Produktion
    ENVIRONMENT development production
    HOST_PORT z. B. 8080 nach Bedarf
    SECRET_KEY beliebig lang mind. 32 zufällige Zeichen
    ALLOWED_HOSTS localhost,127.0.0.1 konkreter Hostname
    COOKIE_SECURE false true (mit TLS)
    ADMIN_BOOTSTRAP_EMAIL Admin-E-Mail Admin-E-Mail
    ADMIN_BOOTSTRAP_PASSWORD Bootstrap-Passwort starkes Passwort
  3. Start:

    docker compose up --build -d
    
  4. Zugriff:

Hinweis: Mit ENVIRONMENT=production prüft die App beim Start strikt die Konfiguration. Fehlen starke Secrets oder sind unsichere Defaults gesetzt, startet der Container nicht.

Konfiguration (.env)

Vollständige Vorlage: .env.example

Variable Beschreibung
ENVIRONMENT development = lokale Entwicklung ohne harte Checks; production = erzwingt sichere Einstellungen
SECRET_KEY JWT-Signierung und Verschlüsselung von SMTP-Passwörtern in der DB
ALGORITHM JWT-Algorithmus (Standard: HS256)
ACCESS_TOKEN_EXPIRE_MINUTES Gültigkeit der Login-Session in Minuten (Standard: 120)
JWT_ISSUER / JWT_AUDIENCE JWT-Claims zur Token-Validierung
HOST_PORT Host-Port für Docker Compose (nur Compose, nicht App-intern)
DATABASE_URL SQLite (Standard) oder PostgreSQL
WIKI_API_URL MediaWiki-API-Endpunkt
ALLOWED_HOSTS Kommagetrennte erlaubte Host-Header
COOKIE_SECURE Secure-Flag für Session- und CSRF-Cookies (Pflicht true in Produktion)
HSTS_MAX_AGE HSTS-Header-Dauer in Sekunden (nur bei HTTPS)
ADMIN_BOOTSTRAP_EMAIL / ADMIN_BOOTSTRAP_PASSWORD Erster Admin-Account beim Start
ADMIN_BOOTSTRAP_RESET Admin auf .env-Werte zurücksetzen (nur Entwicklung/Notfall, in Produktion verboten)
EDITOR_TIP_MAX_LENGTH Max. Zeichen für Redaktionsnotiz (Standard: 10000)
HIGHLIGHTS_MAX_LENGTH Max. Zeichen für Top-Highlights (Standard: 5000)

Container-Image (Gitea Packages)

Fertige Images werden automatisch in die Gitea Container Registry veröffentlicht:

git.hexahost.dev/smueller/tk-wiki-newsletter

Verfügbare Tags: latest, die Version (X.Y.Z, X.Y, X) sowie der kurze Commit-SHA.

Image ziehen und mit vorhandener .env starten:

docker login git.hexahost.dev
docker pull git.hexahost.dev/smueller/tk-wiki-newsletter:latest
docker run -d --name tk-newsletter-admin \
  --env-file .env \
  -p 8080:8000 \
  -v newsletter_data:/app/data \
  --read-only \
  --tmpfs /tmp \
  --security-opt no-new-privileges:true \
  git.hexahost.dev/smueller/tk-wiki-newsletter:latest

Alternativ in docker-compose.yml statt build: . das Image referenzieren:

services:
  newsletter-admin:
    image: git.hexahost.dev/smueller/tk-wiki-newsletter:latest
    # build: .   # <- nicht mehr nötig, wenn das fertige Image genutzt wird

Die mitgelieferte docker-compose.yml setzt bereits read_only, no-new-privileges und ein tmpfs für /tmp. Persistente Daten liegen im Volume newsletter_data unter /app/data.

Automatischer Build (CI/CD)

Der Workflow .gitea/workflows/docker-build.yml baut und pusht das Image über Gitea Actions.

  • Auslöser: nur beim Setzen eines Versions-Tags v* (kein Build bei normalen Pushes auf dev/main).

  • Vor dem Build: pip-audit prüft die Python-Abhängigkeiten aus requirements.txt.

  • Release-Ablauf (Build bei Merge devmain mit Version):

    git checkout main
    git merge --no-ff dev
    git push origin main
    git tag v1.0.0
    git push origin v1.0.0   # <- startet Build & Push
    
  • Benötigte Repo-Secrets (Settings → Actions → Secrets):

    • REGISTRY_TOKEN: Gitea Access-Token mit Scope Package: Read and write
    • REGISTRY_USER (optional): Registry-Benutzername, falls abweichend vom Repo-Owner
  • Optionale Repo-Variable: REGISTRY, um den Registry-Host zu überschreiben (Default git.hexahost.dev).

Admin-Login & Passwort zurücksetzen

  • Das Login erfolgt über E-Mail + Passwort (kein separater Benutzername). Beim ersten Start wird der Admin aus ADMIN_BOOTSTRAP_EMAIL / ADMIN_BOOTSTRAP_PASSWORD angelegt.

  • Passwortpolitik: mindestens 10 Zeichen, mindestens ein Großbuchstabe, ein Kleinbuchstabe und eine Ziffer.

  • Rate-Limiting: nach 5 fehlgeschlagenen Anmeldeversuchen pro IP/E-Mail innerhalb von 5 Minuten wird der Login temporär blockiert.

  • Wichtig: Existiert der Admin bereits (persistente DB im Volume newsletter_data), wird eine spätere Passwort-Änderung in der .env normalerweise nicht übernommen.

  • Um Passwort/Rolle/Status auf die .env-Werte zurückzusetzen (nur Entwicklung): ADMIN_BOOTSTRAP_RESET=true setzen und Container neu starten:

    docker compose up -d --force-recreate
    

    Nach erfolgreichem Login ADMIN_BOOTSTRAP_RESET=false setzen. In ENVIRONMENT=production ist ADMIN_BOOTSTRAP_RESET=true nicht erlaubt die App startet dann nicht.

  • Passwort ändern (Profil) oder Abmelden beendet alle aktiven Sessions des Benutzers.

Rollenmodell

Rolle Rechte
reader Newsletter-Vorschau und Artikellisten ansehen
editor Newsletter generieren, exportieren und manuell versenden; Versandprotokoll und Empfängerliste einsehen
admin Zusätzlich Benutzerverwaltung (anlegen, Rolle ändern, aktivieren/deaktivieren) und SMTP-Konfiguration

Admins können in der Benutzerverwaltung (/admin/users):

  • neue Benutzer mit Rolle anlegen
  • die Rolle bestehender Benutzer ändern (beendet deren Sessions)
  • Benutzer aktivieren oder deaktivieren (beendet deren Sessions)

Das eigene Konto kann weder deaktiviert noch die eigene Rolle geändert werden.

Sicherheit

Eingebaute Schutzmaßnahmen

  • bcrypt für Passwort-Hashes
  • CSRF Double-Submit-Cookie auf allen POST-Formularen
  • HttpOnly + SameSite=Strict Session-Cookies; Secure bei HTTPS (COOKIE_SECURE=true)
  • JWT mit iss, aud, Ablaufzeit und Session-Version (session_version)
  • Session-Invalidierung bei Logout, Passwortwechsel, Rollen- oder Statusänderung
  • SMTP-Passwort verschlüsselt in der Datenbank (Fernet), nicht im HTML-Formular
  • Security-Header: CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, HSTS (bei HTTPS), Cache-Control: no-store auf geschützten Seiten
  • OpenAPI (/docs, /redoc) in Produktion deaktiviert
  • Abhängigkeiten in requirements.txt versioniert; CI führt pip-audit aus

Produktions-Checkliste

Bei ENVIRONMENT=production erzwingt die App beim Start:

  • SECRET_KEY mit mindestens 32 Zeichen (keine bekannten Defaults)
  • starkes ADMIN_BOOTSTRAP_PASSWORD
  • ADMIN_BOOTSTRAP_RESET=false
  • ALLOWED_HOSTS mit konkreten Hostnamen (nicht *)
  • COOKIE_SECURE=true

Zusätzlich empfohlen:

  • Reverse Proxy (z. B. Nginx/Traefik) mit TLS vor den Container; Proxy muss X-Forwarded-Proto: https setzen
  • Bootstrap-Admin-Passwort nach erstem Login im Profil ändern
  • Netzwerkzugriff auf interne IPs/Netze beschränken
  • Regelmäßige Backups des newsletter_data Volumes (SQLite-Datei unverschlüsselt)

Beispiel .env für Produktion

ENVIRONMENT=production
SECRET_KEY=<mind. 32 zufällige Zeichen>
ALLOWED_HOSTS=newsletter.intern.firma.de
COOKIE_SECURE=true
ADMIN_BOOTSTRAP_EMAIL=admin@firma.de
ADMIN_BOOTSTRAP_PASSWORD=<starkes Passwort>
ADMIN_BOOTSTRAP_RESET=false
Description
No description provided
Readme 474 KiB
Languages
Python 55.9%
HTML 28%
CSS 8.6%
JavaScript 7.2%
Dockerfile 0.2%