mirror of
https://github.com/LemmyNet/activitypub-federation-rust.git
synced 2024-05-21 02:18:04 +00:00
Compare commits
6 commits
Author | SHA1 | Date | |
---|---|---|---|
16844f048a | |||
cf1f84993b | |||
24afad7abc | |||
c48de9e944 | |||
be69efdee3 | |||
ddc455510b |
42
Cargo.toml
42
Cargo.toml
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "activitypub_federation"
|
||||
version = "0.5.4"
|
||||
version = "0.5.6"
|
||||
edition = "2021"
|
||||
description = "High-level Activitypub framework"
|
||||
keywords = ["activitypub", "activitystreams", "federation", "fediverse"]
|
||||
|
@ -32,21 +32,21 @@ redundant_closure_for_method_calls = "deny"
|
|||
unwrap_used = "deny"
|
||||
|
||||
[dependencies]
|
||||
chrono = { version = "0.4.34", features = ["clock"], default-features = false }
|
||||
serde = { version = "1.0.197", features = ["derive"] }
|
||||
async-trait = "0.1.77"
|
||||
chrono = { version = "0.4.38", features = ["clock"], default-features = false }
|
||||
serde = { version = "1.0.200", features = ["derive"] }
|
||||
async-trait = "0.1.80"
|
||||
url = { version = "2.5.0", features = ["serde"] }
|
||||
serde_json = { version = "1.0.114", features = ["preserve_order"] }
|
||||
reqwest = { version = "0.11.24", features = ["json", "stream"] }
|
||||
reqwest-middleware = "0.2.4"
|
||||
serde_json = { version = "1.0.116", features = ["preserve_order"] }
|
||||
reqwest = { version = "0.11.27", features = ["json", "stream"] }
|
||||
reqwest-middleware = "0.2.5"
|
||||
tracing = "0.1.40"
|
||||
base64 = "0.21.7"
|
||||
base64 = "0.22.1"
|
||||
openssl = "0.10.64"
|
||||
once_cell = "1.19.0"
|
||||
http = "0.2.11"
|
||||
http = "0.2.12"
|
||||
sha2 = "0.10.8"
|
||||
thiserror = "1.0.57"
|
||||
derive_builder = "0.12.0"
|
||||
thiserror = "1.0.59"
|
||||
derive_builder = "0.20.0"
|
||||
itertools = "0.12.1"
|
||||
dyn-clone = "1.0.17"
|
||||
enum_delegate = "0.2.0"
|
||||
|
@ -57,20 +57,20 @@ http-signature-normalization-reqwest = { version = "0.10.0", default-features =
|
|||
"default-spawner",
|
||||
] }
|
||||
http-signature-normalization = "0.7.0"
|
||||
bytes = "1.5.0"
|
||||
bytes = "1.6.0"
|
||||
futures-core = { version = "0.3.30", default-features = false }
|
||||
pin-project-lite = "0.2.13"
|
||||
pin-project-lite = "0.2.14"
|
||||
activitystreams-kinds = "0.3.0"
|
||||
regex = { version = "1.10.3", default-features = false, features = ["std", "unicode-case"] }
|
||||
tokio = { version = "1.36.0", features = [
|
||||
regex = { version = "1.10.4", default-features = false, features = ["std", "unicode-case"] }
|
||||
tokio = { version = "1.37.0", features = [
|
||||
"sync",
|
||||
"rt",
|
||||
"rt-multi-thread",
|
||||
"time",
|
||||
] }
|
||||
diesel = { version = "2.1.4", features = ["postgres"], default-features = false, optional = true }
|
||||
diesel = { version = "2.1.6", features = ["postgres"], default-features = false, optional = true }
|
||||
futures = "0.3.30"
|
||||
moka = { version = "0.12.5", features = ["future"] }
|
||||
moka = { version = "0.12.7", features = ["future"] }
|
||||
|
||||
# Actix-web
|
||||
actix-web = { version = "4.5.1", default-features = false, optional = true }
|
||||
|
@ -82,12 +82,12 @@ axum = { version = "0.6.20", features = [
|
|||
], default-features = false, optional = true }
|
||||
tower = { version = "0.4.13", optional = true }
|
||||
hyper = { version = "0.14", optional = true }
|
||||
http-body-util = {version = "0.1.0", optional = true }
|
||||
http-body-util = {version = "0.1.1", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
anyhow = "1.0.80"
|
||||
anyhow = "1.0.82"
|
||||
rand = "0.8.5"
|
||||
env_logger = "0.10.2"
|
||||
env_logger = "0.11.3"
|
||||
tower-http = { version = "0.5.2", features = ["map-request-body", "util"] }
|
||||
axum = { version = "0.6.20", features = [
|
||||
"http1",
|
||||
|
@ -95,7 +95,7 @@ axum = { version = "0.6.20", features = [
|
|||
"query",
|
||||
], default-features = false }
|
||||
axum-macros = "0.3.8"
|
||||
tokio = { version = "1.36.0", features = ["full"] }
|
||||
tokio = { version = "1.37.0", features = ["full"] }
|
||||
|
||||
[profile.dev]
|
||||
strip = "symbols"
|
||||
|
|
|
@ -174,11 +174,17 @@ impl<T: Clone> FederationConfig<T> {
|
|||
/// Returns true if the url refers to this instance. Handles hostnames like `localhost:8540` for
|
||||
/// local debugging.
|
||||
pub(crate) fn is_local_url(&self, url: &Url) -> bool {
|
||||
let mut domain = url.host_str().expect("id has domain").to_string();
|
||||
if let Some(port) = url.port() {
|
||||
domain = format!("{}:{}", domain, port);
|
||||
match url.host_str() {
|
||||
Some(domain) => {
|
||||
let domain = if let Some(port) = url.port() {
|
||||
format!("{}:{}", domain, port)
|
||||
} else {
|
||||
domain.to_string()
|
||||
};
|
||||
domain == self.domain
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
domain == self.domain
|
||||
}
|
||||
|
||||
/// Returns the local domain
|
||||
|
@ -355,13 +361,17 @@ mod test {
|
|||
.await
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_url_is_local() -> Result<(), Error> {
|
||||
let config = config().await;
|
||||
assert!(config.is_local_url(&Url::parse("http://example.com")?));
|
||||
assert!(!config.is_local_url(&Url::parse("http://other.com")?));
|
||||
// ensure that missing domain doesnt cause crash
|
||||
assert!(!config.is_local_url(&Url::parse("http://127.0.0.1")?));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_domain() {
|
||||
let config = config().await;
|
||||
|
|
|
@ -53,19 +53,21 @@ pub async fn fetch_object_http<T: Clone, Kind: DeserializeOwned>(
|
|||
url: &Url,
|
||||
data: &Data<T>,
|
||||
) -> Result<FetchObjectResponse<Kind>, Error> {
|
||||
static CONTENT_TYPE: HeaderValue = HeaderValue::from_static(FEDERATION_CONTENT_TYPE);
|
||||
static ALT_CONTENT_TYPE: HeaderValue = HeaderValue::from_static(
|
||||
r#"application/ld+json; profile="https://www.w3.org/ns/activitystreams""#,
|
||||
);
|
||||
static ALT_CONTENT_TYPE_MASTODON: HeaderValue =
|
||||
HeaderValue::from_static(r#"application/activity+json; charset=utf-8"#);
|
||||
let res = fetch_object_http_with_accept(url, data, &CONTENT_TYPE).await?;
|
||||
static FETCH_CONTENT_TYPE: HeaderValue = HeaderValue::from_static(FEDERATION_CONTENT_TYPE);
|
||||
const VALID_RESPONSE_CONTENT_TYPES: [&str; 3] = [
|
||||
FEDERATION_CONTENT_TYPE, // lemmy
|
||||
r#"application/ld+json; profile="https://www.w3.org/ns/activitystreams""#, // activitypub standard
|
||||
r#"application/activity+json; charset=utf-8"#, // mastodon
|
||||
];
|
||||
let res = fetch_object_http_with_accept(url, data, &FETCH_CONTENT_TYPE).await?;
|
||||
|
||||
// Ensure correct content-type to prevent vulnerabilities.
|
||||
if res.content_type.as_ref() != Some(&CONTENT_TYPE)
|
||||
&& res.content_type.as_ref() != Some(&ALT_CONTENT_TYPE)
|
||||
&& res.content_type.as_ref() != Some(&ALT_CONTENT_TYPE_MASTODON)
|
||||
{
|
||||
// Ensure correct content-type to prevent vulnerabilities, with case insensitive comparison.
|
||||
let content_type = res
|
||||
.content_type
|
||||
.as_ref()
|
||||
.and_then(|c| c.to_str().ok())
|
||||
.ok_or(Error::FetchInvalidContentType(res.url.clone()))?;
|
||||
if !VALID_RESPONSE_CONTENT_TYPES.contains(&content_type) {
|
||||
return Err(Error::FetchInvalidContentType(res.url));
|
||||
}
|
||||
|
||||
|
|
|
@ -189,8 +189,11 @@ fn verify_signature_inner(
|
|||
uri: &Uri,
|
||||
public_key: &str,
|
||||
) -> Result<(), Error> {
|
||||
static CONFIG: Lazy<http_signature_normalization::Config> =
|
||||
Lazy::new(|| http_signature_normalization::Config::new().set_expiration(EXPIRES_AFTER));
|
||||
static CONFIG: Lazy<http_signature_normalization::Config> = Lazy::new(|| {
|
||||
http_signature_normalization::Config::new()
|
||||
.set_expiration(EXPIRES_AFTER)
|
||||
.require_digest()
|
||||
});
|
||||
|
||||
let path_and_query = uri.path_and_query().map(PathAndQuery::as_str).unwrap_or("");
|
||||
|
||||
|
|
Loading…
Reference in a new issue