use base64::Engine; use j_db::database::Database; use serde::{Deserialize, Serialize}; use std::str::FromStr; use bitflags::bitflags; use rand::RngCore; use sha2::Digest; bitflags! { #[derive(Serialize, Deserialize, Clone, Debug)] pub struct ApiPermissions: u32 { const WRITE = 0b00000001; const DELETE = 0b00000010; } } impl FromStr for ApiPermissions { type Err = bitflags::parser::ParseError; fn from_str(s: &str) -> Result { bitflags::parser::from_str(s) } } #[derive(Serialize, Deserialize, Clone, Debug)] pub struct ApiKey { pub token_hash: String, pub description: String, pub permissions: ApiPermissions, id: Option, } impl ApiKey { pub fn create_new_key( db: &Database, description: String, permissions: ApiPermissions, ) -> Result<(Vec, ApiKey), j_db::error::JDbError> { let mut key = [0u8; 32]; rand::thread_rng().fill_bytes(&mut key); let hash = sha2::Sha256::digest(key); let api_key = ApiKey { token_hash: base64::prelude::BASE64_STANDARD.encode(hash), description, permissions, id: None, }; let api_key = db.insert(api_key)?; Ok((key.to_vec(), api_key)) } pub fn find_api_key_by_token( db: &Database, token: &str, ) -> Result, j_db::error::JDbError> { let token = base64::prelude::BASE64_STANDARD.decode(token).unwrap(); let hash = sha2::Sha256::digest(token); let hash = base64::prelude::BASE64_STANDARD.encode(hash); Ok(db .filter(move |_, api_key: &ApiKey| api_key.token_hash == hash)? .next()) } } impl j_db::model::JdbModel for ApiKey { fn id(&self) -> Option { self.id } fn set_id(&mut self, id: u64) { self.id = Some(id); } fn tree() -> String { "ApiKey".to_string() } }