use axum::{
body::Body,
http::Request,
middleware::Next,
response::Response,
};
#[derive(Debug, Clone)]
pub struct RequestNamespace(pub Option<String>);
pub async fn namespace_extractor(
mut req: Request<Body>,
next: Next,
) -> Response {
let namespace = extract_namespace_from_token(&req);
req.extensions_mut().insert(RequestNamespace(namespace));
next.run(req).await
}
#[cfg(feature = "auth")]
fn extract_namespace_from_token(req: &Request<Body>) -> Option<String> {
let auth_header = req.headers().get("authorization")?.to_str().ok()?;
let token = auth_header.strip_prefix("Bearer ")?;
match crate::auth::verify_token(token) {
Ok(claims) => claims.namespace.clone(),
Err(_) => None,
}
}
#[cfg(not(feature = "auth"))]
fn extract_namespace_from_token(_req: &Request<Body>) -> Option<String> {
None
}
pub fn is_in_namespace(subject: &str, namespace: &str) -> bool {
subject.starts_with(&format!("{}:", namespace))
}
pub fn scope_subject(subject: &str, namespace: &str) -> String {
if subject.starts_with(&format!("{}:", namespace)) {
subject.to_string()
} else {
format!("{}:{}", namespace, subject)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_is_in_namespace() {
assert!(is_in_namespace("mayros:agent:a1", "mayros"));
assert!(!is_in_namespace("other:agent:a1", "mayros"));
assert!(!is_in_namespace("agent:a1", "mayros"));
}
#[test]
fn test_scope_subject() {
assert_eq!(scope_subject("agent:a1", "mayros"), "mayros:agent:a1");
assert_eq!(
scope_subject("mayros:agent:a1", "mayros"),
"mayros:agent:a1"
);
}
}