New admin-only page (nav: "LDAP Info") that answers "what do I put in my
app's LDAP settings" without reading a doc: LDAPS URL, base DN, user/group
search bases, user filter, username attribute, and an example bind DN, all
derived from the running conf.ldap + request host rather than hardcoded --
so it's always correct for the actual deployment, copy-button on every
field.
Also generates a copy-pasteable bash snippet that clones
theta42/ldap-client and writes its ldap.vars file with the real host/base
DN/sso_url already filled in (bind password and SSO API token left as
placeholders with inline instructions, since those need to be created,
not derived).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The admin UI is a traditional multi-page app that loads ~13 separate
vendor/app JS+CSS files on every full navigation; none were compressed and
Cache-Control was max-age=0 (Express's default), forcing a revalidation
round-trip for every asset on every page view. Add gzip (compression
middleware) and sane Cache-Control (7d for vendor libs under
/static-modules, 1h for the app's own /static JS/CSS, which isn't
cache-busted). Matches the equivalent fix in theta42/proxy.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
theta42/proxy fronts an arbitrary number of hosts behind SSO, each with its
own callback URL (https://<host>/__proxy_auth/callback) — proxy's own code
comment already assumed "a wildcard redirect URI covers all", but no
wildcard matching existed here, so every proxied host's callback had to be
registered on the shared OAuth client individually or /oauth/authorize
would reject it with InvalidRedirectURI.
Add `*` (one hostname label) / `**` (any number of labels) wildcard support
to redirect_uri matching, e.g. `https://**.example.com/__proxy_auth/callback`
now covers every host proxy fronts under example.com. Exact matches still
work exactly as before.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Replace the separate Profile/API Tokens nav items with a single link
showing the logged-in user's name, pointing at their own profile.
- Merge admin.ejs + notifications.ejs into a new dashboard.ejs page.
/admin and /notifications now 301-redirect to /dashboard.
- Fold the API Tokens page into profile.ejs as a self-service-only
section, gated on isOwnProfile so it never appears when an admin
views another user's profile via /users/:uid. /api-tokens 301s to /.
- Fix: the section must not carry class="row" — app-base.js runs a
page-wide $('div.row').fadeIn() on every page load that would reveal
it regardless of the isOwnProfile check, since it fires before this
page's own gating logic.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* docs: cleanup for public release (fix stale/wrong API docs, LICENSE, versions)
Documentation cleanup ahead of the public release announcement. Fixes a set
of confirmed issues from a prior audit:
- LICENSE: fill in MIT template placeholders (theta42, 2026).
- README.md: fix broken API docs link (api.md -> API.md), correct required
Node.js version (13.x -> 20.x), add the missing app_sso_invite group to
the LDAP groups table, scrub hardcoded dc=theta42,dc=com to the generic
dc=example,dc=com used elsewhere, add a "Recommended: Docker or
install.sh" section pointing to DEPLOYMENT.md/docs before the manual
OpenLDAP walkthrough, and drop an emoji from a warning callout.
- nodejs/api.md: deleted — it was a stale/legacy doc with wrong routes,
wrong request bodies, and endpoints that are dead/commented-out code.
The root API.md is the accurate, current reference; README now links
there directly.
- API.md: add the missing app_sso_invite permission group, fix the
documented invite response to match the real {token, link, mail_sent}
payload, document the previously-undocumented GET/PUT/DELETE
/api/user/invite endpoints, add the real allowed_groups field to the
OAuth client management examples, and document POST /api/oauth/authorize
(the endpoint that actually issues the code after consent).
- nodejs/routes/auth.js + API.md: fix "emaill address" typo in the
password-reset response message (source and docs kept in sync).
- DEPLOYMENT.md: fix the top-level summary to mention Redis, matching
docs/deployment.md and the entrypoint behavior it already documents.
Flagged, not changed: tos.md reads like a personal home-lab acceptable-use
policy (Emby/Gitea/Proxmox/Discord/Signal, first-person "the admin") rather
than generic OSS docs. Left in place pending a manual decision to
genericize, relocate, or remove it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* docs: genericize tos.md template, track runtime-editable terms in #39
Removes operator-specific references (Emby, Gitea, Proxmox, Discord,
Signal, first-person "the admin") so the shipped tos.md reads as a
neutral starting template rather than one operator's internal policy.
Actual runtime editability (admin/legal editing terms without a code
change) is tracked in issue #39, not implemented here.
---------
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Personal access tokens so scripts/CI can call the management API without a
browser session. Each logged-in user mints their own token; it authenticates as
the creator (carries their LDAP group permissions, re-resolved live), so the
existing permission.byGroup checks apply unchanged.
- models/api_token.js: new ApiToken model (sso_<id>_<secret> format; id is the
lookup key, secret bcrypt-hashed + isPrivate, shown once). add()/rotate()/
authenticate(); optional expires_at; best-effort last_used_on. No _ttl
(persists; lifetime via expires_at).
- routes/api_token.js: self-service CRUD (list/get/update/delete/rotate),
owner-scoped (created_by === req.user.uid, 403 otherwise).
- middleware/auth.js + models/auth.js: accept `Authorization: Bearer sso_...`
(precedence over the auth-token session header); checkApiToken collapses
every failure to one generic 401 (no existence/secret/expiry leak).
- views/api_tokens.ejs + routes/index.js (GET /api-tokens): self-service page
(forceLogin, no group gate) — create (token shown once), edit, rotate, revoke.
- views/top.ejs: "API Tokens" nav entry visible to all logged-in users.
- public/js/app.js: app.apiToken client module.
- DEPLOYMENT.md + docs/deployment.md: API tokens section.
Co-authored-by: Claude <noreply@anthropic.com>