operserv: type the X-line kind as an enum at the command/store boundary, wire token in storage
This commit is contained in:
parent
2c8ba4460d
commit
ef34c04c8d
9 changed files with 96 additions and 45 deletions
|
|
@ -40,7 +40,7 @@ pub(crate) use event::{apply, Scope};
|
|||
// echo-api SDK crate; re-exported so the engine keeps naming them locally and
|
||||
// modules importing `crate::engine::db::{ChanError, ...}` are unaffected.
|
||||
pub use echo_api::{
|
||||
AccountView, AjoinView, AkillView, BotView, Caps, ForbidKind, ForbidView, GroupView, HelpView, IgnoreView, MemoView, NewsView, Privs, ReportView, SuspensionView, ChanAccessView, ChanAkickView, ChanError, ChanSetting, ChannelView, CertError, CodeKind, Kicker, RegError, Store, TriggerView, VhostView,
|
||||
AccountView, AjoinView, AkillView, BotView, Caps, ForbidKind, ForbidView, GroupView, HelpView, IgnoreView, MemoView, NewsView, Privs, ReportView, SuspensionView, ChanAccessView, ChanAkickView, ChanError, ChanSetting, ChannelView, CertError, CodeKind, Kicker, RegError, Store, TriggerView, VhostView, XlineKind,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
|
|
|
|||
|
|
@ -2,36 +2,42 @@ use super::*;
|
|||
|
||||
impl Db {
|
||||
/// Add (or refresh) a `kind` network ban. Returns whether it was newly added.
|
||||
pub fn akill_add(&mut self, kind: &str, mask: &str, setter: &str, reason: &str, expires: Option<u64>) -> Result<bool, RegError> {
|
||||
let same = |a: &Akill| a.kind == kind && a.mask.eq_ignore_ascii_case(mask);
|
||||
pub fn akill_add(&mut self, kind: XlineKind, mask: &str, setter: &str, reason: &str, expires: Option<u64>) -> Result<bool, RegError> {
|
||||
// Storage/gossip keep the ircd's line token; the API is typed.
|
||||
let wire = kind.wire();
|
||||
let same = |a: &Akill| a.kind == wire && a.mask.eq_ignore_ascii_case(mask);
|
||||
let fresh = !self.net.akills.iter().any(|a| same(a) && a.expires.is_none_or(|e| e > now()));
|
||||
self.log
|
||||
.append(Event::AkillAdded { kind: kind.to_string(), mask: mask.to_string(), setter: setter.to_string(), reason: reason.to_string(), ts: now(), expires })
|
||||
.append(Event::AkillAdded { kind: wire.to_string(), mask: mask.to_string(), setter: setter.to_string(), reason: reason.to_string(), ts: now(), expires })
|
||||
.map_err(|_| RegError::Internal)?;
|
||||
self.net.akills.retain(|a| !same(a));
|
||||
self.net.akills.push(Akill { kind: kind.to_string(), mask: mask.to_string(), setter: setter.to_string(), reason: reason.to_string(), ts: now(), expires });
|
||||
self.net.akills.push(Akill { kind: wire.to_string(), mask: mask.to_string(), setter: setter.to_string(), reason: reason.to_string(), ts: now(), expires });
|
||||
Ok(fresh)
|
||||
}
|
||||
|
||||
/// Lift a `kind` network ban. Returns whether a live one was removed.
|
||||
pub fn akill_del(&mut self, kind: &str, mask: &str) -> Result<bool, RegError> {
|
||||
let same = |a: &Akill| a.kind == kind && a.mask.eq_ignore_ascii_case(mask);
|
||||
pub fn akill_del(&mut self, kind: XlineKind, mask: &str) -> Result<bool, RegError> {
|
||||
let wire = kind.wire();
|
||||
let same = |a: &Akill| a.kind == wire && a.mask.eq_ignore_ascii_case(mask);
|
||||
let existed = self.net.akills.iter().any(|a| same(a) && a.expires.is_none_or(|e| e > now()));
|
||||
if !existed {
|
||||
return Ok(false);
|
||||
}
|
||||
self.log.append(Event::AkillRemoved { kind: kind.to_string(), mask: mask.to_string() }).map_err(|_| RegError::Internal)?;
|
||||
self.log.append(Event::AkillRemoved { kind: wire.to_string(), mask: mask.to_string() }).map_err(|_| RegError::Internal)?;
|
||||
self.net.akills.retain(|a| !same(a));
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
/// The live network bans (expired ones hidden lazily), oldest first.
|
||||
/// The live network bans (expired ones hidden lazily), oldest first. A stored
|
||||
/// kind we don't model (peer-gossiped) is skipped from the typed view.
|
||||
pub fn akills(&self) -> Vec<AkillView> {
|
||||
let now = now();
|
||||
self.net.akills
|
||||
.iter()
|
||||
.filter(|a| a.expires.is_none_or(|e| e > now))
|
||||
.map(|a| AkillView { kind: a.kind.clone(), mask: a.mask.clone(), setter: a.setter.clone(), reason: a.reason.clone(), ts: a.ts, expires: a.expires })
|
||||
.filter_map(|a| {
|
||||
XlineKind::from_wire(&a.kind).map(|kind| AkillView { kind, mask: a.mask.clone(), setter: a.setter.clone(), reason: a.reason.clone(), ts: a.ts, expires: a.expires })
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -209,10 +209,10 @@ impl Store for Db {
|
|||
fn set_channel_noexpire(&mut self, channel: &str, on: bool) -> Result<bool, ChanError> {
|
||||
Db::set_channel_noexpire(self, channel, on)
|
||||
}
|
||||
fn akill_add(&mut self, kind: &str, mask: &str, setter: &str, reason: &str, expires: Option<u64>) -> Result<bool, RegError> {
|
||||
fn akill_add(&mut self, kind: XlineKind, mask: &str, setter: &str, reason: &str, expires: Option<u64>) -> Result<bool, RegError> {
|
||||
Db::akill_add(self, kind, mask, setter, reason, expires)
|
||||
}
|
||||
fn akill_del(&mut self, kind: &str, mask: &str) -> Result<bool, RegError> {
|
||||
fn akill_del(&mut self, kind: XlineKind, mask: &str) -> Result<bool, RegError> {
|
||||
Db::akill_del(self, kind, mask)
|
||||
}
|
||||
fn akills(&self) -> Vec<AkillView> {
|
||||
|
|
|
|||
|
|
@ -609,7 +609,7 @@
|
|||
db.group_set_flags("!grp", "carol", "").unwrap();
|
||||
db.group_register("!other", "bob").unwrap();
|
||||
db.group_set_flags("!other", "alice", "").unwrap();
|
||||
db.akill_add("G", "*@evil", "oper", "spam", None).unwrap();
|
||||
db.akill_add(XlineKind::Gline, "*@evil", "oper", "spam", None).unwrap();
|
||||
db.forbid_add(ForbidKind::Nick, "bad*", "oper", "squat").unwrap();
|
||||
db.vhost_offer_add("cool.vhost").unwrap();
|
||||
db.vhost_forbid_add("(?i)admin").unwrap();
|
||||
|
|
@ -640,8 +640,8 @@
|
|||
db.del_vhost("bob").unwrap();
|
||||
db.suspend_account("carol", "oper", "oops", None).unwrap();
|
||||
db.unsuspend_account("carol").unwrap();
|
||||
db.akill_add("Q", "spam*", "oper", "nick", None).unwrap();
|
||||
db.akill_del("Q", "spam*").unwrap();
|
||||
db.akill_add(XlineKind::Qline, "spam*", "oper", "nick", None).unwrap();
|
||||
db.akill_del(XlineKind::Qline, "spam*").unwrap();
|
||||
db.forbid_add(ForbidKind::Chan, "#evil*", "oper", "bad").unwrap();
|
||||
db.forbid_del(ForbidKind::Chan, "#evil*").unwrap();
|
||||
let nid = db.news_add("logon", "temp notice", "oper");
|
||||
|
|
@ -703,7 +703,7 @@
|
|||
a.set_greet("alice", "hi there").unwrap();
|
||||
a.set_account_kill("alice", false).unwrap();
|
||||
a.suspend_account("bob", "op", "bad", None).unwrap();
|
||||
a.akill_add("G", "*@evil", "op", "spam", None).unwrap();
|
||||
a.akill_add(XlineKind::Gline, "*@evil", "op", "spam", None).unwrap();
|
||||
a.forbid_add(ForbidKind::Nick, "bad*", "op", "squat").unwrap();
|
||||
a.group_register("!g", "alice").unwrap();
|
||||
a.group_set_flags("!g", "bob", "").unwrap();
|
||||
|
|
|
|||
|
|
@ -1044,7 +1044,7 @@ impl Engine {
|
|||
let now = self.now_secs();
|
||||
for a in self.db.akills() {
|
||||
let duration = a.expires.map(|e| e.saturating_sub(now)).unwrap_or(0);
|
||||
out.push(NetAction::AddLine { kind: a.kind, mask: a.mask, setter: a.setter, duration, reason: a.reason });
|
||||
out.push(NetAction::AddLine { kind: a.kind.wire().to_string(), mask: a.mask, setter: a.setter, duration, reason: a.reason });
|
||||
}
|
||||
// Re-introduce our juped servers over the fresh link.
|
||||
for (name, sid, reason) in self.db.jupes() {
|
||||
|
|
@ -1524,14 +1524,10 @@ impl Engine {
|
|||
}
|
||||
|
||||
// A human label for a network-ban X-line kind, for the audit feed.
|
||||
// The audit feed labels the ban kind from the persisted (string) event token; an
|
||||
// unmodelled/peer kind falls back to the generic label.
|
||||
fn ban_kind_label(kind: &str) -> &'static str {
|
||||
match kind {
|
||||
"Q" => "nick ban",
|
||||
"R" => "realname ban",
|
||||
"SHUN" => "shun",
|
||||
"CBAN" => "channel ban",
|
||||
_ => "network ban",
|
||||
}
|
||||
echo_api::XlineKind::from_wire(kind).map(|k| k.label()).unwrap_or("network ban")
|
||||
}
|
||||
|
||||
// A rough human span for an expiry deadline in an email ("7 days", "12 hours").
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue