use axum::extract::Extension;
use axum::http::StatusCode;
use uuid::Uuid;
use crate::auth::types::AuthClaims;
pub type OptionalAuthClaims = Option<Extension<AuthClaims>>;
pub fn extract_user_id_from_claims(claims: &OptionalAuthClaims) -> Option<Uuid> {
claims
.as_ref()
.and_then(|Extension(claims)| claims.sub.as_ref())
.and_then(|sub| Uuid::parse_str(sub).ok())
}
pub fn require_user_id_from_claims(claims: &OptionalAuthClaims) -> Result<Uuid, StatusCode> {
extract_user_id_from_claims(claims).ok_or(StatusCode::UNAUTHORIZED)
}
pub fn extract_username_from_claims(claims: &OptionalAuthClaims) -> Option<String> {
claims.as_ref().and_then(|Extension(claims)| claims.username.clone())
}
#[cfg(test)]
mod tests {
use super::*;
fn claims_with_sub(sub: &str) -> OptionalAuthClaims {
let mut claims = AuthClaims::new();
claims.sub = Some(sub.to_string());
Some(Extension(claims))
}
#[test]
fn require_rejects_unauthenticated() {
assert_eq!(require_user_id_from_claims(&None), Err(StatusCode::UNAUTHORIZED));
}
#[test]
fn require_extracts_authenticated_sub() {
let id =
require_user_id_from_claims(&claims_with_sub("00000000-0000-0000-0000-000000000042"))
.expect("valid sub must extract");
assert_eq!(id, Uuid::parse_str("00000000-0000-0000-0000-000000000042").unwrap());
}
#[test]
fn require_rejects_non_uuid_sub() {
assert!(require_user_id_from_claims(&claims_with_sub("not-a-uuid")).is_err());
}
}