fn is_disguise_control(c: char) -> bool {
matches!(c,
'\u{202A}'..='\u{202E}' | '\u{2066}'..='\u{2069}' | '\u{200E}' | '\u{200F}' | '\u{061C}' | '\u{200B}' | '\u{200C}' | '\u{200D}' | '\u{FEFF}' ) || c.is_control()
}
pub fn has_disguise_control(text: &str) -> bool {
text.chars().any(is_disguise_control)
}
pub fn is_spoofed_token(name: &str, symbol: &str) -> bool {
has_disguise_control(name) || has_disguise_control(symbol)
}
pub fn sanitize_display(text: &str) -> String {
text.chars().filter(|c| !is_disguise_control(*c)).collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn plain_text_is_not_spoofed() {
assert!(!is_spoofed_token("USD Coin", "USDC"));
assert_eq!(sanitize_display("USDC"), "USDC");
}
#[test]
fn rlo_disguise_is_detected_and_stripped() {
let sym = "USD\u{202E}C";
assert!(is_spoofed_token("", sym));
assert_eq!(sanitize_display(sym), "USDC");
}
#[test]
fn zero_width_and_bom_are_detected() {
assert!(is_spoofed_token("Te\u{200B}st", ""));
assert!(is_spoofed_token("", "\u{FEFF}SOL"));
assert_eq!(sanitize_display("\u{FEFF}SOL"), "SOL");
}
#[test]
fn control_chars_are_detected() {
assert!(is_spoofed_token("line\nbreak", ""));
assert_eq!(sanitize_display("a\tb"), "ab");
}
}