signore: persist per-account via services metadata — push on edit, replay on login

This commit is contained in:
Jean Chevronnet 2026-08-20 15:40:19 +00:00
parent 6c5f330746
commit 1824af5d90
No known key found for this signature in database
GPG key ID: 439666D63A9477E4
4 changed files with 35 additions and 0 deletions

View file

@ -366,6 +366,8 @@ impl Command for Signore {
} }
s.send(uid, format!(":{sn} NOTICE {nick} :SIGNORE \x02{mask}\x02 removed.")); 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 CmdResult::Ok
} }
} }

View file

@ -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) -------------------------- // --- SASL relay (client AUTHENTICATE ⇄ services) --------------------------
/// The local link toward the configured SASL services server, if connected. /// The local link toward the configured SASL services server, if connected.
@ -2818,6 +2847,7 @@ mod tests {
watch: Vec::new(), watch: Vec::new(),
monitor: Vec::new(), monitor: Vec::new(),
silence: Vec::new(), silence: Vec::new(),
signore: Vec::new(),
accept: Vec::new(), accept: Vec::new(),
quitting: None, quitting: None,
flags: UserFlags::default(), flags: UserFlags::default(),
@ -2906,6 +2936,7 @@ mod tests {
watch: Vec::new(), watch: Vec::new(),
monitor: Vec::new(), monitor: Vec::new(),
silence: Vec::new(), silence: Vec::new(),
signore: Vec::new(),
accept: Vec::new(), accept: Vec::new(),
quitting: None, quitting: None,
flags: UserFlags::default(), flags: UserFlags::default(),

View file

@ -396,6 +396,7 @@ mod tests {
watch: Vec::new(), watch: Vec::new(),
monitor: Vec::new(), monitor: Vec::new(),
silence: Vec::new(), silence: Vec::new(),
signore: Vec::new(),
accept: Vec::new(), accept: Vec::new(),
quitting: None, quitting: None,
flags: UserFlags::default(), flags: UserFlags::default(),

View file

@ -96,6 +96,7 @@ impl Node {
watch: Vec::new(), watch: Vec::new(),
monitor: Vec::new(), monitor: Vec::new(),
silence: Vec::new(), silence: Vec::new(),
signore: Vec::new(),
accept: Vec::new(), accept: Vec::new(),
quitting: None, quitting: None,
flags: UserFlags::default(), flags: UserFlags::default(),