forked from MightyPork/group-actor
parent
5a631f785e
commit
99d9b83c68
@ -0,0 +1,443 @@ |
||||
use once_cell::sync::Lazy; |
||||
use regex::{Regex, RegexSetBuilder}; |
||||
|
||||
#[derive(Debug, Clone, PartialEq)] |
||||
pub enum StatusCommand { |
||||
Boost, |
||||
Ignore, |
||||
BanUser(String), |
||||
UnbanUser(String), |
||||
BanServer(String), |
||||
UnbanServer(String), |
||||
AddMember(String), |
||||
RemoveMember(String), |
||||
GrantAdmin(String), |
||||
RemoveAdmin(String), |
||||
OpenGroup, |
||||
CloseGroup, |
||||
Help, |
||||
ListMembers, |
||||
Leave, |
||||
} |
||||
|
||||
macro_rules! p_user { |
||||
() => { |
||||
r"(@?[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.-]+\.[a-z0-9_-]+|@[a-zA-Z0-9_.-]+)" |
||||
} |
||||
} |
||||
macro_rules! p_server { |
||||
() => { |
||||
r"([a-zA-Z0-9_.-]+\.[a-zA-Z0-9_-]+)" |
||||
} |
||||
} |
||||
|
||||
macro_rules! command { |
||||
($($val:expr),+) => { |
||||
Regex::new(concat!(r"(?:^|\s|>|\n)[\\/]", $($val,)+ r"(?:$|[!,]|\W)")).unwrap() |
||||
} |
||||
} |
||||
|
||||
static RE_BOOST: once_cell::sync::Lazy<Regex> = Lazy::new(|| { |
||||
command!(r"b(?:oost)?") |
||||
}); |
||||
|
||||
static RE_IGNORE: once_cell::sync::Lazy<Regex> = Lazy::new(|| { |
||||
command!(r"i(?:gn(?:ore)?)?") |
||||
}); |
||||
|
||||
static RE_BAN_USER: once_cell::sync::Lazy<Regex> = Lazy::new(|| { |
||||
command!(r"ban\s+", p_user!()) |
||||
}); |
||||
|
||||
static RE_UNBAN_USER: once_cell::sync::Lazy<Regex> = Lazy::new(|| { |
||||
command!(r"unban\s+", p_user!()) |
||||
}); |
||||
|
||||
static RE_BAN_SERVER: once_cell::sync::Lazy<Regex> = Lazy::new(|| { |
||||
command!(r"ban\s+", p_server!()) |
||||
}); |
||||
|
||||
static RE_UNBAN_SERVER: once_cell::sync::Lazy<Regex> = Lazy::new(|| { |
||||
command!(r"unban\s+", p_server!()) |
||||
}); |
||||
|
||||
static RE_ADD_MEMBER: once_cell::sync::Lazy<Regex> = Lazy::new(|| { |
||||
command!(r"(?:accept|invite|member|add)\s+", p_user!()) |
||||
}); |
||||
|
||||
static RE_REMOVE_MEMBER: once_cell::sync::Lazy<Regex> = Lazy::new(|| { |
||||
command!(r"(?:expel|kick|remove)\s+", p_user!()) |
||||
}); |
||||
|
||||
static RE_GRANT_ADMIN: once_cell::sync::Lazy<Regex> = Lazy::new(|| { |
||||
command!(r"(?:op|admin|grant)\s+", p_user!()) |
||||
}); |
||||
|
||||
static RE_REVOKE_ADMIN: once_cell::sync::Lazy<Regex> = Lazy::new(|| { |
||||
command!(r"(?:deop|unop|deadmin|unadmin|ungrant|revoke)\s+", p_user!()) |
||||
}); |
||||
|
||||
static RE_OPEN_GROUP: once_cell::sync::Lazy<Regex> = Lazy::new(|| { |
||||
command!(r"opengroup") |
||||
}); |
||||
|
||||
static RE_CLOSE_GROUP: once_cell::sync::Lazy<Regex> = Lazy::new(|| { |
||||
command!(r"closegroup") |
||||
}); |
||||
|
||||
static RE_HELP: once_cell::sync::Lazy<Regex> = Lazy::new(|| { |
||||
command!(r"help") |
||||
}); |
||||
|
||||
static RE_MEMBERS: once_cell::sync::Lazy<Regex> = Lazy::new(|| { |
||||
command!(r"(?:list|members)") |
||||
}); |
||||
|
||||
static RE_LEAVE: once_cell::sync::Lazy<Regex> = Lazy::new(|| { |
||||
command!(r"(?:leave|quit)") |
||||
}); |
||||
|
||||
pub fn parse_status(content: &str) -> Vec<StatusCommand> { |
||||
debug!("Raw content: {}", content); |
||||
|
||||
let content = content.replace("<br/>", " "); |
||||
// let content = content.replace("<br />", " ");
|
||||
// let content = content.replace("<BR/>", " ");
|
||||
// let content = content.replace("<BR />", " ");
|
||||
|
||||
let content = voca_rs::strip::strip_tags(&content); |
||||
debug!("Stripped tags: {}", content); |
||||
|
||||
// short-circuiting commands
|
||||
|
||||
if RE_IGNORE.is_match(&content) { |
||||
debug!("IGNORE"); |
||||
return vec![StatusCommand::Ignore]; |
||||
} |
||||
|
||||
if RE_HELP.is_match(&content) { |
||||
debug!("HELP"); |
||||
return vec![StatusCommand::Help]; |
||||
} |
||||
|
||||
// additive commands
|
||||
|
||||
let mut commands = vec![]; |
||||
|
||||
if RE_BOOST.is_match(&content) { |
||||
debug!("BOOST"); |
||||
commands.push(StatusCommand::Boost); |
||||
} |
||||
|
||||
if RE_LEAVE.is_match(&content) { |
||||
debug!("LEAVE"); |
||||
commands.push(StatusCommand::Leave); |
||||
} |
||||
|
||||
if RE_MEMBERS.is_match(&content) { |
||||
debug!("MEMBERS"); |
||||
commands.push(StatusCommand::ListMembers); |
||||
} |
||||
|
||||
if RE_OPEN_GROUP.is_match(&content) { |
||||
debug!("OPEN GROUP"); |
||||
commands.push(StatusCommand::OpenGroup); |
||||
} |
||||
|
||||
if RE_CLOSE_GROUP.is_match(&content) { |
||||
debug!("CLOSE GROUP"); |
||||
commands.push(StatusCommand::CloseGroup); |
||||
} |
||||
|
||||
if let Some(c) = RE_BAN_USER.captures(&content) { |
||||
if let Some(s) = c.get(1) { |
||||
let s = s.as_str(); |
||||
let s = s.trim_start_matches('@'); |
||||
debug!("BAN USER: {}", s); |
||||
commands.push(StatusCommand::BanUser(s.to_owned())); |
||||
} |
||||
} |
||||
|
||||
if let Some(c) = RE_UNBAN_USER.captures(&content) { |
||||
if let Some(s) = c.get(1) { |
||||
let s = s.as_str(); |
||||
let s = s.trim_start_matches('@'); |
||||
debug!("UNBAN USER: {}", s); |
||||
commands.push(StatusCommand::UnbanUser(s.to_owned())); |
||||
} |
||||
} |
||||
|
||||
if let Some(c) = RE_BAN_SERVER.captures(&content) { |
||||
if let Some(s) = c.get(1) { |
||||
debug!("BAN SERVER: {}", s.as_str()); |
||||
commands.push(StatusCommand::BanServer(s.as_str().to_owned())); |
||||
} |
||||
} |
||||
|
||||
if let Some(c) = RE_UNBAN_SERVER.captures(&content) { |
||||
if let Some(s) = c.get(1) { |
||||
debug!("UNBAN SERVER: {}", s.as_str()); |
||||
commands.push(StatusCommand::UnbanServer(s.as_str().to_owned())); |
||||
} |
||||
} |
||||
|
||||
if let Some(c) = RE_ADD_MEMBER.captures(&content) { |
||||
if let Some(s) = c.get(1) { |
||||
let s = s.as_str(); |
||||
let s = s.trim_start_matches('@'); |
||||
debug!("ADD MEMBER: {}", s); |
||||
commands.push(StatusCommand::AddMember(s.to_owned())); |
||||
} |
||||
} |
||||
|
||||
if let Some(c) = RE_REMOVE_MEMBER.captures(&content) { |
||||
if let Some(s) = c.get(1) { |
||||
let s = s.as_str(); |
||||
let s = s.trim_start_matches('@'); |
||||
debug!("UNBAN USER: {}", s); |
||||
commands.push(StatusCommand::RemoveMember(s.to_owned())); |
||||
} |
||||
} |
||||
|
||||
if let Some(c) = RE_GRANT_ADMIN.captures(&content) { |
||||
if let Some(s) = c.get(1) { |
||||
let s = s.as_str(); |
||||
let s = s.trim_start_matches('@'); |
||||
debug!("ADD ADMIN: {}", s); |
||||
commands.push(StatusCommand::GrantAdmin(s.to_owned())); |
||||
} |
||||
} |
||||
|
||||
if let Some(c) = RE_REVOKE_ADMIN.captures(&content) { |
||||
if let Some(s) = c.get(1) { |
||||
let s = s.as_str(); |
||||
let s = s.trim_start_matches('@'); |
||||
debug!("REMOVE ADMIN: {}", s); |
||||
commands.push(StatusCommand::RemoveAdmin(s.to_owned())); |
||||
} |
||||
} |
||||
|
||||
commands |
||||
} |
||||
|
||||
#[cfg(test)] |
||||
mod test { |
||||
use crate::command::{parse_status, StatusCommand}; |
||||
|
||||
use super::{RE_ADD_MEMBER, RE_BAN_SERVER, RE_BAN_USER, RE_BOOST, RE_CLOSE_GROUP, RE_GRANT_ADMIN, RE_HELP, |
||||
RE_IGNORE, RE_LEAVE, RE_MEMBERS, RE_OPEN_GROUP, RE_REMOVE_MEMBER, RE_REVOKE_ADMIN}; |
||||
|
||||
#[test] |
||||
fn test_boost() { |
||||
assert!(RE_BOOST.is_match("/b")); |
||||
assert!(RE_BOOST.is_match(">/b")); |
||||
assert!(RE_BOOST.is_match("/b mm")); |
||||
assert!(RE_BOOST.is_match("/b.")); |
||||
assert!(RE_BOOST.is_match("\\b")); |
||||
assert!(!RE_BOOST.is_match("boo/b")); |
||||
assert!(RE_BOOST.is_match("bla\n/b")); |
||||
assert!(RE_BOOST.is_match("/boost")); |
||||
assert!(RE_BOOST.is_match("/boost\n")); |
||||
assert!(RE_BOOST.is_match("/boost dfdfg")); |
||||
assert!(!RE_BOOST.is_match("/boosty")); |
||||
assert!(RE_BOOST.is_match("/b\nxxx")); |
||||
assert!(!RE_BOOST.is_match("/bleble\n")); |
||||
} |
||||
|
||||
#[test] |
||||
fn test_ignore() { |
||||
assert!(RE_IGNORE.is_match("/i")); |
||||
assert!(RE_IGNORE.is_match("/i mm")); |
||||
assert!(RE_IGNORE.is_match("/i.")); |
||||
assert!(RE_IGNORE.is_match("\\i")); |
||||
assert!(!RE_IGNORE.is_match("boo/i")); |
||||
assert!(RE_IGNORE.is_match("bla\n/i")); |
||||
assert!(RE_IGNORE.is_match("/ign")); |
||||
assert!(RE_IGNORE.is_match("/ignore")); |
||||
assert!(RE_IGNORE.is_match("/ignore x")); |
||||
assert!(RE_IGNORE.is_match("/ignore\n")); |
||||
assert!(RE_IGNORE.is_match("/ignore dfdfg")); |
||||
assert!(!RE_IGNORE.is_match("/ignorey")); |
||||
assert!(RE_IGNORE.is_match("/i\nxxx")); |
||||
assert!(!RE_IGNORE.is_match("/ileble\n")); |
||||
} |
||||
|
||||
#[test] |
||||
fn test_ban_user() { |
||||
assert!(RE_BAN_USER.is_match("/ban lain@pleroma.soykaf.com")); |
||||
assert!(RE_BAN_USER.is_match("/ban lain@stupidname.uk")); |
||||
assert!(RE_BAN_USER.is_match("bababababa /ban lain@stupidname.uk lala")); |
||||
assert!(!RE_BAN_USER.is_match("/ban stupidname.uk")); |
||||
|
||||
assert!(RE_BAN_USER.is_match("/ban @lain")); |
||||
assert!(RE_BAN_USER.is_match("/ban @lain aaa")); |
||||
|
||||
assert!(RE_BAN_USER.is_match("/ban \t lain@pleroma.soykaf.com")); |
||||
assert!(RE_BAN_USER.is_match("/ban @lain@pleroma.soykaf.com")); |
||||
assert!(RE_BAN_USER.is_match("/ban @l-a_i.n9@xn--999pleroma-weirdname.com")); |
||||
assert!(RE_BAN_USER.is_match("/ban @LAIN@PleromA.soykaf.com")); |
||||
|
||||
let c = RE_BAN_USER.captures("/ban lain@pleroma.soykaf.com"); |
||||
assert!(c.is_some()); |
||||
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "lain@pleroma.soykaf.com"); |
||||
|
||||
let c = RE_BAN_USER.captures("/ban lain@pleroma.soykaf.com xx"); |
||||
assert!(c.is_some()); |
||||
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "lain@pleroma.soykaf.com"); |
||||
|
||||
let c = RE_BAN_USER.captures("/ban @lain@pleroma.soykaf.com"); |
||||
assert!(c.is_some()); |
||||
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "@lain@pleroma.soykaf.com"); |
||||
|
||||
let c = RE_BAN_USER.captures("/ban @lain"); |
||||
assert!(c.is_some()); |
||||
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "@lain"); |
||||
|
||||
let c = RE_BAN_USER.captures("/ban @lain xx"); |
||||
assert!(c.is_some()); |
||||
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "@lain"); |
||||
} |
||||
|
||||
#[test] |
||||
fn test_ban_server() { |
||||
assert!(!RE_BAN_SERVER.is_match("/ban lain@pleroma.soykaf.com")); |
||||
assert!(RE_BAN_SERVER.is_match("/ban pleroma.soykaf.com")); |
||||
assert!(RE_BAN_SERVER.is_match("/ban xn--999pleroma-weirdname.com")); |
||||
assert!(RE_BAN_SERVER.is_match("/ban \t xn--999pleroma-weirdname.com")); |
||||
assert!(RE_BAN_SERVER.is_match("mamama /ban pleroma.soykaf.com momomo")); |
||||
assert!(!RE_BAN_SERVER.is_match("/ban @pleroma.soykaf.com")); |
||||
|
||||
let c = RE_BAN_SERVER.captures("/ban pleroma.soykaf.com"); |
||||
assert!(c.is_some()); |
||||
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "pleroma.soykaf.com"); |
||||
|
||||
let c = RE_BAN_SERVER.captures("/ban pleroma.soykaf.com xx"); |
||||
assert!(c.is_some()); |
||||
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "pleroma.soykaf.com"); |
||||
} |
||||
|
||||
#[test] |
||||
fn test_add_member() { |
||||
assert!(RE_ADD_MEMBER.is_match("/accept lain@pleroma.soykaf.com")); |
||||
assert!(RE_ADD_MEMBER.is_match("/accept @lain@pleroma.soykaf.com")); |
||||
assert!(RE_ADD_MEMBER.is_match("\\accept @lain")); |
||||
|
||||
assert!(RE_ADD_MEMBER.is_match("/invite @lain")); |
||||
assert!(RE_ADD_MEMBER.is_match("/add @lain")); |
||||
assert!(RE_ADD_MEMBER.is_match("/member @lain")); |
||||
|
||||
let c = RE_ADD_MEMBER.captures("/add @lain"); |
||||
assert!(c.is_some()); |
||||
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "@lain"); |
||||
} |
||||
|
||||
#[test] |
||||
fn test_remove_member() { |
||||
assert!(!RE_REMOVE_MEMBER.is_match("/admin lain@pleroma.soykaf.com")); |
||||
|
||||
assert!(RE_REMOVE_MEMBER.is_match("/expel lain@pleroma.soykaf.com")); |
||||
assert!(RE_REMOVE_MEMBER.is_match("/expel @lain@pleroma.soykaf.com")); |
||||
assert!(RE_REMOVE_MEMBER.is_match("\\expel @lain")); |
||||
|
||||
assert!(RE_REMOVE_MEMBER.is_match("/kick @lain")); |
||||
assert!(RE_REMOVE_MEMBER.is_match("/remove @lain")); |
||||
|
||||
let c = RE_REMOVE_MEMBER.captures("/kick lain@pleroma.soykaf.com"); |
||||
assert!(c.is_some()); |
||||
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "lain@pleroma.soykaf.com"); |
||||
} |
||||
|
||||
#[test] |
||||
fn test_add_admin() { |
||||
assert!(!RE_GRANT_ADMIN.is_match("/expel lain@pleroma.soykaf.com")); |
||||
|
||||
assert!(RE_GRANT_ADMIN.is_match("/admin lain@pleroma.soykaf.com")); |
||||
assert!(RE_GRANT_ADMIN.is_match("/grant @lain@pleroma.soykaf.com")); |
||||
assert!(RE_GRANT_ADMIN.is_match("\\op @lain")); |
||||
|
||||
let c = RE_GRANT_ADMIN.captures("/op @lain@pleroma.soykaf.com"); |
||||
assert!(c.is_some()); |
||||
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "@lain@pleroma.soykaf.com"); |
||||
} |
||||
|
||||
#[test] |
||||
fn test_remove_admin() { |
||||
assert!(!RE_REVOKE_ADMIN.is_match("/admin lain@pleroma.soykaf.com")); |
||||
|
||||
assert!(RE_REVOKE_ADMIN.is_match("/revoke @lain")); |
||||
assert!(RE_REVOKE_ADMIN.is_match("/deop @lain")); |
||||
assert!(RE_REVOKE_ADMIN.is_match("/unop @lain")); |
||||
assert!(RE_REVOKE_ADMIN.is_match("/deadmin @lain")); |
||||
assert!(RE_REVOKE_ADMIN.is_match("/unadmin @lain")); |
||||
assert!(RE_REVOKE_ADMIN.is_match("/ungrant @lain")); |
||||
|
||||
let c = RE_REVOKE_ADMIN.captures("/ungrant @lain"); |
||||
assert!(c.is_some()); |
||||
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "@lain"); |
||||
} |
||||
|
||||
#[test] |
||||
fn test_opengroup() { |
||||
assert!(!RE_OPEN_GROUP.is_match("/admin lain@pleroma.soykaf.com")); |
||||
assert!(RE_OPEN_GROUP.is_match("/opengroup")); |
||||
assert!(RE_OPEN_GROUP.is_match("x /opengroup")); |
||||
assert!(RE_OPEN_GROUP.is_match("/opengroup dfgdfg")); |
||||
assert!(RE_OPEN_GROUP.is_match("\n\n/opengroup\n dfgdfg\n\n")); |
||||
} |
||||
|
||||
#[test] |
||||
fn test_closegroup() { |
||||
assert!(!RE_CLOSE_GROUP.is_match("/admin lain@pleroma.soykaf.com")); |
||||
assert!(RE_CLOSE_GROUP.is_match("/closegroup")); |
||||
assert!(RE_CLOSE_GROUP.is_match("x /closegroup")); |
||||
assert!(RE_CLOSE_GROUP.is_match("/closegroup dfgdfg")); |
||||
assert!(RE_CLOSE_GROUP.is_match("\n\n/closegroup\n dfgdfg\n\n")); |
||||
} |
||||
|
||||
#[test] |
||||
fn test_help() { |
||||
assert!(!RE_HELP.is_match("/admin lain@pleroma.soykaf.com")); |
||||
assert!(RE_HELP.is_match("/help")); |
||||
|
||||
assert!(!RE_HELP.is_match("/helpx")); |
||||
assert!(!RE_HELP.is_match("a/help")); |
||||
assert!(!RE_HELP.is_match("help")); |
||||
|
||||
assert!(RE_HELP.is_match("x /help")); |
||||
assert!(RE_HELP.is_match("/help dfgdfg")); |
||||
assert!(RE_HELP.is_match("\n\n/help\n dfgdfg\n\n")); |
||||
} |
||||
|
||||
#[test] |
||||
fn test_members() { |
||||
assert!(!RE_MEMBERS.is_match("/admin lain@pleroma.soykaf.com")); |
||||
assert!(RE_MEMBERS.is_match("/members")); |
||||
assert!(RE_MEMBERS.is_match("/list")); |
||||
} |
||||
|
||||
#[test] |
||||
fn test_leave() { |
||||
assert!(!RE_LEAVE.is_match("/list")); |
||||
assert!(RE_LEAVE.is_match("/leave")); |
||||
assert!(RE_LEAVE.is_match("/quit")); |
||||
assert!(RE_LEAVE.is_match("x /quit")); |
||||
assert!(RE_LEAVE.is_match("/quit z")); |
||||
} |
||||
|
||||
#[test] |
||||
fn test_real_post() { |
||||
assert_eq!(Vec::<StatusCommand>::new(), parse_status("Hello there is nothing here /fake command")); |
||||
assert_eq!(vec![StatusCommand::Help], parse_status("lets see some \\help and /ban @lain")); |
||||
assert_eq!(vec![StatusCommand::Ignore], parse_status("lets see some /ignore and /ban @lain")); |
||||
assert_eq!(vec![StatusCommand::BanUser("lain".to_string()), StatusCommand::BanServer("soykaf.com".to_string())], |
||||
parse_status("let's /ban @lain! and also /ban soykaf.com")); |
||||
} |
||||
|
||||
#[test] |
||||
fn test_strip() { |
||||
assert_eq!(vec![StatusCommand::BanUser("betty".to_string())], |
||||
parse_status(r#"Let's bad the naughty bot: /ban <span class="h-card"><a class="u-url mention" data-user="9nXpaGZL88fPAiP8xU" href="https://piggo.space/users/betty" rel="ugc">@<span>betty</span></a></span>"#)); |
||||
assert_eq!(vec![StatusCommand::BanUser("betty@abstarbauze.com".to_string())], |
||||
parse_status(r#"Let's bad the naughty bot: /ban <span class="h-card"><a class="u-url mention" data-user="9nXpaGZL88fPAiP8xU" href="https://piggo.space/users/betty" rel="ugc">@<span>betty@abstarbauze.com</span></a></span>"#)); |
||||
} |
||||
} |
Loading…
Reference in new issue