Commit Graph

6 Commits

Author SHA1 Message Date
Keysat 798a698132 Add Users dashboard tab with per-user balances and credit grants
New cookie-gated "Users" tab on the operator dashboard: a sortable view
of every credit-ledger row (typed cloud/license/install) with computed
remaining/total balances, key filter, and a per-row "grant free credits"
action.

Endpoints (routes/admin.js):
- GET /admin/credits — snapshotAll() enriched with a type derived from
  the credit-key prefix and a computed balance (computeRemaining against
  live tier quotas), since the ledger stores consumed counters only.
- POST /admin/credits/grant {credit_key, amount} — adds free top-up via
  addPurchasedCredits. Grants land in the never-expires purchased bucket
  (spent after the tier allowance). Guards: positive integer, <=1,000,000,
  and the row must already exist (a typo can't spawn a ghost row).

Admin-only; no /relay/* client contract change. Tests added in
server/test/admin-credits.test.js (mount the real router over HTTP).
Version bumped 0.2.124 -> 0.2.125.
2026-06-15 16:25:14 -05:00
Keysat cbd9748a79 Guard meeting :id against path traversal
saveMeeting/loadMeeting/deleteMeeting built path.join(meetingsDir, id +
'.json') straight from req.params.id, so an admin-authed :id like
'../../etc/passwd' could read/write/delete outside internal-meetings/.
Centralize a meetingPath() helper that strips anything outside
[A-Za-z0-9_-] (mirrors output-store.js) and throws on an empty result;
load/delete catch it as 404/no-op. Add a regression test.
2026-06-13 18:22:00 -05:00
Keysat d2caa98248 Fix credit-counter reset on early subscription renewal
extendUserTier called setUserTier, which unconditionally zeroed
monthly_consumed and re-anchored the cycle. A user who renewed mid-cycle
(or a webhook double-firing across a restart) got their full monthly
allotment back for free. The monthly cycle already rolls on its own
anniversary via ensureRenewalRollover, so renewal must not reset it. Add
resetCycle to setUserTier (default true, preserving operator-grant
behavior); extendUserTier passes false for an in-force subscription and
true only for a brand-new or lapsed one. Add regression tests.
2026-06-13 16:23:26 -05:00
Keysat 8ad7c54da4 Block SSRF on media_url downloads (transcribe-url/summarize-url)
downloadDirect fetched any caller-supplied media_url with redirect-follow
and no host/scheme validation; the route is reachable via a self-chosen
X-Recap-Install-Id, so a caller could probe the operator's LAN or cloud
metadata (169.254.169.254). Add safe-url.js: assertPublicHttpUrl rejects
non-http(s) schemes and hosts resolving to private/loopback/link-local/
reserved ranges, and safeFetch follows redirects manually, re-validating
each hop. Route downloadDirect through it (covers transcribe-url,
summarize-url, and admin-test-run).
2026-06-13 16:23:26 -05:00
Keysat 0aa648706e Add self-serve billing: tiers, credits, BTCPay and Zaprite 2026-06-13 13:36:05 -05:00
Keysat 705807e286 Add internal-meetings pipeline and post-hoc speaker tools 2026-06-13 13:35:53 -05:00