439 Commits

Author SHA1 Message Date
wmantly 426fa111ec Add plain-language concept docs; fix docs viewer rendering; link API tokens
- New docs/concepts-{hosts,dns,access,api-tokens}.md -- plain-language
  guides aimed at less technical readers, each linking onward to the
  existing system-design-level doc for anyone who wants that detail.
  Card help links (Proxy List, Add/Edit host, DNS Provider cards,
  Users/Permissions/Groups cards) now point here instead of straight at
  Installation/Architecture.
- The "New API Token" card had no help link at all -- added, pointing to
  the new API Tokens doc.
- Fixed the in-app docs viewer rendering every docs/*.md page with a
  garbled heading + stray <hr> at the top: Jekyll front matter (meant
  only for the GitHub Pages build) was never stripped before being
  handed to the markdown renderer.
- Fixed cross-doc links never resolving in-app, since this viewer serves
  docs at /docs/<slug> with no .html suffix: rewritten to the correct
  in-app URL, first by registered slug, falling back to the doc's real
  filename (the correct, working link form on the Jekyll/GitHub Pages
  build) -- same idea as the existing image-path fix, and lets one link
  written in a doc work on both targets.

Bumps to v1.1.13.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KDEx8ghuZR61pqPXc6da9C
2026-07-17 22:09:53 -04:00
wmantly f0b282b679 Merge pull request #162 from theta42/wildcard-edit-and-nginx-fix
Fix wildcard-parent edit greying and deprecated nginx http2 directive
v1.1.12
2026-07-17 21:35:28 -04:00
wmantly 4f1fce367e Fix wildcard-parent edit greying and deprecated nginx http2 directive
- The edit form's "Parent Wildcard" option stayed greyed out even when a
  valid wildcard existed, since hostEditOpen() never ran the eligibility
  check (only the host field's keyup handler did, which setting .val()
  programmatically doesn't fire) -- and the check itself, GET
  /host/lookup/:item, had the same self-match bug as the recently-fixed
  Host.prototype.update() case: it resolves an already-existing host to
  its own record instead of a sibling wildcard. Added a dedicated
  /host/wildcard-parent/:item route combining lookUp() (handles a
  brand-new subdomain) with lookUpWildcardParent() (handles an
  already-existing host), and hostEditOpen() now actually runs it.

- Migrated ops/nginx_conf/autossl.conf's deprecated "listen ... http2"
  directive to the standalone "http2 on;" directive (nginx 1.25.1+).

Bumps to v1.1.12.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KDEx8ghuZR61pqPXc6da9C
2026-07-17 21:33:26 -04:00
wmantly 9eb3dfa2e6 Merge pull request #161 from theta42/help-icon-relocate
Move help links from the global header onto each relevant card
v1.1.11
2026-07-17 20:02:08 -04:00
wmantly a40da55993 Move help links from the global header onto each relevant card
The single header-wide help icon (added last release) pointed at a
per-page doc guess, but a page can have several cards covering different
topics. Removed it and added a small help icon directly to each card
that has real corresponding doc content, linking straight to that doc:
Proxy List + Add/Edit host modal (hosts.ejs), Add DNS Provider + Dynamic
A Records (dns.ejs), Add New User + User List (users.ejs), Add
Permission + Permissions (permissions.ejs), Add Group (groups.ejs).

Bumps to v1.1.11.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KDEx8ghuZR61pqPXc6da9C
2026-07-17 20:00:34 -04:00
wmantly e5df0d3370 Merge pull request #160 from theta42/docs-help-search
Add header help icon and in-app docs search
v1.1.10
2026-07-17 19:29:22 -04:00
wmantly fcd73169e0 Add header help icon and in-app docs search
- A ? icon in the top-right header deep-links to the doc most relevant to
  the current page (client-side path mapping, same pattern already used
  for top-nav active-link highlighting -- no server-side "current section"
  local exists to key off of instead). Falls back to the docs index.
- GET /docs/search does a plain line-substring search over the existing
  allowlisted doc set. No new dependency, stays usable with no internet
  access.

Bumps to v1.1.10.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KDEx8ghuZR61pqPXc6da9C
2026-07-17 19:28:07 -04:00
wmantly 876ea6cfd0 Merge pull request #159 from theta42/host-form-ux-polish
Host form/list UX polish: editable hostname, created-by column, mobile tabs, more help text
v1.1.9
2026-07-17 19:05:09 -04:00
wmantly 9100e92549 Host form/list UX polish: editable hostname, created-by column, mobile tabs, more help text
- Plain hosts can now be renamed after creation (wildcard/child/cache hosts
  stay locked, since other records reference them by name). Migrates the
  cert cache key on rename.
- Along the way, found and fixed a real bug in the vendored model-redis
  library: its rename path leaves a stray, incomplete hash behind under
  the old key when an `always`-type field (updated_on) is defined earlier
  in the schema than the primary key -- silently blocking that hostname
  from ever being reused. Worked around at the Host model level (can't
  patch node_modules).
- Host list now shows who created each host, and when.
- Host modal's tabs now scroll horizontally on narrow screens instead of
  overflowing awkwardly.
- Added missing inline help text (Target SSL, wildcard matching behavior).

Bumps to v1.1.9.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KDEx8ghuZR61pqPXc6da9C
2026-07-17 19:03:26 -04:00
wmantly 9a83fb8252 Merge pull request #158 from theta42/wildcard-cert-fixes
Fix wildcard-cert gaps: attach existing host, and register wildcard's own base domain
v1.1.8
2026-07-17 18:47:28 -04:00
wmantly 17b903e228 Fix two wildcard-cert gaps: attaching an existing host, and the wildcard's own base domain
- Host.prototype.update() had no challengeType handling (only create() did),
  so selecting "Parent Wildcard" on an existing host's edit form silently
  did nothing. Added the same wildcard-parent lookup to update(), using a
  new Host.lookUpWildcardParent() -- the existing lookUp() can't be reused
  here since an already-created host resolves to its own leaf rather than
  falling through to a sibling wildcard.

- A wildcard's issued cert covers both the base domain and *.base domain
  (altNames), but the lookup tree stores the wildcard one level below its
  base -- looking up the bare base domain landed on an empty parent node
  and found nothing. buildLookUpObj() now also stamps that parent node,
  order-independent (a real host explicitly created at that exact name
  always still wins).

Verified both fixes against a real Redis-backed Host model (not just the
mocked lookup-tree tests) -- see PR description.

Bumps to v1.1.8.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KDEx8ghuZR61pqPXc6da9C
2026-07-17 18:46:09 -04:00
wmantly 11f44176c0 Merge pull request #157 from theta42/bump-1.1.7
Bump version to 1.1.7
v1.1.7
2026-07-16 20:23:17 -04:00
wmantly b4d971b508 Bump version to 1.1.7; update CHANGELOG 2026-07-16 20:22:02 -04:00
wmantly 28f1c53d06 Merge pull request #156 from theta42/redesign-docs-site
Redesign docs site: match the app's own look, add SEO, mobile-ready
2026-07-16 20:06:38 -04:00
wmantly 8c3a263937 Redesign docs site: match the app's own look, add SEO, mobile-ready
Same treatment as the sso-manager-node companion PR: replaced the
generic jekyll-theme-cayman theme with a custom layout mirroring the
actual app UI -- dark fixed navbar with the theta42 logo, Bootstrap 5
+ Font Awesome (same stack the app uses), content in a card, dark
footer matching bottom.ejs. Keeps this repo's own favicon.svg
(confirmed genuinely distinct SVG artwork from the shared theta42
logo, not a duplicate) as the browser-tab icon.

- New cross-page nav (Home/Installation/Architecture/API/Docker/
  Contributing/Changelog).
- SEO: jekyll-seo-tag + jekyll-sitemap, per-page meta description,
  OG/Twitter card tags, canonical URLs, JSON-LD, sitemap.xml,
  robots.txt.
- Mobile: Bootstrap's responsive grid + collapsible navbar; the
  screenshot pairs in index.md stack to full-width below 576px.

Verified with a real Jekyll build (jekyll/jekyll Docker image) +
Playwright: desktop and mobile (375px) screenshots, mobile nav
toggle, active-link highlighting, zero console/page errors, and
confirmed real SEO output + the correct (non-shared) favicon via curl
against the served site.
2026-07-16 20:05:32 -04:00
wmantly e249b4e168 Merge pull request #155 from theta42/bump-1.1.6
Bump version to 1.1.6
v1.1.6
2026-07-16 19:04:34 -04:00
wmantly 34b1413c96 Bump version to 1.1.6; update CHANGELOG 2026-07-16 19:02:59 -04:00
wmantly eded87b6f9 Merge pull request #154 from theta42/fix-host-auth-mode-radios
hosts.ejs: fix Authentication tab radios not enforcing mutual exclusivity
2026-07-16 19:01:26 -04:00
wmantly a57f3f03f6 hosts.ejs: fix Authentication tab radios not enforcing mutual exclusivity
The three auth_mode radios (Off / Basic / SSO) had no shared [name]
attribute, so per the HTML spec each was its own independent group --
clicking one didn't uncheck the others, letting multiple options
appear selected at once despite the page's own text saying "basic
auth and SSO can't both be enabled."

Added name="auth_mode" to restore native browser radio-group
behavior. The original comment claimed the radios were deliberately
kept nameless to avoid polluting the submitted form data (formAJAX
serializes every [name] field in the form), but that reasoning
doesn't hold: model-redis's processKeys() rebuilds the saved object
strictly from the Host model's own _keyMap, so an unrecognized
auth_mode field is silently stripped before anything is ever
persisted -- confirmed directly with model-redis's own
object_validate.js. Updated the stale comment accordingly.
2026-07-16 18:59:50 -04:00
wmantly 5b08eecca9 Merge pull request #151 from theta42/bump-1.1.5
Bump version to 1.1.5
v1.1.5
2026-07-16 18:35:41 -04:00
wmantly 7c0cb5eabd Bump version to 1.1.5; update CHANGELOG 2026-07-16 18:34:03 -04:00
wmantly 3f0d6fb438 Merge pull request #150 from theta42/jq-repeat-2.1.0
Update jq-repeat to 2.1.0; fix removed __setPut/__setTake API
2026-07-16 18:27:28 -04:00
wmantly 6cd3a5bc58 Update jq-repeat to 2.1.0; fix removed __setPut/__setTake API
jq-repeat 2.1.0 (release notes: https://github.com/wmantly/jq-repeat/releases/tag/v2.1.0)
brings real fixes (throttled-update race conditions, sorted-list
reverse() leaking elements, nested-scope isolation) and a few
behavior changes. Audited every usage in this repo against the
changelog before upgrading:

- push()/unshift() now return the new array length -- every call
  site in this repo is a bare statement, none consume the return
  value. No risk.
- update() is now trailing-edge throttled (~50ms) even on the first
  call, not just rapid subsequent ones -- no code in this repo reads
  DOM/item state immediately after calling update(), so no risk here
  (unlike sso-manager-node's companion PR, which needed a fix).
- jr-order-reverse and nested jq-repeat templates: not used anywhere
  in this repo.

Real breakage found and fixed: users.ejs/groups.ejs/permissions.ejs
called $.scope.X.__setPut(fn)/__setTake(fn) as setter METHODS -- that
API is gone in 2.1.0. Insert/remove hooks are now set via direct
property assignment ($.scope.X.__put = fn), per the current README.
Verified live (real dev server + Playwright): before the fix, all
three pages threw "__setTake is not a function" and the
insert/remove row animations were broken; after, zero errors and the
hooks fire correctly.
2026-07-16 18:26:02 -04:00
wmantly 88cf5cf281 Merge pull request #149 from theta42/bump-1.1.4
Bump version to 1.1.4
v1.1.4
2026-07-16 17:45:22 -04:00
wmantly 526545ee68 Bump version to 1.1.4; update CHANGELOG 2026-07-16 17:44:00 -04:00
wmantly ecf064b9ae Merge pull request #148 from theta42/white-label
White-label: title/logo now driven by conf
2026-07-16 17:36:55 -04:00
wmantly fd71485960 White-label: title/logo now driven by conf (closes #45)
<title>, the navbar brand text, and the logo were all hardcoded
"Proxy - Theta 42"/"Dynamic Proxy". New conf.name/conf.logo keys
(defaults matching current text/asset) thread through the existing
values object pattern in routes/render.js and routes/docs.js, and
top.ejs now renders <%- name %>/<%- logo %> for the title and a new
navbar logo image.

Footer (copyright, theta42.com link, GitHub/license links) and the
existing favicon.svg are left as-is -- open-source attribution and a
distinct, already-working icon asset, not deployment branding.
2026-07-16 17:35:49 -04:00
wmantly 1c29ba7206 Merge pull request #147 from theta42/bump-1.1.3
Bump version to 1.1.3
v1.1.3
2026-07-16 16:04:24 -04:00
wmantly 17e9ef2783 Bump version to 1.1.3; update CHANGELOG 2026-07-16 16:02:59 -04:00
wmantly 983f2a71f0 Merge pull request #146 from theta42/add-changelog
Add CHANGELOG.md, serve it in-app at /docs/changelog
2026-07-16 16:00:31 -04:00
wmantly edf60b3e3d Add CHANGELOG.md, serve it in-app at /docs/changelog (closes theta42/theta-env#43)
GitHub Releases already carried real changelog notes per tag, but
those require internet access to view -- exactly what the /docs
route exists to avoid. CHANGELOG.md is a committed, Keep-a-Changelog
style file (backfilled from the v1.1.0/v1.1.1/v1.1.2 release notes),
linked from README and served at /docs/changelog alongside the rest
of the project's docs.
2026-07-16 15:59:16 -04:00
wmantly 1f10d0db14 Revert "Add CHANGELOG.md, serve it in-app at /docs/changelog (closes theta42/theta-env#43)"
This reverts commit 4bf1768529.
2026-07-16 15:59:01 -04:00
wmantly 4bf1768529 Add CHANGELOG.md, serve it in-app at /docs/changelog (closes theta42/theta-env#43)
GitHub Releases already carried real changelog notes per tag, but
those require internet access to view -- exactly what the /docs
route exists to avoid. CHANGELOG.md is a committed, Keep-a-Changelog
style file (backfilled from the v1.1.0/v1.1.1/v1.1.2 release notes),
linked from README and served at /docs/changelog alongside the rest
of the project's docs.
2026-07-16 15:58:26 -04:00
wmantly ed275acbe7 Merge pull request #145 from theta42/bump-1.1.2
Bump version to 1.1.2
v1.1.2
2026-07-16 15:38:15 -04:00
wmantly 8565f4aa27 Bump version to 1.1.2 2026-07-16 15:36:50 -04:00
wmantly 8c22d69e44 Merge pull request #144 from theta42/airgap-and-docs
Air-gap fixes + in-app /docs
2026-07-16 15:30:21 -04:00
wmantly c71b23ef82 docs.js: rate-limit the doc routes (CodeQL: missing rate limiting)
Public route reading from disk on every request with no throttling
-- add a per-IP limiter matching the routes/auth.js/routes/host.js
convention already used elsewhere in this repo.
2026-07-16 15:29:06 -04:00
wmantly 7d9c63b049 Air-gap fixes + in-app /docs (README/DEPLOYMENT/api.md/docs/*)
Air-gap:
- DynamicRecord.refreshAll() called getPublicIp() (api.ipify.org,
  icanhazip.com, ifconfig.me) every 4h on a timer regardless of
  whether any dynamic records were configured -- the one background
  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.

Docs:
- New GET /docs (index) and /docs/:slug routes render this project's
  own README, DEPLOYMENT, api.md, and docs/*.md server-side via
  marked (new dependency) -- so the documentation is readable from
  the running app with no route to GitHub Pages, where it otherwise
  only lives. Public, no auth, same tier as the health endpoint.
- .dockerignore/Dockerfile updated: docs/, DEPLOYMENT.md, and
  nodejs/api.md were previously excluded from the image entirely
  ("served via GitHub Pages, not from the image") -- now copied in
  alongside README.md/tos.md-style, since they're needed at runtime.
2026-07-16 15:26:10 -04:00
wmantly 5a685e9dd7 Merge pull request #143 from theta42/bump-1.1.1
Bump version to 1.1.1
v1.1.1
2026-07-16 13:58:10 -04:00
wmantly f98c4ec44f Bump version to 1.1.1 2026-07-16 13:56:57 -04:00
wmantly 8deecdba73 Merge pull request #142 from theta42/duckdns-validate-via-txt
DuckDNS: validate token via a TXT write, not the A/AAAA record
2026-07-16 12:56:24 -04:00
wmantly 3e90062255 DuckDNS: validate token via a TXT write, not the A/AAAA record
listDomains() used to validate the token by calling DuckDNS's update
endpoint with ip/ipv6 omitted, which makes DuckDNS auto-detect and
apply this host's public IP -- so adding a provider instantly
repointed the domain. Validate via a fixed TXT marker instead, which
DuckDNS's API supports independently and doesn't touch routing.
2026-07-16 12:55:06 -04:00
wmantly 5333864e19 Merge pull request #141 from theta42/bump-1.1.0
Bump version to 1.1.0
v1.1.0
2026-07-15 22:39:27 -04:00
wmantly 22274eddbe Bump version to 1.1.0 2026-07-15 22:38:00 -04:00
wmantly 908bd76501 Merge pull request #140 from theta42/backup-and-update-check
Add standalone backup script and admin update-check banner
2026-07-15 22:34:08 -04:00
wmantly 1df9916c91 Add standalone backup script and admin update-check banner
ops/backup.sh snapshots Redis (BGSAVE, dynamic RDB path lookup) and
./config for standalone deployments, with retention. A background
service polls GitHub releases every 24h and surfaces an admin-only
banner in the UI when a newer version is published.
2026-07-15 22:32:31 -04:00
wmantly c6b5479a94 Merge pull request #137 from theta42/marketing-pages
Turn GitHub Pages into a marketing landing page
2026-07-15 16:09:44 -04:00
wmantly 547aa1ea55 Turn GitHub Pages into a marketing landing page; cross-link, drop download buttons
- Rewrite docs/index.md as a short landing page (what it is, screenshots,
  why this over the alternatives, features, a minimal "get it" snippet)
  instead of a full documentation dump — full docs live in the repo
  (README, docs/*.md) and are linked from here.
- Cross-link to SSO Manager and theta-env's own Pages sites.
- Screenshots are now clickable (open full size) on both the Pages site
  and the README.
- Disable show_downloads in docs/_config.yml — the Cayman theme's
  "Download .zip/.tar.gz" buttons are gone; "View on GitHub" (which links
  back to the repo) is the only header link now.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 16:06:14 -04:00
wmantly 3b9f587664 Merge pull request #136 from theta42/docs-screenshots
Add screenshots to README and docs site
2026-07-15 15:44:51 -04:00
wmantly 9fcb7c0246 Remove unused permissions.png screenshot
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 15:41:22 -04:00