255835af7a
The Permissions page only offered Delete, so changing a role or scope meant removing the grant and re-adding it from memory. A permission's id is derived from (subjectType, subject, scope, domain), so changing any of those is a different record rather than an update. The new PUT creates the new grant and removes the superseded one in that order, so an edit can never leave the old grant behind still conferring access. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
328 lines
28 KiB
Markdown
328 lines
28 KiB
Markdown
## v1.35.0
|
|
- feat: **permission entries can be edited.** The Permissions page only offered Delete, so changing a role or scope meant removing the grant and re-adding it from memory. New `PUT /api/permission/:id` plus an Edit modal pre-filled from the record.
|
|
- fix: a permission's id is derived from (subjectType, subject, scope, domain), so changing any of those is a *different* record, not an update. The endpoint creates the new grant and removes the superseded one in that order, so an edit can never leave the old grant behind still conferring access.
|
|
|
|
## v1.34.0
|
|
- feat: the per-host SSO **Allowed groups** field now autocompletes from the SSO directory's groups. Suggestions previously came only from local groups, permission subjects and `conf.auth` maps — none of which can match an SSO-gated host, because its allow-list is checked against the `groups` claim the SSO issues. New `conf.sso` block (`url` + read-only `apiToken`, minted by theta-suite's bootstrap); results are cached for 5 minutes and the endpoint degrades silently to the old local-only list when unset.
|
|
- fix: the SSO group lookup authenticates with `Authorization: Bearer <token>`, not the `auth-token` header — the latter is for browser session UUIDs and would be rejected for a minted API token.
|
|
- docs: `docs/concepts-hosts.md` gains a "Putting a host behind single sign-on" section covering the per-host `/__proxy_auth` flow, the wildcard redirect URI the IdP must allow, and where group suggestions come from.
|
|
- docs: `secrets.js.example` documents the new `sso` block.
|
|
|
|
## v1.33.0
|
|
- feat: Add SSO-style error page (404/500) for browser navigation instead of a bare JSON/text response
|
|
- feat: DNS page is now admin-only (hidden from non-admins; API already admin-gated)
|
|
- feat: navbar — username no longer underlined; only the active link is bold + underlined
|
|
|
|
## v1.13.3
|
|
- fix: remove missing DEPLOYMENT.md and docs/ from Docker build context
|
|
|
|
## v1.13.2
|
|
- chore: Update CI pipeline integration
|
|
|
|
# Changelog
|
|
|
|
All notable changes to this project are documented here. Format loosely
|
|
follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions
|
|
correspond to git tags (`vX.Y.Z`) and `nodejs/package.json`'s `version`.
|
|
|
|
## [Unreleased]
|
|
|
|
## [1.13.1] - 2026-08-01
|
|
|
|
### Fixed
|
|
- **Bumped `@simpleworkjs/bao-conf` to 1.0.1** so standalone/no-OpenBao boots
|
|
don't crash. bao-conf 1.0.0's `init()` threw when `VAULT_TOKEN` was unset,
|
|
which — combined with `bin/www`'s `.catch(() => process.exit(1))` — made the
|
|
proxy exit at boot in any deployment without an OpenBao sidecar (standalone
|
|
Docker, bare metal). 1.0.1 makes `init()` fail-soft on a missing token (warn
|
|
+ continue from `CONF_SECRETS`), matching the documented contract. The
|
|
theta-env stack is unaffected (it always sets a scoped `VAULT_TOKEN`).
|
|
|
|
## [1.13.0] - 2026-08-01
|
|
|
|
### Changed
|
|
- **Secrets now load from OpenBao at boot** via
|
|
[@simpleworkjs/bao-conf](https://simpleworkjs.github.io/bao-conf/), which
|
|
deep-merges `secret/proxy/conf` over the file-loaded config. The proxy
|
|
authenticates to OpenBao with a scoped `VAULT_TOKEN` (policy `proxy` —
|
|
read-only on its own path), never the root token. Because the OIDC
|
|
`clientSecret` is captured at require time inside `createOidcClient` (during
|
|
`require('../models')`, which `require('../app')` triggers transitively),
|
|
`bin/www` now defers `require('../app')` until after `bao-conf.init()`
|
|
resolves. Fail-soft: if OpenBao is unreachable, boot continues from
|
|
`CONF_SECRETS`. The `config/proxy-secrets.js` file is now an operator-edit
|
|
seed artifact (gitignored); OpenBao is authoritative. See theta-env's
|
|
[Secrets docs](https://theta42.github.io/theta-env/secrets/).
|
|
- Bumped package version to track the release tag.
|
|
|
|
## [1.12.1] - 2026-08-01
|
|
|
|
### Changed
|
|
- Bumped `body-parser` 2.2.2 → 2.3.0 (Dependabot #175).
|
|
- Bumped `ejs` and `brace-expansion` (Dependabot #179, security maintenance).
|
|
|
|
## [1.12.0] - 2026-08-01
|
|
|
|
### Fixed
|
|
- Changed UNIX socket permission in `unix_socket_json.js` to `666` so OpenResty Nginx workers running as `nobody` can resolve targets properly.
|
|
|
|
## [1.9.0] - 2026-07-30
|
|
|
|
### Added
|
|
- **`app_super_admin` cross-app group** recognized as a global admin (`conf.auth.adminGroups`), same group also recognized by sso-manager-node and jump-host, and by `ldap-client`'s SSSD access filter (SSH login on every host).
|
|
|
|
### Changed
|
|
- **Users and Permissions pages**: the always-visible sidebar "Add" forms are now an "Add User"/"Add Permission" button in the list header that opens an `app.modal` dialog, matching the hosts.ejs convention.
|
|
- **Let's Encrypt ACME account key** now defaults to the already-persisted `/data` volume instead of a CWD-relative path (`./le_key.cert` -> `/app/le_key.cert` in the container), which was lost on every image rebuild.
|
|
|
|
## [1.8.0] - 2026-07-28
|
|
|
|
### Added
|
|
- **Users backed by SSO/OIDC login are now marked "External (SSO)"** and read-only: their password-change control is hidden, and `PUT /password/:username` rejects with 403 server-side. Deletion stays allowed. Redis user-backend only.
|
|
- **`app.util.revealItem()`** (shared `app-base.js`): scrolls a just-added/-edited element into view and flashes its background. Wired into the Users/Permissions create flows.
|
|
|
|
### Changed
|
|
- **All pages now wrap their content in a standard-width container**, matching sso-manager-node instead of rendering full-bleed.
|
|
- **Users and Permissions pages converted from bare `<table>`s to the card-grid convention** already used on the Groups page.
|
|
- `@simpleworkjs/frontend` bumped to `^0.2.7`.
|
|
|
|
## [1.7.0] - 2026-07-28
|
|
|
|
### Added
|
|
- **API tokens: "+ New Token" modal button (replacing the always-visible inline create-form card) and a new Edit modal** — continues the cross-app API-token UI unification started in jump-host. The Edit modal's footer shows real created-by/on data; the `PUT /api-token/:id` route already fully supported editing, so no backend change was needed.
|
|
|
|
### Fixed
|
|
- **Creating an API token didn't show the "save this secret now" reveal modal** — the create flow called `app.modal.close()` immediately before `app.modal.open()` (to show the secret) in the same tick; since `app.modal` is a singleton, that collided with Bootstrap's hide-transition guard and the reveal modal silently never appeared.
|
|
|
|
## [1.6.0] - 2026-07-28
|
|
|
|
### Added
|
|
- **Host modal: footer with created/updated-by/on metadata, linkable `/hosts/{host}` URL** — migrated onto the shared `app.modal` component (`@simpleworkjs/frontend` 0.2.6), continuing the entity-modal standardization started in sso-manager-node. Kept the existing 6-tab layout (General/TLS & Wildcard/Traffic/Headers/Access/Authentication) unchanged.
|
|
|
|
### Fixed
|
|
- **The Let's-Encrypt challenge-type/wildcard-matching visibility logic could stop reacting to the hostname field after the first Add/Edit** — its `keyup` handler was bound once directly against a selector captured at page load; now delegated so it survives the modal being rebuilt on every open.
|
|
- **The SSO allow-list autocomplete (users/groups) could go empty starting on the second Add/Edit** — its backing `<datalist>`s are rebuilt fresh on every modal open now, so the suggestions are refetched each time too.
|
|
|
|
## [1.5.3] - 2026-07-28
|
|
|
|
### Fixed
|
|
- **`formAJAX`'s loading indicator showed literal HTML**, not a spinner — same fix as sso-manager-node's companion release. Replaced with plain text.
|
|
|
|
## [1.5.2] - 2026-07-28
|
|
|
|
### Added
|
|
- **Regression test**: a static check across all views/client-side scripts fails CI if any native `alert()`/`confirm()`/`prompt()` call appears — these block all further browser events on the page and were fully removed in 1.5.1.
|
|
|
|
## [1.5.1] - 2026-07-27
|
|
|
|
### Fixed
|
|
- **Removed native `confirm()` calls in `revokeToken`/`rotateToken`** (`profile.ejs`), replacing them with `app.messages.confirm`. Native `confirm()` blocks all further browser events on the page (discovered live, mid browser-verification of sso-manager-node's equivalent flow, where it froze the tab).
|
|
|
|
## [1.5.0] - 2026-07-27
|
|
|
|
### Changed
|
|
- **Adopted `@simpleworkjs/frontend`'s `app.messages`, `app.modal`, and `app.validate` modules**, replacing the vendored `app.util.actionMessage`/`actionConfirm` in `public/lib/js/app-base.js` and the vendored `public/lib/js/val.js`. Message content is now HTML-escaped, and `app.messages.action` falls back to a page-wide toast when there's no inline `.actionMessage` target. proxy's `host`/`target`/`hostname` wildcard-DNS validation rules (mirroring `utils/hostname_validate.js`) moved to `public/js/app.js`, registered via `$.validateSettings`, since they're proxy-specific and don't belong in the shared package's generic rule set. `app.api`/`app.auth`/`app.pubsub`/`app.socket` are untouched.
|
|
|
|
## [1.4.0] - 2026-07-26
|
|
|
|
### Changed
|
|
- **Unified the front-end UI shell across the three theta42 apps.** `views/top.ejs`, `views/bottom.ejs` and `public/lib/js/app-base.js` are now byte-identical in sso-manager-node, proxy and jump-host, so the apps look and behave the same and a shell change lands in one edit per repo instead of three divergent ones. Everything that differs between the apps moved into a new `nodejs/utils/ui.js`, exposed to every render as `ui` via `app.locals`: nav items and the groups that may see them, footer repo/license/docs/Terms links, favicon, the profile and post-logout targets, and whether the update banner exists at all.
|
|
- **One nav-gating model everywhere.** `app-base.js` reveals `.group-required-<cn>` elements for each group the current user is in, read from `GET /api/user/me`. sso-manager-node reports LDAP DNs in `memberOf` and the OIDC clients report CNs in `groups`; both normalise to CNs client-side, and the clients' effective-rights `isAdmin` flag is exposed as a synthetic `admin` group — so one gating model covers a group-based provider and boolean-admin clients without either app learning the other's response shape.
|
|
- **`GET /api/user/me` is fetched once per page load and cached** (`app.auth.loadUser`). The nav, per-view `forceLogin` and every group-gated element read that one promise instead of issuing their own request.
|
|
- `app.auth.isLoggedIn` is dual-mode: it returns a Promise **and** invokes an optional node-style callback, so the async and callback call styles both work against one shared `top.ejs`.
|
|
- `app.auth.forceLogin` no longer uses `$.holdReady` (removed in jQuery 4). An unauthenticated user is redirected to `/login?redirect=<path>`; group requirements are still enforced, and `logOut` now only clears the session, leaving the destination to the caller (`ui.logoutRedirect`).
|
|
- Dependency alignment across all three apps: `jquery` `^4.0.0` and `ejs` `^3.1.10`.
|
|
|
|
### Fixed
|
|
- **`app.api.delete` dropped its callback when called by `formAJAX`.** `formAJAX` always passes the serialized form as the second argument, so a DELETE-method form's callback landed in the data slot and never ran. `delete` now accepts both `(url, callback)` and `(url, data, callback)`.
|
|
- **`app.api.post`/`put` referenced an undefined `callback2`** and threw when handed a non-function callback. Both are now dual-mode Promise/callback.
|
|
- **The login page's "reveal the card once we know you're logged out" branch threw** (`Cannot read properties of null`) whenever the logged-in check answered before the parser reached that element — which it always did without a stored token. It now runs on DOM ready.
|
|
- **`logInRedirect` on the legacy `/login/<path>` form kept only the path.** The OIDC provider routes an unauthenticated authorization request through `/login/oauth/authorize?client_id=…&state=…`; dropping the query there loses the entire authorization request. The suffix form now preserves its query string.
|
|
|
|
### Added
|
|
- `.group-required { display: none }` in `public/css/styles.css`, the base rule the shared gating model reveals against.
|
|
- Admin-only nav items lost their inline `display: none` in favour of that class, and the brand link points at `/` instead of `#`.
|
|
|
|
### Verified
|
|
- Browser-verified against a full theta-env stack (sso-manager + proxy + jump-host): every top-level page renders with a clean console; nav gating is correct for admin and non-admin; `forceLogin`'s onboarding and group gates fire; `val.js` blocks a weak password and accepts a strong one through a real form submit; the DELETE-method forms work; and the OIDC login round trip (authorize with PKCE -> login -> consent -> callback -> token fragment) completes on both OIDC clients.
|
|
|
|
## [1.3.0] - 2026-07-25
|
|
|
|
### Added
|
|
- Adopted the shared `@simpleworkjs/*` packages published under the simpleworkjs org, replacing this app's byte-identical forks of the same code so the theta42 apps share one codebase and API schema:
|
|
- `@simpleworkjs/oidc-client` — the OIDC client (session models, auth router, OIDC utils, safe-redirect, local-admin bootstrap). Deleted the local `utils/oidc.js`, `utils/safe_redirect.js`, `models/oidc_state.js`, `models/token.js`, `models/auth.js`, and `routes/auth.js`; `models/index.js` now wires the factory. The per-host SSO in `routes/host_auth.js` is unchanged but consumes the shared OIDC utils.
|
|
- `@simpleworkjs/ldap` — the ldapts client + RFC 4515/4514 escaping.
|
|
- `@simpleworkjs/app-stack` — unified `build_info` (`{buildVersion, buildHash, buildYear}`) and the `static-modules` mounting helper. `utils/build_info.js` and the static-modules loop in `routes/render.js` now use the shared helpers.
|
|
|
|
### Security
|
|
- **LDAP filter injection in `User.get`.** The user lookup built its search filter by interpolating `data.username` raw into `(&(objectClass=inetOrgPerson)(uid=<username>))`. A username containing `*`, `(`, `)`, `\`, or NUL could widen or alter the filter (e.g. `*` → match-all). The filter value is now passed through `escapeFilter` from `@simpleworkjs/ldap` (RFC 4515 escaping).
|
|
|
|
### Changed
|
|
- Dependency alignment: `model-redis` `^1.5` → `^1.6.0`, `ldapts` `^8.1.2` → `^8.1.8`. The four new `@simpleworkjs/*` deps resolve from the npm registry (`^1.0.0`); no `file:`/`link:` entries in the lockfile, so `npm ci` is clean in docker builds.
|
|
- `build_info` export shape changed from `{commit, version}` to `{buildVersion, buildHash, buildYear}` (the shared shape used by all three apps). The `/health` endpoint and footer now report `buildVersion`/`buildHash`.
|
|
|
|
## [1.2.2] - 2026-07-21
|
|
|
|
### Fixed
|
|
- Multi-target load balancing (added in 1.2.0) crashed every request to a load-balanced host: `ops/nginx_conf/targetinfo.lua` required a nonexistent `resty.balancer.round_robin` module. The `lua-resty-balancer` rock installed by the Dockerfile/`install.sh` doesn't provide that path — it provides `resty.roundrobin` (constructed as `roundrobin:new(nodes)`, not `:new()` + `:reinit(nodes)`). Fixed `targetinfo.lua` to use the real module and API; verified end-to-end that requests now round-robin across targets with no Lua errors.
|
|
|
|
## [1.2.1] - 2026-07-21
|
|
|
|
### Fixed
|
|
- The bootstrap anti-lockout admin account was always created as `proxyadmin2` regardless of `conf.auth.adminUsers`, while `migrations/permission_bootstrap.js` grants the global-admin permission to `conf.auth.adminUsers[0]`. If an operator customized `adminUsers` away from the default, the bootstrapped account and the permissioned account were two different (non-matching) usernames, so the anti-lockout account ended up with no admin access. `models/user_redis.js` now derives the bootstrap username from `conf.auth.adminUsers[0]` (falling back to `proxyadmin2`), matching `permission_bootstrap.js`.
|
|
- Corrected a `secrets.js.example` comment that claimed the bootstrap admin's password "defaults to the username itself" — it actually generates a random password printed to the container log on first boot.
|
|
|
|
### Changed
|
|
- Refreshed all README screenshots (hosts, per-host SSO auth, per-host basic auth) against the current UI, and added a new load-balancing screenshot for the multi-target feature.
|
|
|
|
## [1.2.0] - 2026-07-21
|
|
|
|
### Added
|
|
- Multi-target load balancing: hosts can now specify additional backend targets (`IP:port`, one per line) alongside the primary target; the proxy distributes requests across all of them round-robin via `lua-resty-balancer`. Fixes #47.
|
|
|
|
## [1.1.17] - 2026-07-20
|
|
|
|
### Fixed
|
|
- An existing single-label subdomain host (e.g. `sso.nl.wgnode.com`) could not be attached to a wildcard cert added later (e.g. `*.nl.wgnode.com`): `Host.lookUpWildcardParent()` only checked the wildcard-as-child position (the wildcard's own base domain) and missed the far more common wildcard-as-sibling case, so the edit form's "Parent Wildcard" option stayed permanently greyed out. It now checks both positions, and a regression test covers the sibling case.
|
|
|
|
## [1.1.16] - 2026-07-18
|
|
|
|
### Changed
|
|
- Public-release packaging: removed `"private": true` from `nodejs/package.json`, corrected the repository URL to `https://github.com/theta42/proxy.git`, and fixed the MIT `LICENSE` copyright line.
|
|
- Genericized committed defaults in `conf/base.js` and `conf/development.js`: LDAP now defaults to `ldap://localhost` with `dc=example,dc=com`, and OIDC endpoints default to `https://sso.example.com` instead of internal theta42 infrastructure.
|
|
- The bootstrap `proxyadmin2` account now gets a random, one-time password when `auth.localAdminPass` is unset, instead of the well-known default `proxyadmin2`. The password is printed to the log on first creation and can be made deterministic by setting `auth.localAdminPass` in the secrets file.
|
|
|
|
### Security
|
|
- Sanitized rendered docs HTML via `xss` in `routes/docs.js` so malicious markdown cannot inject scripts or other dangerous markup into the in-app docs viewer.
|
|
- The Unix socket JSON-RPC socket is now created with mode `660` instead of world-writable `777`.
|
|
|
|
### Fixed
|
|
- The global error handler no longer leaks `err.keys`, stack traces, or other internal details in JSON responses; only `name` and `message` are returned to clients.
|
|
- `DEPLOYMENT.md` and `docs/docker.md` now correctly describe the `CONF_SECRETS` env-var mechanism instead of the old symlink behavior.
|
|
|
|
## [1.1.15] - 2026-07-18
|
|
|
|
### Changed
|
|
- `ops/install.sh` now installs to `/opt/theta42/proxy` (was `/var/www/proxy`) and seeds `/etc/proxy/secrets.js` from `secrets.js.example` on first run (never overwritten on later runs), instead of requiring a manual `nodejs/conf/secrets.js` edit inside the repo checkout. `ops/proxy.service` sets `CONF_SECRETS=/etc/proxy/secrets.js` to match.
|
|
- `install.sh` now prints the version it's updating from/to (or "Already up to date") on every run, instead of updating silently.
|
|
|
|
### Fixed
|
|
- `install.sh` could hang indefinitely on a fresh host if a base package pulled in `tzdata` as a new dependency — it prompted interactively for a timezone with no TTY attached. Set `DEBIAN_FRONTEND=noninteractive`.
|
|
|
|
## [1.1.14] - 2026-07-17
|
|
|
|
### Changed
|
|
- Bumped `@simpleworkjs/conf` to 1.2.0 and `jq-repeat` to 2.2.0. The Docker entrypoint now sets the new `CONF_SECRETS` env var to point directly at a mounted `proxy-secrets.js` instead of symlinking it into `/app/conf/secrets.js` — the app no longer needs write access to its own `conf/` directory to pick up mounted secrets.
|
|
|
|
## [1.1.13] - 2026-07-17
|
|
|
|
### Added
|
|
- Four new plain-language docs aimed at less technical readers, replacing the system-design-level Architecture/Installation docs as the target of most card help links: **Hosts & HTTPS**, **DNS Providers**, **Users, Groups & Permissions**, and **API Tokens**. Each links onward to the deeper technical reference for readers who want it; the technical docs link back the other way too. The personal-access-token card (previously missed entirely) now has a help link.
|
|
|
|
### Fixed
|
|
- The in-app docs viewer rendered every `docs/*.md` page with a garbled heading and a stray horizontal rule at the top — Jekyll front matter (meant only for the GitHub Pages build) was never stripped before being handed to the markdown renderer. Also fixed: cross-doc links never resolved in-app, since this viewer serves docs at `/docs/<slug>` with no `.html` suffix — they're now rewritten to the correct in-app URL (by registered slug, falling back to the doc's real filename), the same way image paths already were.
|
|
|
|
## [1.1.12] - 2026-07-17
|
|
|
|
### Fixed
|
|
- The host edit form's "Parent Wildcard" option stayed greyed out even when a valid wildcard actually existed for that host, so an already-created host could never be switched onto one from the edit modal (only brand-new hosts, via the field's `keyup` handler, ever saw it become available). The underlying `/host/lookup/:item` check also had the same self-match issue as the recently-fixed backend bug: it resolved an already-existing host to its own record instead of a sibling wildcard. Added a dedicated `/host/wildcard-parent/:item` endpoint that checks both directions, and the edit form now actually runs the check when it opens.
|
|
- Fixed an nginx startup warning: `the "listen ... http2" directive is deprecated, use the "http2" directive instead`. Migrated to the standalone `http2 on;` directive (nginx 1.25.1+).
|
|
|
|
## [1.1.11] - 2026-07-17
|
|
|
|
### Changed
|
|
- Moved the help (❓) link out of the global header and onto each relevant card individually (Proxy List, Add/Edit host, Add DNS Provider, Dynamic A Records, Add New User, User List, Add Permission, Permissions, Add Group) — each now deep-links straight to the doc that actually covers it, instead of one generic header icon.
|
|
|
|
## [1.1.10] - 2026-07-17
|
|
|
|
### Added
|
|
- A help icon (❓) in the top-right header now deep-links to the doc most relevant to the current page (falls back to the docs index elsewhere).
|
|
- The in-app docs viewer (`/docs`) is now searchable — a simple line-substring search over the same local doc set, no new dependency, still works with no internet access.
|
|
|
|
## [1.1.9] - 2026-07-17
|
|
|
|
### Added
|
|
- The host list now shows who created each host, and when.
|
|
- Plain (non-wildcard) hosts can now be renamed after creation — the hostname field is no longer permanently locked. Wildcard hosts, wildcard children, and auto-created subdomain cache entries stay locked, since other records reference them by name.
|
|
- More inline help text on the host create/edit form (Target SSL, wildcard matching behavior).
|
|
|
|
### Fixed
|
|
- The host create/edit modal's tabs could overflow awkwardly on narrow (mobile) screens — they now scroll horizontally instead.
|
|
- Fixed a bug in the vendored `model-redis` library's record-rename path: renaming a record's primary key while another `always`-type field (e.g. `updated_on`) is defined earlier in the schema left a stray, incomplete hash behind under the old key, making that name permanently unavailable for reuse. Worked around in `Host.prototype.update()`.
|
|
|
|
## [1.1.8] - 2026-07-17
|
|
|
|
### Fixed
|
|
- **Couldn't attach an existing host to a parent wildcard.** The host edit form's "Parent Wildcard" option submitted correctly, but `Host.prototype.update()` had no `challengeType` handling at all (only `Host.create()` did) — selecting it and saving silently did nothing. Added the same wildcard-parent lookup to `update()`.
|
|
- **Couldn't register a wildcard's own base domain as a host.** A wildcard cert's `altNames` already cover both the base domain and `*.base domain`, but the lookup tree stores the wildcard one level below its base domain, and a lookup for the bare base domain landed on that empty parent node and found nothing — even though the already-issued cert covers it. `buildLookUpObj()` now also stamps the parent node so this resolves correctly, without re-issuing or duplicating the cert.
|
|
|
|
Both required a corrected lookup: attaching an *existing* host (which already has its own tree leaf) needed a new `Host.lookUpWildcardParent()` that checks the sibling wildcard slot instead of resolving to the host's own record.
|
|
|
|
## [1.1.7] - 2026-07-16
|
|
|
|
### Changed
|
|
- Redesigned the GitHub Pages docs site to match the app's own look (dark navbar/footer, Bootstrap 5, Font Awesome) instead of the generic `jekyll-theme-cayman` theme, added a real cross-page nav, SEO (`jekyll-seo-tag` + `jekyll-sitemap`, per-page descriptions, OG/Twitter tags, sitemap.xml, robots.txt), and mobile-responsive layout.
|
|
|
|
## [1.1.6] - 2026-07-16
|
|
|
|
### Fixed
|
|
- Hosts admin UI's Authentication tab radios (Off / Basic / SSO) had no shared `name`, so clicking one didn't uncheck the others -- multiple options could appear selected at once. Added `name="auth_mode"` to restore standard exclusive radio-group behavior.
|
|
|
|
## [1.1.5] - 2026-07-16
|
|
|
|
### Fixed
|
|
- Bumped `jq-repeat` 2.0.1 -> 2.1.0. Fixed real breakage: `users.ejs`/`groups.ejs`/`permissions.ejs` called the removed `$.scope.X.__setPut(fn)`/`__setTake(fn)` setter-method API; insert/remove row hooks are now set via direct property assignment (`$.scope.X.__put = fn`), matching 2.1.0's API.
|
|
|
|
## [1.1.4] - 2026-07-16
|
|
|
|
### Added
|
|
- **White-label**: `<title>`, the navbar brand text, and the nav logo image were hardcoded "Proxy - Theta 42"/"Dynamic Proxy". Now driven by new `conf.name`/`conf.logo` keys (defaults unchanged). Footer attribution (copyright, `theta42.com` link, GitHub/license links) and favicon are left as-is. Closes [#45](https://github.com/theta42/proxy/issues/45).
|
|
|
|
## [1.1.3] - 2026-07-16
|
|
|
|
### Added
|
|
- `CHANGELOG.md` (this file), backfilled from the release notes for every tag so far and served in-app at `/docs/changelog`. Closes [theta-env#43](https://github.com/theta42/theta-env/issues/43).
|
|
|
|
## [1.1.2] - 2026-07-16
|
|
|
|
### Fixed
|
|
- **Air-gap**: `DynamicRecord.refreshAll()` called the public-IP resolvers (`api.ipify.org`, `icanhazip.com`, `ifconfig.me`) every 4h on a timer regardless of whether any dynamic DNS records were configured — the one background network call in the repo not actually gated by feature use. Now skips the lookup entirely when there's nothing to refresh.
|
|
- Removed the stray, unauthenticated `GET /test` page (a leftover jq-repeat demo) that loaded jQuery + Mustache from external CDNs.
|
|
- Removed a dead IE<9-only `html5shim` script tag pointing at a domain that no longer resolves.
|
|
|
|
### Added
|
|
- **In-app documentation**: `GET /docs` and `GET /docs/:slug` render this project's own README, DEPLOYMENT, `api.md`, and `docs/*.md` server-side — readable from the running app with no dependency on GitHub Pages, which requires internet access to view. Public, no auth, rate-limited.
|
|
|
|
## [1.1.1] - 2026-07-16
|
|
|
|
### Fixed
|
|
- **DuckDNS provider**: adding a DuckDNS provider no longer pushes this host's public IP to the domain's live A/AAAA record as a side effect of token validation. Validation now writes a fixed marker to the TXT record instead, leaving routing untouched. ([#142](https://github.com/theta42/proxy/pull/142))
|
|
|
|
## [1.1.0] - 2026-07-16
|
|
|
|
First tagged release. Establishes the `vX.Y.Z` tag convention that the in-app update-check banner polls against going forward.
|
|
|
|
### Added
|
|
- Standalone backup script (`ops/backup.sh`) for deployments not using theta-env's orchestrator — snapshots Redis and `./config`, with retention.
|
|
- Admin-only in-app banner that checks GitHub releases every 24h and surfaces available updates.
|
|
|
|
[Unreleased]: https://github.com/theta42/proxy/compare/v1.1.17...HEAD
|
|
[1.1.17]: https://github.com/theta42/proxy/compare/v1.1.16...v1.1.17
|
|
[1.1.16]: https://github.com/theta42/proxy/compare/v1.1.15...v1.1.16
|
|
[1.1.15]: https://github.com/theta42/proxy/compare/v1.1.14...v1.1.15
|
|
[1.1.14]: https://github.com/theta42/proxy/compare/v1.1.13...v1.1.14
|
|
[1.1.13]: https://github.com/theta42/proxy/compare/v1.1.12...v1.1.13
|
|
[1.1.12]: https://github.com/theta42/proxy/compare/v1.1.11...v1.1.12
|
|
[1.1.11]: https://github.com/theta42/proxy/compare/v1.1.10...v1.1.11
|
|
[1.1.10]: https://github.com/theta42/proxy/compare/v1.1.9...v1.1.10
|
|
[1.1.9]: https://github.com/theta42/proxy/compare/v1.1.8...v1.1.9
|
|
[1.1.8]: https://github.com/theta42/proxy/compare/v1.1.7...v1.1.8
|
|
[1.1.7]: https://github.com/theta42/proxy/compare/v1.1.6...v1.1.7
|
|
[1.1.6]: https://github.com/theta42/proxy/compare/v1.1.5...v1.1.6
|
|
[1.1.5]: https://github.com/theta42/proxy/compare/v1.1.4...v1.1.5
|
|
[1.1.4]: https://github.com/theta42/proxy/compare/v1.1.3...v1.1.4
|
|
[1.1.3]: https://github.com/theta42/proxy/compare/v1.1.2...v1.1.3
|
|
[1.1.2]: https://github.com/theta42/proxy/compare/v1.1.1...v1.1.2
|
|
[1.1.1]: https://github.com/theta42/proxy/compare/v1.1.0...v1.1.1
|
|
[1.1.0]: https://github.com/theta42/proxy/releases/tag/v1.1.0
|