use std::error::Error; use std::fmt; use crate::crypto_wrapper::CryptoWrapper; use crate::remote_ip::RemoteIP; use crate::time_utils::time; use crate::Res; use bincode::{Decode, Encode}; use std::net::IpAddr; pub struct StateManager; static mut WRAPPER: Option = None; #[derive(Encode, Decode, Debug)] struct State { ip: IpAddr, expire: u64, } impl State { pub fn new(ip: IpAddr) -> Self { Self { ip, expire: time() + 15 * 60, } } } #[derive(Debug, Copy, Clone)] enum StateError { InvalidIp, Expired, } impl Error for StateError {} impl fmt::Display for StateError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "StateManager error {:?}", self) } } impl StateManager { pub fn init() { unsafe { WRAPPER = Some(CryptoWrapper::new_random()); } } /// Generate a new state pub fn gen_state(ip: &RemoteIP) -> Res { let state = State::new(ip.0); unsafe { WRAPPER.as_ref().unwrap() }.encrypt(&state) } /// Validate generated state pub fn validate_state(ip: &RemoteIP, state: &str) -> Res { let state: State = unsafe { WRAPPER.as_ref().unwrap() }.decrypt(state)?; if state.ip != ip.0 { return Err(Box::new(StateError::InvalidIp)); } if state.expire < time() { return Err(Box::new(StateError::Expired)); } Ok(()) } }