Spaces:
Sleeping
Sleeping
File size: 4,821 Bytes
7856e60 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | use once_cell::sync::Lazy;
use regex::Regex;
static PHONE_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"^[6-9]\d{9}$").unwrap());
static EMAIL_REGEX: Lazy<Regex> =
Lazy::new(|| Regex::new(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$").unwrap());
static PINCODE_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"^[1-9]\d{5}$").unwrap());
pub fn validate_email(email: &str) -> Result<(), ValidationError> {
if email.is_empty() {
return Err(ValidationError::new("Email cannot be empty"));
}
if email.len() > 255 {
return Err(ValidationError::new("Email too long"));
}
if !EMAIL_REGEX.is_match(email) {
return Err(ValidationError::new("Invalid email format"));
}
Ok(())
}
pub fn validate_pincode(pincode: &str) -> Result<(), ValidationError> {
if pincode.is_empty() {
return Err(ValidationError::new("Pincode cannot be empty"));
}
if !PINCODE_REGEX.is_match(pincode) {
return Err(ValidationError::new(
"Invalid Indian pincode format (6 digits starting with 1-9)",
));
}
Ok(())
}
pub fn validate_price(price: f64) -> Result<(), ValidationError> {
if price <= 0.0 {
return Err(ValidationError::new("Price must be greater than 0"));
}
if price > 1_000_000.0 {
return Err(ValidationError::new("Price exceeds maximum allowed value"));
}
if price.is_nan() || price.is_infinite() {
return Err(ValidationError::new("Invalid price value"));
}
Ok(())
}
pub fn validate_product_name(name: &str) -> Result<(), ValidationError> {
if name.trim().is_empty() {
return Err(ValidationError::new("Product name cannot be empty"));
}
if name.len() > 200 {
return Err(ValidationError::new(
"Product name too long (max 200 characters)",
));
}
Ok(())
}
pub fn validate_weight(weight: f64) -> Result<(), ValidationError> {
if weight < 0.0 {
return Err(ValidationError::new("Weight cannot be negative"));
}
if weight > 100_000.0 {
// 100kg limit for social checkout
return Err(ValidationError::new(
"Weight exceeds maximum allowed value (100kg)",
));
}
if weight.is_nan() || weight.is_infinite() {
return Err(ValidationError::new("Invalid weight value"));
}
Ok(())
}
pub fn sanitize_string(input: &str) -> String {
input
.trim()
.chars()
.filter(|c| !c.is_control())
.take(1000)
.collect()
}
pub fn normalize_phone(phone: &str) -> Result<String, ValidationError> {
if phone.is_empty() {
return Err(ValidationError::new("Phone cannot be empty"));
}
let digits: String = phone.chars().filter(|c| c.is_ascii_digit()).collect();
let normalized = match digits.len() {
10 => digits,
11 if digits.starts_with('0') => digits[1..].to_string(),
12 if digits.starts_with("91") => digits[2..].to_string(),
_ => return Err(ValidationError::new("Invalid Indian phone number format")),
};
if !PHONE_REGEX.is_match(&normalized) {
return Err(ValidationError::new("Invalid Indian phone number format"));
}
Ok(normalized)
}
pub fn validate_base64_payload(data: &str, max_bytes: usize) -> Result<Vec<u8>, ValidationError> {
if data.is_empty() {
return Err(ValidationError::new("Base64 payload cannot be empty"));
}
let raw_data = if let Some(pos) = data.find(',') {
&data[pos + 1..]
} else {
data
};
use base64::{engine::general_purpose, Engine as _};
match general_purpose::STANDARD.decode(raw_data) {
Ok(bytes) => {
if bytes.len() > max_bytes {
return Err(ValidationError::new(&format!(
"Payload exceeds maximum size of {} bytes",
max_bytes
)));
}
Ok(bytes)
}
Err(_) => Err(ValidationError::new("Invalid Base64 encoding")),
}
}
pub fn sanitize_filename(filename: &str) -> String {
let sanitized: String = filename
.replace("..", "")
.chars()
.filter(|c| c.is_alphanumeric() || *c == '.' || *c == '-' || *c == '_')
.collect();
if sanitized.starts_with('.') || sanitized.is_empty() {
return "unnamed".to_string();
}
sanitized.chars().take(255).collect()
}
#[derive(Debug, Clone)]
pub struct ValidationError {
pub message: String,
}
impl ValidationError {
pub fn new(msg: &str) -> Self {
Self {
message: msg.to_string(),
}
}
}
impl std::fmt::Display for ValidationError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.message)
}
}
impl std::error::Error for ValidationError {}
|