engine: log out local sessions on a gossiped account suspension
All checks were successful
CI / check (push) Successful in 3m43s
All checks were successful
CI / check (push) Successful in 3m43s
A local SUSPEND logs out the account's active sessions, but a suspension arriving by gossip only set the flag — a session already identified on a remote node stayed logged in despite the network-wide suspension. ingest now signals AccountChange::Suspended, and gossip_ingest ends those sessions (the account and its channels are kept). Factors the per-session logout into a shared logout_uid helper.
This commit is contained in:
parent
58af1187fc
commit
886fe65e4d
3 changed files with 84 additions and 10 deletions
|
|
@ -432,6 +432,43 @@
|
|||
assert!(parted, "the assigned bot parts the released channel");
|
||||
}
|
||||
|
||||
// A suspension that arrives by gossip must end local sessions on that account,
|
||||
// just as a local SUSPEND does — the account and its channels stay put.
|
||||
#[test]
|
||||
fn gossiped_suspension_logs_out_local_sessions() {
|
||||
use echo_nickserv::NickServ;
|
||||
let path = std::env::temp_dir().join("echo-gossipsusp.jsonl");
|
||||
let _ = std::fs::remove_file(&path);
|
||||
let mut db = Db::open(&path, "test");
|
||||
db.scram_iterations = 4096;
|
||||
db.register("alice", "sesame", None).unwrap();
|
||||
let mut e = Engine::new(vec![Box::new(NickServ { uid: "42SAAAAAA".into(), guest_nick: "Guest".into(), guest_seq: 0 })], db);
|
||||
e.set_sid("42S".into());
|
||||
e.handle(NetEvent::UserConnect { uid: "000AAAAAB".into(), nick: "alice".into(), host: "h".into() , ip: "0.0.0.0".into() });
|
||||
e.handle(NetEvent::Privmsg { from: "000AAAAAB".into(), to: "42SAAAAAA".into(), text: "IDENTIFY sesame".into() });
|
||||
assert_eq!(e.network.account_of("000AAAAAB"), Some("alice"), "logged in first");
|
||||
|
||||
let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel();
|
||||
e.set_irc_out(tx);
|
||||
// A peer suspends alice; the suspension gossips in.
|
||||
let entry = LogEntry::for_test("peer", 0, 1, db::Event::AccountSuspended { account: "alice".into(), by: "peer-oper".into(), reason: "spam".into(), ts: 0, expires: None });
|
||||
e.gossip_ingest(entry).unwrap();
|
||||
|
||||
assert!(e.db.is_suspended("alice"), "suspension applied locally");
|
||||
assert!(e.network.account_of("000AAAAAB").is_none(), "the live session is logged out");
|
||||
assert!(e.db.exists("alice"), "the account itself is kept");
|
||||
let (mut cleared, mut told) = (false, false);
|
||||
while let Ok(a) = rx.try_recv() {
|
||||
match a {
|
||||
NetAction::Metadata { target, key, value } if target == "000AAAAAB" && key == "accountname" && value.is_empty() => cleared = true,
|
||||
NetAction::Notice { to, text, .. } if to == "000AAAAAB" && text.contains("suspended") => told = true,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
assert!(cleared, "accountname metadata cleared on the ircd");
|
||||
assert!(told, "the user is told they were suspended");
|
||||
}
|
||||
|
||||
// Losing a registration conflict logs out the local session on that name and
|
||||
// notifies them over the services-initiated outbound path.
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue