Commit Graph
8 Commits
Author SHA1 Message Date
Krystie fef7e07b49 DC-026/027/028: close 3 more auth security holes + rate limit /auth/* + audit credential exposures
CI / Test & Lint (push) Has been cancelled
CI / Security audit (push) Has been cancelled
[DC-026] routes/auth/sso-gate.js — fix sessionDuration='never' bypass
  Both /auth/gate/:serviceId and /auth/app-token/:serviceId had a session
  check gated on `sessionDuration !== 'never'`. An admin setting TOTP to
  never-expire accidentally created an authentication-free path to credential
  injection (Basic Auth, X-Api-Key, Plex/Prowlarr tokens). Patched: session
  required whenever TOTP is enabled, period. Added 8 regression tests.

[DC-027] src/utilities/middleware.js — rate limit /auth/*
  New authLimiter (20 req / 15 min) on /auth/keys, /auth/jwt, /auth/gate,
  /auth/app-token. These endpoints expose credentials and were unmetered.
  Without this, an attacker with a guessed session cookie could burn through
  every credential-touching endpoint. Added 5 tests.

[DC-028] src/security/audit-logger.js — log credential exposures
  /auth/gate and /auth/app-token were in SKIP_PATHS, silently dropping
  every credential-exposure event from the audit log. Combined with the
  GET-skip rule, NONE of these events were being recorded. Now logged
  with named actions: auth.credential-injection, auth.app-token-issue,
  auth.api-key-generate, auth.api-key-revoke, auth.jwt-mint. Added 9 tests.

[start.sh] Disable in-container self-updater
  DASHCADDY_UPDATE_ENABLED=false. Without this, the container kept writing
  trigger.json every 30 min and clobbered my in-progress host edits. The
  path unit on the host is still active for manual triggers, but the
  container won't auto-update itself — only when an admin clicks the
  update button or a new release is manually published.

[package.json] Bump to 1.14.7

Test results: 1066/1066 passing across 39 suites (added 22 new tests).
2026-07-01 04:20:57 -07:00
Krystie bfa4ba570e DC-025: harden updater — channel gate + safe locked-file replacement
CI / Test & Lint (push) Has been cancelled
CI / Security audit (push) Has been cancelled
The host-side updater has been silently broken in two ways:

1. Empty staging directories would cause rm -rf of live routes/src with no
   replacement, leaving the host tree gutted while the container kept serving
   from its own image. Now deploy_tree() refuses to delete unless the staging
   source has actual files.

2. chattr +i on critical files (used to protect security-hotfixed routes from
   being clobbered by upstream tarballs) caused rm -rf to partially execute
   then fail under set -e, leaving the host in a half-deleted state. Now
   deploy_tree() scans for immutable files, unlocks them before replace,
   and re-locks them after — so security-locked files survive every update.

Also adds:
- Channel gate: trigger.json channel=prerelease/beta/rc/alpha is rejected
  unless ALLOW_PRERELEASE=true is set in /opt/dashcaddy/updates/channel.conf.
  Default is 'stable only', safe for production. Staging hosts opt in.
- channel.conf.example documenting the new opt-in mechanism.

Verified end-to-end: manual trigger.json → path unit fired → routes (53 files)
+ src (62 files) deployed → container rebuilt → health check passed. totp.js
remained locked with security edits intact.
2026-07-01 04:02:30 -07:00
Krystie b7624cc507 DC-024: Bump installer version to 1.14.6 and sync VERSION to current commit
CI / Test & Lint (push) Has been cancelled
CI / Security audit (push) Has been cancelled
- dashcaddy-installer/install.sh: 1.1.0 → 1.14.6 (matches current release)
- dashcaddy-api/VERSION: 10f72afa5f51e4 (current HEAD with TOTP security fixes)

The host source tree was rebuilt from the published v1.14.6 tarball to fix a
deletion gap where /opt/dashcaddy/dashcaddy-api/{routes,src}/ were gutted by an
interrupted prior update cycle. Container was unaffected (built from image).
2026-07-01 03:50:00 -07:00
Krystie a5f51e4a0c DC-023: operational fixes — DNS, rate limiter, version sync
CI / Test & Lint (push) Has been cancelled
CI / Security audit (push) Has been cancelled
- VERSION: bump from 1.14.4 to 1.14.6 to match package.json (HEAD had stale value)
- middleware.js: apply existing totpLimiter (10/15min) to /totp/setup endpoint
  (was previously unmetered, allowing secret enumeration)
- dashcaddy-update.sh: hook post-deploy-patches.sh into the update flow
  so the container can survive transitions between broken → fixed tarballs
- start.sh: add --add-host flags for get.dashcaddy.net and get2.dashcaddy.net
  so the container can resolve the release server (was failing with ENOTFOUND)
2026-07-01 03:10:53 -07:00
Krystie e73bfbb0a1 DC-021: build pipeline now ships src/ + hygiene for generated artifacts
The release tarball previously omitted dashcaddy-api/src/, which meant the
in-container self-updater had to apply post-deploy patches (dashcaddy-post-
deploy-patches.sh) to work around missing files. That script generates 37
flat copies of src/ files at the dashcaddy-api/ root level to satisfy
broken require() paths. With proper src/ shipping, those files become
obsolete, but they were still being shown as untracked in git.

Changes:
- BUILD-PIPELINE-FIX.md documents the build pipeline fix (in /opt/dashcaddy-release/
  build-release.sh — sibling repo, not tracked here)
- .gitignore now ignores the 37 generated post-deploy artifacts plus the
  backups/ and updates/ runtime directories, so 'git status' stays clean
- scripts/dashcaddy-post-deploy-patches.sh is now tracked so it's preserved
  across rebuilds (still useful as a safety net for transitional installs)
2026-07-01 03:09:59 -07:00
Krystie 2439ed3e85 DC-022: close 3 TOTP auth security holes
1. /totp/recovery-info: was PUBLIC, leaking TOTP configuration status
   to unauthenticated attackers. Now requires valid session (401 otherwise).

2. /totp/check-session: had an unconditional bypass that returned
   authenticated:true whenever totpConfig.enabled was false. This let
   anyone reach authenticated endpoints without credentials.
   Now throws AuthenticationError instead.

3. /totp/setup: was unmetered despite generating secrets. Added 3/hour
   per-IP rate limit in addition to the existing global 10/15min limiter.

All changes verified live via https://status.sami:
- recovery-info unauth → 401 [DC-110] (was 200)
- check-session no cookie → 401 TOTP protection required (was 200)
- 4th setup attempt → 429 [DC-429]
2026-07-01 03:09:33 -07:00
Krystie 69be51b8aa chore(release): bump to 1.14.6 — patched source
CI / Test & Lint (push) Has been cancelled
CI / Security audit (push) Has been cancelled
Following DC-021 (commit 10f72af) which restored working require paths and
license-keygen.js, this commit bumps the version metadata so the next
release build publishes v1.14.6 instead of re-tagging v1.14.4.

The source is functionally v1.14.4 + fixes; the version bump tells the
updater we're ahead of upstream's broken v1.14.4.
2026-07-01 00:55:13 -07:00
Krystie 10f72af959 fix(update): proper require path fixes + license-keygen restore for v1.14.4 compatibility
CI / Test & Lint (push) Has been cancelled
CI / Security audit (push) Has been cancelled
v1.14.4 (commit d2a48b1) shipped with broken relative paths and missing
license-keygen.js module. This commit:

- server.js: 26 '../src/...' requires rewritten to './src/...' (server is
  at API root, must use ./src for files in src/)
- src/managers/license-manager.js: './license-keygen' rewritten to
  '../../license-keygen' (license-keygen.js lives at API root)
- src/docker/self-updater.js: './platform-paths' rewritten to
  '../../platform-paths' (platform-paths.js lives at API root)
- license-keygen.js: restored to root (was missing from v1.14.4 tarball)
- VERSION: bumped to d2a48b1-patched (matches upstream commit but with
  our fixes baked in)

Makes the v1.14.4 source buildable and runnable without external patches.
Companion to scripts/dashcaddy-post-deploy-patches.sh which applies these
fixes automatically during the host-side update flow.
2026-07-01 00:32:23 -07:00