Commit Graph
100 Commits
Author SHA1 Message Date
binwiederhier b65e642d05 Merge remote-tracking branch 'origin/main' into up-payer
# Conflicts:
#	docs/releases.md
2026-11-01 11:13:01 +00:00
binwiederhier 859e6443c7 Count forwarded messages for topics without local subscribers as wasted, and do not keep those topics alive
A cluster message whose topic is known on the receiving node but has no subscriber there was published to nobody and uncounted, and its Keepalive kept the topic from ever expiring: a passive node held every topic the active one published to. It is now counted in ntfy_cluster_messages_wasted_total and not published, so idle topics expire after topicExpungeAfter.
2026-10-31 19:43:29 +00:00
binwiederhier 25f595f8e7 Drop a node's leftover usage of a finished period instead of adding it to the new one
With several nodes, counts one node admitted in the last seconds of a key's period could be written after another node moved the row to the new period, and were added to the new day. They are the old day's usage, so they are dropped: an undercount of at most one sync interval, never a double count.
2026-10-31 19:27:12 +00:00
binwiederhier abcfd88cd8 Rename topic.Topic to topic.State, so the live topic can take the name later
The package comment now says the server's live topics are meant to move into the topic package.
2026-10-31 18:29:29 +00:00
binwiederhier cc590ca391 Drop the admin socket directory from the Docker images
The RUN step broke the armv7 release image (no QEMU on the release
runner), and the admin socket is off by default now, so the directory
is unused.
2026-10-31 17:54:47 +00:00
binwiederhier 3938bc6886 Shorten the v2.36.0 release notes, install docs for v2.36.0 2026-10-31 15:02:51 +00:00
binwiederhier ea71722ba7 Release notes for v2.36.0 2026-10-31 15:00:21 +00:00
binwiederhier 2e8506f827 Make the admin socket experimental and off by default
Rename listen-admin-unix to experimental-listen-admin-unix and drop the
/run/ntfy/admin.sock default: the CLI side (#2089, #2135) is not merged,
so nothing uses the socket yet. The startup warning no longer points at a
CLI fallback, and the docs say the commands do not use it yet.
2026-10-31 15:00:21 +00:00
binwiederhier ef3514e42c Add the topic package to the Docker build 2026-10-31 14:37:16 +00:00
binwiederhier 31f2143a3a Document the rate visitor key, the 7-day Matrix rule and the tier refresh 2026-10-31 14:05:37 +00:00
binwiederhier ac9c6b2bac Keep the UnifiedPush rate visitors in the topic service, derive the limiter key at push time
The server uses the topic package instead of the limit service for the rate
visitors: a subscribe sets the rate visitor (user ID and masked IP), a poll,
a stream close and the manager's keepalive record subscriber activity, a
refused push notes an unknown topic (insert-only). The limiter key is derived
on every push from the rate visitor's current tier (refreshed in the
background every minute, never on the publish path), so a downgrade or a
deleted account charges the IP. Before a 404 for an abandoned topic the row
is read from the database. The Matrix gateway rejects the pushkey under the
same 7-day rule; its 12 h per-node rule is gone.
2026-10-31 14:05:37 +00:00
binwiederhier 14f631da8f Add Manager.UsersByIDs, a bulk user lookup for the rate visitor refresh 2026-10-31 13:51:38 +00:00
binwiederhier 6ae42e7590 Add the topic package: per-topic cluster-wide state synced through the topic table
One row per topic (first_seen_at, subscribed_at, rate visitor user and IP,
updated_at), merged by rule (earliest, latest, last written) so the nodes can
write in any order, synced by the package's own 5 s worker from a dirty set.
User schema 10 -> 11 now creates this table.
2026-10-31 13:51:38 +00:00
Philipp Heckel a11f090df3 Rename the UnifiedPush payer to rate visitor, and its table to topic
"Rate visitor" is the term the docs already use. The table is called topic so it can hold more per-topic, cluster-wide state later. seen_at keeps its name, since a noted row's seen_at is a refused push, not a subscription.
2026-10-31 13:05:33 +00:00
binwiederhier 1c72a97736 Document shared UnifiedPush payers and the 404 for abandoned topics 2026-10-31 11:31:32 +00:00
binwiederhier b552856219 Merge remote-tracking branch 'origin/main' into up-payer 2026-10-31 11:31:18 +00:00
binwiederhier 9c6733d06c Bill UnifiedPush pushes to the topic's payer on every node, answer 404 for topics abandoned for 7 days 2026-10-31 11:31:09 +00:00
binwiederhier ffd16e16b7 Credit Jonathan Kats for reporting the same-IP visitor race 2026-10-31 11:28:49 +00:00
binwiederhier 2b726f4ea7 Split readUsersAndGrants into readUserAndGrants and readAllUsersAndGrants 2026-10-31 11:19:48 +00:00
binwiederhier d3ca4b1126 Keep the payers of UnifiedPush topics in the limit service, synced through the topic_payer table 2026-10-31 11:17:02 +00:00
binwiederhier 633d592095 Keep the admin socket in the startup 'Listening on' line 2026-10-31 11:13:01 +00:00
binwiederhier d4b5f383ed Add the topic_payer table to the user schema, migration 10 to 11 2026-10-31 11:12:46 +00:00
binwiederhier b4d9df9807 Move the shard types to types.go, trim the daily limit docs to what admins need 2026-10-31 10:56:28 +00:00
binwiederhier fdc88a3163 Decide in the Postgres writer whether a failed chunk may have been written, drop the dialect hook 2026-10-31 10:34:52 +00:00
binwiederhier bfa0bfa333 Admin socket: single-user lookup, safer socket file handling, Docker socket directory
- GET /v1/users?username= returns one user, so the CLI does not download all users
- Never replace a non-socket file at listen-admin-unix, and say so when the socket belongs to another user's server
- Log when the admin socket is listening; default to /var/run/ntfy on the BSDs too
- Deleting an admin user over HTTP returns 40302 (admin socket only), like the other admin-only operations
- Docker images ship a /run/ntfy directory for the socket
2026-10-31 03:31:01 +00:00
binwiederhier a40af7e627 Count a Postgres write that timed out after it was sent as written, not twice
A chunk whose statement was sent but whose answer came after the deadline may have committed
(lab: 60 messages counted as 86-89 at 2.2-2.4 s to Postgres). It is now retired like a written
chunk; if it did not commit, its counts are lost, which fails open like an outage. Errors from
the server, errors before sending, and every SQLite error still retry.
2026-10-31 03:15:45 +00:00
binwiederhier 0f3a57a2a2 Merge remote-tracking branch 'origin/main' into shared-daily-limits
# Conflicts:
#	docs/releases.md
#	server/server.go
2026-10-31 03:14:26 +00:00
binwiederhier 398cc69b52 Test that a daily denial keeps the bucket's tokens and that read-back keys are not used here, add benchmarks
The benchmarks (400k request-only keys, 50k publishers) measure a publish, the sync scan and
memory per key; they were used to compare the split counter/bucket shards with one merged map
(publish ~10% faster merged, sync scan 50x slower, memory the same), so the shards stay split.
2026-10-31 03:07:26 +00:00
binwiederhier 8e16b880c8 Close the cluster when the server stops
Server.stop never closed the cluster, so a stopped node stayed registered and its
heartbeat kept running against the closed database, logging from leaked goroutines.
In CI that raced with captureLog's unsynchronized buffer in a later test. captureLog
now uses syncBuffer as well.
2026-10-31 01:55:42 +00:00
binwiederhier 521ca530b5 Open the SQLite user database in the server and pass it to the user manager and the usage store
Like the Postgres pool: user.OpenSQLite opens the auth-file (case-sensitive LIKE),
NewSQLiteManager takes the handle and migrates it, and the usage store gets the same handle
instead of reaching into the manager (Manager.DB is gone). The usage table stays part of the
user schema.
2026-10-31 01:50:10 +00:00
binwiederhier 9ecbf4dc16 Export ntfy_db_up and health-check the primary like the replicas
A node cut off from its database only showed in the logs. The health check loop now always
runs and pings the primary too; ntfy_db_up (1/0, per pool, next to ntfy_db_pool_*) is the
result of the last check, so an alert can fire on ntfy_db_up{role="primary"} == 0.
2026-10-31 01:31:13 +00:00
binwiederhier 6c32bee44e Use the node's clock for periods and updated_at, require synced clocks
The service no longer reads the database clock: no clock offset, no clock query per sync
round. Periods, the read-back watermark and the rows' updated_at all use the node's clock, so
the database's clock does not matter; the app nodes must run NTP (documented in config.md).
2026-10-31 01:16:50 +00:00
binwiederhier 84861a015c Docs: show the admin socket startup warning instead of a CLI message that does not exist 2026-10-31 00:44:26 +00:00
binwiederhier a2656890d1 Drop the date from the admin socket startup warning 2026-10-31 00:42:49 +00:00
binwiederhier 6b4eca0654 Warn if the admin socket directory lets other users use or replace the socket 2026-10-31 00:37:42 +00:00
binwiederhier 6cb87c31b4 Rename adminSocketListener to adminUnixListener 2026-10-30 23:51:28 +00:00
binwiederhier c30365bc7b Test --wait-pid on processes owned by other users, add release note 2026-10-30 23:39:46 +00:00
binwiederhier 64d2819039 Merge branch 'fix/wait-pid-eperm-and-pidof-docs' of github.com:bekoeppel/ntfy into pr-1710 2026-10-30 23:36:04 +00:00
binwiederhier 89cd122952 Start the admin socket listener like the unix listener, without a server field 2026-10-30 23:35:33 +00:00
binwiederhier 0e0b2e4c7c Mention the deprecated database fallback in the admin socket startup warning 2026-10-30 23:27:00 +00:00
binwiederhier 0f49391494 Drop the deprecation of starting without the admin socket, just warn 2026-10-30 23:22:08 +00:00
binwiederhier e67d24b36a Merge remote-tracking branch 'origin/main' into pr-1969
# Conflicts:
#	docs/releases.md
2026-10-30 21:29:48 +00:00
binwiederhier fd3a48436b Keep the serve config checks running after base-url and message-size-limit
Move the base-url check out of the else-if chain instead of into a
helper, and test both cases with an invalid auth-default-access, which
fails right after the checks, instead of starting a server.
2026-10-30 21:27:59 +00:00
binwiederhier 1ca0e5a766 Merge remote-tracking branch 'origin/main' into pr-1969
# Conflicts:
#	cmd/serve.go
#	cmd/serve_test.go
2026-10-30 21:27:43 +00:00
binwiederhier 5737b0bd8c Start the admin socket in Run like the other listeners, and deprecate starting without it 2026-10-30 21:26:40 +00:00
binwiederhier 2cbf4abd95 Say that counts converge in about two sync intervals, and what promotion and the email cap leave out 2026-10-30 21:25:44 +00:00
binwiederhier ce476d676d Restore the utils tests next to the reset_at ones 2026-10-30 21:25:17 +00:00
binwiederhier 02446d985a Do not crash the account page when the server sends no reset_at 2026-10-30 21:25:01 +00:00
binwiederhier 05d7ae22cc Report the in-memory counts of the kinds without a daily counter again 2026-10-30 21:24:21 +00:00
binwiederhier 6a573ab5c1 Round the Postgres clock down to the second, like SQLite 2026-10-30 21:23:03 +00:00
binwiederhier 6674f3b5bd Cancel a stuck usage load or sync on Close instead of waiting for it 2026-10-30 21:22:38 +00:00
binwiederhier 3fef91d342 Read the period end of a daily denial under the counter lock 2026-10-30 21:21:59 +00:00
binwiederhier 2b46b90df9 Check the row's age in the outer prune delete, so a row refreshed meanwhile survives 2026-10-30 21:21:40 +00:00
binwiederhier 614242e10f Make the admin socket visitor IP a var 2026-10-30 21:20:28 +00:00
binwiederhier e6a6049d23 Web app: notify for a message only a poll stored, and test replays end to end
A message the poll stored before its live delivery has no unread marker
yet, so the WebSocket delivery that follows marks it unread and notifies
again, while a replayed message that came in live keeps its state.

The e2e tests publish within one second and reload, so the reconnect
and the startup poll replay the earlier messages: deleted ones stay
gone, and read ones stay read without a new browser notification.
2026-10-30 21:14:26 +00:00
binwiederhier df332a9942 Disable the admin socket with "-", like listen-http 2026-10-30 21:14:06 +00:00
binwiederhier fd6e83134a Drop the admin socket peer credentials from the audit log 2026-10-30 21:03:16 +00:00
binwiederhier c43c475be3 Web app: mark deleted notifications instead of keeping a separate store
Like the Android app, a deleted notification stays in the notifications
table with a deleted flag, so the existing duplicate checks skip it when
the server replays it, and a deleted newer version keeps an older one
out. The lists leave deleted notifications out, and they are pruned with
the others. The service worker does not store a deleted message again.
2026-10-30 20:54:03 +00:00
binwiederhier 59775edc72 Rename admin-socket to listen-admin-unix 2026-10-30 20:52:50 +00:00
binwiederhier 851d98c475 Merge remote-tracking branch 'origin/main' into replay-tombstones
# Conflicts:
#	docs/releases.md
2026-10-30 20:47:27 +00:00
binwiederhier a96b35e242 Web app: keep read state of a replayed WebSocket message
The WebSocket handler deleted every version of a message's sequence
before adding it, so a replayed message that was already stored came
back as unread and notified again, and a replayed older version
replaced a newer one. addNotification now replaces older versions of
the sequence itself, and skips a message if a newer version is stored.

Fixes #2090
2026-10-30 20:45:30 +00:00
binwiederhier c3ecea55c4 Show the reset time and the sync delay on the account page, document shared daily limits
Claude-Session: https://claude.ai/code/session_01DeXuhSjq5Gta5qPJgSceFe
2026-10-30 20:42:27 +00:00
binwiederhier c113e20677 Share daily limits through the usage table, drop the midnight reset and the stats queue
The server builds the usage store on the user database (the shared pool on
Postgres, the auth-file on SQLite) and starts the limiter before serving. A
visitor without a user writes its message count from a tenth of the cap on,
everyone else from the first message; anonymous emails get the daily cap the
replenish interval implies. The account API reports reset_at. The user stats
columns are no longer read or written.

Claude-Session: https://claude.ai/code/session_01DeXuhSjq5Gta5qPJgSceFe
2026-10-30 20:41:36 +00:00
binwiederhier e73282539a Merge branch 'adminsock-api' into adminsock-socket
# Conflicts:
#	docs/releases.md
2026-10-30 20:40:54 +00:00
binwiederhier ceb0666d36 Shorter release notes for the internal admin API 2026-10-30 20:40:41 +00:00
binwiederhier f8f0d87253 Merge branch 'adminsock-api' into adminsock-socket
# Conflicts:
#	docs/releases.md
#	server/server.go
#	server/server_admin_socket.go
#	server/server_admin_test.go
2026-10-30 20:40:33 +00:00
binwiederhier 862bc5e14f Merge remote-tracking branch 'origin/main' into adminsock-api
# Conflicts:
#	docs/releases.md
2026-10-30 20:37:09 +00:00
binwiederhier dad9cfa03b Sync daily counts with the usage table in a background worker
Every 5 s a node writes the unflushed counts of its promoted keys and reads back
the rows changed since the last round; at startup it loads the current rows
(waiting up to 30 s, then serving from memory while it keeps loading). A key is
promoted once it reaches its rule's threshold, or when another node's row for it
shows up. Rows not written for 25 h are pruned hourly.

Claude-Session: https://claude.ai/code/session_01DeXuhSjq5Gta5qPJgSceFe
2026-10-30 20:33:09 +00:00
binwiederhier e074eaffa3 Add the usage store on SQLite and Postgres
One row per key: same period adds, a newer period replaces, and a leftover of an
older period is added to the stored one rather than taking the row back. Writes
are sorted by key and chunked; reads stream rows changed since a database time.

Claude-Session: https://claude.ai/code/session_01DeXuhSjq5Gta5qPJgSceFe
2026-10-30 20:28:56 +00:00
binwiederhier b4669de064 Add the usage table in user schema migration 9 -> 10, zero the stats_* columns
Claude-Session: https://claude.ai/code/session_01DeXuhSjq5Gta5qPJgSceFe
2026-10-30 20:27:29 +00:00
binwiederhier 59cee8430a Split daily counters from token buckets, roll each key over on its own 24h period
Daily counts (messages, emails, calls) now live in per-key counters that start
over lazily when the key's period ends; buckets keep their tokens. ResetAt
reports the end of the key's period. Seed, ResetUsage and Config.ResetTime are
gone, and an idle key is forgotten only once its buckets are full again.

Claude-Session: https://claude.ai/code/session_01DeXuhSjq5Gta5qPJgSceFe
2026-10-30 20:23:47 +00:00
binwiederhier 9280bc1e14 Add per-key 24h periods from a hashed reset offset
Claude-Session: https://claude.ai/code/session_01DeXuhSjq5Gta5qPJgSceFe
2026-10-30 20:15:19 +00:00
binwiederhier 5c2a1ddeef Release notes and install docs, prep v2.35.0
Claude-Session: https://claude.ai/code/session_01DeXuhSjq5Gta5qPJgSceFe
2026-10-30 13:24:49 +00:00
binwiederhier e7cc914087 Keep a topic's rate visitor alive while any stream is open on it
Liveness no longer comes from keepalives: a topic keeps its rate visitor
while it has an open stream, and for a day after the last one closed or
the last subscribe. This removes the keepalive matching, taking a stale
topic back and its write re-check.

Claude-Session: https://claude.ai/code/session_01DeXuhSjq5Gta5qPJgSceFe
2026-10-30 03:35:14 +00:00
binwiederhier f666779ee8 Check that a stream may still write before it takes a topic back
Claude-Session: https://claude.ai/code/session_01DeXuhSjq5Gta5qPJgSceFe
2026-10-29 23:39:13 +00:00
binwiederhier 1883645c1a Keep a topic's rate visitor alive by the topic, for any stream with its key
A stream's keepalives refreshed only its own visitor, so a topic that held
the visitor of a newer stream or a poll from the same key lost it after a
day although a stream was still open. The topic now keeps when a
subscriber with its rate visitor's key was last seen, and a stream takes a
stale topic back.

Claude-Session: https://claude.ai/code/session_01DeXuhSjq5Gta5qPJgSceFe
2026-10-29 22:54:19 +00:00
binwiederhier 1185578dc5 Do not turn off email without a tier when the refill is slower than a day
Claude-Session: https://claude.ai/code/session_01DeXuhSjq5Gta5qPJgSceFe
2026-10-29 22:45:43 +00:00
binwiederhier be440b62ae Make the v2.35.0 release notes briefer and accurate
Tier to tier changes keep spend (no tier to a tier never did), only a tier's daily email limit is a cap, only the read over the size limit is refunded, and the #2119 bullet describes the fix.

Claude-Session: https://claude.ai/code/session_01DeXuhSjq5Gta5qPJgSceFe
2026-10-29 21:10:24 +00:00
binwiederhier 4ed82ddd69 Do not cap the emails of visitors without a tier at a day's refill
Without a tier, the daily email limit is only derived from the refill, for
display. Enforcing it as a cap cut what the email bucket allowed: with a burst
of 5 and a refill every 288 minutes, 5 emails a day instead of about 10. Only
a tier's daily email limit is a cap now, as before.

Claude-Session: https://claude.ai/code/session_01DeXuhSjq5Gta5qPJgSceFe
2026-10-29 21:10:24 +00:00
binwiederhier 63e25d667e Keep a same-key rate visitor on a poll even if it is stale
A stale one has only its tier from back then to lose, and a publish drops it anyway. Simpler without the check.

Claude-Session: https://claude.ai/code/session_01DeXuhSjq5Gta5qPJgSceFe
2026-10-29 20:31:33 +00:00
binwiederhier 3cae50f18d Keep a stream as the topic's rate visitor when its subscriber polls
Since every request gets its own visitor, a poll from the subscriber of an
open stream replaced the stream's visitor as the topic's rate visitor. Only
the stream's keepalives keep a rate visitor alive, so a day later UnifiedPush
publishes failed with 50701 while the stream was still open. A poll from the
same key now keeps the live rate visitor (and keeps it alive) instead.

Claude-Session: https://claude.ai/code/session_01DeXuhSjq5Gta5qPJgSceFe
2026-10-29 19:46:13 +00:00
binwiederhier d397e9d075 Put security first in the v2.35.0 release notes and merge the bug fix sections
Claude-Session: https://claude.ai/code/session_01DeXuhSjq5Gta5qPJgSceFe
2026-10-29 16:44:17 +00:00
binwiederhier 7aa105bdec Show the day's remaining emails on the account again
emails_remaining was clamped to what the email bucket holds right now, so a fresh
Supporter saw 10 of 50. It is the daily limit minus today's emails again, as in
v2.34.0 and like messages_remaining; the bucket still refuses a burst past it.

Claude-Session: https://claude.ai/code/session_01DeXuhSjq5Gta5qPJgSceFe
2026-10-29 16:10:36 +00:00
binwiederhier 1e54713e29 Credit the reporter of the Matrix push key fix 2026-10-29 13:49:36 +00:00
binwiederhier eb9a12d734 Name the visitor's shared environment field env instead of embedding it
Claude-Session: https://claude.ai/code/session_01DeXuhSjq5Gta5qPJgSceFe
2026-10-29 13:46:56 +00:00
binwiederhier 647698c607 Keep the visitor's subscription methods in visitor.go
Only the gauge lives in visitor_subscriptions.go; the tests follow their code.

Claude-Session: https://claude.ai/code/session_01DeXuhSjq5Gta5qPJgSceFe
2026-10-29 13:24:57 +00:00
binwiederhier 31840bef1a Move the subscription gauge into visitor_subscriptions.go and test it
Covers the limit, release on stream close without leaving keys behind,
concurrent acquires, sharing per key, and the end of the Firebase penalty.

Claude-Session: https://claude.ai/code/session_01DeXuhSjq5Gta5qPJgSceFe
2026-10-29 12:22:41 +00:00
binwiederhier 02be719ce2 Web app: don't add deleted notifications again when a poll replays them
The server replays the whole second of a since=<id> marker, so a poll
returns messages the user deleted. Remember deleted notifications and
skip them (and older versions of their sequence), and don't move the
marker back when a poll only replayed known messages, which made each
poll replay a different part of that second.

Fixes #2098
2026-10-29 11:31:45 +00:00
binwiederhier 89cee1cd11 Keep a topic's rate visitor for as long as its subscriber is, not its key
Stale read the limiter key's last use, which every charged publish refreshes, so a topic kept
a vanished subscriber's limits (and its UnifiedPush subscription) for as long as anyone
published to it. The visitor now carries its own keepalive, set when it is built and by the
subscribe handlers' keepalive loops, like the shared visitor's seen was.

Also from the review: Prune returns and the manager logs the number of forgotten keys, the
unused visitorID wrapper goes, a stale comment and test name are updated, and the release
notes get the #1051 entry.

Claude-Session: https://claude.ai/code/session_01DeXuhSjq5Gta5qPJgSceFe
2026-10-29 03:21:37 +00:00
binwiederhier d61081fe4e Name the shared visitor environment Server.visitors
Claude-Session: https://claude.ai/code/session_01DeXuhSjq5Gta5qPJgSceFe
2026-10-29 03:04:24 +00:00
binwiederhier e2250f1671 Merge remote-tracking branch 'origin/main' into limit-2118 2026-10-29 02:43:07 +00:00
binwiederhier 90fb310464 Name the hash field correctly in admin API errors, and report unused tokens as never used 2026-10-29 02:37:38 +00:00
binwiederhier 9693d393c8 Merge branch 'limit-fixes' into visitor-per-request
The three fixes apply as they are (the email guard without the visitor mutex, which this
branch no longer has). Of the new tests, the two that pin the shared visitor's SetUser flush
and the expunge of visitor objects have no counterpart here; the rest compare visitor keys
where they compared object identity.

Claude-Session: https://claude.ai/code/session_01DeXuhSjq5Gta5qPJgSceFe
2026-10-29 02:30:47 +00:00
binwiederhier aa9b89ef7b Add release note for terabyte size units 2026-10-29 02:29:50 +00:00
binwiederhier 62abb9b729 Close three gaps in the limit rework and pin its behavior with tests
A tier with a daily email limit of zero sends no emails (the limit service reads a daily
limit of zero as "no cap"), a tier edited in place flushes the visitor's pending user stats
before resetting its local counts like a tier ID change does, and a bucket refill with a
timestamp older than its last one neither charges tokens nor moves the refill point back.

The tests pin what the rework changed and what it must keep: shared keys count once in the
user stats, an expunged visitor continues its counts, the daily reset keeps the buckets,
zero bursts admit nothing, seeds apply once, prefix keying, tier changes in all directions,
concurrency on a shared key, and the account page's remaining values matching admissions.

Claude-Session: https://claude.ai/code/session_01DeXuhSjq5Gta5qPJgSceFe
2026-10-29 02:28:25 +00:00
binwiederhier 8baa89871f Reset the whole ACL and list all users' tokens only over the admin socket 2026-10-29 02:21:01 +00:00
binwiederhier 64c65311be Inline readAdminTokenUser into the token handlers 2026-10-29 02:08:15 +00:00
binwiederhier a6cd0e4d7e Build the shared visitor config and IP limits once
Visitors are built per request, so what they share (the keying and limit
config, the config-based limits of visitors without a tier, the limiter and
the subscription gauge) is built once in New. Keys are built with string
concatenation instead of fmt.Sprintf.
2026-10-29 02:06:26 +00:00
binwiederhier f90c97f3de Keep new visitors fresh and stop checking the user in the auth and account limits
A visitor's key is touched when the visitor is built, so a subscriber whose
request skipped the limiter (an exempt prefix on an existing topic) is not
dropped as a stale rate visitor. The auth and account limits are per key and
ignore the user, as on main.
2026-10-29 01:55:33 +00:00
binwiederhier e0ee4b090f Merge remote-tracking branch 'origin/main' into adminsock-api
# Conflicts:
#	docs/releases.md
#	server/server_admin.go
#	server/server_admin_test.go
2026-10-29 01:46:43 +00:00