Skip to main content

cloudillo_core/
extract.rs

1// SPDX-FileCopyrightText: Szilárd Hajba
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
4//! Custom extractors for Cloudillo-specific data
5
6use async_trait::async_trait;
7use axum::extract::FromRequestParts;
8use axum::http::request::Parts;
9
10use crate::app::AppState;
11use crate::prelude::*;
12use cloudillo_types::auth_adapter;
13
14// Re-export IdTag and TnIdResolver from cloudillo-types
15pub use cloudillo_types::extract::{IdTag, TnIdResolver};
16
17// Implement TnIdResolver for AppState so TnId can be extracted from requests.
18// The blanket impl `TnIdResolver for Arc<T>` in cloudillo-types makes this
19// work for `App = Arc<AppState>` automatically.
20#[async_trait]
21impl TnIdResolver for AppState {
22	async fn resolve_tn_id(&self, id_tag: &str) -> Result<TnId, Error> {
23		self.auth_adapter.read_tn_id(id_tag).await.map_err(|_| Error::PermissionDenied)
24	}
25}
26
27// Auth //
28//******//
29#[derive(Debug, Clone)]
30pub struct Auth(pub auth_adapter::AuthCtx);
31
32impl<S> FromRequestParts<S> for Auth
33where
34	S: Send + Sync,
35{
36	type Rejection = Error;
37
38	async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
39		if let Some(auth) = parts.extensions.get::<Auth>().cloned() {
40			Ok(auth)
41		} else {
42			Err(Error::PermissionDenied)
43		}
44	}
45}
46
47// OptionalAuth //
48//***************//
49/// Optional auth extractor that doesn't fail if auth is missing
50#[derive(Debug, Clone)]
51pub struct OptionalAuth(pub Option<auth_adapter::AuthCtx>);
52
53impl<S> FromRequestParts<S> for OptionalAuth
54where
55	S: Send + Sync,
56{
57	type Rejection = Error;
58
59	async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
60		let auth = parts.extensions.get::<Auth>().cloned().map(|a| a.0);
61		Ok(OptionalAuth(auth))
62	}
63}
64
65// RequestId //
66//***********//
67/// Request ID for tracing and debugging
68#[derive(Clone, Debug)]
69pub struct RequestId(pub String);
70
71/// Optional Request ID extractor - always succeeds, returns None if not available
72#[derive(Clone, Debug)]
73pub struct OptionalRequestId(pub Option<String>);
74
75impl<S> FromRequestParts<S> for OptionalRequestId
76where
77	S: Send + Sync,
78{
79	type Rejection = Error;
80
81	async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
82		let req_id = parts.extensions.get::<RequestId>().map(|r| r.0.clone());
83		Ok(OptionalRequestId(req_id))
84	}
85}
86
87// vim: ts=4