use base64::Engine; use serde::Deserialize; #[derive(Debug, Clone, Deserialize)] #[serde(default)] pub struct PowConfig { pub difficulty: u32, pub max_difficulty: u32, pub expires_secs: u64, pub mac_key: Option, } impl Default for PowConfig { fn default() -> Self { Self { difficulty: 16, max_difficulty: 24, expires_secs: 60, mac_key: None, } } } impl PowConfig { pub fn new() -> Self { Self::default() } pub fn with_difficulty(mut self, difficulty: u32) -> Self { self.difficulty = difficulty; self } pub fn with_max_difficulty(mut self, max_difficulty: u32) -> Self { self.max_difficulty = max_difficulty; self } pub fn with_expires_secs(mut self, expires_secs: u64) -> Self { self.expires_secs = expires_secs; self } pub fn with_mac_key(mut self, mac_key: impl Into) -> Self { self.mac_key = Some(mac_key.into()); self } pub fn validate(&self) -> Result<(), String> { if self.max_difficulty > 256 { return Err("pow.max_difficulty must be <= 256".to_string()); } if self.difficulty > self.max_difficulty { return Err("pow.difficulty must be <= pow.max_difficulty".to_string()); } if self.expires_secs == 0 { return Err("pow.expires_secs must be greater than 0".to_string()); } match &self.mac_key { Some(key) => { let length = base64::engine::general_purpose::STANDARD .decode(key) .map(|bytes| bytes.len()) .unwrap_or(0); if length < 32 { return Err("pow.mac_key must be base64 of at least 32 bytes".to_string()); } } None => return Err("pow.mac_key is required".to_string()), } Ok(()) } }