operserv: SPAMFILTER — persisted content filters pushed to the ircd m_filter via metadata, re-asserted at burst
All checks were successful
CI / check (push) Successful in 3m56s

This commit is contained in:
Jean Chevronnet 2026-07-18 00:04:24 +00:00
parent 9908548978
commit 0c3e09ea00
No known key found for this signature in database
9 changed files with 267 additions and 0 deletions

View file

@ -190,6 +190,20 @@ pub struct Akill {
pub expires: Option<u64>,
}
// A spam filter (OperServ SPAMFILTER), pushed to the ircd's m_filter. `expires`
// is absolute unix seconds (None = permanent), like an Akill.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Filter {
pub pattern: String,
pub action: String,
pub flags: String,
pub reason: String,
pub setter: String,
pub ts: u64,
#[serde(default)]
pub expires: Option<u64>,
}
// A registration ban: an account name, channel, or email pattern that may not be
// registered. `kind` is "NICK", "CHAN", or "EMAIL". Network-wide policy like an
// AKILL, so it gossips and every node enforces it.
@ -288,6 +302,7 @@ pub type ChanStats = Vec<(String, u64, Vec<(String, u64)>)>;
#[derive(Debug, Clone, Default)]
pub struct NetData {
pub akills: Vec<Akill>,
pub filters: Vec<Filter>,
pub forbids: Vec<Forbid>,
pub news: Vec<News>,
pub news_seq: u64,
@ -1213,6 +1228,9 @@ impl Db {
for a in self.net.akills.iter().filter(|a| a.expires.is_none_or(|e| e > now)) {
snapshot.push(Event::AkillAdded { kind: a.kind.clone(), mask: a.mask.clone(), setter: a.setter.clone(), reason: a.reason.clone(), ts: a.ts, expires: a.expires });
}
for f in self.net.filters.iter().filter(|f| f.expires.is_none_or(|e| e > now)) {
snapshot.push(Event::FilterAdded { pattern: f.pattern.clone(), action: f.action.clone(), flags: f.flags.clone(), reason: f.reason.clone(), setter: f.setter.clone(), ts: f.ts, expires: f.expires });
}
for n in &self.net.news {
snapshot.push(Event::NewsAdded { id: n.id, kind: n.kind.clone(), text: n.text.clone(), setter: n.setter.clone(), ts: n.ts });
}