Commit Graph

38 Commits

Author SHA1 Message Date
wmantly 34b1413c96 Bump version to 1.1.6; update CHANGELOG 2026-07-16 19:02:59 -04:00
wmantly 7c0cb5eabd Bump version to 1.1.5; update CHANGELOG 2026-07-16 18:34:03 -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 526545ee68 Bump version to 1.1.4; update CHANGELOG 2026-07-16 17:44:00 -04:00
wmantly 17e9ef2783 Bump version to 1.1.3; update CHANGELOG 2026-07-16 16:02:59 -04:00
wmantly 8565f4aa27 Bump version to 1.1.2 2026-07-16 15:36:50 -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 f98c4ec44f Bump version to 1.1.1 2026-07-16 13:56:57 -04:00
wmantly 22274eddbe Bump version to 1.1.0 2026-07-15 22:38:00 -04:00
wmantly a19ff81c76 Fix a worker-blocking Lua socket call and add gzip/caching for static assets
- ops/nginx_conf/targetinfo.lua's wildcard-subdomain lookup fallback used
  classic LuaSocket (require("socket.unix")) instead of an OpenResty
  cosocket. LuaSocket is blocking, and called from an nginx worker it
  stalls the ENTIRE worker — every other in-flight connection on it — for
  the round-trip to the Node app. Worse, the Node side never
  newline-terminated its response, so the old blocking receive() only ever
  returned via its read-timeout-then-partial-read fallback, meaning every
  single cache-miss lookup paid a fixed timeout penalty while blocking the
  whole worker. Replaced with an ngx.socket.tcp() cosocket (unix-domain via
  "unix:/path", the only cosocket API this lua-nginx-module ships) and
  newline-terminated the Node service's responses so receive() actually
  completes instead of timing out. Verified against a live container:
  previously this crashed OpenResty's Lua VM entirely
  (ngx.socket.unix doesn't exist); fixed version resolves fresh wildcard
  subdomains in ~2ms.
- Add gzip compression (`compression` middleware) and far-future
  Cache-Control on static assets (7d for vendor libs under
  /static-modules, 1h for the app's own /static JS/CSS, which isn't
  cache-busted). The admin UI is a traditional multi-page app that loads
  ~13 separate vendor/app JS+CSS files on every full navigation; previously
  none of them were compressed and Cache-Control was `max-age=0` (Express's
  default), forcing a revalidation round-trip for every asset on every page
  view.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 00:41:31 -04:00
wmantly 94ad6143cc Dockerize the proxy (all-in-one image) + Docker docs
All-in-one Dockerfile bundling OpenResty + the Node mgmt app + Redis in one
container, mirroring the bare-metal ops/install.sh layout:
- Dockerfile (openresty/openresty:1.31.1.1-2-bookworm-fat base; dumb-init PID 1;
  luarocks install lua-resty-auto-ssl/luasocket/lua-resty-ipmatcher; node 22.x;
  npm ci --omit=dev; OpenResty confs + lua copied into place).
- docker-entrypoint.sh: fallback cert, sed-parameterize RESOLVER/REAL_IP_FROM,
  start bundled redis + node app, exec openresty foreground.
- docker-compose.yml (standalone), .dockerignore, DEPLOYMENT.md.
- nodejs/routes/render.js: /health endpoint for healthchecks.
- nodejs/models/user_ldap.js: tlsOptions forwarded to ldapts Client so the
  proxy can bind ldaps:// with a self-signed cert (app_ldap__tlsOptions__*).
- nodejs/package.json: bump @simpleworkjs/conf to ^1.1.0 (app_* env overrides).
- docs/docker.md + index.md: Docker deployment guide + fronting an SSO Manager.
- ops/proxy.service: add WorkingDirectory=/var/www/proxy/nodejs (bare-metal
  cwd fix so relative conf/ paths resolve).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-11 17:02:52 -04:00
wmantly cff816fa06 Address CodeQL findings on the OIDC auth flow
- Open redirect / client-side XSS (app-base.js): the post-login `redirect`
  read from the URL fragment was assigned straight to window.location. Add a
  same-origin guard (safeInternalPath) that rejects absolute URLs,
  protocol-relative "//host"/"/\\host", and scheme targets like
  "javascript:". Apply it in consumeTokenFragment and logInRedirect.
- Server-side defense in depth: sanitize `redirect` when storing OidcState
  and when building the callback fragment (utils/safe_redirect.js, shared +
  unit-tested).
- Missing rate limiting: throttle the unauthenticated auth endpoints
  (/login, /oidc/start, /oidc/callback) with express-rate-limit (60/IP/15m).
  Set `trust proxy: 1` so req.ip reflects the real client behind OpenResty.

Adds test/unit/safe_redirect.test.js; unit suite 77 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 13:22:12 -04:00
wmantly 58ba837cbd Merge branch 'master' into deps/audit-fix 2026-07-10 11:13:51 -04:00
wmantly 7ee8202a11 Update dependencies and clear all npm audit vulnerabilities
`npm audit fix` resolved all 12 advisories (7 high, 5 moderate) by
bumping transitive deps (axios/form-data/node-forge/path-to-regexp/qs/
ws/socket.io-parser/brace-expansion/follow-redirects/picomatch) within
the existing semver ranges. Audit is now clean (0 vulnerabilities).

Also refreshed direct deps:
- @fortawesome/fontawesome-free 7.1 -> 7.3 (minor)
- ldapts 8.1.2 -> 8.1.8 (patch)
- ejs 3.1 -> 6.0 (major)
- jquery 3.7 -> 4.0 (major)

All views render under ejs 6 (modern <%- include() %> syntax, no legacy
filters) and no jQuery-4-removed APIs are used in the views or public JS.
Unit + integration tests pass (55).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 10:58:38 -04:00
wmantly 7cc7f95019 Add TTL-based expiry for wildcard subdomain cache entries
Adopt model-redis v1.5.0 and give the on-demand is_cache Host records
(and their Cached tracking records) created by Host.addCache a TTL, so
they auto-expire instead of accumulating forever. Only the record hash
carries the TTL, so OpenResty's direct HGETALL sees a miss once it
expires and re-resolves through the lookup path.

The lifetime is configurable via conf.cacheTTL (seconds, default 3600;
0 disables expiry). This also mitigates the matchAny=false "wrong host"
bug: stale leftover cache entries now expire (and are still busted on
parent update), so undefined subdomains stop being served by old caches.

Add test/unit/wildcard_matchany.test.js covering the matchAny routing
decision (defined vs undefined subdomains, mixed-policy sibling
wildcards, and cache-entry behavior) and wire it into the test scripts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 10:51:06 -04:00
wmantly 77674c6b1c Upgrade model-redis to ^1.4.0 and redis to ^6.1.0
model-redis 1.4.0 requires redis 6, so bump both together to keep a
single deduped redis version. Verified: unit tests pass (38), and the
real models load and run against live redis 7 on the new stack,
including model-redis 1.4.0's findOrphans().

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 20:13:38 -04:00
wmantly b522e5064a Package updates 2026-02-25 12:16:38 -05:00
wmantly 5913c5e8c3 Moved to model-redis package 2025-12-31 20:32:21 -05:00
wmantly 6cb2880131 Using the simpleworks conf now 2025-12-31 19:28:26 -05:00
wmantly 9c762e0e0c Updated versions 2025-12-31 19:08:56 -05:00
wmantly 5dd07edf1a Moved jq-repeat to use NPM package 2025-12-31 16:01:34 -05:00
dependabot[bot] 25ac1ed961 Bump axios from 1.7.2 to 1.7.4 in /nodejs
Bumps [axios](https://github.com/axios/axios) from 1.7.2 to 1.7.4.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.7.2...v1.7.4)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-16 03:31:09 +00:00
wmantly e86de04a69 Better UI for DNS 2024-08-11 22:57:18 -04:00
wmantly 3caa4087b7 Updated package versions 2024-08-07 15:00:29 -04:00
wmantly 84db245f4a fixed issue with redis models 2024-08-06 13:11:55 -04:00
wmantly 0eb6af1723 syntax cleanups 2024-07-31 20:19:14 -04:00
wmantly 441e372987 Added socket.io 2024-07-31 19:01:55 -04:00
wmantly fc66225cf5 new front end #33 2024-07-30 20:47:46 -04:00
wmantly 99ab768f45 fixed prefix issue 2023-08-17 13:26:47 -04:00
wmantly deca906ce1 vagrant update 2023-06-26 22:18:42 -04:00
wmantly 6e1b987c34 better wild cards 2020-12-21 00:14:12 -05:00
wmantly 0c337716d3 merged 2020-04-09 22:47:08 -04:00
wmantly 255d6568fd new model model 2020-04-09 22:22:54 -04:00
wmantly e81fd45373 removed forever 2019-12-20 20:50:20 -05:00
wmantly 088c7207c1 updated package.json 2019-12-20 13:38:08 -05:00
wmantly ac8ab0828b updated package.json 2019-12-12 13:28:50 -05:00
wmantly 565eb9c2e7 vagrant works 2019-12-10 01:39:53 -05:00
wmantly 236753b383 moved all files to code directory 2019-09-02 11:26:48 -04:00