foxchat/chat/src/fed/mod.rs

103 lines
2.6 KiB
Rust
Raw Normal View History

2024-01-18 16:34:40 +01:00
use std::sync::Arc;
use axum::{
async_trait,
extract::FromRequestParts,
http::{
header::{CONTENT_LENGTH, DATE, HOST},
request::Parts,
},
Extension,
};
use foxchat::{
fed::{SERVER_HEADER, SIGNATURE_HEADER, USER_HEADER},
http::ApiError,
signature::{parse_date, verify_signature},
FoxError,
};
use tracing::error;
use crate::{app_state::AppState, model::identity_instance::IdentityInstance};
pub struct FoxRequestData {
pub instance: IdentityInstance,
pub user_id: Option<String>,
}
#[async_trait]
impl<S> FromRequestParts<S> for FoxRequestData
where
S: Send + Sync,
{
type Rejection = ApiError;
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
let state: Extension<Arc<AppState>> = Extension::from_request_parts(parts, state)
.await
.expect("AppState was not added as an extension");
let domain = parts
.headers
.get(SERVER_HEADER)
.ok_or(FoxError::InvalidHeader)?
.to_str()?;
let instance = IdentityInstance::get(state.0, domain).await?;
let public_key = instance.parse_public_key()?;
let date = parse_date(
parts
.headers
.get(DATE)
.ok_or(FoxError::InvalidHeader)?
.to_str()?,
)?;
let signature = parts
.headers
.get(SIGNATURE_HEADER)
.ok_or(FoxError::MissingSignature)?
.to_str()?
.to_string();
let host = parts
.headers
.get(HOST)
.ok_or(FoxError::InvalidHeader)?
.to_str()?;
let content_length = if let Some(raw_length) = parts.headers.get(CONTENT_LENGTH) {
Some(raw_length.to_str()?.parse::<usize>()?)
} else {
None
};
let user_id = if let Some(raw_id) = parts.headers.get(USER_HEADER) {
Some(raw_id.to_str()?)
} else {
None
};
if let Err(e) = verify_signature(
&public_key,
signature,
date,
host,
parts.uri.path(),
content_length,
user_id,
) {
error!(
"Verifying signature from request for {} from {}: {}",
parts.uri.path(),
domain,
e
);
return Err(FoxError::InvalidSignature.into());
}
Ok(FoxRequestData {
instance,
user_id: user_id.map(|v| v.to_string()),
})
}
}