use oxidite_core::{OxiditeRequest, Result as OxiditeResult, Error};
use oxidite_db::Database;
use std::sync::Arc;
use crate::api_key::ApiKey;
pub struct ApiKeyMiddleware {
db: Arc<dyn Database>,
}
impl ApiKeyMiddleware {
pub fn new(db: Arc<dyn Database>) -> Self {
Self { db }
}
pub async fn authenticate(&self, req: &mut OxiditeRequest) -> OxiditeResult<i64> {
let key = self.extract_key(req)?;
let api_key = ApiKey::verify_key(&*self.db, &key).await
.map_err(|_| Error::InternalServerError("Database error".to_string()))?
.ok_or_else(|| Error::Unauthorized("Invalid or expired API key".to_string()))?;
req.extensions_mut().insert(api_key.user_id);
Ok(api_key.user_id)
}
fn extract_key(&self, req: &OxiditeRequest) -> OxiditeResult<String> {
if let Some(auth_header) = req.headers().get("authorization") {
if let Ok(auth_str) = auth_header.to_str() {
if let Some(key) = auth_str.strip_prefix("Bearer ") {
return Ok(key.to_string());
}
}
}
if let Some(api_key_header) = req.headers().get("x-api-key") {
if let Ok(key) = api_key_header.to_str() {
return Ok(key.to_string());
}
}
if let Some(query) = req.uri().query() {
for param in query.split('&') {
if let Some((k, v)) = param.split_once('=') {
if k == "api_key" {
return Ok(v.to_string());
}
}
}
}
Err(Error::Unauthorized("API key required".to_string()))
}
}