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.
This commit is contained in:
parent
253d4c2a2d
commit
d2c1d076fb
12 changed files with 430 additions and 12 deletions
45
operserv/src/lib.rs
Normal file
45
operserv/src/lib.rs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
//! OperServ gives services operators network-wide tools. The first is AKILL:
|
||||
//! network bans (G-lines) that keep matching users off the whole network,
|
||||
//! event-sourced so they survive a restart and re-apply at burst, with lazy
|
||||
//! expiry like the rest of the store. `lib.rs` dispatches; each command is its
|
||||
//! own file.
|
||||
|
||||
use fedserv_api::{NetView, Sender, Service, ServiceCtx, Store};
|
||||
|
||||
#[path = "akill.rs"]
|
||||
mod akill;
|
||||
|
||||
pub struct OperServ {
|
||||
pub uid: String,
|
||||
}
|
||||
|
||||
impl Service for OperServ {
|
||||
fn nick(&self) -> &str {
|
||||
"OperServ"
|
||||
}
|
||||
fn uid(&self) -> &str {
|
||||
&self.uid
|
||||
}
|
||||
fn gecos(&self) -> &str {
|
||||
"Operator Service"
|
||||
}
|
||||
|
||||
fn on_command(&mut self, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, _net: &dyn NetView, db: &mut dyn Store) {
|
||||
let me = self.uid.as_str();
|
||||
// Every OperServ command is operator-only: reveal nothing to others.
|
||||
if !from.privs.any() {
|
||||
ctx.notice(me, from.uid, "Access denied — OperServ is for services operators.");
|
||||
return;
|
||||
}
|
||||
match args.first().copied() {
|
||||
Some(cmd) if cmd.eq_ignore_ascii_case("AKILL") => akill::handle(me, from, args, ctx, db),
|
||||
Some(cmd) if cmd.eq_ignore_ascii_case("HELP") => help(me, from, ctx),
|
||||
None => help(me, from, ctx),
|
||||
Some(other) => ctx.notice(me, from.uid, format!("I don't know \x02{other}\x02. Try \x02AKILL\x02 or \x02HELP\x02.")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn help(me: &str, from: &Sender, ctx: &mut ServiceCtx) {
|
||||
ctx.notice(me, from.uid, "OperServ holds network operator tools. \x02AKILL ADD\x02 [+expiry] <user@host> <reason>, \x02AKILL DEL\x02 <user@host|number>, \x02AKILL LIST\x02 [pattern] — network bans (Priv::Admin).");
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue