From 100b08bd00025c791a8ce165b020b3e0ecc7f761 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Mon, 10 Mar 2025 15:31:24 +0100 Subject: [PATCH 1/7] Speedup RSA key generation --- Cargo.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 5c40f42..d7a74dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -108,3 +108,8 @@ path = "examples/local_federation/main.rs" [[example]] name = "live_federation" path = "examples/live_federation/main.rs" + +# Speedup RSA key generation +# https://github.com/RustCrypto/RSA/blob/master/README.md#example +[profile.dev.package.num-bigint-dig] +opt-level = 3 From 716dee24ea7c9eaef78606b9a056c2ceb4b54a8f Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Mon, 10 Mar 2025 15:39:21 +0100 Subject: [PATCH 2/7] Version 0.6.3 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d7a74dd..e87011f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "activitypub_federation" -version = "0.6.2" +version = "0.6.3" edition = "2021" description = "High-level Activitypub framework" keywords = ["activitypub", "activitystreams", "federation", "fediverse"] From f75231ab48cb0494aaf4a92eb9a1a77c1275d599 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Mon, 10 Mar 2025 17:44:52 +0100 Subject: [PATCH 3/7] Add note about faster rsa key generation --- src/http_signatures.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/http_signatures.rs b/src/http_signatures.rs index f30e75c..ca6a02f 100644 --- a/src/http_signatures.rs +++ b/src/http_signatures.rs @@ -54,6 +54,10 @@ impl Keypair { } /// Generate a random asymmetric keypair for ActivityPub HTTP signatures. +/// +/// Note that this method is very slow in debug mode. To make it faster, follow +/// instructions in the RSA crate's readme. +/// https://github.com/RustCrypto/RSA/blob/master/README.md pub fn generate_actor_keypair() -> Result { let mut rng = rand::thread_rng(); let rsa = RsaPrivateKey::new(&mut rng, 2048)?; From 697eb01185ca1e850c8c66f71238e944316b71f2 Mon Sep 17 00:00:00 2001 From: Nutomic Date: Thu, 20 Mar 2025 11:16:03 +0000 Subject: [PATCH 4/7] Implement Object trait for Either (#139) * Implement Object, Actor traits for Either * Upgrade Rust version * 1.82 --- .woodpecker.yml | 2 +- Cargo.toml | 1 + src/traits/either.rs | 116 +++++++++++++++++++++++++++++++ src/{traits.rs => traits/mod.rs} | 3 + 4 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 src/traits/either.rs rename src/{traits.rs => traits/mod.rs} (99%) diff --git a/.woodpecker.yml b/.woodpecker.yml index b82dd94..5e522f5 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -1,5 +1,5 @@ variables: - - &rust_image "rust:1.78-bullseye" + - &rust_image "rust:1.82-bullseye" steps: cargo_fmt: diff --git a/Cargo.toml b/Cargo.toml index e87011f..6fd6a84 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -81,6 +81,7 @@ diesel = { version = "2.2.1", features = [ ], default-features = false, optional = true } futures = "0.3.30" moka = { version = "0.12.8", features = ["future"] } +either = "1.15.0" # Actix-web actix-web = { version = "4.8.0", default-features = false, optional = true } diff --git a/src/traits/either.rs b/src/traits/either.rs new file mode 100644 index 0000000..63a6ba4 --- /dev/null +++ b/src/traits/either.rs @@ -0,0 +1,116 @@ +use crate::{config::Data, error::Error}; +use async_trait::async_trait; +use chrono::{DateTime, Utc}; +use either::Either; +use url::Url; + +use super::{Actor, Object}; + +#[async_trait] +impl Object for Either +where + T: Object + Object + Send, + R: Object + Object + Send, + ::Kind: Send + Sync, + ::Kind: Send + Sync, + D: Sync + Send + Clone, + E: From, +{ + type DataType = D; + type Kind = Either; + type Error = E; + + fn last_refreshed_at(&self) -> Option> { + match self { + Either::Left(l) => l.last_refreshed_at(), + Either::Right(r) => r.last_refreshed_at(), + } + } + + async fn read_from_id( + object_id: Url, + data: &Data, + ) -> Result, Self::Error> { + let l = T::read_from_id(object_id.clone(), data).await?; + if let Some(l) = l { + return Ok(Some(Either::Left(l))); + } + let r = R::read_from_id(object_id.clone(), data).await?; + if let Some(r) = r { + return Ok(Some(Either::Right(r))); + } + Err(Error::NotFound.into()) + } + + async fn delete(self, data: &Data) -> Result<(), Self::Error> { + match self { + Either::Left(l) => l.delete(data).await, + Either::Right(r) => r.delete(data).await, + } + } + + async fn into_json(self, data: &Data) -> Result { + Ok(match self { + Either::Left(l) => Either::Left(l.into_json(data).await?), + Either::Right(r) => Either::Right(r.into_json(data).await?), + }) + } + + async fn verify( + json: &Self::Kind, + expected_domain: &Url, + data: &Data, + ) -> Result<(), Self::Error> { + match json { + Either::Left(l) => T::verify(l, expected_domain, data).await?, + Either::Right(r) => R::verify(r, expected_domain, data).await?, + }; + Ok(()) + } + + async fn from_json(json: Self::Kind, data: &Data) -> Result { + Ok(match json { + Either::Left(l) => Either::Left(T::from_json(l, data).await?), + Either::Right(r) => Either::Right(R::from_json(r, data).await?), + }) + } +} + +#[async_trait] +impl Actor for Either +where + T: Actor + Object + Object + Send + 'static, + R: Actor + Object + Object + Send + 'static, + ::Kind: Send + Sync, + ::Kind: Send + Sync, + D: Sync + Send + Clone, + E: From, +{ + fn id(&self) -> Url { + match self { + Either::Left(l) => l.id(), + Either::Right(r) => r.id(), + } + } + + fn public_key_pem(&self) -> &str { + match self { + Either::Left(l) => l.public_key_pem(), + Either::Right(r) => r.public_key_pem(), + } + } + + fn private_key_pem(&self) -> Option { + match self { + Either::Left(l) => l.private_key_pem(), + Either::Right(r) => r.private_key_pem(), + } + } + + fn inbox(&self) -> Url { + match self { + Either::Left(l) => l.inbox(), + Either::Right(r) => r.inbox(), + } + } +} diff --git a/src/traits.rs b/src/traits/mod.rs similarity index 99% rename from src/traits.rs rename to src/traits/mod.rs index 9976bda..6d7d043 100644 --- a/src/traits.rs +++ b/src/traits/mod.rs @@ -7,6 +7,9 @@ use serde::Deserialize; use std::{fmt::Debug, ops::Deref}; use url::Url; +/// `Either` implementations for traits +pub mod either; + /// Helper for converting between database structs and federated protocol structs. /// /// ``` From ae075b4f950c381fa63de37c164298b41e5bb448 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Thu, 20 Mar 2025 12:16:25 +0100 Subject: [PATCH 5/7] Version 0.6.4 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 6fd6a84..b557004 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "activitypub_federation" -version = "0.6.3" +version = "0.6.4" edition = "2021" description = "High-level Activitypub framework" keywords = ["activitypub", "activitystreams", "federation", "fediverse"] From b3dac339907c56c5b80df5a61b88602662735422 Mon Sep 17 00:00:00 2001 From: Nutomic Date: Thu, 27 Mar 2025 14:58:45 +0000 Subject: [PATCH 6/7] Fixes for either impl (#140) * Fixes for either impl * link --- src/http_signatures.rs | 2 +- src/traits/either.rs | 31 ++++++++++++++++++++----------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/http_signatures.rs b/src/http_signatures.rs index ca6a02f..c255f03 100644 --- a/src/http_signatures.rs +++ b/src/http_signatures.rs @@ -57,7 +57,7 @@ impl Keypair { /// /// Note that this method is very slow in debug mode. To make it faster, follow /// instructions in the RSA crate's readme. -/// https://github.com/RustCrypto/RSA/blob/master/README.md +/// pub fn generate_actor_keypair() -> Result { let mut rng = rand::thread_rng(); let rsa = RsaPrivateKey::new(&mut rng, 2048)?; diff --git a/src/traits/either.rs b/src/traits/either.rs index 63a6ba4..95c2411 100644 --- a/src/traits/either.rs +++ b/src/traits/either.rs @@ -1,10 +1,19 @@ +use super::{Actor, Object}; use crate::{config::Data, error::Error}; use async_trait::async_trait; use chrono::{DateTime, Utc}; use either::Either; +use serde::{Deserialize, Serialize}; +use std::fmt::Debug; use url::Url; -use super::{Actor, Object}; +#[doc(hidden)] +#[derive(Serialize, Deserialize)] +#[serde(untagged)] +pub enum UntaggedEither { + Left(L), + Right(R), +} #[async_trait] impl Object for Either @@ -14,10 +23,10 @@ where ::Kind: Send + Sync, ::Kind: Send + Sync, D: Sync + Send + Clone, - E: From, + E: From + Debug, { type DataType = D; - type Kind = Either; + type Kind = UntaggedEither; type Error = E; fn last_refreshed_at(&self) -> Option> { @@ -39,7 +48,7 @@ where if let Some(r) = r { return Ok(Some(Either::Right(r))); } - Err(Error::NotFound.into()) + Ok(None) } async fn delete(self, data: &Data) -> Result<(), Self::Error> { @@ -51,8 +60,8 @@ where async fn into_json(self, data: &Data) -> Result { Ok(match self { - Either::Left(l) => Either::Left(l.into_json(data).await?), - Either::Right(r) => Either::Right(r.into_json(data).await?), + Either::Left(l) => UntaggedEither::Left(l.into_json(data).await?), + Either::Right(r) => UntaggedEither::Right(r.into_json(data).await?), }) } @@ -62,16 +71,16 @@ where data: &Data, ) -> Result<(), Self::Error> { match json { - Either::Left(l) => T::verify(l, expected_domain, data).await?, - Either::Right(r) => R::verify(r, expected_domain, data).await?, + UntaggedEither::Left(l) => T::verify(l, expected_domain, data).await?, + UntaggedEither::Right(r) => R::verify(r, expected_domain, data).await?, }; Ok(()) } async fn from_json(json: Self::Kind, data: &Data) -> Result { Ok(match json { - Either::Left(l) => Either::Left(T::from_json(l, data).await?), - Either::Right(r) => Either::Right(R::from_json(r, data).await?), + UntaggedEither::Left(l) => Either::Left(T::from_json(l, data).await?), + UntaggedEither::Right(r) => Either::Right(R::from_json(r, data).await?), }) } } @@ -84,7 +93,7 @@ where ::Kind: Send + Sync, ::Kind: Send + Sync, D: Sync + Send + Clone, - E: From, + E: From + Debug, { fn id(&self) -> Url { match self { From 4c1c0f7928fe42753ffca2488e317fe385bf8aa1 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Fri, 28 Mar 2025 11:23:56 +0100 Subject: [PATCH 7/7] 0.6.5 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b557004..9efc56b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "activitypub_federation" -version = "0.6.4" +version = "0.6.5" edition = "2021" description = "High-level Activitypub framework" keywords = ["activitypub", "activitystreams", "federation", "fediverse"]