From 1824af5d904d5d03d566dac21a9eb7061bb494c0 Mon Sep 17 00:00:00 2001 From: reverse Date: Thu, 20 Aug 2026 15:40:19 +0000 Subject: [PATCH] =?UTF-8?q?signore:=20persist=20per-account=20via=20servic?= =?UTF-8?q?es=20metadata=20=E2=80=94=20push=20on=20edit,=20replay=20on=20l?= =?UTF-8?q?ogin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/coremods/core_watch.rs | 2 ++ src/link.rs | 31 +++++++++++++++++++++++++++++++ src/modules/reputation.rs | 1 + src/s2s_sim.rs | 1 + 4 files changed, 35 insertions(+) diff --git a/src/coremods/core_watch.rs b/src/coremods/core_watch.rs index 6bf96be..dff4a73 100644 --- a/src/coremods/core_watch.rs +++ b/src/coremods/core_watch.rs @@ -366,6 +366,8 @@ impl Command for Signore { } s.send(uid, format!(":{sn} NOTICE {nick} :SIGNORE \x02{mask}\x02 removed.")); } + // Persist the change to the user's services account (no-op if not logged in). + s.push_signore_to_services(uid); CmdResult::Ok } } diff --git a/src/link.rs b/src/link.rs index 0ee049e..b60c00b 100644 --- a/src/link.rs +++ b/src/link.rs @@ -976,10 +976,39 @@ impl Server { } } } + // Persistent SIGNORE list: services store it per-account and replay it on + // each login (space-separated masks; empty value clears it). + "signore" => { + if let Some(u) = self.users.get_mut(&tuid) { + u.signore = value + .split(' ') + .filter(|m| !m.is_empty()) + .map(str::to_string) + .collect(); + } + } _ => {} } } + /// Push a user's current SIGNORE list up to the services server so it's saved on + /// their account and replayed on the next login. No-op when the user isn't logged + /// in (no account to store it on) or services aren't linked — the list then stays + /// session-only, exactly as it worked before persistence. + pub fn push_signore_to_services(&self, uid: Uid) { + let Some(via) = self.sasl_link() else { + return; + }; + let Some(u) = self.users.get(&uid) else { + return; + }; + if u.account.is_none() { + return; + } + let masks = u.signore.join(" "); + self.link_out(via, format!(":{} METADATA {} signore :{masks}", self.sid, u.uuid)); + } + // --- SASL relay (client AUTHENTICATE ⇄ services) -------------------------- /// The local link toward the configured SASL services server, if connected. @@ -2818,6 +2847,7 @@ mod tests { watch: Vec::new(), monitor: Vec::new(), silence: Vec::new(), + signore: Vec::new(), accept: Vec::new(), quitting: None, flags: UserFlags::default(), @@ -2906,6 +2936,7 @@ mod tests { watch: Vec::new(), monitor: Vec::new(), silence: Vec::new(), + signore: Vec::new(), accept: Vec::new(), quitting: None, flags: UserFlags::default(), diff --git a/src/modules/reputation.rs b/src/modules/reputation.rs index 9dbbace..cd26f2f 100644 --- a/src/modules/reputation.rs +++ b/src/modules/reputation.rs @@ -396,6 +396,7 @@ mod tests { watch: Vec::new(), monitor: Vec::new(), silence: Vec::new(), + signore: Vec::new(), accept: Vec::new(), quitting: None, flags: UserFlags::default(), diff --git a/src/s2s_sim.rs b/src/s2s_sim.rs index 7ad52e4..bb00010 100644 --- a/src/s2s_sim.rs +++ b/src/s2s_sim.rs @@ -96,6 +96,7 @@ impl Node { watch: Vec::new(), monitor: Vec::new(), silence: Vec::new(), + signore: Vec::new(), accept: Vec::new(), quitting: None, flags: UserFlags::default(),