use crate::error::Error; use base64::{Engine as _, engine::general_purpose}; use j_db::database::Database; use j_db::model::JdbModel; use poise::serenity_prelude::model::id::UserId; use rand::distr::Alphanumeric; use rand::{Rng, rng}; use serde::{Deserialize, Serialize}; use sha3::digest::FixedOutput; use sha3::{Digest, Sha3_256}; #[derive(Debug, Deserialize, Serialize, Clone)] pub struct Apikey { id: Option, pub name: String, pub hash: String, pub user_id: Option, } impl 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() } } impl Apikey { pub fn new(name: &str, user_id: Option) -> (Self, String) { let secret: String = rng() .sample_iter(&Alphanumeric) .take(64) .map(char::from) .collect(); let hash = Self::hash_secret(&secret); ( Self { id: None, name: name.to_string(), hash, user_id, }, secret, ) } fn hash_secret(secret: &str) -> String { let mut hasher = Sha3_256::default(); hasher.update(secret); let hash = hasher.finalize_fixed().to_vec(); general_purpose::STANDARD_NO_PAD.encode(hash) } #[allow(dead_code)] pub fn find_key_from_secret(db: &Database, secret: &str) -> Result, Error> { let hash = Self::hash_secret(secret); Ok(db.filter(move |_, key: &Self| key.hash == hash)?.next()) } }