mirror of
https://github.com/LemmyNet/activitypub-federation-rust.git
synced 2024-06-11 01:39:31 +00:00
update
This commit is contained in:
parent
3fe565b14d
commit
5afb1d50db
11
Cargo.toml
11
Cargo.toml
|
@ -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]
|
||||||
|
|
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue