Q-line a FORBIDden nick so it can't be used, not just registered
All checks were successful
CI / check (push) Successful in 5m17s
All checks were successful
CI / check (push) Successful in 5m17s
This commit is contained in:
parent
7cb1c61afa
commit
ab8ea65a42
3 changed files with 52 additions and 5 deletions
|
|
@ -20,10 +20,14 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
|
||||||
let reason = args[4..].join(" ");
|
let reason = args[4..].join(" ");
|
||||||
let setter = from.account.unwrap_or(from.nick);
|
let setter = from.account.unwrap_or(from.nick);
|
||||||
let label = kind.wire().to_lowercase();
|
let label = kind.wire().to_lowercase();
|
||||||
match db.forbid_add(kind, mask, setter, &reason) {
|
let ok = match db.forbid_add(kind, mask, setter, &reason) {
|
||||||
Ok(true) => ctx.notice(me, from.uid, t!(ctx, "Forbade {label} \x02{mask}\x02.", label = label, mask = mask)),
|
Ok(true) => { ctx.notice(me, from.uid, t!(ctx, "Forbade {label} \x02{mask}\x02.", label = label, mask = mask)); true }
|
||||||
Ok(false) => ctx.notice(me, from.uid, t!(ctx, "Updated the forbid on {label} \x02{mask}\x02.", label = label, mask = mask)),
|
Ok(false) => { ctx.notice(me, from.uid, t!(ctx, "Updated the forbid on {label} \x02{mask}\x02.", label = label, mask = mask)); true }
|
||||||
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
Err(_) => { ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."); false }
|
||||||
|
};
|
||||||
|
// A forbidden NICK is Q-lined so it can't even be USED, not only registered.
|
||||||
|
if ok && matches!(kind, ForbidKind::Nick) {
|
||||||
|
ctx.add_line(echo_api::XlineKind::Qline, mask, setter, 0, &reason);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some("DEL") | Some("REMOVE") => {
|
Some("DEL") | Some("REMOVE") => {
|
||||||
|
|
@ -33,7 +37,12 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db:
|
||||||
};
|
};
|
||||||
let label = kind.wire().to_lowercase();
|
let label = kind.wire().to_lowercase();
|
||||||
match db.forbid_del(kind, mask) {
|
match db.forbid_del(kind, mask) {
|
||||||
Ok(true) => ctx.notice(me, from.uid, t!(ctx, "Removed the forbid on {label} \x02{mask}\x02.", label = label, mask = mask)),
|
Ok(true) => {
|
||||||
|
ctx.notice(me, from.uid, t!(ctx, "Removed the forbid on {label} \x02{mask}\x02.", label = label, mask = mask));
|
||||||
|
if matches!(kind, ForbidKind::Nick) {
|
||||||
|
ctx.del_line(echo_api::XlineKind::Qline, mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(false) => ctx.notice(me, from.uid, t!(ctx, "No forbid on {label} \x02{mask}\x02.", label = label, mask = mask)),
|
Ok(false) => ctx.notice(me, from.uid, t!(ctx, "No forbid on {label} \x02{mask}\x02.", label = label, mask = mask)),
|
||||||
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
Err(_) => ctx.notice(me, from.uid, "Sorry, that didn't work. Please try again in a moment."),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1245,6 +1245,13 @@ impl Engine {
|
||||||
let duration = a.expires.map(|e| e.saturating_sub(now)).unwrap_or(0);
|
let duration = a.expires.map(|e| e.saturating_sub(now)).unwrap_or(0);
|
||||||
out.push(NetAction::AddLine { kind: a.kind.wire().to_string(), 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-assert a Q-line for every forbidden nick, so a FORBID keeps the nick
|
||||||
|
// unusable across a relink (services X-lines don't survive the split).
|
||||||
|
for f in self.db.forbids() {
|
||||||
|
if matches!(f.kind, echo_api::ForbidKind::Nick) {
|
||||||
|
out.push(NetAction::AddLine { kind: echo_api::XlineKind::Qline.wire().to_string(), mask: f.mask, setter: f.setter, duration: 0, reason: f.reason });
|
||||||
|
}
|
||||||
|
}
|
||||||
// Re-assert the spam filters so they survive an ircd restart (m_filter has
|
// Re-assert the spam filters so they survive an ircd restart (m_filter has
|
||||||
// no s2s delete, so echo is the durable source of truth for them).
|
// no s2s delete, so echo is the durable source of truth for them).
|
||||||
for f in self.db.filters() {
|
for f in self.db.filters() {
|
||||||
|
|
|
||||||
|
|
@ -5372,6 +5372,37 @@
|
||||||
assert!(e.db.is_verified("bob"), "bob is now active after the vouch");
|
assert!(e.db.is_verified("bob"), "bob is now active after the vouch");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FORBID NICK also Q-lines the nick so it can't be used, and the Q-line is
|
||||||
|
// removed on unforbid and re-asserted on a relink.
|
||||||
|
#[test]
|
||||||
|
fn forbid_nick_qlines_it() {
|
||||||
|
use echo_operserv::OperServ;
|
||||||
|
let path = std::env::temp_dir().join("echo-forbid-qline.jsonl");
|
||||||
|
let _ = std::fs::remove_file(&path);
|
||||||
|
let mut db = Db::open(&path, "42S");
|
||||||
|
db.scram_iterations = 4096;
|
||||||
|
db.register("alice", "sesame", None).unwrap();
|
||||||
|
let ns = NickServ { uid: "42SAAAAAA".into(), guest_nick: "Guest".into(), guest_seq: 0 };
|
||||||
|
let os = OperServ { uid: "42SAAAAAH".into() };
|
||||||
|
let mut e = Engine::new(vec![Box::new(ns), Box::new(os)], db);
|
||||||
|
e.set_sid("42S".into());
|
||||||
|
let mut opers = std::collections::HashMap::new();
|
||||||
|
opers.insert("alice".to_string(), Privs::default().with(echo_api::Priv::Admin));
|
||||||
|
e.set_opers(opers);
|
||||||
|
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() });
|
||||||
|
let to_os = |e: &mut Engine, text: &str| e.handle(NetEvent::Privmsg { from: "000AAAAAB".into(), to: "42SAAAAAH".into(), text: text.into() });
|
||||||
|
|
||||||
|
let out = to_os(&mut e, "FORBID ADD NICK badname reserved");
|
||||||
|
assert!(out.iter().any(|a| matches!(a, NetAction::AddLine { kind, mask, .. } if kind == "Q" && mask == "badname")), "qline set: {out:?}");
|
||||||
|
|
||||||
|
let burst = e.startup_actions();
|
||||||
|
assert!(burst.iter().any(|a| matches!(a, NetAction::AddLine { kind, mask, .. } if kind == "Q" && mask == "badname")), "qline re-asserted on relink: {burst:?}");
|
||||||
|
|
||||||
|
let out = to_os(&mut e, "FORBID DEL NICK badname");
|
||||||
|
assert!(out.iter().any(|a| matches!(a, NetAction::DelLine { kind, mask } if kind == "Q" && mask == "badname")), "qline removed: {out:?}");
|
||||||
|
}
|
||||||
|
|
||||||
// ChanServ SET: description and founder transfer, founder-gated.
|
// ChanServ SET: description and founder transfer, founder-gated.
|
||||||
#[test]
|
#[test]
|
||||||
fn chanserv_set() {
|
fn chanserv_set() {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue