83 lines
3.4 KiB
Rust
83 lines
3.4 KiB
Rust
//! rpc ban provider — `xline.list`, `xline.add`, `xline.del`. InspIRCd's
|
|
//! `m_rpc_ban`. Covers every echoIRCd x-line kind (K/G/Z/E/SHUN/Q/CBAN) through the
|
|
//! same `add_xline`/`remove_xline` primitives the oper commands use.
|
|
|
|
use super::json::{self, obj, qstr};
|
|
use super::RpcError;
|
|
use crate::server::Server;
|
|
use crate::xline::{parse_duration, XKind};
|
|
|
|
/// Map a request `type` (letter or unreal-ish name) to an `XKind`.
|
|
fn kind_of(t: &str) -> Option<XKind> {
|
|
let up = t.to_ascii_uppercase();
|
|
XKind::from_tag(&up).or_else(|| {
|
|
Some(match up.as_str() {
|
|
"KLINE" => XKind::Kline,
|
|
"GLINE" => XKind::Gline,
|
|
"ZLINE" => XKind::Zline,
|
|
"ELINE" => XKind::Eline,
|
|
"QLINE" => XKind::Qline,
|
|
_ => return None,
|
|
})
|
|
})
|
|
}
|
|
|
|
pub fn handle(s: &mut Server, action: &str, params: &str) -> Result<String, RpcError> {
|
|
match action {
|
|
"list" => {
|
|
let want = json::get_str(params, "type").and_then(|t| kind_of(&t));
|
|
let items: Vec<String> = s
|
|
.xlines
|
|
.iter()
|
|
.filter(|x| want.is_none_or(|k| x.kind == k))
|
|
.map(|x| {
|
|
let expires_at = if x.expires == 0 {
|
|
"null".to_string()
|
|
} else {
|
|
x.expires.to_string()
|
|
};
|
|
obj(&[
|
|
("type", qstr(x.kind.tag())),
|
|
("mask", qstr(&x.mask)),
|
|
("reason", qstr(&x.reason)),
|
|
("setter", qstr(&x.setter)),
|
|
("expires_at", expires_at),
|
|
])
|
|
})
|
|
.collect();
|
|
Ok(obj(&[("xlines", format!("[{}]", items.join(",")))]))
|
|
}
|
|
"add" => {
|
|
let kind = json::get_str(params, "type")
|
|
.and_then(|t| kind_of(&t))
|
|
.ok_or_else(|| RpcError::invalid_params("missing/unknown 'type'"))?;
|
|
let mask = json::get_str(params, "mask")
|
|
.or_else(|| json::get_str(params, "name"))
|
|
.ok_or_else(|| RpcError::invalid_params("missing 'mask'"))?;
|
|
let duration = json::get_num::<u64>(params, "duration")
|
|
.or_else(|| {
|
|
json::get_str(params, "duration_string").and_then(|d| parse_duration(&d))
|
|
})
|
|
.unwrap_or(0);
|
|
let reason = json::get_str(params, "reason").unwrap_or_else(|| "Set via RPC".into());
|
|
let setter = json::get_str(params, "setter").unwrap_or_else(|| "RPC".into());
|
|
s.add_xline(kind, &mask, duration, &setter, &reason);
|
|
Ok(obj(&[("result", "true".into())]))
|
|
}
|
|
"del" => {
|
|
let kind = json::get_str(params, "type")
|
|
.and_then(|t| kind_of(&t))
|
|
.ok_or_else(|| RpcError::invalid_params("missing/unknown 'type'"))?;
|
|
let mask = json::get_str(params, "mask")
|
|
.or_else(|| json::get_str(params, "name"))
|
|
.ok_or_else(|| RpcError::invalid_params("missing 'mask'"))?;
|
|
let removed = s.remove_xline(kind, &mask);
|
|
if removed {
|
|
Ok(obj(&[("result", "true".into())]))
|
|
} else {
|
|
Err(RpcError::not_found("no matching x-line"))
|
|
}
|
|
}
|
|
other => Err(RpcError::method_not_found(&format!("xline.{other}"))),
|
|
}
|
|
}
|