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 } } } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct User { name: String, hashed_password: String, id: UID, sessions: HashMap, tokovec: Vec, } impl User { pub fn new(name: String, password: String, id: UID) -> 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, hashed_password, id, tokovec: base_tokens, sessions: HashMap::new() } } 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, } 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 } } 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 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 new_user(&mut self, name: String, password: String, id: UID) -> Result { let user = User::new(name, password, id); self.users.push(user.clone()); match self.save().await { Ok(_) => Ok(user), Err(n) => Err(n), } } 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) -> Result { 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 } 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()) } } }