Commit graph

101 commits

Author SHA1 Message Date
d819b2c75f
MemoServ: add RSEND read receipts
Some checks failed
CI / check (push) Has been cancelled
2026-07-16 00:43:01 +00:00
2850620be1
ChanServ: add SET AUTOOP
All checks were successful
CI / check (push) Successful in 3m35s
SET AUTOOP {ON|OFF} controls whether access members are auto-opped/voiced
on join (on by default). Stored inverted as a settings flag so the
default stays on, and gated in the join handler.
2026-07-16 00:36:19 +00:00
2c282d036f
MemoServ: add SET NOTIFY and SET LIMIT
All checks were successful
CI / check (push) Successful in 3m35s
SET NOTIFY {ON|OFF} controls whether you're told about new memos on login;
SET LIMIT <n>|NONE sets your mailbox cap (honoured on SEND, NONE = the
network default). New memo_notify/memo_limit account fields + one
MemoPrefsSet event.
2026-07-16 00:29:33 +00:00
125b8c7701
NickServ: RECOVER regains your nick
All checks were successful
CI / check (push) Successful in 3m41s
Split RECOVER from GHOST: GHOST just frees a session off a nick you own,
while RECOVER also puts you back onto it (frees the ghost if present, then
SVSNICKs you to the nick). RECOVER works on an already-free nick too.
2026-07-16 00:21:07 +00:00
b5e08c33cf
MemoServ: add IGNORE
All checks were successful
CI / check (push) Successful in 3m34s
IGNORE ADD/DEL/LIST manages a per-account memo-ignore list; a memo from
an ignored account is silently dropped, and the sender is still told it
was sent so the ignore isn't revealed. New memo_ignore account field +
events, and a check in SEND.
2026-07-16 00:10:34 +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
53d3d63464
NickServ GETEMAIL + ChanServ SET RESTRICTED
All checks were successful
CI / check (push) Successful in 3m51s
GETEMAIL (auspex) lists accounts whose email matches a glob. SET
RESTRICTED makes a channel kick anyone without access (or oper) as they
join, mirroring the SECUREOPS on-join enforcement.
2026-07-15 19:25:41 +00:00
be4860c9a8
OperServ: add FORBID (nick/channel/email registration bans)
All checks were successful
CI / check (push) Successful in 3m56s
FORBID ADD/DEL/LIST bans a NICK, CHAN, or EMAIL glob from being
registered — a network-wide policy that gossips like an AKILL and every
node enforces. Nick registration is blocked in pre_register_check (both
NickServ REGISTER and the account-registration relay), and channel
registration in ChanServ REGISTER. New Forbid store + events, mirroring
the akill subsystem.
2026-07-15 19:14:07 +00:00
ac50af92fc
ChanServ: add SET SUCCESSOR with founder inheritance
All checks were successful
CI / check (push) Successful in 3m59s
SET <#channel> SUCCESSOR <account>|OFF names an account that inherits the
channel if the founder's account is dropped or expires, instead of the
channel being released. Adds a ChannelInfo.successor field + event, and
centralises the founder-gone channel release into a single
release_founded_channels store method used by DROP, expiry, and the
gossip account-gone path so all three transfer consistently.
2026-07-15 18:58:08 +00:00
6e3a758cc1
ChanServ: add OWNER/PROTECT/HALFOP status commands
All checks were successful
CI / check (push) Successful in 3m47s
OWNER/DEOWNER (+q), PROTECT/DEPROTECT (+a, alias ADMIN), and
HALFOP/DEHALFOP (+h) set the higher channel-status modes. They reuse the
OP handler's target resolution and PEACE check; OWNER is founder-only,
the rest need op access.
2026-07-15 18:40:19 +00:00
30e91bb295
MemoServ SENDALL + ChanServ AKICK CLEAR
All checks were successful
CI / check (push) Successful in 3m46s
SENDALL (admin) leaves a memo on every registered account for a
network-wide announcement that persists until read. AKICK CLEAR empties a
channel's auto-kick list in one command.
2026-07-15 18:32:46 +00:00
21efbd32c1
NickServ: add UPDATE and LIST
All checks were successful
CI / check (push) Successful in 3m46s
UPDATE re-applies your auto-joins and vhost and re-checks for waiting
memos without re-identifying. LIST (auspex-gated) shows registered
accounts matching a glob, capped at 100. Adds an accounts_matching store
method.
2026-07-15 18:24:52 +00:00
959d085e7a
ChanServ: add UP and DOWN
All checks were successful
CI / check (push) Successful in 3m47s
UP re-applies the op/voice status your channel access entitles you to;
DOWN removes your status. Mirrors the OP/VOICE command's access check and
mode emission, and requires you to actually be in the channel.
2026-07-15 18:14:39 +00:00
98ecbca414
MemoServ: add CANCEL, CHECK, and INFO
All checks were successful
CI / check (push) Successful in 3m49s
CANCEL recalls the sender's most recent unread memo to a target (one the
recipient already read can't be recalled); CHECK reports whether the last
memo you sent someone has been read; INFO summarises your mailbox. Adds
memo_cancel/memo_check store methods and shares MAX_MEMOS from the module
root instead of duplicating it in send.rs.
2026-07-15 18:09:33 +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
d9c0878b00
Log store write failures at the source; share the oper guard
The store's map_err(|_| Internal) discarded the real IO error, so a
disk-full or permissions failure was invisible; log it once in the log
append path where it happens. Add echo_api::require_oper (parameterised
by the required privilege) and route the three copied per-service guards
through it, keeping each service's own wording and policy.
2026-07-14 23:19:00 +00:00
fcca8e4e3b
Front the whole network's help through HelpServ
Each service now exposes its help catalog via Service::help_topics; the
engine collects them into a network-wide index on Network, reachable
through two new NetView methods. HelpServ uses it: HELP <service>
[command] (or a bare service name) serves any service's per-command
help, bare HELP lists the services, and its own ticket commands still
work. No cross-crate dependency: the catalog flows through the SDK's
NetView, keeping every module dependent only on echo-api.
2026-07-14 18:37:45 +00:00
69a93198ff
Wire centralized HELP into the remaining services
ChanServ, BotServ, HostServ, MemoServ, OperServ, and StatServ now route
HELP through the shared renderer with per-command topic tables, so every
service supports HELP <command>. The renderer matches slash-grouped
names (OP/DEOP/VOICE/DEVOICE) so a paired command resolves as one topic.
Adds unit tests for the renderer.
2026-07-14 17:23:40 +00:00
c9e392630b
Add centralized HELP with per-command subcommands
New echo-api primitive: a HelpEntry table plus a shared help() renderer.
HELP lists a service's commands; HELP <command> prints that command's
detail. Every service routes its HELP arm through the one renderer, so
the shape is identical across the network. Wired into NickServ and the
six newer services so far.
2026-07-14 17:12:14 +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
92383cee0e
Split DiceServ command out of lib.rs
The one command handler (ROLL/EXROLL/CALC/EXCALC all route to it) and
its formatting helpers move to roll.rs; lib.rs keeps the dispatcher, the
expression-evaluator module, and its tests. No behaviour change.
2026-07-14 14:49:42 +00:00
a29becb8b9
Split ReportServ into one file per command
REPORT/LIST/VIEW/CLOSE/DEL each move to their own file; the shared oper
guard stays in lib.rs beside the dispatcher. No behaviour change.
2026-07-14 14:48:12 +00:00
0ba736615b
Split InfoServ into one file per command
POST/DEL/LIST each move to their own file (each still parameterised by
bulletin kind, so OPOST/ODEL/OLIST route to the same handler); the kind
constants stay in lib.rs beside the dispatcher. No behaviour change.
2026-07-14 14:46:56 +00:00
368e6ba090
Split HelpServ into one file per command
REQUEST/CANCEL/LIST/VIEW/TAKE/NEXT/CLOSE each move to their own file;
the oper guard and the shared claim helper stay in lib.rs beside the
dispatcher. No behaviour change.
2026-07-14 14:45:22 +00:00
1916e5fce5
Split GroupServ into one file per command
REGISTER/DROP/INFO/LIST/ADD/DEL/FLAGS each move to their own file; the
two shared guards (login check, can-manage) stay in lib.rs beside the
dispatcher. No behaviour change.
2026-07-14 14:43:18 +00:00
feba6700cb
Split ChanFix into one file per command
lib.rs kept only the struct and the dispatcher; SCORES and CHANFIX now
each live in their own file (scores.rs, fix.rs), matching every other
service. No behaviour change.
2026-07-14 14:40:43 +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
ad2a623120
Group the module crates under modules/
The service pseudo-clients and the ircd protocol link sat flat at the
repo root, mixed in with the daemon core and the SDK. Move them all
under modules/ so the tree separates concerns cleanly: the daemon in
src/, the SDK every module links against in api/, and the loadable
modules — the pseudo-clients plus the protocol link — in modules/.

Workspace members, the daemon's per-crate dependency paths, and each
module's api path are updated to match; the docs follow. No code change.
2026-07-14 14:19:43 +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
8ed1a9ab70
modules: capability-scoped Store/NetView boundary (Tier 2)
Services no longer receive the concrete account store. on_command now takes
&mut dyn Store + &dyn NetView (both defined in fedserv-api); the engine's Db
and Network implement them. Reads hand back plain views (AccountView,
ChannelView, ...) carrying only non-secret fields, so the event log, gossip,
and credential material (password hash, SCRAM verifiers) are unreachable from
a module. All command modules ported; behaviour unchanged.
2026-07-13 01:04:07 +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
bdcce01f11
email: optional logo image in the header
A configurable logo URL renders as an image beside the brand name in the
email header (falling back to the brand text when unset). Email clients
need a hosted image, so it takes a URL rather than an inline asset.
2026-07-12 16:36:06 +00:00
98630c7d36
email: premium HTML template with accent colour and copy affordance
Redesigns the mail template (branded header bar, hero code block, copy
button, muted footer) and adds a configurable accent colour alongside the
brand name.
2026-07-12 16:07:36 +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
fbcf0eaac7
nickserv: email confirmation (CONFIRM) on registration
When email is configured and a REGISTER includes an address, the account
starts unverified and a confirmation code is emailed. CONFIRM <code>
verifies it (a federated AccountVerified event); INFO shows an unconfirmed
email until then. Emailed codes now carry a purpose (reset vs confirm).
2026-07-12 15:36:30 +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
020e9bd576
nickserv: grouped nicks (GROUP/GLIST/UNGROUP) and GHOST
A nick can be grouped to an account and then identifies to it; the store
resolves an alias to its account everywhere it authenticates. GHOST (and
RECOVER) rename off a session using a nick you own. Grouped nicks
federate and are dropped with their account.
2026-07-12 14:59:23 +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
0427819f86
nickserv: add INFO and ALIST
INFO shows an account's registration date and (to its owner) email; ALIST
lists the channels an account founds or has access on. The UTC time
formatter moves to the db module so both services share it.
2026-07-12 14:19:29 +00:00
9d6cf3bb08
nickserv: split into one file per command
Mirrors the chanserv layout: nickserv.rs keeps the service and dispatch,
each command (register, identify, logout, cert) lives in its own file
with its subcommands and parameters. Behaviour is unchanged.
2026-07-12 14:05:59 +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
aab64baf86
nickserv: log out the loser of a registration conflict
When a peer's registration wins a name a local session was logged into,
that session authenticated against a credential that no longer exists.
The node now clears its accountname (the ircd emits RPL_LOGGEDOUT) and
tells the user why. A new outbound channel lets the engine push these
services-initiated actions to the uplink from the gossip path, drained
by the link loop alongside incoming traffic.
2026-07-12 13:34:38 +00:00
4408281d20
nickserv: IDENTIFY reports an unregistered account distinctly
A failed IDENTIFY now says whether the account isn't registered or the
password was wrong, instead of one message for both.
2026-07-12 12:38:09 +00:00
914c3874ce
nickserv: accept IDENTIFY [account] <password>
IDENTIFY now takes an optional leading account name, so logging into an
account whose name differs from your current nick works. Without it, the
account still defaults to the current nick as before.
2026-07-12 12:30:16 +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
674f543b40
chanserv: SET founder and description
SET <#channel> FOUNDER <account> transfers ownership; SET DESC <text>
stores a description shown in INFO. Both are founder-gated and persisted
to the event log.
2026-07-12 11:33:33 +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
f0ce2d9d1b
Add ChanServ ACCESS list with auto-op/voice on join
ACCESS <#channel> LIST|ADD|DEL manages op/voice by account (founder-only
changes). Entries are ChannelAccessAdd/Del events, so they replicate and
compact like the rest, and join grants +o/+v from the list.
2026-07-12 10:59:15 +00:00
b299c4f02e
Move the ChanServ MODE command into modules/chanserv/mode.rs 2026-07-12 10:46:27 +00:00