diff --git a/Cargo.toml b/Cargo.toml index e2ae8bb..3634df7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,4 @@ json = "^0.12.4" num-bigint = "^0.4.3" serde = { version = "1.0.149", features = ["serde_derive"] } serde_json = "1.0.89" +regex = "1.8.1" diff --git a/src/server.rs b/src/server.rs index cafc5d9..8ab7c10 100644 --- a/src/server.rs +++ b/src/server.rs @@ -4,6 +4,7 @@ use crate::types::edge::EdgeDB; use crate::types::{Address, Edge, U256}; use json::JsonValue; use num_bigint::BigUint; +use regex::Regex; use std::error::Error; use std::fmt::{Debug, Display, Formatter}; use std::io::Read; @@ -35,6 +36,38 @@ impl Display for InputValidationError { } } +fn validate_and_parse_ethereum_address(address: &str) -> Result> { + let re = Regex::new(r"^0x[0-9a-fA-F]{40}$").unwrap(); + if re.is_match(address) { + Ok(Address::from(address)) + } else { + Err(Box::new(InputValidationError(format!( + "Invalid Ethereum address: {}", + address + )))) + } +} + +fn validate_and_parse_u256(value_str: &str) -> Result> { + match BigUint::from_str(value_str) { + Ok(parsed_value) => { + if parsed_value > U256::MAX.into() { + Err(Box::new(InputValidationError(format!( + "Value {} is too large. Maximum value is {}.", + parsed_value, + U256::MAX + )))) + } else { + Ok(U256::from_bigint_truncating(parsed_value)) + } + } + Err(e) => Err(Box::new(InputValidationError(format!( + "Invalid value: {}. Couldn't parse value: {}", + value_str, e + )))), + } +} + pub fn start_server(listen_at: &str, queue_size: usize, threads: u64) { let edges: Arc>> = Arc::new(RwLock::new(Arc::new(EdgeDB::default()))); @@ -156,38 +189,26 @@ fn compute_transfer( socket.write_all(chunked_header().as_bytes())?; let parsed_value_param = match request.params["value"].as_str() { - Some(value_str) => match BigUint::from_str(value_str) { - Ok(parsed_value) => parsed_value, - Err(e) => { - return Err(Box::new(InputValidationError(format!( - "Invalid value: {}. Couldn't parse value: {}", - value_str, e - )))); - } - }, - None => U256::MAX.into(), + Some(value_str) => validate_and_parse_u256(value_str)?, + None => U256::MAX, }; - if parsed_value_param > U256::MAX.into() { - return Err(Box::new(InputValidationError(format!( - "Value {} is too large. Maximum value is {}.", - parsed_value_param, - U256::MAX - )))); - } + let from_address = validate_and_parse_ethereum_address(&request.params["from"].to_string())?; + let to_address = validate_and_parse_ethereum_address(&request.params["to"].to_string())?; let max_distances = if request.params["iterative"].as_bool().unwrap_or_default() { vec![Some(1), Some(2), None] } else { vec![None] }; + let max_transfers = request.params["max_transfers"].as_u64(); for max_distance in max_distances { let (flow, transfers) = graph::compute_flow( - &Address::from(request.params["from"].to_string().as_str()), - &Address::from(request.params["to"].to_string().as_str()), + &from_address, + &to_address, edges, - U256::from_bigint_truncating(parsed_value_param.clone()), + parsed_value_param, max_distance, max_transfers, );