diff --git a/services/identity/Cargo.lock b/services/identity/Cargo.lock --- a/services/identity/Cargo.lock +++ b/services/identity/Cargo.lock @@ -1494,6 +1494,7 @@ "once_cell", "prost", "rand 0.8.5", + "regex", "serde", "serde_json", "siwe", diff --git a/services/identity/Cargo.toml b/services/identity/Cargo.toml --- a/services/identity/Cargo.toml +++ b/services/identity/Cargo.toml @@ -30,6 +30,7 @@ moka = { version = "0.10", features = ["future"] } uuid = { version = "1.3", features = [ "v4" ] } base64 = "0.21.2" +regex = "1" [build-dependencies] tonic-build = "0.9.1" diff --git a/services/identity/src/client_service.rs b/services/identity/src/client_service.rs --- a/services/identity/src/client_service.rs +++ b/services/identity/src/client_service.rs @@ -33,7 +33,7 @@ use crate::id::generate_uuid; use crate::nonce::generate_nonce_data; use crate::reserved_users::{ - validate_add_reserved_usernames_message, + is_valid_ethereum_address, validate_add_reserved_usernames_message, validate_remove_reserved_username_message, validate_signed_account_ownership_message, }; @@ -116,7 +116,9 @@ return Err(tonic::Status::already_exists("username already exists")); } - if CONFIG.reserved_usernames.contains(&message.username) { + if CONFIG.reserved_usernames.contains(&message.username) + || is_valid_ethereum_address(&message.username) + { return Err(tonic::Status::invalid_argument("username reserved")); } diff --git a/services/identity/src/reserved_users.rs b/services/identity/src/reserved_users.rs --- a/services/identity/src/reserved_users.rs +++ b/services/identity/src/reserved_users.rs @@ -2,6 +2,7 @@ use chrono::{DateTime, Utc}; use constant_time_eq::constant_time_eq; use ed25519_dalek::{PublicKey, Signature, Verifier}; +use regex::Regex; use serde::Deserialize; use tonic::Status; @@ -112,3 +113,52 @@ Ok(deserialized_message.payload) } + +pub fn is_valid_ethereum_address(candidate: &str) -> bool { + let ethereum_address_regex = Regex::new(r"^0x[a-fA-F0-9]{40}$").unwrap(); + ethereum_address_regex.is_match(candidate) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_valid_ethereum_address() { + assert!(is_valid_ethereum_address( + "0x1234567890123456789012345678901234567890" + ),); + assert!(is_valid_ethereum_address( + "0xABCDEF123456789012345678901234567890ABCD" + )); + assert!(is_valid_ethereum_address( + "0xabcdef123456789012345678901234567890abcd" + )); + } + + #[test] + fn test_invalid_ethereum_address() { + // Shorter than 42 characters + assert_eq!( + is_valid_ethereum_address("0x12345678901234567890123456789012345678"), + false + ); + // Longer than 42 characters + assert_eq!( + is_valid_ethereum_address("0x123456789012345678901234567890123456789012"), + false + ); + // Missing 0x prefix + assert_eq!( + is_valid_ethereum_address("1234567890123456789012345678901234567890"), + false + ); + // Contains invalid characters + assert_eq!( + is_valid_ethereum_address("0x1234567890GHIJKL9012345678901234567890"), + false + ); + // Empty string + assert_eq!(is_valid_ethereum_address(""), false); + } +}