diff --git a/BACKLOG.md b/BACKLOG.md index bda0b62..cf21e81 100644 --- a/BACKLOG.md +++ b/BACKLOG.md @@ -255,6 +255,37 @@ Tickets DC-033 through DC-041 were added after the DNS2 v1.14.4 / v1.14.8 / 0.0. - **impact:** Workflow health checks now actually check container health, instead of silently reporting 0/0 every cycle. Stops the "Health check failed" notification spam. - **result:** Fixed in src/recipes/bundled-workflows.js. New regression test `__tests__/bundled-workflows-health-check.test.js` — 5 cases (uses .read() not .getState(), correct counts, graceful degrade on read() throw, no servicesStateManager on ctx, single-service path). Full suite: 1219/1219 pass (+5 new). +### DC-046: Pluggable AuthProvider interface — refactor TOTP into one of N providers +- **status:** todo +- **owner:** unclaimed +- **details:** Today DashCaddy has only one login method (TOTP). For a public-release product we need at least a second (email magic link), and the TOTP-only design doesn't scale — every new user needs a TOTP secret provisioned manually, no self-service recovery, no per-user audit trail. Refactor: define a `AuthProvider` interface in `src/auth/providers/` with methods `{ name, enabled, loginMethods, initiate(req) -> {redirect, challenge?}, verify(req) -> {user} }`. Move the existing TOTP code into `src/auth/providers/totp.js` as one implementation of that interface. `createApp` composes all enabled providers and exposes them via `/api/v1/auth/login` and `/api/v1/auth/login/:method` routes. Login page lists all enabled providers with their own button. Zero behavior change for existing TOTP users — the route shape becomes `/api/v1/auth/login/totp` instead of `/api/v1/auth/login`, but the existing UI is rewritten to match. Effort: ~1 hr. Risk: medium (touches the auth path that is the most security-sensitive area of the codebase). +- **impact:** Unlocks every other auth provider (DC-047 email magic link, DC-048+ OIDC, SAML, etc.) without further refactors of the auth path. + +### DC-047: EmailMagicLinkProvider — email-only login via nodemailer +- **status:** todo +- **owner:** unclaimed +- **details:** Second AuthProvider implementation, sitting alongside TOTP. Flow: user enters email at `/login`, server generates a single-use token (32 random bytes, base64url), stores it in `data/email-tokens.json` with 15-min TTL, sends an email via the existing nodemailer connection in `src/managers/notification-manager.js:290` (reuse the same SMTP config — `providers.email.host/port/username/password/from`). Email body contains a link like `https://dashcaddy.example.com/auth/verify?token=abc123`. Click → server validates token (exists, not expired, not already used) → marks used → creates session cookie → redirect to dashboard. On subsequent visits, session cookie is the credential. Rate-limit the request-link endpoint to 5 per email per hour to prevent email-bombing. Tokens stored as SHA-256 hashes in the JSON store so a read-only compromise can't be used to forge links. Effort: ~3 hrs. Risk: medium (depends on SMTP creds being configured; if not, fall back to console-logging the link in dev mode). +- **impact:** Public product readiness. Zero-password login. Reuses existing nodemailer config — no new dependency, no new credential surface. Works with any SMTP server Sami already uses (he mentioned using the SMTP server his website runs). +- **prerequisite:** DC-046 (the interface to implement against). + +### DC-048: Multi-user bootstrap + admin invites +- **status:** todo +- **owner:** unclaimed +- **details:** The user model shifts from "one implicit operator" to "many users with explicit roles". Bootstrap rule: the FIRST email to ever successfully log in via email magic link becomes the admin. Subsequent emails are denied with a `not authorized` error UNLESS the email appears in `data/authorized-users.json`. Admin UI: a `/users` page that lists authorized users, lets admin add emails (manual entry) or generate single-use invite links (which work like magic links but pre-add the email to the allowlist on first use). Audit log gets `userEmail` attribution on every entry. License model is unchanged (still per-host) but note in the ticket that this may need revisiting. Effort: ~2 hrs. Risk: low (mostly UI + JSON-store CRUD). +- **impact:** First real multi-user DashCaddy. Per-user audit attribution. Self-service invites. Foundation for any future "team" features. +- **prerequisite:** DC-047 (needs email auth working first). + +### DC-049: Update login UI to show multiple providers +- **status:** todo +- **owner:** unclaimed +- **details:** Currently the login page is TOTP-only. Once DC-046/047/048 ship, login needs to render ALL enabled providers as a list of buttons, each routing to its provider-specific initiate flow (`/api/v1/auth/login/totp`, `/api/v1/auth/login/email`). Frontend work — `status/js/core/login.js` and the login modal markup. Add a small "Choose how to sign in" header. Effort: ~1 hr. Risk: low (pure UI, no backend changes). +- **impact:** Makes the pluggable auth provider pattern visible to users. Without this, providers other than TOTP are unreachable. +- **prerequisite:** DC-046 + DC-047 (needs at least two providers to be meaningful). + +### Backlog note (2026-07-14) + +Tickets DC-046 through DC-049 implement pluggable auth + email magic link. Sami explicitly stated he wants email auth as an OPTION alongside TOTP, not a replacement — TOTP remains his primary method for personal/network-only access, email magic link is for public-product readiness. Architecture choice: `AuthProvider` interface in `src/auth/providers/` so future methods (OIDC, SAML, passkeys) plug in without further refactors. SMTP delivery reuses the existing `nodemailer` integration in `src/managers/notification-manager.js:290` — no new dependency. Sami plans to use the SMTP server his website runs (sami-ahmed.net) so the host field will be configurable. Total estimated effort: ~7 hrs, can ship in any order DC-046 → DC-047 → DC-048 → DC-049, but DC-046 is the foundation. + ### DC-045: Fix WorkflowEngine init — `new (require(...))()` precedence bug on ES6 classes - **status:** done - **owner:** hermes