Commit graph

26 commits

Author SHA1 Message Date
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
952078aa7e services: configurable pseudo-client umodes
All checks were successful
CI / check (push) Successful in 3m43s
2026-07-17 00:01:24 +00:00
eaf3111917 whois: answer IDLE for pseudo-clients 2026-07-16 23:22:35 +00:00
9bdda721f3 keycard: redeem website login keycards over SASL 2026-07-16 22:27:59 +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
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
d1685f7e53
inspircd: include membid in outbound IJOIN
All checks were successful
CI / check (push) Successful in 3m49s
Services IJOIN was ':<uid> IJOIN <chan>' with no membership id, but InspIRCd
requires <chan> <membid> (min 2 params). On link the ircd rejected the whole
server connection with 'Insufficient parameters' the moment a BotServ bot joined
its assigned channel, splitting services. Add a monotonic membid, matching how
InspIRCd itself sends IJOIN. Validated against a real InspIRCd 4 with production
data: full burst to ENDBURST, all bot IJOINs accepted, no split.
2026-07-16 16:36:19 +00:00
320a591ae3
engine: track the server tree so a hub SQUIT cascades
All checks were successful
CI / check (push) Successful in 3m50s
SQUIT arrives once for a splitting server (by SID), but a hub takes its
whole subtree with it — users behind downstream servers were left as stale
state. The parser now distinguishes a sourced downstream SERVER (tracked
with its parent) from the unsourced uplink handshake, the engine keeps the
SID->parent tree, and a SQUIT forgets every user across the departed
server's subtree. Tree is rebuilt each link. Wire formats verified against
the InspIRCd 4 m_spanningtree source.
2026-07-16 10:31:29 +00:00
4aff734340
engine: forget a split server's users on SQUIT
All checks were successful
CI / check (push) Successful in 3m47s
A netsplit is signalled once via SQUIT, not as a QUIT per user, so every
user behind the departed server lingered in services' state — stale
sessions, session-limit slots, and channel memberships. The parser now
surfaces ServerSplit and the engine forgets every uid carrying that
server's SID prefix, leaving other servers' users untouched.
2026-07-16 10:10:20 +00:00
63ecd79b12
engine: handle inbound KILL — forget users, reintroduce bots
KILL was never parsed, so a killed user lingered in services' state (stale
session, session-limit slot, channel membership) and a killed services bot
vanished for good. The parser now surfaces UserKilled; a killed real user is
forgotten like a QUIT (shared forget_user helper), while a killed bot is
dropped and reconciled so it is reintroduced and rejoins its channels.
2026-07-16 10:06:36 +00:00
7e868babc3
inspircd: restore logins from replayed accountname metadata
All checks were successful
CI / check (push) Successful in 3m45s
The inbound parser ignored METADATA entirely, so on a services netburst
(after a restart/relink) the ircd's replayed 'accountname' metadata was
dropped — every logged-in user looked logged out to services until they
re-identified, losing ChanServ access. Parse METADATA <uid> accountname
into a new AccountLogin event that restores account_of (empty = logout);
our own echoes and other keys are filtered.
2026-07-16 09:54:35 +00:00
b2442f85e6
OperServ: add SHUTDOWN and RESTART
All checks were successful
CI / check (push) Successful in 3m31s
2026-07-16 01:02:10 +00:00
ccbbb91fda
OperServ: add SVSPART
All checks were successful
CI / check (push) Successful in 3m36s
SVSPART <nick> <#channel> [reason] forces a user out of a channel
(admin-only), completing the SVS command family alongside SVSNICK and
SVSJOIN. New ForcePart action rendered as the ircd SVSPART command.
2026-07-16 00:00:18 +00:00
54ad013e49
Wire account registration to the ircd's ENCAP SWACCTREG/SWACCTRES relay
All checks were successful
CI / check (push) Successful in 3m53s
Echo is the authority the ircd account module forwards to: parse
ENCAP <us> SWACCTREG <reqid> <origin> <kind> <account> <p2> :<p3> into an
account request, and answer the origin server with
ENCAP <origin> SWACCTRES <reqid> <kind> <account> <status> <code> :<message>.
Thread the origin through the reply so responses route back to the
requesting server. Replaces the placeholder ACCTREGISTER/ACCTREGRESULT
names that nothing on the wire actually spoke.
2026-07-15 16:34:20 +00:00
993f5b2eea
Rename the project to Echo (was fedserv)
Rebrand the daemon and workspace: the binary is now `echo`, every crate
is `echo-*` (`echo-api` and the module crates), Rust imports use
`echo_*`, the gRPC proto is `proto/echo.proto` with package `echo.v1`,
and the log filter, gossip peer-name default, and on-disk store default
(`echo.db.jsonl`) follow. Docs updated throughout. No behaviour change;
crate directories and the config schema are untouched.
2026-07-14 15:24:41 +00:00
a803177f8b
Nest the ircd link under modules/protocol/
The protocol link is a different kind of module from the service
pseudo-clients, so give it its own home: modules/inspircd ->
modules/protocol/inspircd. A future ircd link is a new crate alongside
it. Workspace member, dependency path, the crate's own api path, and the
docs are updated to match. No code change.
2026-07-14 14:28:18 +00:00
596630df53
modules: split services and the ircd link into external crates
nickserv, chanserv and the InspIRCd protocol move out of the binary into their
own workspace crates (fedserv-nickserv, fedserv-chanserv, fedserv-inspircd),
each depending only on fedserv-api. human_time and the branded account emails
move into the SDK crate so a module needs nothing from core; the engine keeps
its own inherent methods and builds emails via fedserv-api too. The bin now
constructs each module from its crate instead of an in-tree #[path] include.
Proves the SDK is self-sufficient: a third-party module is the same shape.
2026-07-13 01:33:56 +00:00
931b8727e9
modules: extract fedserv-api leaf crate (protocol + service vocabulary)
Move NetEvent/NetAction/RegReply/Protocol and Sender/ServiceCtx into a
dependency-free fedserv-api crate that a module builds against. Core keeps
referring to them through re-export shims at crate::proto and
crate::engine::service, so no consumer changes. Groundwork for external
service and protocol modules.
2026-07-13 00:36:42 +00:00
06e9da4dc8
email: HTML templates and multipart messages
Emails now render an HTML template from templates/email with a plaintext
fallback, sent as multipart/alternative. A configurable brand name shows
in the template. Reset and confirmation mails share one styled base.
2026-07-12 15:57:34 +00:00
a2957ffe02
email: outbound mail subsystem and RESETPASS
Adds a config-driven mailer: a SendEmail action the link layer pipes to
a configured command (sendmail -t, msmtp, ...) off-thread. NickServ
RESETPASS <account> emails a short-lived code to the address on file;
RESETPASS <account> <code> <newpassword> completes the reset. Codes are
node-local; the password change itself federates.
2026-07-12 15:28:15 +00:00
ef89f97158
nickserv: add SET (password/email) and DROP
SET PASSWORD changes your password (derived off-thread like register) and
SET EMAIL sets an address. DROP deletes your account, releases and drops
the channels you founded, and logs you out. A dropped account federates,
and each node logs out any local session that was relying on it.
2026-07-12 14:32:53 +00:00
921088bfca
chanserv: require channel-operator status to register
Registering a channel now needs the caller to actually hold operator
status in it, so you can't register a channel you don't control. The
network view tracks per-channel ops from FJOIN prefixes and FMODE +o/-o.
2026-07-12 13:57:29 +00:00
e8b55bdb27
chanserv: entrymsg, enforce, getkey, seen, clone, aop/sop/vop
Tracks channel membership (join/part/kick), the current key, and per-nick
last-seen in the network view. Entry messages greet joiners; enforce
re-applies the lock, access modes and auto-kicks to everyone present;
getkey reports the key; seen reports last activity; clone copies a
channel's settings; aop/sop/vop are tiered shortcuts over the access list.
2026-07-12 11:53:48 +00:00
ba3803e01c
chanserv: topic, invite, akick, list, status
Adds the remaining moderation and listing commands. Auto-kick masks are
stored in the event log and enforced on join: a matching user is banned
and kicked. Topic and invite are sourced from the ChanServ pseudoclient.
2026-07-12 11:30:07 +00:00
acd0e60946
chanserv: op, deop, voice, devoice, kick, ban, unban
Adds channel moderation commands sourced from the ChanServ pseudoclient.
Tracks connected users' nicks and hosts so targets can be resolved by
nick and banned by *!*@host. All commands require operator access.
2026-07-12 11:21:35 +00:00
677963924a
Reorganize protocol and pseudoclients into a modules/ tree
The core stays in src/; protocol and pseudoclients move to modules/,
pulled in with #[path].
2026-07-12 10:37:59 +00:00