All checks were successful
continuous-integration/drone/push Build is passing
73 lines
1.5 KiB
Rust
73 lines
1.5 KiB
Rust
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<CryptoWrapper> = 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<String> {
|
|
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(())
|
|
}
|
|
}
|