dash_platform_queries/
dpns_usernames.rs1pub fn convert_to_homograph_safe_chars(input: &str) -> String {
10 input
11 .chars()
12 .map(|c| match c {
13 'o' | 'O' => '0',
14 'i' | 'I' => '1',
15 'l' | 'L' => '1',
16 _ => c.to_ascii_lowercase(),
17 })
18 .collect()
19}
20
21pub fn is_valid_username(label: &str) -> bool {
39 if label.len() < 3 || label.len() > 63 {
41 return false;
42 }
43
44 let chars: Vec<char> = label.chars().collect();
45
46 if !chars[0].is_ascii_alphanumeric() {
48 return false;
49 }
50
51 if !chars[chars.len() - 1].is_ascii_alphanumeric() {
53 return false;
54 }
55
56 for &ch in &chars[1..chars.len() - 1] {
58 if !ch.is_ascii_alphanumeric() && ch != '-' {
59 return false;
60 }
61 }
62
63 for i in 0..chars.len() - 1 {
65 if chars[i] == '-' && chars[i + 1] == '-' {
66 return false;
67 }
68 }
69
70 true
71}
72
73pub fn is_contested_username(label: &str) -> bool {
87 let normalized = convert_to_homograph_safe_chars(label);
88
89 if normalized.len() < 3 || normalized.len() > 19 {
91 return false;
92 }
93
94 normalized
96 .chars()
97 .all(|c| matches!(c, 'a'..='z' | '0' | '1' | '-'))
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103
104 #[test]
105 fn test_convert_to_homograph_safe_chars() {
106 assert_eq!(convert_to_homograph_safe_chars("alice"), "a11ce");
107 assert_eq!(convert_to_homograph_safe_chars("bob"), "b0b");
108 assert_eq!(convert_to_homograph_safe_chars("COOL"), "c001");
109 assert_eq!(convert_to_homograph_safe_chars("test123"), "test123");
110 }
111
112 #[test]
113 fn test_is_valid_username() {
114 assert!(is_valid_username("abc"));
116 assert!(is_valid_username("alice"));
117 assert!(is_valid_username("Alice123"));
118 assert!(is_valid_username("dash-p2p"));
119 assert!(is_valid_username("test-name-123"));
120 assert!(is_valid_username("a-b-c"));
121 assert!(is_valid_username("user2024"));
122 assert!(is_valid_username("CryptoKing"));
123 assert!(is_valid_username("web3-developer"));
124 assert!(is_valid_username("a".repeat(63).as_str())); assert!(!is_valid_username("ab"));
128 assert!(!is_valid_username("a"));
129 assert!(!is_valid_username(""));
130
131 assert!(!is_valid_username("a".repeat(64).as_str()));
133
134 assert!(!is_valid_username("-alice"));
136 assert!(!is_valid_username("-test"));
137
138 assert!(!is_valid_username("alice-"));
140 assert!(!is_valid_username("test-"));
141
142 assert!(!is_valid_username("-alice-"));
144
145 assert!(!is_valid_username("alice_bob")); assert!(!is_valid_username("alice.bob")); assert!(!is_valid_username("alice@dash")); assert!(!is_valid_username("alice!")); assert!(!is_valid_username("alice bob")); assert!(!is_valid_username("alice#1")); assert!(!is_valid_username("alice$")); assert!(!is_valid_username("alice%20")); assert!(!is_valid_username("alice--bob"));
157 assert!(!is_valid_username("test---name"));
158 }
159
160 #[test]
161 fn test_is_contested_username() {
162 assert!(is_contested_username("abc"));
164 assert!(is_contested_username("alice")); assert!(is_contested_username("b0b"));
166 assert!(is_contested_username("cool")); assert!(is_contested_username("a-b-c"));
168 assert!(is_contested_username("hello")); assert!(is_contested_username("world")); assert!(is_contested_username("dash"));
171 assert!(is_contested_username("a11ce")); assert!(is_contested_username("dash-dao")); assert!(!is_contested_username("ab"));
176 assert!(!is_contested_username("io")); assert!(!is_contested_username("a"));
178
179 assert!(!is_contested_username("twenty-characters-ab")); assert!(!is_contested_username(
182 "this-is-a-very-long-username-that-exceeds-limit"
183 ));
184
185 assert!(!is_contested_username("alice2")); assert!(!is_contested_username("alice_bob")); assert!(!is_contested_username("alice.bob")); assert!(!is_contested_username("alice@dash")); assert!(!is_contested_username("alice!")); assert!(!is_contested_username("test123")); assert!(!is_contested_username("dash-p2p")); assert!(!is_contested_username("user5")); assert!(!is_contested_username("name_with_underscore")); }
196}