use serde::{Serialize, Deserialize}; use sha2::{Digest, Sha256}; use std::collections::HashMap; use std::path::PathBuf; use std::{fs::File, io::Write}; use crate::uid::{self, UID}; #[derive(Serialize, Deserialize)] pub struct Config { dbsave: PathBuf, realm: String, } impl Config { pub fn new() -> Config { Config { dbsave: "db.json".into(), realm: "localhost".into() } } } #[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] pub enum Color { White, Red, Blue, Green, Yellow, } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Token { color: Color, amount: usize, } impl Token { pub fn new(color: Color, amount: usize) -> Token { Token { color, amount } } } fn default_is_admin() -> bool { false } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct User { name: String, hashed_password: String, #[serde(default = "default_is_admin")] is_admin: bool, id: UID, sessions: HashMap, tokovec: Vec, } impl User { pub fn new(name: String, password: String, id: UID, admin: bool) -> User { let base_tokens = vec![ Token::new(Color::White, 2), Token::new(Color::Red, 2), Token::new(Color::Blue, 2), Token::new(Color::Green, 2), Token::new(Color::Yellow, 2), ]; let hashed_password = User::hash(&password); User { name, is_admin: admin, hashed_password, id, tokovec: base_tokens, sessions: HashMap::new() } } pub fn is_admin(&self) -> bool { self.is_admin } fn update_name(&mut self, new_name: String) { self.name = new_name; } fn update_password(&mut self, old_password: &String, new_password: &String) -> Result<(), String> { if self.same_password(old_password) { self.hashed_password = User::hash(&new_password); return Ok(()); } else { return Err("Old Password is Incorrect".into()) } } fn same_password(&self, password: &String) -> bool { User::hash(password) == self.hashed_password } fn hash(t: &String) -> String { let hashed = Sha256::digest(&t); let hashed = base16ct::lower::encode_string(&hashed); hashed } fn new_session(&mut self, client: String) -> String { let hash: [u8; 32] = rand::random(); let hash = User::hash(&hash.iter().map(|v| {format!("{}", v)}).collect()); self.sessions.insert(hash.clone(), client); hash } fn rm_session(&mut self, session: &String) -> Result<(), String> { match self.sessions.remove(session) { Some(_) => Ok(()), None => Err("Could not find sessoin".into()), } } fn clear_sessions(&mut self, session: &String) { if self.authenticate(session) { self.sessions.clear() } } fn get_sessions(&self, session: &String) -> Result, String> { if self.authenticate(session) { let v = self.sessions.iter().map(|(k, v)| { (k.clone(), v.clone()) }).collect(); Ok(v) } else { Err("Not Authenticated".into()) } } fn login(&mut self, password: &String, clientid: &String) -> Result { if self.hashed_password == User::hash(password) { Ok(self.new_session(clientid.clone())) } else { Err("Could not login".into()) } } fn authenticate(&self, session: &String) -> bool { match self.sessions.get(session) { // Session authenticated/found Some(_) => true, // Session not found None => false, } } fn logout(&mut self, session: &String) -> Result<(), String> { if self.authenticate(session) { self.rm_session(session) } else { Err("Not Authenticated".into()) } } pub fn get_name(&self) -> String { self.name.clone() } pub fn get_tokovec(&self) -> Vec { self.tokovec.clone() } pub fn get_id(&self) -> UID { self.id } } #[derive(Serialize, Deserialize)] pub struct DB { pub uid_generator: uid::Generator, users: Vec, config: Config, registration_keys: Vec, } impl DB { async fn save(&self) -> Result<(), String> { let mut f = match File::create(&self.config.dbsave) { Ok(n) => n, Err(n) => { match n.kind() { std::io::ErrorKind::PermissionDenied => panic!("{:?}: Permission Denied", &self.config.dbsave), n => return Err(n.to_string()), } }, }; let s = match serde_json::to_string(self) { Ok(n) => n, Err(n) => return Err(n.to_string()), }; match f.write(s.as_bytes()) { Ok(_) => return Ok(()), Err(n) => return Err(n.to_string()), }; } pub fn load(c: Config) -> Self { match File::open(&c.dbsave) { Ok(n) => { match serde_json::from_reader(n) { Ok(n) => n, Err(n) => panic!("{}", n), } }, Err(n) => match n.kind() { std::io::ErrorKind::PermissionDenied => panic!("{:?}: Permission Denied", &c.dbsave), _ => DB::new(c), }, } } pub fn new(config: Config) -> Self { DB { uid_generator: uid::Generator::new(), users: vec![], config, registration_keys: vec!["ADMIN".into()] } } pub fn get_user(&self, id: UID) -> Result<&User, String> { for u in self.users.iter() { if u.id == id { return Ok(u) } } Err("User Not Found".into()) } pub async fn update_user_password(&mut self, id: UID, session: &String, old_password: &String, new_password: &String) -> Result<(), String> { self.get_user_authenticated(id, session).await?; let user = self.get_mut_user(id).await?; user.update_password(old_password, new_password)?; self.save().await?; Ok(()) } pub async fn update_user_name(&mut self, id: UID, session: &String, name: &String) -> Result<(), String> { self.get_user_authenticated(id, session).await?; let user = self.get_mut_user(id).await?; user.update_name(name.clone()); self.save().await?; Ok(()) } pub async fn get_user_authenticated(&self, id: UID, session: &String) -> Result<&User, String> { match self.get_user(id) { Ok(u) => { if u.authenticate(session) { Ok(u) } else { Err("Not Authenticated".into()) } }, Err(n) => Err(n) } } pub async fn get_mut_user(&mut self, id: UID) -> Result<&mut User, String> { for u in self.users.iter_mut() { if u.id == id { return Ok(u) } } Err("User Not Found".into()) } pub async fn get_user_by_name(&self, name: &str) -> Result, String> { let mut vec = vec![]; for u in self.users.clone() { if u.name == name { vec.push(u) } } if vec.len() == 0 { Err("User(s) Not Found".into()) } else { return Ok(vec) } } pub async fn get_all_users(&self) -> Result, String> { if self.users.len() == 0 { Err("No Users".into()) } else { Ok(self.users.clone()) } } pub async fn use_key(&mut self, key: &String) -> Result<(), String> { let mut result = Err("Could not find key".into()); let new_vec = self.registration_keys.clone().into_iter().filter_map(|k| { if *key == k { result = Ok(()); None } else { Some(k) } }).collect(); self.registration_keys = new_vec; result } fn add_key(&mut self, key: &String) -> Result<(), String> { if self.registration_keys.contains(key) { Err("Key already exists".into()) } else { self.registration_keys.push(key.clone()); Ok(()) } } pub async fn new_registration_key(&mut self, id: UID, session: &String, key: &String) -> Result<(), String> { let u = self.get_user_authenticated(id, session).await?; if u.is_admin() { self.add_key(key)?; self.save().await } else { Err("Not an admin".into()) } } pub async fn del_registration_key(&mut self, id: UID, session: &String, key: &String) -> Result<(), String> { let u = self.get_user_authenticated(id, session).await?; if u.is_admin() { self.use_key(key).await?; self.save().await } else { Err("Not an admin".into()) } } pub async fn list_registration_keys(&self, id: UID, session: &String) -> Result, String> { let u = self.get_user_authenticated(id, session).await?; if u.is_admin() { Ok(self.registration_keys.clone()) } else { Err("Not an admin".into()) } } pub async fn new_user(&mut self, name: String, password: String, id: UID, key: &String) -> Result { if self.use_key(key).await.is_ok() { let mut is_admin = false; if key == "ADMIN" { is_admin = true; } let user = User::new(name, password, id, is_admin); self.users.push(user.clone()); match self.save().await { Ok(_) => Ok(user), Err(n) => { self.add_key(key)?; Err(n) }, } } else { Err("Invalid key".into()) } } pub async fn login(&mut self, id: UID, password: &String, clientid: &String) -> Result { let r = match self.get_mut_user(id).await { Ok(n) => { n.login(password, clientid) }, Err(n) => Err(n) }; let _ = self.save().await; r } pub async fn logout(&mut self, id: UID, session: &String) -> Result<(), String> { let r = match self.get_mut_user(id).await { Ok(n) => { n.logout(session) }, Err(n) => Err(n) }; let _ = self.save().await; r } pub async fn logout_all(&mut self, id: UID, session: &String) -> Result { let r = match self.get_mut_user(id).await { Ok(n) => { n.clear_sessions(session); Ok("Logged out of everything".into()) }, Err(n) => Err(n) }; let _ = self.save().await; r } pub async fn get_sessions(&self, id: UID, session: &String) -> Result, String> { let r = match self.get_user(id) { Ok(n) => { n.get_sessions(session) }, Err(n) => Err(n) }; let _ = self.save().await; r } pub async fn delete_user(&mut self, id: UID, session: &String, password: &String) -> Result { let u = self.get_user(id)?; if u.same_password(password) { self.users = self.users.clone().into_iter().filter(|u| !u.authenticate(session) && id != u.id).collect(); self.uid_generator.delete_uid(id); // Validate let r = match self.get_user(id) { Ok(_) => Err("Could not delete".into()), Err(_) => { Ok("Deleted".into()) }, }; let _ = self.save().await; r } else { return Err("Password does not match".into()) } } pub async fn transfer(&mut self, from: UID, to: UID, session: &String, color: Color, amount: usize) -> Result<(), String> { let mut subtracted = false; let from = self.get_mut_user(from).await?; // If authenticated if from.authenticate(session) { for v in from.tokovec.iter_mut() { // Get the token of the right color if v.color == color { // If amount is greater or equal to amount being sent // and if the amount does not overflow past 0 if v.amount >= amount && v.amount.checked_sub(amount) != None { // Remove from account v.amount -= amount; subtracted = true; } } } } let to = self.get_mut_user(to).await?; if subtracted { for v in to.tokovec.iter_mut() { if v.color == color { v.amount += amount } } let _ = self.save().await; Ok(()) } else { Err("Could not complete transaction".into()) } } }