Make it work with Lemmy
This commit is contained in:
parent
6b3a4f8942
commit
29d040bcd3
6 changed files with 36 additions and 11 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -4,7 +4,7 @@ version = 3
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "activitypub_federation"
|
name = "activitypub_federation"
|
||||||
version = "0.4.0-rc1"
|
version = "0.4.0-rc2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"activitystreams-kinds",
|
"activitystreams-kinds",
|
||||||
"actix-rt",
|
"actix-rt",
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use crate::{
|
||||||
error::Error,
|
error::Error,
|
||||||
http_signatures::sign_request,
|
http_signatures::sign_request,
|
||||||
reqwest_shim::ResponseExt,
|
reqwest_shim::ResponseExt,
|
||||||
traits::ActivityHandler,
|
traits::{ActivityHandler, Actor},
|
||||||
APUB_JSON_CONTENT_TYPE,
|
APUB_JSON_CONTENT_TYPE,
|
||||||
};
|
};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
|
|
@ -40,9 +40,9 @@ use url::Url;
|
||||||
/// signature. Generated with [crate::http_signatures::generate_actor_keypair].
|
/// signature. Generated with [crate::http_signatures::generate_actor_keypair].
|
||||||
/// - `inboxes`: List of actor inboxes that should receive the activity. Should be built by calling
|
/// - `inboxes`: List of actor inboxes that should receive the activity. Should be built by calling
|
||||||
/// [crate::traits::Actor::shared_inbox_or_inbox] for each target actor.
|
/// [crate::traits::Actor::shared_inbox_or_inbox] for each target actor.
|
||||||
pub async fn send_activity<Activity, Datatype>(
|
pub async fn send_activity<Activity, Datatype, ActorType>(
|
||||||
activity: Activity,
|
activity: Activity,
|
||||||
private_key: String,
|
actor: ActorType,
|
||||||
inboxes: Vec<Url>,
|
inboxes: Vec<Url>,
|
||||||
data: &RequestData<Datatype>,
|
data: &RequestData<Datatype>,
|
||||||
) -> Result<(), <Activity as ActivityHandler>::Error>
|
) -> Result<(), <Activity as ActivityHandler>::Error>
|
||||||
|
|
@ -50,11 +50,14 @@ where
|
||||||
Activity: ActivityHandler + Serialize,
|
Activity: ActivityHandler + Serialize,
|
||||||
<Activity as ActivityHandler>::Error: From<anyhow::Error> + From<serde_json::Error>,
|
<Activity as ActivityHandler>::Error: From<anyhow::Error> + From<serde_json::Error>,
|
||||||
Datatype: Clone,
|
Datatype: Clone,
|
||||||
|
ActorType: Actor,
|
||||||
|
for<'de2> ActorType::ApubType: Deserialize<'de2>,
|
||||||
{
|
{
|
||||||
let config = &data.config;
|
let config = &data.config;
|
||||||
let actor_id = activity.actor();
|
let actor_id = activity.actor();
|
||||||
let activity_id = activity.id();
|
let activity_id = activity.id();
|
||||||
let activity_serialized = serde_json::to_string_pretty(&activity)?;
|
let activity_serialized = serde_json::to_string_pretty(&activity)?;
|
||||||
|
let private_key = actor.private_key_pem().unwrap();
|
||||||
let inboxes: Vec<Url> = inboxes
|
let inboxes: Vec<Url> = inboxes
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.unique()
|
.unique()
|
||||||
|
|
|
||||||
|
|
@ -112,8 +112,8 @@ mod test {
|
||||||
let request_builder =
|
let request_builder =
|
||||||
ClientWithMiddleware::from(Client::default()).post("https://example.com/inbox");
|
ClientWithMiddleware::from(Client::default()).post("https://example.com/inbox");
|
||||||
let activity = Follow {
|
let activity = Follow {
|
||||||
actor: ObjectId::new("http://localhost:123").unwrap(),
|
actor: ObjectId::parse("http://localhost:123").unwrap(),
|
||||||
object: ObjectId::new("http://localhost:124").unwrap(),
|
object: ObjectId::parse("http://localhost:124").unwrap(),
|
||||||
kind: Default::default(),
|
kind: Default::default(),
|
||||||
id: "http://localhost:123/1".try_into().unwrap(),
|
id: "http://localhost:123/1".try_into().unwrap(),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,21 @@ use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
fmt::{Debug, Display, Formatter},
|
fmt::{Debug, Display, Formatter},
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
|
str::FromStr,
|
||||||
};
|
};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
impl<T> FromStr for ObjectId<T>
|
||||||
|
where
|
||||||
|
T: ApubObject + Send + 'static,
|
||||||
|
for<'de2> <T as ApubObject>::ApubType: Deserialize<'de2>,
|
||||||
|
{
|
||||||
|
type Err = url::ParseError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
ObjectId::parse(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
/// Typed wrapper for Activitypub Object ID which helps with dereferencing and caching.
|
/// Typed wrapper for Activitypub Object ID which helps with dereferencing and caching.
|
||||||
///
|
///
|
||||||
/// It provides convenient methods for fetching the object from remote server or local database.
|
/// It provides convenient methods for fetching the object from remote server or local database.
|
||||||
|
|
@ -32,7 +44,7 @@ use url::Url;
|
||||||
/// .app_data(db_connection)
|
/// .app_data(db_connection)
|
||||||
/// .build()?;
|
/// .build()?;
|
||||||
/// let request_data = config.to_request_data();
|
/// let request_data = config.to_request_data();
|
||||||
/// let object_id = ObjectId::<DbUser>::new("https://lemmy.ml/u/nutomic")?;
|
/// let object_id = ObjectId::<DbUser>::parse("https://lemmy.ml/u/nutomic")?;
|
||||||
/// // Attempt to fetch object from local database or fall back to remote server
|
/// // Attempt to fetch object from local database or fall back to remote server
|
||||||
/// let user = object_id.dereference(&request_data).await;
|
/// let user = object_id.dereference(&request_data).await;
|
||||||
/// assert!(user.is_ok());
|
/// assert!(user.is_ok());
|
||||||
|
|
@ -55,7 +67,7 @@ where
|
||||||
for<'de2> <Kind as ApubObject>::ApubType: serde::Deserialize<'de2>,
|
for<'de2> <Kind as ApubObject>::ApubType: serde::Deserialize<'de2>,
|
||||||
{
|
{
|
||||||
/// Construct a new objectid instance
|
/// Construct a new objectid instance
|
||||||
pub fn new<T>(url: T) -> Result<Self, url::ParseError>
|
pub fn parse<T>(url: T) -> Result<Self, url::ParseError>
|
||||||
where
|
where
|
||||||
T: TryInto<Url>,
|
T: TryInto<Url>,
|
||||||
url::ParseError: From<<T as TryInto<Url>>::Error>,
|
url::ParseError: From<<T as TryInto<Url>>::Error>,
|
||||||
|
|
@ -238,7 +250,7 @@ pub mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_deserialize() {
|
fn test_deserialize() {
|
||||||
let id = ObjectId::<DbUser>::new("http://test.com/").unwrap();
|
let id = ObjectId::<DbUser>::parse("http://test.com/").unwrap();
|
||||||
|
|
||||||
let string = serde_json::to_string(&id).unwrap();
|
let string = serde_json::to_string(&id).unwrap();
|
||||||
assert_eq!("\"http://test.com/\"", string);
|
assert_eq!("\"http://test.com/\"", string);
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ impl PublicKey {
|
||||||
/// Create a new [PublicKey] struct for the `owner` with `public_key_pem`.
|
/// Create a new [PublicKey] struct for the `owner` with `public_key_pem`.
|
||||||
///
|
///
|
||||||
/// It uses an standard key id of `{actor_id}#main-key`
|
/// It uses an standard key id of `{actor_id}#main-key`
|
||||||
pub fn new(owner: Url, public_key_pem: String) -> Self {
|
pub(crate) fn new(owner: Url, public_key_pem: String) -> Self {
|
||||||
let id = main_key_id(&owner);
|
let id = main_key_id(&owner);
|
||||||
PublicKey {
|
PublicKey {
|
||||||
id,
|
id,
|
||||||
|
|
|
||||||
|
|
@ -227,7 +227,7 @@ pub trait ActivityHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait to allow retrieving common Actor data.
|
/// Trait to allow retrieving common Actor data.
|
||||||
pub trait Actor: ApubObject {
|
pub trait Actor: ApubObject + Send + 'static {
|
||||||
/// `id` field of the actor
|
/// `id` field of the actor
|
||||||
fn id(&self) -> &Url;
|
fn id(&self) -> &Url;
|
||||||
|
|
||||||
|
|
@ -237,6 +237,12 @@ pub trait Actor: ApubObject {
|
||||||
/// actor keypair.
|
/// actor keypair.
|
||||||
fn public_key_pem(&self) -> &str;
|
fn public_key_pem(&self) -> &str;
|
||||||
|
|
||||||
|
/// The actor's private key for signing outgoing activities.
|
||||||
|
///
|
||||||
|
/// Use [generate_actor_keypair](crate::http_signatures::generate_actor_keypair) to create the
|
||||||
|
/// actor keypair.
|
||||||
|
fn private_key_pem(&self) -> Option<String>;
|
||||||
|
|
||||||
/// The inbox where activities for this user should be sent to
|
/// The inbox where activities for this user should be sent to
|
||||||
fn inbox(&self) -> Url;
|
fn inbox(&self) -> Url;
|
||||||
|
|
||||||
|
|
@ -412,6 +418,10 @@ pub mod tests {
|
||||||
&self.public_key
|
&self.public_key
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn private_key_pem(&self) -> Option<String> {
|
||||||
|
self.private_key.clone()
|
||||||
|
}
|
||||||
|
|
||||||
fn inbox(&self) -> Url {
|
fn inbox(&self) -> Url {
|
||||||
self.inbox.clone()
|
self.inbox.clone()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue