Commit Graph

9 Commits

Author SHA1 Message Date
thomas f3b4b309b6 fix(docker): Geocode-Cache-Volume war funktionslos (EISDIR)
Beim Hochfahren des echten Stacks aufgefallen: d9fecb6 mountet ein Named
Volume auf einen DATEIpfad (geocode-cache:/app/geocode-cache.json). Ein Named
Volume ist immer ein Verzeichnis — im laufenden Container liegt an der Stelle
also ein Ordner. Jeder Lese- und Schreibversuch lief in EISDIR und wurde von
den try/catch-Bloecken in utils/geocode.js still verschluckt: der Cache wurde
nie geladen und nie gespeichert.

Im laufenden drohnenfuehrer-backend nachgestellt:
  Schreiben schlaegt fehl: EISDIR - illegal operation on a directory
  Lesen schlaegt fehl:     EISDIR

- Der Cache-Pfad ist jetzt ueber GEOCODE_CACHE_FILE konfigurierbar und faellt
  ohne die Variable auf den bisherigen Ort zurueck.
- Das Volume wird als Verzeichnis unter /app/cache gemountet, die Compose-
  Dateien setzen GEOCODE_CACHE_FILE=/app/cache/geocode-cache.json.
- .dockerignore schliesst geocode-cache.json aus: eine bei lokalen Tests
  entstandene Datei war ueber COPY . . ins Image gewandert und liess den
  Container gar nicht mehr starten ("not a directory").

Geprueft: im neu gebauten nachsuche-backend ist /app/cache/geocode-cache.json
schreibbar.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-01 08:25:25 +02:00
thomas d0e48f3385 fix(deploy): Backend startet wieder — JWT-Secret kam leer im Container an
Startblocker aus d9fecb6: die Compose-Dateien lesen seither
${NACHSUCHE_JWT_SECRET} (bzw. DROHNENFUEHRER_/STOEBERHUNDE_), die .env-Dateien
definieren aber weiterhin JWT_SECRET. Compose ersetzte die unbekannte Variable
still durch einen Leerstring, config/env.js beendete den Prozess daraufhin mit
Exit-Code 1 — mit restart: unless-stopped ein Crash-Loop. Nachgewiesen mit
`docker compose config` (JWT_SECRET: "") und einem Startversuch.

- Compose nutzt jetzt ${..._JWT_SECRET:?...}: fehlt der Wert, bricht compose
  mit einer Meldung ab, statt ihn stillschweigend zu leeren.
- Die .env-Dateien (nicht versioniert) tragen die korrekten Namen und je App
  ein EIGENES 32-Byte-Secret. Vorher stand in allen drei derselbe 16-Zeichen-
  Wert, wodurch die App-Trennung aus d9fecb6 wirkungslos war.
  FOLGE: alle laufenden Admin-Sitzungen und Fuehrer-Tokens sind ungueltig,
  alle muessen sich einmal neu anmelden.
- Fuehrer-Tokens tragen jetzt app: config.appName, und handlerAuth.js sowie
  die umbenannten Varianten pruefen den Claim. Vorher trugen sie nur
  { id, role } — die app-Pruefung in middleware/auth.js lief bei ihnen ins
  Leere, weil sie an `decoded.app &&` haengt.
  Geprueft: Fuehrer-Token aus App A gegen /me von App B -> 403, gegen die
  eigene -> 200.
- APP_URL steht in Compose wieder auf ${APP_URL:-}. Der Default aus der
  letzten Runde hat die Warnung aus config/env.js unterdrueckt, die auf eine
  fehlende Konfiguration hinweisen sollte.
- .env.example dokumentiert die neuen Namen, den openssl-Aufruf und dass
  CORS_ORIGIN/APP_URL produktiv nicht auf localhost stehen duerfen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 20:47:02 +02:00
thomas 868699a1bc fix(backend): Geocode-Cache begrenzen, Reset-Link reparieren
- Der Geocode-Cache war nur auf dem Erfolgspfad begrenzt. Die beiden
  Negativ-Pfade (cache.set(key, null)) schrieben ungebremst — über den
  öffentlichen GET /api/public/geocode genügten erfundene Postleitzahlen,
  um Speicher und die alle 60 s geschriebene Cache-Datei beliebig wachsen
  zu lassen. Bei NODE_OPTIONS=--max_old_space_size=256 eine reale Grenze.
  Alle Schreibpfade laufen jetzt über rememberInCache(); loadCache()
  beschneidet eine bereits gewachsene Datei auf das Limit.
  Geprüft: eine künstlich auf 5000 Einträge aufgeblähte Cache-Datei wird
  beim Start auf 1000 reduziert.
- Der Cache war trotz Kommentar kein LRU, sondern ein FIFO: ein Treffer
  hat den Eintrag nicht ans Ende gerückt, häufig genutzte Adressen flogen
  zuerst raus. Treffer werden jetzt neu einsortiert.
- /api/public/geocode bekommt einen eigenen Limiter (20/15 min). Der
  Endpunkt löst ausgehende Nominatim-Anfragen aus und teilt sich mit dem
  Geocoding im Admin-Bereich die globale Wartezeit von 1100 ms.
  Geprüft: Anfragen 21-24 liefern 429.
- resetPassword prüfte 6 Zeichen, das Admin-Schema verlangt 12. Passwörter
  dazwischen kamen durch und scheiterten erst an der Mongoose-Validierung
  — beim Nutzer kam "Serverfehler" (500) an. Jetzt 400 mit klarer Meldung.
- APP_URL wird aktiv gesetzt statt auskommentiert, und der Rückfallwert
  hängt den Unterpfad an. Vorher fiel appUrl auf CORS_ORIGIN zurück, und
  der Link in der Reset-Mail zeigte auf das Portal statt in die App.
  Geprüft: erzeugte URL lautet .../nachsuche/passwort-zuruecksetzen?token=…
- Die beim Zusammenführen verlorengegangene Platzhalter-Prüfung für
  JWT_SECRET ist wieder da (fängt auch CHANGE_ME_IN_PRODUCTION).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 19:41:08 +02:00
thomas 63f6d97318 fix(frontend): Vite-Build reparieren und Unterpfad-Deployment korrigieren
Der Build läuft über Vite ("build": "vite build"), der Code las
Umgebungsvariablen aber über process.env – das gibt es im Browser-Bundle
nicht. Damit war der Build-Arg REACT_APP_API_URL wirkungslos und der
Zugriff selbst lief in "process is not defined".

- constants.js nutzt import.meta.env und leitet den Deployment-Basispfad
  aus import.meta.env.BASE_URL ab (Fallback: Laufzeit-Erkennung).
  REACT_APP_* heißt überall VITE_* (Dockerfile, Compose, .env.example,
  Doku).
- /verwaltung und /passwort-zuruecksetzen wurden gegen
  window.location.pathname ohne Basispfad verglichen und trafen unter
  /nachsuche/ nie zu – die Passwort-Reset-Seite war produktiv nicht
  erreichbar. Neue Helfer withBase()/normalizePath().
- Der Service Worker wurde als '/sw.js' registriert und war damit der des
  Portals mit Scope '/'. Registrierung läuft jetzt über BASE_URL, inkl.
  passendem Scope.
- index.html verlinkte '/manifest.json' absolut, also das Portal-Manifest:
  die App hätte sich als Portal installiert. Jetzt %BASE_URL%.
- public/index.html (CRA-Rest) kollidierte im Vite-Build mit der
  index.html im Projektwurzelverzeichnis und wurde entfernt.
- manifest.json verwies auf ein favicon.ico, das es nicht gibt.
- package.json: Scripts auf Vite umgestellt. react-scripts,
  @testing-library/* und web-vitals entfernt – nichts davon wird
  importiert, und react-scripts stand im Widerspruch zum Build.
- Die ungenutzten Konstanten USER_TYPES/USER_TYPE_LABELS/RULES sind
  entfallen (die echten Werte kommen aus der Datenbank).
- Header bekam eine Prop onXLogin, die er gar nicht entgegennimmt und die
  den Logout-Handler durchreichte.

Verifiziert: alle drei Frontends bauen, im Bundle kein process.env mehr,
alle Pfade korrekt auf den jeweiligen Basispfad.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 08:10:55 +02:00
User d9fecb6914 security: implement audit fixes and backend optimizations
- L-03: PasswordReset.js minLength 6 -> 12 for all 3 apps
- B-01: PLZ geocoding proxy endpoint (GET /api/public/geocode) in all 3 backends;
  frontend PublicUserList now uses backend instead of direct Nominatim calls
- B-02: type filter server-side via onRefetch useEffect; removed redundant local
  available/type filters from PublicUserList useMemo
- audit fixes: app-specific JWT secrets, bcrypt cost 12, LRU geocode cache,
  auth middleware app-claim check, nginx CSP script-src cleanup,
  nginx.conf renamed to nginx.conf.dev, geocode-cache Docker volume
- add mailer.js utility (password reset emails)
2026-05-03 11:20:45 +02:00
User 8384ad9432 security: port binding, invite token auth, cookie flags, rate limiting
- Docker: bind all backend/frontend ports to 127.0.0.1 only (was 0.0.0.0)
- Docker: add shared jagd-network; portal uses container names instead of host ports
- Fix: set-password endpoints now require valid invite token (drohnenfuehrer, stoeberhunde)
- Fix: auth cookie secure flag enabled in production
- Fix: password reset token no longer logged in production
- Add: inviteLimiter (10/15min) on set-password routes in all three apps
- Add: importUsers capped at 500 entries to prevent DoS
- Refactor: rename handler -> drohnenfuehrer/stoeberhundefuehrer across all apps
2026-05-03 10:15:03 +02:00
User edcce520d4 Commit aller Änderungen: Audit- und Produktionsfixes und weitere Anpassungen 2026-05-02 22:55:22 +02:00
User 52f21d964c fix: PWA install banner und Icons
- Dockerfile: icon-192.png und icon-512.png in Container aufgenommen
- manifest.json: favicon.ico entfernt (wurde als text/html geliefert)
- manifest.json: Cache-Busting ?v=2 für alle Icons
- index.html: Logo-Bild auf ?v=2 aktualisiert
- extra8002.conf: manifest.json Content-Type auf application/manifest+json gesetzt
- Alle Sub-App manifest.json: scope von '/' auf jeweiligen Pfad korrigiert
  (/nachsuche/, /drohnenfuehrer/, /stoeberhunde/)
- icon-192.png und icon-512.png: aus logo-fallingbostel.png generiert
2026-05-02 22:04:24 +02:00
thomas 5eb14a7826 init: Jagd Apps Heidekreis – Portal, Nachsuche, Drohnenführer, Stöberhunde 2026-05-02 17:31:20 +02:00