Skip to content

v3.8.0 - per-user history deletes and a registration switch

Choose a tag to compare

@syswave-dev syswave-dev released this 31 Jul 17:55
· 14 commits to main since this release

Two things drove this release: a reported bug where a logged-in non-admin could not remove anything from their own history, and the need to run a public demo instance in multi-user mode without collecting stranger accounts. Diagnosing the first turned up four more defects in the same code paths, all fixed here.

Cache deletes are scoped to the caller (closes #49)

DELETE /api/cache/:id and DELETE /api/cache used to sit behind an admin-only guard, so a non-admin got 403 {"error":"Admin required"} while the UI still offered them the button. The premise held only halfway: conversions is deduplicated by URL and shared between all users, but each user's history is a separate user_fetches join table where unlinking a row affects nobody else.

An admin (and every caller when PULLMD_AUTH_MODE is disabled or unset) still purges the shared row. A regular user now unlinks only their own history entry, so the shared row and its /s/:id share link survive and other users keep it. Both responses gained scope: "user" | "global", delete-all gained removed, and existing status codes are unchanged.

For API consumers: in single-admin and multi-user modes, a non-admin DELETE /api/cache* now answers 200 with scope: "user" where it previously answered 403.

PULLMD_ALLOW_SIGNUP

Default on, so nothing changes for an existing instance. Setting it to false (or 0/no/off) means the /signup routes are not mounted at all: GET and POST answer 404, no account can be created by a crafted request, the login page drops its "create an account" link, and /api/config reports signupOpen: false.

Paired with the new node scripts/admin.js create-user <email>, so a closed instance is not a dead end.

Also fixed

  • Orphaned history rows inflated the archive count. pruneOld dropped conversions older than 90 days without removing the matching user_fetches rows, and countForUser counts without the join historyPageForUser uses, so the archive advertised entries it could never return and drifted further with every prune. Existing databases repair themselves on the next start.
  • reset-password silently did nothing when the password came from a pipe - and had done so for as long as the command existed. The non-interactive branch passed a callback to node:readline/promises' question(), which returns a promise and ignores callbacks, so the process exited 0 without writing anything. Interactive use was never affected.
  • Read-only admin CLI commands wrote to the database. list-users ran the auth migration, which on an auth-disabled instance either aborted with a stack trace or silently bootstrapped an admin and claimed every existing conversion for it.
  • Failed deletes are visible now instead of being reduced to a red border, including from inside the archive view, where the shared error banner was suppressed by an inline style.
  • The login page no longer links to /signup in modes where that route does not exist.

Backward compatible for anyone setting none of the new variables. 1091 tests.

Full notes: CHANGELOG.md