Commit Graph

19 Commits

Author SHA1 Message Date
Ulas 44d1b88e3d fix: resolve iOS forbidden errors by delivering CSRF token in response body
iOS Safari (especially PWA/standalone mode) unreliably exposes cookies
via document.cookie, causing CSRF token mismatch on state-changing
requests. The CSRF token is now included in /auth/login and /auth/me
response bodies and stored in-memory on the client. Cookie remains as
fallback. Retry mechanism also improved to read token from response
body and handle expired sessions.
2026-04-14 18:53:42 +02:00
Ulas 8d99c3d2d6 fix: resolve iOS PWA session/CSRF issues causing forbidden errors
- Renew CSRF cookie on /auth/me (first call after iOS PWA resume)
- Add try-catch + hex validation to CSRF middleware for corrupted tokens
- Auto-retry state-changing requests on 403 by refreshing CSRF token
- Add 200ms delay before SW controllerchange reload to prevent blank page on iOS
2026-04-14 17:37:22 +02:00
Ulas 35186ca87f fix: change SameSite=Strict to SameSite=Lax for session and CSRF cookies (#46)
Safari's ITP blocks Strict cookies on certain navigations (direct URL entry,
reverse proxy context), resulting in a 401 on login even with valid credentials.
Lax is safe: CSRF attacks are prevented by the double-submit token and the
HTTPS-only secure flag. Firefox and Chrome were unaffected.
2026-04-13 21:36:35 +02:00
Ulas 9a68fb7b0c fix(auth): remove SESSION_SECRET fallback - always throw if unset
App refuses to start without SESSION_SECRET regardless of NODE_ENV.
Removes risk of accidental insecure deployment when NODE_ENV is not
explicitly set to production.
2026-04-04 01:16:59 +02:00
Ulas c1176de661 fix(audit): address security audit findings
- Translate German error/warn messages in auth.js to English
- Add CODE_OF_CONDUCT.md (Contributor Covenant v2.1)
- Remove docs/claude-md-migration.md (internal migration artifact)
- Clarify README first-login instruction with credential hint
2026-04-04 01:13:50 +02:00
Ulas 2f6127911e fix(imports): convert require() to ESM import for randomBytes in auth.js 2026-04-03 23:00:38 +02:00
Ulas 3b90074723 refactor(logging): replace console.* with structured logger across server
Add server/logger.js - zero-dependency, level-based logger that outputs
JSON in production and human-readable format in development. Controlled
via LOG_LEVEL env var (debug/info/warn/error, default: info).

Replaces all 100 console.log/warn/error calls in 14 server files.
2026-04-03 22:05:22 +02:00
Ulas 5b1e6915ac fix(security): replace hardcoded session secret fallback with random generation
Instead of a static 'dev-only-secret-not-for-production' fallback,
generate a random one-time secret in development. Warns that sessions
won't survive restarts. Production guard unchanged.
2026-04-03 21:59:41 +02:00
Ulas 3d2604bab9 fix(security): address critical and high findings from security audit
Fix stored XSS in tasks (titles/subtasks) and settings (member list)
by applying escHtml(). Harden trust proxy to loopback default, add
OAuth state parameter for Google Calendar CSRF protection, sanitize
CSV export against formula injection, invalidate sessions on user
deletion, restrict usernames to alphanumeric chars, and require admin
role for calendar sync triggers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 17:28:36 +02:00
Ulas 1122bd269b style: replace em dashes with hyphens throughout codebase
Replace all — with - in all source files (JS, CSS, HTML, JSON,
Markdown) for consistency and readability.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 17:04:39 +02:00
Ulas 6e0eda8ba4 fix(security): address multiple security findings from audit
- Fix SQLCipher PRAGMA key interpolation (hex-encode key to prevent crash on single quotes)
- Enforce min password length (8 chars) on admin user creation
- Add length bounds on username/display_name and login inputs
- Invalidate other sessions on password change
- Multi-stage Docker build (exclude build tools from runtime)
- Exclude docs/ from Docker image
- Consolidate dotenv.config() to single entry point
- Document flat family authorization model in SECURITY.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 09:11:17 +02:00
Ulas 59791df248 fix: enforce Secure flag on session and CSRF cookies by default
Cookies were sent without Secure flag outside of production (NODE_ENV check).
New logic: secure=true by default; set SESSION_SECURE=false in .env to
allow HTTP explicitly (local dev without reverse proxy). Affects session
cookie, CSRF cookie in login handler, and CSRF middleware.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 18:34:31 +02:00
Ulas 91c2e0ad98 fix: address CodeQL security findings (v0.5.2)
- Rate-limit SPA fallback route (missing rate limiting on fs access)
- Add csrfMiddleware to all state-changing auth routes (logout, create
  user, change password, delete user) — previously bypassed global CSRF
  middleware due to router registration order
- Fix incomplete vCard escaping: escape backslashes before other special
  characters to prevent injection via contact fields
- Restrict CI GITHUB_TOKEN to contents: read (least privilege)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 18:30:03 +02:00
ulsklyc 7244fc95f1 fix: Session-Store, DOM-Timing und API-Pfad-Fehler beheben
- connect-sqlite3 durch eigenen BetterSQLiteStore ersetzt (sessions-Tabelle
  in der bestehenden DB, keine native Kompilierung nötig)
- db.init() vor require('./auth') gezogen damit BetterSQLiteStore-Konstruktor
  db.get() erfolgreich aufrufen kann
- router.js: App-Shell und pageWrapper vor module.render() in DOM einfügen
  damit document.getElementById() in Seiten-Modulen funktioniert
- Seiten-Module (meals, notes, contacts, calendar, budget): _container-Referenz
  eingeführt, alle document.getElementById() auf _container.querySelector() bzw.
  document.querySelector() für body-Elemente umgestellt
- login.js: User-Objekt nach erfolgreichem Login an navigate() übergeben
  damit auth.me()-Roundtrip entfällt
- calendar.js: /users → /auth/users korrigiert (404-Fix)
- SW-Cache v8 (erzwingt Reload aller gecachten Seiten-Module)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 11:49:10 +01:00
ulsklyc f354af0876 fix: Login schlägt fehl bei HTTP ohne Reverse Proxy (Secure-Cookie)
SESSION_SECURE=false in .env deaktiviert das Secure-Flag für Session-
und CSRF-Cookie. Notwendig wenn die App direkt per HTTP erreichbar ist
(kein Nginx/HTTPS davor). Standard bleibt secure=true in production.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 09:11:33 +01:00
ulsklyc 0dac77773a security: MIT-Lizenz, .gitignore härten, Fail-Fast für SESSION_SECRET
- LICENSE: MIT-Lizenz (bereits vorhanden, korrekt)
- package.json: "license": "MIT" ergänzt
- README.md: Lizenz-Badge auf MIT aktualisiert, Lizenz-Sektion angepasst
- .gitignore: .claude/ und *.txt hinzugefügt (verhindert versehentliches
  Committen von Claude Code Einstellungen und Token-Textdateien)
- server/auth.js: Fail-Fast in Produktion wenn SESSION_SECRET fehlt;
  Fallback-String auf 'dev-only-secret-not-for-production' umbenannt
  (klarere Intention, kein bekannter Produktions-Wert im Public Repo)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 23:01:08 +01:00
ulsklyc 72d6d5126e feat: Schritte 14–15 — Google Calendar OAuth + Apple CalDAV Sync + Settings-Seite
- server/services/google-calendar.js: OAuth 2.0, bidirektionaler Sync via
  Google Calendar API v3, inkrementeller syncToken, 410-Fallback auf Vollsync
- server/services/apple-calendar.js: CalDAV via tsdav (dynamic ESM import),
  minimaler ICS-Parser + ICS-Builder, bidirektionaler Sync
- server/routes/calendar.js: 7 neue Sync-Routen (google/auth, google/callback,
  google/sync, google/status, google/disconnect, apple/status, apple/sync)
- server/db.js: Migration 2 — sync_config Tabelle + idx_calendar_external_id
- server/db-schema-test.js: MIGRATIONS_SQL[2] für Tests synchronisiert
- server/auth.js: PATCH /me/password Endpoint
- server/index.js: Auto-Sync-Scheduler (setInterval, SYNC_INTERVAL_MINUTES)
- public/pages/settings.js: vollständige Settings-Seite (Konto, Passwort,
  Kalender-Sync-Status + Aktionen, Familienmitglieder-Verwaltung)
- public/styles/settings.css: neue Stylesheet-Datei
- public/index.html + public/sw.js: settings.css eingebunden und gecacht
- .env.example: SYNC_INTERVAL_MINUTES ergänzt
- README.md: vollständige Setup-Anleitung, Google/Apple-Sync-Dokumentation,
  modernes GitHub-Layout mit Badges und aufklappbaren Abschnitten

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 22:53:44 +01:00
ulsklyc dd8ad80eb4 feat: Phase 5 — Härtung (CSRF, Rate-Limit, Validation, Error Boundary, README)
Schritt 28 — CSRF-Schutz (Double Submit Cookie Pattern):
- server/middleware/csrf.js: generiert 32-Byte-Token, speichert in Session + Cookie;
  validiert X-CSRF-Token-Header auf POST/PUT/PATCH/DELETE via timingSafeEqual
- server/auth.js: CSRF-Token beim Login erzeugen und als Cookie setzen
- public/api.js: getCsrfToken() liest Cookie; apiFetch() sendet Header auf
  state-ändernden Requests automatisch

Schritt 29 — Globaler Rate-Limiter:
- server/index.js: apiLimiter (300 req/min/IP) auf allen /api/-Routen;
  ergänzt den bestehenden loginLimiter (5 req/min)

Schritt 27 — Zentralisierte Eingabe-Validierung:
- server/middleware/validate.js: str(), oneOf(), date(), time(), num(), color(),
  collectErrors() mit einheitlichen Längengrenzen (MAX_TITLE=200, MAX_TEXT=5000)
- server/routes/tasks.js: validateTaskInput() nutzt nun validate.js

Schritt 31 — Frontend Error Boundary:
- public/router.js: window.onerror + unhandledrejection-Handler zeigen Toast

Schritt 33 — README.md:
- Setup-Anleitung (Docker + Node.js), Nginx-Config, User-Verwaltung,
  Umgebungsvariablen-Referenz, Backup, Sicherheitsübersicht

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 22:00:47 +01:00
ulsklyc d49cbe33b3 feat: Phase 1 — Projektstruktur, DB-Schema, Auth-System
- Vollständige Verzeichnisstruktur gemäß CLAUDE.md
- Express-Server mit Helmet, Sessions, Rate Limiting, SPA-Fallback
- SQLite-Schema (Migration v1): 10 Tabellen, updated_at-Triggers, Indizes
- Versioniertes Migrations-System (schema_migrations)
- Auth-Routen: Login, Logout, /me, Admin-User-CRUD
- Frontend App-Shell: SPA-Router, API-Client, Design-System (CSS Tokens)
- PWA: Service Worker, Web App Manifest
- Setup-Script für ersten Admin-User (node setup.js)
- DB-Tests mit node:sqlite built-in: 29/29 bestanden
- Docker Compose + Dockerfile + Nginx-Beispielkonfiguration

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 14:32:36 +01:00