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.
This commit is contained in:
parent
dc2331f439
commit
a7aacf347e
3 changed files with 98 additions and 25 deletions
|
|
@ -33,6 +33,8 @@ mod session;
|
|||
mod jupe;
|
||||
#[path = "chankill.rs"]
|
||||
mod chankill;
|
||||
#[path = "logsearch.rs"]
|
||||
mod logsearch;
|
||||
|
||||
pub struct OperServ {
|
||||
pub uid: String,
|
||||
|
|
@ -76,6 +78,7 @@ impl Service for OperServ {
|
|||
Some(cmd) if cmd.eq_ignore_ascii_case("EXCEPTION") => session::handle_exception(me, from, args, ctx, db),
|
||||
Some(cmd) if cmd.eq_ignore_ascii_case("JUPE") => jupe::handle(me, from, args, ctx, db),
|
||||
Some(cmd) if cmd.eq_ignore_ascii_case("CHANKILL") => chankill::handle(me, from, args, ctx, net, db),
|
||||
Some(cmd) if cmd.eq_ignore_ascii_case("LOGSEARCH") => logsearch::handle(me, from, args, ctx, net),
|
||||
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 \x02HELP\x02.")),
|
||||
|
|
@ -84,5 +87,5 @@ impl Service for OperServ {
|
|||
}
|
||||
|
||||
fn help(me: &str, from: &Sender, ctx: &mut ServiceCtx) {
|
||||
ctx.notice(me, from.uid, "OperServ holds network operator tools (Priv::Admin): \x02AKILL\x02 ADD|DEL|LIST (user@host bans), \x02SQLINE\x02 ADD|DEL|LIST (nick bans), \x02SNLINE\x02 ADD|DEL|LIST (realname bans), \x02SHUN\x02 ADD|DEL|LIST (silence a host), \x02CHANKILL\x02 <#chan> (clear a channel), \x02GLOBAL\x02 <message> (announce to everyone), \x02KILL\x02 <nick> [reason] (disconnect a user), \x02KICK\x02 <#chan> <nick> [reason], \x02MODE\x02 <#chan> <modes> [params], \x02IGNORE\x02 ADD|DEL|LIST (silence a user from services), \x02STATS\x02 (enforcement overview), \x02SVSNICK\x02 <nick> <newnick>, \x02SVSJOIN\x02 <nick> <#chan> [key], \x02INFO\x02 ADD|DEL <target> (staff notes), \x02NEWS\x02 ADD|DEL|LIST <LOGON|OPER> (announcements), \x02OPER\x02 ADD|DEL|LIST (runtime operators), \x02SESSION\x02 LIST|VIEW + \x02EXCEPTION\x02 ADD|DEL|LIST (per-IP session limits), \x02JUPE\x02 <server> | DEL | LIST.");
|
||||
ctx.notice(me, from.uid, "OperServ holds network operator tools (Priv::Admin): \x02AKILL\x02 ADD|DEL|LIST (user@host bans), \x02SQLINE\x02 ADD|DEL|LIST (nick bans), \x02SNLINE\x02 ADD|DEL|LIST (realname bans), \x02SHUN\x02 ADD|DEL|LIST (silence a host), \x02CHANKILL\x02 <#chan> (clear a channel), \x02GLOBAL\x02 <message> (announce to everyone), \x02KILL\x02 <nick> [reason] (disconnect a user), \x02KICK\x02 <#chan> <nick> [reason], \x02MODE\x02 <#chan> <modes> [params], \x02IGNORE\x02 ADD|DEL|LIST (silence a user from services), \x02STATS\x02 (enforcement overview), \x02SVSNICK\x02 <nick> <newnick>, \x02SVSJOIN\x02 <nick> <#chan> [key], \x02INFO\x02 ADD|DEL <target> (staff notes), \x02NEWS\x02 ADD|DEL|LIST <LOGON|OPER> (announcements), \x02OPER\x02 ADD|DEL|LIST (runtime operators), \x02SESSION\x02 LIST|VIEW + \x02EXCEPTION\x02 ADD|DEL|LIST (per-IP session limits), \x02JUPE\x02 <server> | DEL | LIST, \x02LOGSEARCH\x02 [pattern] (search the action log).");
|
||||
}
|
||||
|
|
|
|||
23
operserv/src/logsearch.rs
Normal file
23
operserv/src/logsearch.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
use fedserv_api::{human_time, NetView, Priv, Sender, ServiceCtx};
|
||||
|
||||
// LOGSEARCH [pattern]: search the recent action log — every kick, kill, ban,
|
||||
// registration/drop, akill, suspension, vhost, note, and so on. A bare id (as
|
||||
// stamped into a kick reason, e.g. from `[#3F]`) or any word from the summary
|
||||
// matches; no argument lists the most recent. Read-only, so any operator who can
|
||||
// see hidden info (Priv::Auspex) may run it.
|
||||
pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, net: &dyn NetView) {
|
||||
if !from.privs.has(Priv::Auspex) {
|
||||
ctx.notice(me, from.uid, "Access denied — LOGSEARCH needs the \x02auspex\x02 privilege.");
|
||||
return;
|
||||
}
|
||||
let pattern = args[1..].join(" ");
|
||||
let hits = net.search_incidents(&pattern, 20);
|
||||
if hits.is_empty() {
|
||||
ctx.notice(me, from.uid, "No matching log entries.");
|
||||
return;
|
||||
}
|
||||
for h in &hits {
|
||||
ctx.notice(me, from.uid, format!("[\x02#{}\x02] {} — {}", h.id, human_time(h.ts), h.summary));
|
||||
}
|
||||
ctx.notice(me, from.uid, format!("End of results ({} shown, newest first — refine the search to narrow).", hits.len()));
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue