2026-03-31 21:59:11 +08:00
|
|
|
PORT=3001 # Port to run the server on
|
|
|
|
|
NODE_ENV=development # development = development mode; production = production mode
|
fix: decouple at-rest encryption from JWT_SECRET, add JWT rotation
Introduces a dedicated ENCRYPTION_KEY for encrypting stored secrets
(API keys, MFA TOTP, SMTP password, OIDC client secret) so that
rotating the JWT signing secret no longer invalidates encrypted data,
and a compromised JWT_SECRET no longer exposes stored credentials.
- server/src/config.ts: add ENCRYPTION_KEY (auto-generated to
data/.encryption_key if not set, same pattern as JWT_SECRET);
switch JWT_SECRET to `export let` so updateJwtSecret() keeps the
CJS module binding live for all importers without restart
- apiKeyCrypto.ts, mfaCrypto.ts: derive encryption keys from
ENCRYPTION_KEY instead of JWT_SECRET
- admin POST /rotate-jwt-secret: generates a new 32-byte hex secret,
persists it to data/.jwt_secret, updates the live in-process binding
via updateJwtSecret(), and writes an audit log entry
- Admin panel (Settings → Danger Zone): "Rotate JWT Secret" button
with a confirmation modal warning that all sessions will be
invalidated; on success the acting admin is logged out immediately
- docker-compose.yml, .env.example, README, Helm chart (values.yaml,
secret.yaml, deployment.yaml, NOTES.txt, README): document
ENCRYPTION_KEY and its upgrade migration path
2026-04-01 12:31:45 +08:00
|
|
|
# ENCRYPTION_KEY=<random-256-bit-hex> # Separate key for encrypting stored secrets (API keys, MFA, SMTP, OIDC, etc.)
|
|
|
|
|
# Auto-generated and persisted to ./data/.encryption_key if not set.
|
2026-04-01 12:38:38 +08:00
|
|
|
# Upgrade from a version that used JWT_SECRET for encryption: set to your old JWT_SECRET value so
|
|
|
|
|
# existing encrypted data remains readable, then re-save credentials via the admin panel.
|
fix: decouple at-rest encryption from JWT_SECRET, add JWT rotation
Introduces a dedicated ENCRYPTION_KEY for encrypting stored secrets
(API keys, MFA TOTP, SMTP password, OIDC client secret) so that
rotating the JWT signing secret no longer invalidates encrypted data,
and a compromised JWT_SECRET no longer exposes stored credentials.
- server/src/config.ts: add ENCRYPTION_KEY (auto-generated to
data/.encryption_key if not set, same pattern as JWT_SECRET);
switch JWT_SECRET to `export let` so updateJwtSecret() keeps the
CJS module binding live for all importers without restart
- apiKeyCrypto.ts, mfaCrypto.ts: derive encryption keys from
ENCRYPTION_KEY instead of JWT_SECRET
- admin POST /rotate-jwt-secret: generates a new 32-byte hex secret,
persists it to data/.jwt_secret, updates the live in-process binding
via updateJwtSecret(), and writes an audit log entry
- Admin panel (Settings → Danger Zone): "Rotate JWT Secret" button
with a confirmation modal warning that all sessions will be
invalidated; on success the acting admin is logged out immediately
- docker-compose.yml, .env.example, README, Helm chart (values.yaml,
secret.yaml, deployment.yaml, NOTES.txt, README): document
ENCRYPTION_KEY and its upgrade migration path
2026-04-01 12:31:45 +08:00
|
|
|
# Generate with: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
2026-03-31 21:59:11 +08:00
|
|
|
TZ=UTC # Timezone for logs, reminders and scheduled tasks (e.g. Europe/Berlin)
|
|
|
|
|
LOG_LEVEL=info # info = concise user actions; debug = verbose admin-level details
|
2026-03-31 07:35:12 +08:00
|
|
|
|
2026-03-31 21:59:11 +08:00
|
|
|
ALLOWED_ORIGINS=https://trek.example.com # Comma-separated origins for CORS and email links
|
|
|
|
|
FORCE_HTTPS=false # Redirect HTTP → HTTPS behind a TLS proxy
|
|
|
|
|
TRUST_PROXY=1 # Number of trusted proxies for X-Forwarded-For
|
2026-03-31 07:35:12 +08:00
|
|
|
|
2026-04-01 10:36:27 +08:00
|
|
|
APP_URL=https://trek.example.com # Base URL of this instance — required when OIDC is enabled; must match the redirect URI registered with your IdP
|
|
|
|
|
|
2026-03-31 21:59:11 +08:00
|
|
|
OIDC_ISSUER=https://auth.example.com # OpenID Connect provider URL
|
|
|
|
|
OIDC_CLIENT_ID=trek # OpenID Connect client ID
|
|
|
|
|
OIDC_CLIENT_SECRET=supersecret # OpenID Connect client secret
|
|
|
|
|
OIDC_DISPLAY_NAME=SSO # Label shown on the SSO login button
|
|
|
|
|
OIDC_ONLY=true # Disable local password auth entirely (SSO only)
|
|
|
|
|
OIDC_ADMIN_CLAIM=groups # OIDC claim used to identify admin users
|
|
|
|
|
OIDC_ADMIN_VALUE=app-trek-admins # Value of the OIDC claim that grants admin role
|
fix: replace JWT tokens in URL query params with short-lived ephemeral tokens
Addresses CWE-598: long-lived JWTs were exposed in WebSocket URLs, file
download links, and Immich asset proxy URLs, leaking into server logs,
browser history, and Referer headers.
- Add ephemeralTokens service: in-memory single-use tokens with per-purpose
TTLs (ws=30s, download/immich=60s), max 10k entries, periodic cleanup
- Add POST /api/auth/ws-token and POST /api/auth/resource-token endpoints
- WebSocket auth now consumes an ephemeral token instead of verifying the JWT
directly from the URL; client fetches a fresh token before each connect
- File download ?token= query param now accepts ephemeral tokens; Bearer
header path continues to accept JWTs for programmatic access
- Immich asset proxy replaces authFromQuery JWT injection with ephemeral token
consumption
- Client: new getAuthUrl() utility, AuthedImg/ImmichImg components, and async
onClick handlers replace the synchronous authUrl() pattern throughout
FileManager, PlaceInspector, and MemoriesPanel
- Add OIDC_DISCOVERY_URL env var and oidc_discovery_url DB setting to allow
overriding the auto-constructed discovery endpoint (required for Authentik
and similar providers); exposed in the admin UI and .env.example
2026-04-01 11:42:27 +08:00
|
|
|
OIDC_DISCOVERY_URL= # Override the auto-constructed discovery endpoint (e.g. Authentik: https://auth.example.com/application/o/trek/.well-known/openid-configuration)
|
2026-03-31 21:45:20 +08:00
|
|
|
|
2026-03-31 21:59:11 +08:00
|
|
|
DEMO_MODE=false # Demo mode - resets data hourly
|