This commit is contained in:
Tangel 2024-01-18 08:39:41 +00:00 committed by GitHub
parent 3fe565b14d
commit 5afb1d50db
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 36 additions and 28 deletions

View file

@ -26,7 +26,7 @@ tracing = "0.1.40"
base64 = "0.21.5" base64 = "0.21.5"
openssl = "0.10.62" openssl = "0.10.62"
once_cell = "1.19.0" once_cell = "1.19.0"
http = "0.2.11" http = "1.0.0"
sha2 = "0.10.8" sha2 = "0.10.8"
thiserror = "1.0.56" thiserror = "1.0.56"
derive_builder = "0.12.0" derive_builder = "0.12.0"
@ -60,12 +60,11 @@ moka = { version = "0.12.2", features = ["future"] }
actix-web = { version = "4.4.1", default-features = false, optional = true } actix-web = { version = "4.4.1", default-features = false, optional = true }
# Axum # Axum
axum = { version = "0.6.20", features = [ axum = { git = "https://github.com/tokio-rs/axum.git", features = [
"json", "json",
"headers",
], default-features = false, optional = true } ], default-features = false, optional = true }
tower = { version = "0.4.13", optional = true } tower = { version = "0.4.13", optional = true }
hyper = { version = "0.14", optional = true } hyper = { version = "1.1.0", optional = true }
http-body-util = {version = "0.1.0", optional = true } http-body-util = {version = "0.1.0", optional = true }
[dev-dependencies] [dev-dependencies]
@ -73,12 +72,12 @@ anyhow = "1.0.79"
rand = "0.8.5" rand = "0.8.5"
env_logger = "0.10.1" env_logger = "0.10.1"
tower-http = { version = "0.5.0", features = ["map-request-body", "util"] } tower-http = { version = "0.5.0", features = ["map-request-body", "util"] }
axum = { version = "0.6.20", features = [ axum = { git = "https://github.com/tokio-rs/axum.git", features = [
"http1", "http1",
"tokio", "tokio",
"query", "query",
], default-features = false } ], default-features = false }
axum-macros = "0.3.8" axum-macros = { git = "https://github.com/tokio-rs/axum.git" }
tokio = { version = "1.35.1", features = ["full"] } tokio = { version = "1.35.1", features = ["full"] }
[profile.dev] [profile.dev]

View file

@ -38,7 +38,7 @@ pub fn listen(config: &FederationConfig<DatabaseHandle>) -> Result<(), Error> {
let addr = tokio::net::TcpListener::from_std(TcpListener::bind(hostname)?)?; let addr = tokio::net::TcpListener::from_std(TcpListener::bind(hostname)?)?;
let server = axum::serve(addr, app.into_make_service()); let server = axum::serve(addr, app.into_make_service());
tokio::spawn(server); tokio::spawn(async move { server.await.unwrap() });
Ok(()) Ok(())
} }

View file

@ -205,7 +205,7 @@ mod tests {
// This will periodically send back internal errors to test the retry // This will periodically send back internal errors to test the retry
async fn dodgy_handler( async fn dodgy_handler(
State(state): State<Arc<AtomicUsize>>, State(state): State<Arc<AtomicUsize>>,
headers: HeaderMap, headers: http::HeaderMap,
body: Bytes, body: Bytes,
) -> Result<(), StatusCode> { ) -> Result<(), StatusCode> {
debug!("Headers:{:?}", headers); debug!("Headers:{:?}", headers);

View file

@ -9,6 +9,7 @@ use crate::{
}; };
use actix_web::{web::Bytes, HttpRequest, HttpResponse}; use actix_web::{web::Bytes, HttpRequest, HttpResponse};
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use std::str::FromStr;
use tracing::debug; use tracing::debug;
/// Handles incoming activities, verifying HTTP signatures and other checks /// Handles incoming activities, verifying HTTP signatures and other checks
@ -34,7 +35,7 @@ where
verify_signature( verify_signature(
request.headers(), request.headers(),
request.method(), request.method(),
request.uri(), &http::Uri::from_str(&request.uri().to_string()).unwrap(),
actor.public_key_pem(), actor.public_key_pem(),
)?; )?;

View file

@ -12,6 +12,7 @@ use crate::{
}; };
use actix_web::{web::Bytes, HttpRequest}; use actix_web::{web::Bytes, HttpRequest};
use serde::Deserialize; use serde::Deserialize;
use std::str::FromStr;
/// Checks whether the request is signed by an actor of type A, and returns /// Checks whether the request is signed by an actor of type A, and returns
/// the actor in question if a valid signature is found. /// the actor in question if a valid signature is found.
@ -27,5 +28,11 @@ where
{ {
verify_body_hash(request.headers().get("Digest"), &body.unwrap_or_default())?; verify_body_hash(request.headers().get("Digest"), &body.unwrap_or_default())?;
http_signatures::signing_actor(request.headers(), request.method(), request.uri(), data).await http_signatures::signing_actor(
request.headers(),
request.method(),
&http::Uri::from_str(&request.uri().to_string()).unwrap(),
data,
)
.await
} }

View file

@ -11,9 +11,8 @@ use crate::{
}; };
use axum::{ use axum::{
async_trait, async_trait,
body::Body, extract::{FromRequest, Request},
extract::FromRequest, http::StatusCode,
http::{Request, StatusCode},
response::{IntoResponse, Response}, response::{IntoResponse, Response},
}; };
use http::{HeaderMap, Method, Uri}; use http::{HeaderMap, Method, Uri};
@ -65,18 +64,20 @@ where
{ {
type Rejection = Response; type Rejection = Response;
async fn from_request(req: Request<Body>, _state: &S) -> Result<Self, Self::Rejection> { async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> {
let (parts, body) = req.into_parts(); let headers = req.headers().clone();
let method = req.method().clone();
let uri = req.uri().clone();
// this wont work if the body is an long running stream // this wont work if the body is an long running stream
let bytes = hyper::body::to_bytes(body) let bytes = hyper::body::Bytes::from_request(req, state)
.await .await
.map_err(|err| (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()).into_response())?; .map_err(|err| (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()).into_response())?;
Ok(Self { Ok(Self {
headers: parts.headers, headers,
method: parts.method, method,
uri: parts.uri, uri,
body: bytes.to_vec(), body: bytes.to_vec(),
}) })
} }

View file

@ -88,7 +88,7 @@ async fn fetch_object_http_with_accept<T: Clone, Kind: DeserializeOwned>(
req.send().await? req.send().await?
}; };
if res.status() == StatusCode::GONE { if res.status().as_u16() == StatusCode::GONE.as_u16() {
return Err(Error::ObjectDeleted(url.clone())); return Err(Error::ObjectDeleted(url.clone()));
} }

View file

@ -14,7 +14,7 @@ use crate::{
}; };
use base64::{engine::general_purpose::STANDARD as Base64, Engine}; use base64::{engine::general_purpose::STANDARD as Base64, Engine};
use bytes::Bytes; use bytes::Bytes;
use http::{header::HeaderName, uri::PathAndQuery, HeaderValue, Method, Uri}; use http::{uri::PathAndQuery, Uri};
use http_signature_normalization_reqwest::{ use http_signature_normalization_reqwest::{
prelude::{Config, SignExt}, prelude::{Config, SignExt},
DefaultSpawner, DefaultSpawner,
@ -26,7 +26,11 @@ use openssl::{
rsa::Rsa, rsa::Rsa,
sign::{Signer, Verifier}, sign::{Signer, Verifier},
}; };
use reqwest::Request; use reqwest::{
header::{HeaderName, HeaderValue},
Method,
Request,
};
use reqwest_middleware::RequestBuilder; use reqwest_middleware::RequestBuilder;
use serde::Deserialize; use serde::Deserialize;
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
@ -292,7 +296,7 @@ pub mod test {
// use hardcoded date in order to test against hardcoded signature // use hardcoded date in order to test against hardcoded signature
headers.insert( headers.insert(
"date", "date",
HeaderValue::from_str("Tue, 28 Mar 2023 21:03:44 GMT").unwrap(), reqwest::header::HeaderValue::from_str("Tue, 28 Mar 2023 21:03:44 GMT").unwrap(),
); );
let request_builder = ClientWithMiddleware::from(Client::new()) let request_builder = ClientWithMiddleware::from(Client::new())

View file

@ -26,7 +26,6 @@ use url::Url;
/// Default context used in Activitypub /// Default context used in Activitypub
const DEFAULT_CONTEXT: &str = "https://www.w3.org/ns/activitystreams"; const DEFAULT_CONTEXT: &str = "https://www.w3.org/ns/activitystreams";
const DEFAULT_SECURITY_CONTEXT: &str = "https://w3id.org/security/v1";
/// Wrapper for federated structs which handles `@context` field. /// Wrapper for federated structs which handles `@context` field.
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@ -40,10 +39,7 @@ pub struct WithContext<T> {
impl<T> WithContext<T> { impl<T> WithContext<T> {
/// Create a new wrapper with the default Activitypub context. /// Create a new wrapper with the default Activitypub context.
pub fn new_default(inner: T) -> WithContext<T> { pub fn new_default(inner: T) -> WithContext<T> {
let context = vec![ let context = Value::String(DEFAULT_CONTEXT.to_string());
Value::String(DEFAULT_CONTEXT.to_string()),
Value::String(DEFAULT_SECURITY_CONTEXT.to_string()),
];
WithContext::new(inner, context) WithContext::new(inner, context)
} }