mirror of
https://github.com/LemmyNet/activitypub-federation-rust.git
synced 2024-06-09 00:39:29 +00:00
merge upstream
This commit is contained in:
commit
3d9fc3e8f2
42
Cargo.toml
42
Cargo.toml
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "activitypub_federation"
|
||||
version = "0.5.0-beta.3"
|
||||
version = "0.5.0-beta.4"
|
||||
edition = "2021"
|
||||
description = "High-level Activitypub framework"
|
||||
keywords = ["activitypub", "activitystreams", "federation", "fediverse"]
|
||||
|
@ -9,38 +9,38 @@ repository = "https://github.com/LemmyNet/activitypub-federation-rust"
|
|||
documentation = "https://docs.rs/activitypub_federation/"
|
||||
|
||||
[dependencies]
|
||||
chrono = { version = "0.4.26", features = ["clock"], default-features = false }
|
||||
serde = { version = "1.0.164", features = ["derive"] }
|
||||
async-trait = "0.1.68"
|
||||
url = { version = "2.4.0", features = ["serde"] }
|
||||
serde_json = { version = "1.0.96", features = ["preserve_order"] }
|
||||
anyhow = "1.0.71"
|
||||
reqwest = { version = "0.11.18", features = ["json", "stream"] }
|
||||
reqwest-middleware = "0.2.2"
|
||||
tracing = "0.1.37"
|
||||
base64 = "0.21.2"
|
||||
openssl = "0.10.54"
|
||||
chrono = { version = "0.4.31", features = ["clock"], default-features = false }
|
||||
serde = { version = "1.0.189", features = ["derive"] }
|
||||
async-trait = "0.1.74"
|
||||
url = { version = "2.4.1", features = ["serde"] }
|
||||
serde_json = { version = "1.0.107", features = ["preserve_order"] }
|
||||
anyhow = "1.0.75"
|
||||
reqwest = { version = "0.11.22", features = ["json", "stream"] }
|
||||
reqwest-middleware = "0.2.3"
|
||||
tracing = "0.1.40"
|
||||
base64 = "0.21.5"
|
||||
openssl = "0.10.57"
|
||||
once_cell = "1.18.0"
|
||||
http = "0.2.9"
|
||||
sha2 = "0.10.6"
|
||||
thiserror = "1.0.40"
|
||||
sha2 = "0.10.8"
|
||||
thiserror = "1.0.50"
|
||||
derive_builder = "0.12.0"
|
||||
itertools = "0.11.0"
|
||||
dyn-clone = "1.0.11"
|
||||
dyn-clone = "1.0.14"
|
||||
enum_delegate = "0.2.0"
|
||||
httpdate = "1.0.2"
|
||||
httpdate = "1.0.3"
|
||||
http-signature-normalization-reqwest = { version = "0.10.0", default-features = false, features = [
|
||||
"default-spawner",
|
||||
"sha-2",
|
||||
"middleware",
|
||||
] }
|
||||
http-signature-normalization = "0.7.0"
|
||||
bytes = "1.4.0"
|
||||
bytes = "1.5.0"
|
||||
futures-core = { version = "0.3.28", default-features = false }
|
||||
pin-project-lite = "0.2.9"
|
||||
pin-project-lite = "0.2.13"
|
||||
activitystreams-kinds = "0.3.0"
|
||||
regex = { version = "1.8.4", default-features = false, features = ["std", "unicode-case"] }
|
||||
tokio = { version = "1.21.2", features = [
|
||||
regex = { version = "1.10.2", default-features = false, features = ["std", "unicode-case"] }
|
||||
tokio = { version = "1.33.0", features = [
|
||||
"sync",
|
||||
"rt",
|
||||
"rt-multi-thread",
|
||||
|
@ -48,7 +48,7 @@ tokio = { version = "1.21.2", features = [
|
|||
] }
|
||||
|
||||
# Actix-web
|
||||
actix-web = { version = "4.3.1", default-features = false, optional = true }
|
||||
actix-web = { version = "4.4.0", default-features = false, optional = true }
|
||||
|
||||
# Axum
|
||||
axum = { git = "https://github.com/tokio-rs/axum.git", features = [
|
||||
|
|
|
@ -40,9 +40,10 @@ where
|
|||
where
|
||||
<Kind as Collection>::Error: From<Error>,
|
||||
{
|
||||
let json = fetch_object_http(&self.0, data).await?;
|
||||
Kind::verify(&json, &self.0, data).await?;
|
||||
Kind::from_json(json, owner, data).await
|
||||
let res = fetch_object_http(&self.0, data).await?;
|
||||
let redirect_url = &res.url;
|
||||
Kind::verify(&res.object, redirect_url, data).await?;
|
||||
Kind::from_json(res.object, owner, data).await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,14 @@ pub mod object_id;
|
|||
/// Resolves identifiers of the form `name@example.com`
|
||||
pub mod webfinger;
|
||||
|
||||
/// Response from fetching a remote object
|
||||
pub struct FetchObjectResponse<Kind> {
|
||||
/// The resolved object
|
||||
pub object: Kind,
|
||||
/// Contains the final URL (different from request URL in case of redirect)
|
||||
pub url: Url,
|
||||
}
|
||||
|
||||
/// Fetch a remote object over HTTP and convert to `Kind`.
|
||||
///
|
||||
/// [crate::fetch::object_id::ObjectId::dereference] wraps this function to add caching and
|
||||
|
@ -38,7 +46,7 @@ pub mod webfinger;
|
|||
pub async fn fetch_object_http<T: Clone, Kind: DeserializeOwned>(
|
||||
url: &Url,
|
||||
data: &Data<T>,
|
||||
) -> Result<Kind, Error> {
|
||||
) -> Result<FetchObjectResponse<Kind>, Error> {
|
||||
fetch_object_http_with_accept(url, data, FEDERATION_CONTENT_TYPE).await
|
||||
}
|
||||
|
||||
|
@ -48,7 +56,7 @@ async fn fetch_object_http_with_accept<T: Clone, Kind: DeserializeOwned>(
|
|||
url: &Url,
|
||||
data: &Data<T>,
|
||||
content_type: &str,
|
||||
) -> Result<Kind, Error> {
|
||||
) -> Result<FetchObjectResponse<Kind>, Error> {
|
||||
let config = &data.config;
|
||||
// dont fetch local objects this way
|
||||
debug_assert!(url.domain() != Some(&config.domain));
|
||||
|
@ -84,5 +92,9 @@ async fn fetch_object_http_with_accept<T: Clone, Kind: DeserializeOwned>(
|
|||
return Err(Error::ObjectDeleted);
|
||||
}
|
||||
|
||||
res.json_limited().await
|
||||
let url = res.url().clone();
|
||||
Ok(FetchObjectResponse {
|
||||
object: res.json_limited().await?,
|
||||
url,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -156,10 +156,11 @@ where
|
|||
return Err(anyhow!("Fetched remote object {} which was deleted", self).into());
|
||||
}
|
||||
|
||||
let res2 = res?;
|
||||
let res = res?;
|
||||
let redirect_url = &res.url;
|
||||
|
||||
Kind::verify(&res2, self.inner(), data).await?;
|
||||
Kind::from_json(res2, data).await
|
||||
Kind::verify(&res.object, redirect_url, data).await?;
|
||||
Kind::from_json(res.object, data).await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,8 @@ where
|
|||
|
||||
let res: Webfinger =
|
||||
fetch_object_http_with_accept(&Url::parse(&fetch_url)?, data, "application/jrd+json")
|
||||
.await?;
|
||||
.await?
|
||||
.object;
|
||||
|
||||
debug_assert_eq!(res.subject, format!("acct:{identifier}"));
|
||||
let links: Vec<Url> = res
|
||||
|
@ -91,14 +92,10 @@ pub fn extract_webfinger_name<T>(query: &str, data: &Data<T>) -> Result<String,
|
|||
where
|
||||
T: Clone,
|
||||
{
|
||||
// Regex to extract usernames from webfinger query. Supports different alphabets using `\p{L}`.
|
||||
// TODO: would be nice if we could implement this without regex and remove the dependency
|
||||
// Regex taken from Mastodon -
|
||||
// https://github.com/mastodon/mastodon/blob/2b113764117c9ab98875141bcf1758ba8be58173/app/models/account.rb#L65
|
||||
let regex = Regex::new(&format!(
|
||||
"^acct:((?i)[a-z0-9_]+([a-z0-9_\\.-]+[a-z0-9_]+)?)@{}$",
|
||||
data.domain()
|
||||
))
|
||||
.map_err(Error::other)?;
|
||||
let regex =
|
||||
Regex::new(&format!(r"^acct:([\p{{L}}0-9_]+)@{}$", data.domain())).map_err(Error::other)?;
|
||||
Ok(regex
|
||||
.captures(query)
|
||||
.and_then(|c| c.get(1))
|
||||
|
@ -238,4 +235,31 @@ mod tests {
|
|||
webfinger_resolve_actor::<DbConnection, DbUser>("graf@poa.st", &data).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_webfinger_extract_name() -> Result<(), Error> {
|
||||
use crate::traits::tests::DbConnection;
|
||||
let data = Data {
|
||||
config: FederationConfig::builder()
|
||||
.domain("example.com")
|
||||
.app_data(DbConnection)
|
||||
.build()
|
||||
.await
|
||||
.unwrap(),
|
||||
request_counter: Default::default(),
|
||||
};
|
||||
assert_eq!(
|
||||
Ok("test123".to_string()),
|
||||
extract_webfinger_name("acct:test123@example.com", &data)
|
||||
);
|
||||
assert_eq!(
|
||||
Ok("Владимир".to_string()),
|
||||
extract_webfinger_name("acct:Владимир@example.com", &data)
|
||||
);
|
||||
assert_eq!(
|
||||
Ok("تجريب".to_string()),
|
||||
extract_webfinger_name("acct:تجريب@example.com", &data)
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue