Commit graph

15 commits

Author SHA1 Message Date
90824513a7
OperServ: CBAN — ban a channel name
CBAN ADD <#channel-glob> <reason> / DEL / LIST blocks users from creating
or joining a matching channel (m_cban is loaded). Another kind ("CBAN")
in the generalized X-line handler with a channel-mask normalizer; the
too-wide guard now ignores a leading channel prefix so #* is refused.
2026-07-14 02:24:13 +00:00
a7aacf347e
OperServ: LOGSEARCH — search the action log
LOGSEARCH [pattern] searches the incident log newest-first: match a bare
id (as stamped into a kick reason), or any word from the summary; no
argument lists the most recent. Auspex-gated (read-only investigation).

To make it comprehensive, the command audit trail now records every
notable action to the same incident log (not just to the audit channel,
and regardless of whether one is configured) — so registrations, drops,
akills, suspensions, vhosts, notes, and the like are all findable
alongside the kicks and kills stamped at the removal choke-point.
2026-07-14 02:16:59 +00:00
1f7591778f
OperServ: SHUN and CHANKILL
- SHUN <user@host> silences a matching user network-wide without
  disconnecting them — another kind ("SHUN") in the generalized X-line
  handler (m_shun is loaded), same event-sourced list and lazy expiry as
  AKILL/SQLINE/SNLINE.
- CHANKILL <#channel> [reason] AKILLs every distinct member host in one
  shot to clear a spam or attack channel; the G-lines the ircd applies
  also kill the sessions. Deduped by host, and never bans the operator who
  ran it. Both admin-only.
2026-07-14 02:00:17 +00:00
1daebc94a5
OperServ: JUPE — hold a server name against a rogue link
JUPE <server.name> [reason] introduces a fake server holding the name so
the real one can't link; JUPE DEL <name> squits it; JUPE LIST shows them.
Node-local (the introducing node owns the jupe, so it isn't federated —
that would collide SIDs across nodes) and re-asserted at burst. A fake
server id is allocated per jupe. New JupeServer/Squit actions serialise to
the mid-link SERVER introduction and SQUIT. Admin-only.
2026-07-14 01:51:07 +00:00
76a7162227
OperServ: per-IP session limiting with exceptions
The connection that puts an IP over its allowance is killed on connect.
The ircd's per-user IP (UID param 7) is now plumbed through UserConnect and
tracked per-IP in the live network view (incremented on connect, released
on quit).

- [session] default_limit sets the base allowance (0/absent = off).
- OperServ SESSION LIST <min> / VIEW <ip> inspect live counts.
- OperServ EXCEPTION ADD <ip-mask> <limit> [reason] / DEL / LIST override
  the limit per IP-mask (limit 0 = unlimited); event-sourced so they
  federate and survive restart, matched most-permissive-wins.

All admin-gated.
2026-07-14 01:46:09 +00:00
78ad909706
OperServ: SNLINE realname bans
SNLINE ADD [+expiry] <realname-regex> <reason> / DEL / LIST — a realname
R-line the ircd matches against connecting users' realnames. It's just
another kind ("R") in the generalized X-line handler: same event-sourced
list, lazy expiry, and burst re-assertion as AKILL/SQLINE, keyed by
(kind, mask). The mask is kept verbatim (a single-token regex; use . or
\\s for spaces) and an all-wildcard pattern is refused. STATS now counts
it too.
2026-07-14 01:36:08 +00:00
a67409e0d3
OperServ: OPER — runtime operator management
OPER ADD <account> <priv[,priv]> / DEL <account> / LIST grants or revokes
services-operator privileges (auspex, suspend, admin) at runtime, without
editing config and restarting. Runtime grants are event-sourced (Global,
so they federate and survive restart) and UNIONED with the declarative
[[oper]] config at the engine, so either source makes an account an
operator; a config oper can't be revoked here. Admin-only.

Factored the privilege-name parsing into Privs::from_names (+ names/union)
so config loading and runtime grants share one definition.
2026-07-14 01:33:30 +00:00
e45eab2cd6
OperServ: NEWS — logon and oper announcements
NEWS ADD <LOGON|OPER> <text> / DEL <LOGON|OPER> <number> / LIST. Logon news
is shown to every user as they connect; oper news is shown to an operator
when they log in. Admin-only to manage. Each item carries a stable id
assigned at add time and embedded in the log, so deletion is order-
independent under replay (DEL by number resolves to that id).

Enabling groundwork: the replicated network-wide lists (bans, now news)
are consolidated into one NetData struct threaded through apply() as a
single parameter — this replaces the akill parameter rather than adding
one, so the fold stays within its argument budget as the lists grow.
2026-07-14 01:26:12 +00:00
51d4ebf789
OperServ: INFO staff notes on accounts and channels
INFO ADD <target> <note> / DEL <target> / <target> attaches a staff note
to an account or channel (a #name is a channel, else an account). The note
is shown in that service's INFO — but to operators only (Priv::Auspex),
never to the account's own owner. Admin-only to set.

Follows the typed-field-on-the-entity pattern: an oper_note field folded
through AccountOperNoteSet (Global) / ChannelOperNoteSet (Local) events,
read via dedicated Store getters so it stays out of the public views and
the directory feed.
2026-07-14 01:15:00 +00:00
8ccc9fa8ea
OperServ: SVSNICK and SVSJOIN
Force a user's nick change or channel join, reusing the ForceNick and
ForceJoin actions the daemon already relies on (guest renames, auto-join)
so the ircd support is proven. SVSNICK validates the new nick; SVSJOIN
takes an optional key. Both admin-gated and resolve the target via
NetView.
2026-07-14 01:08:46 +00:00
f9aea30f81
OperServ: STATS enforcement overview
STATS reports the live counts OperServ holds — AKILL and SQLINE bans by
kind, and services ignores — as a quick at-a-glance check. Read-only, so
any operator can run it.
2026-07-14 01:02:14 +00:00
ab5dc2e931
OperServ: IGNORE — silence a user across all services
IGNORE ADD [+expiry] <mask> [reason] / DEL <mask> / LIST. While a user
matches, the dispatch choke-point drops their service commands silently.
A mask with an @ matches nick!*@host (ident isn't tracked); a bare mask
matches the nick; matching is case-insensitive with lazy expiry. Admin-
only, and an operator is never ignored (so staff can't lock themselves
out). Node-local and in-memory, like the auth and request throttles — a
fast transient moderation tool, not persisted or federated.
2026-07-14 01:00:05 +00:00
c5d93f29c1
OperServ: MODE override and KICK
Two channel operator tools:

- MODE <#chan> <modes> [params] forces a channel mode change (TS 1, so it
  applies regardless of the current TS). A status-mode target may be given
  as a nick — it's resolved to the uid the ircd's FMODE expects.
- KICK <#chan> <nick> [reason] removes a user, sourced from OperServ and
  attributed to the operator.

Both admin-gated. To resolve status-mode params, channel-mode parameter
arity became one shared helper (chanmode_takes_param + STATUS_MODES in the
api): the ircd module now delegates to it instead of keeping its own copy,
so burst-parsing and MODE-building can never drift.
2026-07-14 00:54:29 +00:00
930198b826
Expand OperServ: SQLINE nick bans, GLOBAL, and KILL
Generalise the network-ban store to carry the ircd X-line kind (defaulted
to the user@host G-line for existing records) so one event-sourced,
lazily-expiring, burst-reasserted list backs every ban type, and drive
ADD/DEL/LIST from one implementation per kind:

- AKILL stays the user@host G-line; SQLINE is a nick Q-line, its mask
  validated as a nick glob (an @ is refused so an AKILL-shaped mask can't
  become an over-broad nick ban). Both are keyed by (kind, mask).
- GLOBAL <message> announces to every user via a $* server-glob notice.
- KILL <nick> [reason] disconnects a user, attributed to the operator.

All four are admin-gated, and OperServ itself stays invisible to non-opers.
Bans and kills go out as typed actions (AddLine/DelLine/KillUser) the ircd
link serialises to ADDLINE/DELLINE/KILL.
2026-07-14 00:45:52 +00:00
d2c1d076fb
Add OperServ with AKILL network bans
The first operator module. AKILL manages network bans as a typed,
event-sourced list with lazy expiry, mirroring the patterns the other
modules use:

- AKILL ADD [+expiry] <user@host> <reason> stores the ban and drives an
  ircd G-line (applied to matching users already online and to future
  connections); AKILL DEL <mask|number> lifts it; AKILL LIST [pattern]
  shows the live list, numbered. Admin-only.
- Bans are Global events, so every node holds the list and re-asserts each
  one at burst with its remaining duration. Expired bans are hidden lazily
  and dropped at compaction.
- Masks are normalised to user@host (a nick! prefix is stripped, both
  sides lowercased) and an all-wildcard mask is refused.

Email (send_email) is already reachable from the api via ServiceCtx, and
adds AddLine/DelLine to the action vocabulary for any future X-line kinds.
2026-07-14 00:12:29 +00:00