use authc::{AuthClient, AuthToken, Uuid}; use common::msg::RegisterError; use hashbrown::HashMap; use log::error; use std::str::FromStr; fn derive_uuid(username: &str) -> Uuid { let mut state = 144066263297769815596495629667062367629; for byte in username.as_bytes() { state ^= *byte as u128; state = state.wrapping_mul(309485009821345068724781371); } Uuid::from_slice(&state.to_be_bytes()).unwrap() } pub struct AuthProvider { accounts: HashMap, auth_server: Option, } impl AuthProvider { pub fn new(auth_addr: Option) -> Self { let auth_server = match auth_addr { Some(addr) => Some(AuthClient::new(addr)), None => None, }; AuthProvider { accounts: HashMap::new(), auth_server, } } pub fn logout(&mut self, uuid: Uuid) { if self.accounts.remove(&uuid).is_none() { error!("Attempted to logout user that is not logged in."); }; } pub fn query(&mut self, username_or_token: String) -> Result<(String, Uuid), RegisterError> { // Based on whether auth server is provided or not we expect an username or // token match &self.auth_server { // Token from auth server expected Some(srv) => { log::info!("Validating '{}' token.", &username_or_token); // Parse token let token = AuthToken::from_str(&username_or_token) .map_err(|e| RegisterError::AuthError(e.to_string()))?; // Validate token let uuid = srv.validate(token)?; // Check if already logged in if self.accounts.contains_key(&uuid) { return Err(RegisterError::AlreadyLoggedIn); } // Log in let username = srv.uuid_to_username(uuid)?; self.accounts.insert(uuid, username.clone()); Ok((username, uuid)) }, // Username is expected None => { // Assume username was provided let username = username_or_token; let uuid = derive_uuid(&username); if !self.accounts.contains_key(&uuid) { log::info!("New User '{}'", username); self.accounts.insert(uuid, username.clone()); Ok((username, uuid)) } else { Err(RegisterError::AlreadyLoggedIn) } }, } } }