use crate::action::Action; use crate::error::{AuthControllerError, Result}; use crate::store::{KeyId, KEY_ID_LENGTH}; use chrono::{DateTime, Utc}; use rand::Rng; use serde::{Deserialize, Serialize}; use serde_json::{from_value, Value}; #[derive(Debug, Deserialize, Serialize)] pub struct Key { #[serde(skip_serializing_if = "Option::is_none")] pub description: Option, pub id: KeyId, pub actions: Vec, pub indexes: Vec, pub expires_at: Option>, pub created_at: DateTime, pub updated_at: DateTime, } impl Key { pub fn create_from_value(value: Value) -> Result { let description = value .get("description") .map(|des| { from_value(des.clone()) .map_err(|_| AuthControllerError::InvalidApiKeyDescription(des.clone())) }) .transpose()?; let id = generate_id(); let actions = value .get("actions") .map(|act| { from_value(act.clone()) .map_err(|_| AuthControllerError::InvalidApiKeyActions(act.clone())) }) .ok_or(AuthControllerError::MissingParameter("actions"))??; let indexes = value .get("indexes") .map(|ind| { from_value(ind.clone()) .map_err(|_| AuthControllerError::InvalidApiKeyIndexes(ind.clone())) }) .ok_or(AuthControllerError::MissingParameter("indexes"))??; let expires_at = value .get("expiresAt") .map(|exp| { from_value(exp.clone()) .map_err(|_| AuthControllerError::InvalidApiKeyExpiresAt(exp.clone())) }) .transpose()?; let created_at = Utc::now(); let updated_at = Utc::now(); Ok(Self { description, id, actions, indexes, expires_at, created_at, updated_at, }) } pub fn update_from_value(&mut self, value: Value) -> Result<()> { if let Some(des) = value.get("description") { let des = from_value(des.clone()) .map_err(|_| AuthControllerError::InvalidApiKeyDescription(des.clone())); self.description = des?; } if let Some(act) = value.get("actions") { let act = from_value(act.clone()) .map_err(|_| AuthControllerError::InvalidApiKeyActions(act.clone())); self.actions = act?; } if let Some(ind) = value.get("indexes") { let ind = from_value(ind.clone()) .map_err(|_| AuthControllerError::InvalidApiKeyIndexes(ind.clone())); self.indexes = ind?; } if let Some(exp) = value.get("expiresAt") { let exp = from_value(exp.clone()) .map_err(|_| AuthControllerError::InvalidApiKeyExpiresAt(exp.clone())); self.expires_at = exp?; } self.updated_at = Utc::now(); Ok(()) } pub(crate) fn default_admin() -> Self { Self { description: Some("Default Admin API Key (Use it for all other operations. Caution! Do not use it on a public frontend)".to_string()), id: generate_id(), actions: vec![Action::All], indexes: vec!["*".to_string()], expires_at: None, created_at: Utc::now(), updated_at: Utc::now(), } } pub(crate) fn default_search() -> Self { Self { description: Some( "Default Search API Key (Use it to search from the frontend)".to_string(), ), id: generate_id(), actions: vec![Action::Search], indexes: vec!["*".to_string()], expires_at: None, created_at: Utc::now(), updated_at: Utc::now(), } } } /// Generate a printable key of 64 characters using thread_rng. fn generate_id() -> [u8; KEY_ID_LENGTH] { const CHARSET: &[u8] = b"abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let mut rng = rand::thread_rng(); let mut bytes = [0; KEY_ID_LENGTH]; for byte in bytes.iter_mut() { *byte = CHARSET[rng.gen_range(0..CHARSET.len())]; } bytes }