freshblu_server/handlers/
mod.rs1pub mod auth;
2pub mod devices;
3pub mod messages;
4pub mod status;
5pub mod subscribe;
6pub mod subscriptions;
7pub mod tokens;
8
9use axum::{
10 extract::FromRequestParts,
11 http::request::Parts,
12 response::{IntoResponse, Response},
13};
14use freshblu_core::{auth::parse_basic_auth, device::Device, error::FreshBluError};
15use uuid::Uuid;
16
17use crate::{ApiError, AppState};
18
19pub struct AuthenticatedDevice(pub Device, pub Option<Uuid>);
21
22#[axum::async_trait]
23impl FromRequestParts<AppState> for AuthenticatedDevice {
24 type Rejection = Response;
25
26 async fn from_request_parts(
27 parts: &mut Parts,
28 state: &AppState,
29 ) -> Result<Self, Self::Rejection> {
30 let headers = &parts.headers;
31
32 let creds = headers
34 .get("authorization")
35 .and_then(|v| v.to_str().ok())
36 .and_then(parse_basic_auth);
37
38 let creds = creds.or_else(|| {
40 headers
41 .get("skynet_auth_uuid")
42 .zip(headers.get("skynet_auth_token"))
43 .and_then(|(u, t)| {
44 Some((u.to_str().ok()?.to_string(), t.to_str().ok()?.to_string()))
45 })
46 });
47
48 let (uuid_str, token) =
49 creds.ok_or_else(|| ApiError::from(FreshBluError::Unauthorized).into_response())?;
50
51 let uuid = Uuid::parse_str(&uuid_str)
52 .map_err(|_| ApiError::from(FreshBluError::Unauthorized).into_response())?;
53
54 let device = state
55 .store
56 .authenticate(&uuid, &token)
57 .await
58 .map_err(|e| ApiError::from(e).into_response())?
59 .ok_or_else(|| ApiError::from(FreshBluError::Unauthorized).into_response())?;
60
61 state
63 .rate_limiter
64 .check(&uuid)
65 .map_err(|e| ApiError::from(e).into_response())?;
66
67 let as_uuid = headers
69 .get("x-meshblu-as")
70 .and_then(|v| v.to_str().ok())
71 .and_then(|v| Uuid::parse_str(v).ok());
72
73 Ok(AuthenticatedDevice(device, as_uuid))
74 }
75}