Commit graph

228 commits

Author SHA1 Message Date
8c77016aed
helpserv: HELP EXTBANS lists the network live extban set with a friendly example for each 2026-07-17 22:23:54 +00:00
77d09c4bdc
akick: accept a matching extban only the ircd knows (ircd-enforced +b), reject acting extbans with a clear reason 2026-07-17 22:01:32 +00:00
c990eb1e1e
extban: learn the ircd live set from CAPAB EXTBANS and validate AKICK/MODE against what it actually offers 2026-07-17 21:47:02 +00:00
74a983467c
akick: match the server and fingerprint extbans from the SERVER name and ssl_cert metadata the s2s stream carries 2026-07-17 21:23:25 +00:00
f7c38cedad
chanserv: full AKICK extban registry, [extban] enabled gate, passive extbans pushed as channel bans for the ircd to enforce 2026-07-17 21:06:14 +00:00
9a197fca3d
db: one timestamp for a ban/account's logged event and in-memory record, so a peer replaying it converges (two now() calls could straddle a second)
All checks were successful
CI / check (push) Successful in 3m55s
2026-07-17 20:38:50 +00:00
47dfa76fd5
engine: a takeover keeps the account's founded channels (the account still exists) — only a genuine drop or expiry releases them
Some checks failed
CI / check (push) Failing after 3m56s
2026-07-17 20:23:51 +00:00
426fc694a2
akick: match extbans (account/realname/realmask/unauthed) using the ident, real host and real name the UID carries but was discarding
All checks were successful
CI / check (push) Successful in 4m0s
2026-07-17 19:47:34 +00:00
bc4fada354
api: type GroupServ flags (GroupFlag/GroupFlags via a shared flag_set! macro); delete the stringly apply_flags
All checks were successful
CI / check (push) Successful in 4m0s
2026-07-17 18:47:08 +00:00
65323caaeb
chanserv: FLAGS maps sop/halfop presets to flag letters (oa=+ao), fixing privilege escalation when editing a HOP/SOP entry
All checks were successful
CI / check (push) Successful in 4m2s
2026-07-17 18:14:58 +00:00
5dcd216eeb
api: ordered Rank enum (founder>admin>op>halfop>voice) replaces the coarse u8 access rank, so PEACE distinguishes every tier
All checks were successful
CI / check (push) Successful in 3m59s
2026-07-17 17:33:53 +00:00
f2ba876ce4
botserv: bots join +ao (protected admin + op), keeping op alongside protect
All checks were successful
CI / check (push) Successful in 3m53s
2026-07-17 17:11:25 +00:00
73467b91ca
botserv: bots join channels as protected admins (+a) so ordinary ops can't kick or deop them
All checks were successful
CI / check (push) Successful in 3m50s
2026-07-17 16:52:00 +00:00
e2330c56ff
chanserv: SOP protect (+ao) and founder owner (+qo) with standard ~ & @ prefix tiers
All checks were successful
CI / check (push) Successful in 4m12s
2026-07-17 16:10:36 +00:00
b5aef650f2
chanserv: all op-and-above tiers grant +o for a single @ prefix; tier distinction stays in the access list
All checks were successful
CI / check (push) Successful in 4m12s
2026-07-17 15:58:11 +00:00
2f6fd41465
chanserv: SOP protect tier over AOP (+ao), founder owner (+qo); resolve op access by capability not mode string
All checks were successful
CI / check (push) Successful in 3m59s
2026-07-17 15:43:16 +00:00
f5c976eb56
api/gameserv: type email ExpiryTarget and chess Ending as enums (drop stringly returns)
All checks were successful
CI / check (push) Successful in 3m53s
2026-07-17 14:15:39 +00:00
7a5f1502a4
infoserv: type the news kind as an enum at the store boundary
All checks were successful
CI / check (push) Successful in 3m53s
2026-07-17 13:53:53 +00:00
ef34c04c8d
operserv: type the X-line kind as an enum at the command/store boundary, wire token in storage 2026-07-17 13:47:10 +00:00
2c8ba4460d
forbid: type the FORBID kind as an enum at the store boundary, string only in storage
All checks were successful
CI / check (push) Successful in 3m56s
2026-07-17 13:26:16 +00:00
1fb3615b7e
auth: warn on unknown [[oper]] privilege names instead of silently dropping them
All checks were successful
CI / check (push) Successful in 3m53s
2026-07-17 12:45:41 +00:00
e3b83f4a92
operserv: REHASH announces the reload in the log channel via DebugServ
All checks were successful
CI / check (push) Successful in 4m1s
2026-07-17 11:02:29 +00:00
64b675e61f
operserv: REHASH reloads config live without a restart
All checks were successful
CI / check (push) Successful in 3m54s
2026-07-17 10:46:12 +00:00
e112b8737c
auth: deferred login is authoritative in the account map, not just ircd metadata
All checks were successful
CI / check (push) Successful in 3m46s
2026-07-17 03:30:47 +00:00
75c6537532
standard replies: emit IRCv3 FAIL/WARN/NOTE for service errors, config-gated
All checks were successful
CI / check (push) Successful in 3m42s
2026-07-17 02:53:48 +00:00
fcca7ac12b
chanserv: channel seen checks channel membership, not global presence
All checks were successful
CI / check (push) Successful in 3m45s
2026-07-17 01:54:55 +00:00
66eb644a07
chanserv: channel-scoped seen with last message, replied in-channel
All checks were successful
CI / check (push) Successful in 3m47s
2026-07-17 01:41:47 +00:00
f2774f13fe
services: all pseudo-clients join a configurable channel (default #services)
All checks were successful
CI / check (push) Successful in 3m39s
2026-07-17 01:23:18 +00:00
657154e268
services: assigned bot fronts channel modes, not chanserv
All checks were successful
CI / check (push) Successful in 3m41s
2026-07-17 01:17:29 +00:00
96654b5e5a
groupserv: gate channel access on the c flag, document !group
All checks were successful
CI / check (push) Successful in 3m43s
2026-07-17 01:00:27 +00:00
b87a0c56a2
services: label as network service in whois
All checks were successful
CI / check (push) Successful in 3m44s
2026-07-17 00:30:51 +00:00
eaf3111917 whois: answer IDLE for pseudo-clients 2026-07-16 23:22:35 +00:00
a60a6df19d debugserv: sourced auth feed, drop icons 2026-07-16 23:08:30 +00:00
9bdda721f3 keycard: redeem website login keycards over SASL 2026-07-16 22:27:59 +00:00
38d12cb0bb debugserv: live services activity feed 2026-07-16 22:27:35 +00:00
6c403c01b0 services: configurable pseudo-client host 2026-07-16 19:15:48 +00:00
2f9790feac
auth: offload IDENTIFY + SASL PLAIN verify off the engine lock
All checks were successful
CI / check (push) Successful in 3m47s
Both ran scram verify_plain (~1s PBKDF2 at 1.2M iters) inline under the engine
lock, freezing the whole daemon per login. Add NetAction::DeferAuthenticate +
AuthThen continuation + ctx.defer_authenticate, mirroring DeferPassword: the
module/SASL path fetches the verifier cheaply and defers; the link layer runs
verify_plain on spawn_blocking, then Engine::complete_authenticate finishes the
login (IDENTIFY reuses the same ctx helpers, so its login/AJOIN/vhost/memo
side-effects are unchanged). Tests resolve the defer inline (cfg(test)). The
gRPC web-login path was already fixed; no login path stalls services now.
(GHOST/DROP/CERT/GROUP still verify inline but are rare account ops, not logins.)
2026-07-16 19:04:18 +00:00
63fc2fb2c0
grpc: run authenticate's PBKDF2 verify off the engine lock
All checks were successful
CI / check (push) Successful in 3m54s
The Authenticate RPC held the engine Mutex across scram verify_plain, which at
production iteration counts (1.2M) is ~0.8s of PBKDF2 on the async reactor —
freezing the whole daemon (IRC link, gossip, every RPC) for the duration and
serializing all logins. Fetch the verifier under the lock (cheap), then run
verify_plain on spawn_blocking, lock released. 6 concurrent logins: 823ms (was
~4460ms serialized). set_password/register already offload this way; drop the
now-unused authority_authenticate.
2026-07-16 18:40:30 +00:00
2e92f75a90
chanserv: PEACE never blocks acting on yourself (self-deop)
All checks were successful
CI / check (push) Successful in 3m58s
!deop with no target deops the caller, but peace_blocks compared the target's
access rank to the caller's — equal for self — so PEACE refused it with 'you
can't act against someone with equal or higher access.' Exempt the self case
(target uid == caller uid) in peace_blocks: acting on yourself isn't acting
against anyone, so you can always drop your own status. Covers DEOP/DEVOICE and
the kick/ban paths too.
2026-07-16 17:59:00 +00:00
1f6a11dba2
statserv: persist per-channel activity across restart too
All checks were successful
CI / check (push) Successful in 3m49s
The earlier StatsSet fix persisted only the shared namespaced counters. The
per-channel BOTSTATS view (lines seen + top talkers, from /statserv #chan) lived
on the LiveChannel struct, which is rebuilt from each burst — so it reset to zero
on restart. Move it to a name-keyed Network.chan_activity map (independent of live
membership, seedable before the burst) and carry it in the StatsSet snapshot
(new serde-default `channels` field) alongside the counters. Reworded the
notice from 'seen this session' now that it persists.
2026-07-16 17:50:11 +00:00
8a9b6a37ca
botserv: op assigned bots on join; statserv: persist counters across restart
Some checks failed
CI / check (push) Failing after 3m48s
Problem 1: an assigned bot joined via IJOIN with no status mode, so it had no
+o. Join it with the 4-param IJOIN form (ts 1, mode o) so it's opped, matching
Anope's default bot modes (+o), and exempt bots from SECUREOPS/RESTRICTED so the
op is never stripped.

Problem 2: the shared stat counters lived only in memory, so a restart wiped
them. Snapshot them to the log (StatsSet event, folded into NetData + compaction)
periodically and on shutdown, and reseed the live registry from the log at
startup. Live gauges (online counts) stay re-derived, not stored.
2026-07-16 17:32:20 +00:00
34bc7d69f0
grpc: provision sets the verifier on an already-existing account
All checks were successful
CI / check (push) Successful in 3m50s
An Anope import creates accounts (channel ownership, vhosts, certs) but can't
carry the one-way password hash, so they exist without a verifier. provision
then refused them as AlreadyExists, so the website's backfill could never give
migrated members a credential — every one was locked out of password login.
Make provision update the verifier in place on an existing account (logged as
AccountPasswordSet), and treat an empty scram512 as absent consistently in
apply(). Keyed by name, so imported channel/vhost/ban data stays attached.
2026-07-16 16:53:06 +00:00
9d94dd5eb0
chanserv: support param mode locks (+f flood, +j joinflood)
Some checks failed
CI / check (push) Has been cancelled
Mode locks were char-only, so Anope FLOOD/JOINFLOOD locks were dropped on
migration. Carry a value per locked param-mode through the event log, MLOCK
parsing/display, drift enforcement, compaction, and the Anope importer, so a
migrated network keeps its flood protection verbatim.
2026-07-16 15:23:09 +00:00
062eae703e
add Anope->Echo migration importer (echo import)
All checks were successful
CI / check (push) Successful in 3m41s
New 'echo import <anope.json> <out.log> [node]' subcommand builds a fresh event
log from an Anope db_json: accounts (identity only — Anope's one-way password
hashes can't become SCRAM verifiers, so migrated users auth by certfp/external
authority), grouped nicks, cert fingerprints, vhosts, channels (+desc/topic/
assigned bot), access mapped to op/voice by each channel's AUTOOP/AUTOVOICE
thresholds, param-less mode locks, BotServ bots (service pseudo-clients skipped),
and memos. Read-only on the source; self-verifies by replaying the produced log.
Verified against the live backup (11 accounts, 10 channels, 10 bots) + a unit
test over a synthetic fixture. The prerequisite for a safe cutover.
2026-07-16 13:05:45 +00:00
b23bf5d8a9
test: property-test gossip convergence between two nodes
All checks were successful
CI / check (push) Successful in 3m45s
A fresh peer that backfills a node's log via the version vector must reach the
same global state (accounts, akills, forbids, groups); channels/jupes are Local
and correctly don't replicate. Guards the core federation guarantee — a
distinct invariant from same-node replay (exercises missing_for + version_vector
+ cross-node ingest).
2026-07-16 11:17:43 +00:00
56cac370eb
test: cover removal/mutation events in the parity property tests
Some checks failed
CI / check (push) Has been cancelled
Extends build_broad_state with vhost/suspend/akill/forbid/news/cert/access/
group-member removals and a memo read — the asymmetric removal apply arms are
exactly where the drop-purge bug hid. Both the fold-parity and compaction
round-trip tests pass over the full ~55-operation sequence, so live==replay
==compacted holds across adds, mutations and removals.
2026-07-16 11:15:57 +00:00
289470ca0c
db: compaction was silently dropping channel and jupe state
All checks were successful
CI / check (push) Successful in 3m52s
compact() rebuilds channels field-by-field, and it omitted several fields, so
automatic log compaction (should_compact -> compact) silently deleted them:
channel url, email, successor, noexpire, the restricted/noautoop/bot_greet/
nobot settings, and every jupe. Emits them all now (settings gated on !=
default via a new PartialEq). Adds a compaction round-trip property test
(compact()+reopen == before) alongside the fold-parity one; both share the
broad build/snapshot helpers.
2026-07-16 11:08:55 +00:00
8c55347d80
test: broaden the fold-parity property test to the full event surface
All checks were successful
CI / check (push) Successful in 3m49s
Extends the round-trip live-vs-replay test to ~45 event types (bots, news,
reports, help tickets, oper grants, session exceptions, vhost forbid/template,
entrymsg, noexpire, oper notes, group founder, default bot, account email).
All pass — jupes was the only divergence — so this now guards essentially
every event's live mutation against its apply() arm.
2026-07-16 11:02:07 +00:00
90167dd46f
db: persist jupes across restart (event-source them)
All checks were successful
CI / check (push) Successful in 3m50s
A fold-parity property test caught it: jupes were plain in-memory Db fields
that logged no event, so after any services restart every juped server was
silently un-juped and could relink. Moved jupes into NetData (like akills/
forbids/groups) and event-sourced them with JupeAdded/JupeRemoved (Local
scope), so a jupe now replays from the log. Adds the round-trip property test
(live state == replayed state) as a permanent guard against this bug class.
2026-07-16 10:56:22 +00:00
61005f52f5
services: throttle emailed codes to stop RESEND/RESETPASS email-bombing
All checks were successful
CI / check (push) Successful in 3m46s
REGISTER was rate-limited but RESEND and RESETPASS weren't — anyone could
repeatedly request confirmation/reset codes for any account with an address
on file, flooding the victim's inbox and burning the service's sender
reputation. A per-account 60s cooldown (code_issue_wait, mirroring the vhost
request throttle) now gates both paths; guessing was already infeasible
(2^40 code + 5-try limit), so this closes the abuse, not an auth hole.
2026-07-16 10:41:52 +00:00