From 33afe9111edcdb351f2b4428387fb99da716ab7f Mon Sep 17 00:00:00 2001 From: Kitaiti Makoto Date: Mon, 2 May 2022 17:38:08 +0900 Subject: [PATCH] Remove AsObject --- plume-common/src/activity_pub/inbox.rs | 196 ------------------------- plume-models/src/comments.rs | 41 +----- plume-models/src/follows.rs | 39 +---- plume-models/src/likes.rs | 41 +----- plume-models/src/posts.rs | 101 +------------ plume-models/src/reshares.rs | 43 +----- plume-models/src/users.rs | 15 +- 7 files changed, 6 insertions(+), 470 deletions(-) diff --git a/plume-common/src/activity_pub/inbox.rs b/plume-common/src/activity_pub/inbox.rs index e08321a5..be28eac2 100644 --- a/plume-common/src/activity_pub/inbox.rs +++ b/plume-common/src/activity_pub/inbox.rs @@ -519,146 +519,6 @@ pub trait AsActor { /// } /// } /// ``` -pub trait AsObject -where - V: activitypub::Activity, -{ - /// What kind of error is returned when something fails - type Error; - - /// What is returned by `AsObject::activity`, if anything is returned - type Output = (); - - /// Handle a specific type of activity dealing with this type of objects. - /// - /// The implementations should check that the actor is actually authorized - /// to perform this action. - /// - /// # Parameters - /// - /// - `self`: the object on which the activity acts - /// - `ctx`: the context passed to `Inbox::handle` - /// - `actor`: the actor who did this activity - /// - `id`: the ID of this activity - fn activity(self, ctx: C, actor: A, id: &str) -> Result; -} - -/// Should be implemented by anything representing an ActivityPub object. -/// -/// # Type parameters -/// -/// - `A`: the actor type -/// - `V`: the ActivityPub verb/activity -/// - `O`: the ActivityPub type of the Object for this activity (usually the type corresponding to `Self`) -/// - `C`: the context needed to handle the activity (usually a database connection) -/// -/// # Example -/// -/// An implementation of AsObject that handles Note creation by an Account model, -/// representing the Note by a Message type, without any specific context. -/// -/// ```rust -/// # extern crate activitypub; -/// # use activitypub::{activity::Create, actor::Person, object::Note}; -/// # use plume_common::activity_pub::inbox::{AsActor, AsObject, FromId}; -/// # use plume_common::activity_pub::sign::{gen_keypair, Error as SignError, Result as SignResult, Signer}; -/// # use openssl::{hash::MessageDigest, pkey::PKey, rsa::Rsa}; -/// # use once_cell::sync::Lazy; -/// # -/// # static MY_SIGNER: Lazy = Lazy::new(|| MySigner::new()); -/// # -/// # struct MySigner { -/// # public_key: String, -/// # private_key: String, -/// # } -/// # -/// # impl MySigner { -/// # fn new() -> Self { -/// # let (pub_key, priv_key) = gen_keypair(); -/// # Self { -/// # public_key: String::from_utf8(pub_key).unwrap(), -/// # private_key: String::from_utf8(priv_key).unwrap(), -/// # } -/// # } -/// # } -/// # -/// # impl Signer for MySigner { -/// # fn get_key_id(&self) -> String { -/// # "mysigner".into() -/// # } -/// # -/// # fn sign(&self, to_sign: &str) -> SignResult> { -/// # let key = PKey::from_rsa(Rsa::private_key_from_pem(self.private_key.as_ref()).unwrap()) -/// # .unwrap(); -/// # let mut signer = openssl::sign::Signer::new(MessageDigest::sha256(), &key).unwrap(); -/// # signer.update(to_sign.as_bytes()).unwrap(); -/// # signer.sign_to_vec().map_err(|_| SignError()) -/// # } -/// # -/// # fn verify(&self, data: &str, signature: &[u8]) -> SignResult { -/// # let key = PKey::from_rsa(Rsa::public_key_from_pem(self.public_key.as_ref()).unwrap()) -/// # .unwrap(); -/// # let mut verifier = openssl::sign::Verifier::new(MessageDigest::sha256(), &key).unwrap(); -/// # verifier.update(data.as_bytes()).unwrap(); -/// # verifier.verify(&signature).map_err(|_| SignError()) -/// # } -/// # } -/// # -/// # struct Account; -/// # impl FromId<()> for Account { -/// # type Error = (); -/// # type Object = Person; -/// # -/// # fn from_db(_: &(), _id: &str) -> Result { -/// # Ok(Account) -/// # } -/// # -/// # fn from_activity(_: &(), obj: Person) -> Result { -/// # Ok(Account) -/// # } -/// # -/// # fn get_sender() -> &'static dyn Signer { -/// # &*MY_SIGNER -/// # } -/// # } -/// # impl AsActor<()> for Account { -/// # fn get_inbox_url(&self) -> String { -/// # String::new() -/// # } -/// # fn is_local(&self) -> bool { false } -/// # } -/// #[derive(Debug)] -/// struct Message { -/// text: String, -/// } -/// -/// impl FromId<()> for Message { -/// type Error = (); -/// type Object = Note; -/// -/// fn from_db(_: &(), _id: &str) -> Result { -/// Ok(Message { text: "From DB".into() }) -/// } -/// -/// fn from_activity(_: &(), obj: Note) -> Result { -/// Ok(Message { text: obj.object_props.content_string().map_err(|_| ())? }) -/// } -/// -/// fn get_sender() -> &'static dyn Signer { -/// &*MY_SIGNER -/// } -/// } -/// -/// impl AsObject for Message { -/// type Error = (); -/// type Output = (); -/// -/// fn activity(self, _: (), _actor: Account, _id: &str) -> Result<(), ()> { -/// println!("New Note: {:?}", self); -/// Ok(()) -/// } -/// } -/// ``` pub trait AsObject07 where V: activitystreams::markers::Activity, @@ -769,47 +629,6 @@ mod tests { } } - struct MyObject; - impl AsObject for MyObject { - type Error = (); - type Output = (); - - fn activity(self, _: &(), _actor: MyActor, _id: &str) -> Result { - println!("MyActor is creating a Note"); - Ok(()) - } - } - - impl AsObject for MyObject { - type Error = (); - type Output = (); - - fn activity(self, _: &(), _actor: MyActor, _id: &str) -> Result { - println!("MyActor is liking a Note"); - Ok(()) - } - } - - impl AsObject for MyObject { - type Error = (); - type Output = (); - - fn activity(self, _: &(), _actor: MyActor, _id: &str) -> Result { - println!("MyActor is deleting a Note"); - Ok(()) - } - } - - impl AsObject for MyObject { - type Error = (); - type Output = (); - - fn activity(self, _: &(), _actor: MyActor, _id: &str) -> Result { - println!("MyActor is announcing a Note"); - Ok(()) - } - } - struct MyObject07; impl FromId<()> for MyObject07 { type Error = (); @@ -962,21 +781,6 @@ mod tests { } } - impl AsObject for MyObject { - type Error = (); - type Output = (); - - fn activity( - self, - _: &(), - _actor: FailingActor, - _id: &str, - ) -> Result { - println!("FailingActor is creating a Note"); - Ok(()) - } - } - impl FromId<()> for FailingActor { type Error = (); type Object = Person07; diff --git a/plume-models/src/comments.rs b/plume-models/src/comments.rs index cd28113e..7c2864ce 100644 --- a/plume-models/src/comments.rs +++ b/plume-models/src/comments.rs @@ -30,7 +30,7 @@ use chrono::{self, NaiveDateTime, TimeZone, Utc}; use diesel::{self, ExpressionMethods, QueryDsl, RunQueryDsl, SaveChangesDsl}; use plume_common::{ activity_pub::{ - inbox::{AsActor, AsObject, AsObject07, FromId}, + inbox::{AsActor, AsObject07, FromId}, sign::Signer, Id, IntoId, ToAsString, ToAsUri, PUBLIC_VISIBILITY, }, @@ -431,45 +431,6 @@ impl FromId for Comment { } } -impl AsObject for Comment { - type Error = Error; - type Output = Self; - - fn activity(self, _conn: &DbConn, _actor: User, _id: &str) -> Result { - // The actual creation takes place in the FromId impl - Ok(self) - } -} - -impl AsObject for Comment { - type Error = Error; - type Output = (); - - fn activity(self, conn: &DbConn, actor: User, _id: &str) -> Result<()> { - if self.author_id != actor.id { - return Err(Error::Unauthorized); - } - - for m in Mention::list_for_comment(conn, self.id)? { - for n in Notification::find_for_mention(conn, &m)? { - n.delete(conn)?; - } - m.delete(conn)?; - } - - for n in Notification::find_for_comment(conn, &self)? { - n.delete(&**conn)?; - } - - diesel::update(comments::table) - .filter(comments::in_response_to_id.eq(self.id)) - .set(comments::in_response_to_id.eq(self.in_response_to_id)) - .execute(&**conn)?; - diesel::delete(&self).execute(&**conn)?; - Ok(()) - } -} - impl AsObject07 for Comment { type Error = Error; type Output = Self; diff --git a/plume-models/src/follows.rs b/plume-models/src/follows.rs index 36c24fa7..a4094802 100644 --- a/plume-models/src/follows.rs +++ b/plume-models/src/follows.rs @@ -12,7 +12,7 @@ use activitystreams::{ use diesel::{self, ExpressionMethods, QueryDsl, RunQueryDsl, SaveChangesDsl}; use plume_common::activity_pub::{ broadcast, broadcast07, - inbox::{AsActor, AsObject, AsObject07, FromId}, + inbox::{AsActor, AsObject07, FromId}, sign::Signer, Id, IntoId, PUBLIC_VISIBILITY, }; @@ -242,22 +242,6 @@ impl Follow { } } -impl AsObject for User { - type Error = Error; - type Output = Follow; - - fn activity(self, conn: &DbConn, actor: User, id: &str) -> Result { - // Mastodon (at least) requires the full Follow object when accepting it, - // so we rebuilt it here - let mut follow = FollowAct::default(); - follow.object_props.set_id_string(id.to_string())?; - follow - .follow_props - .set_actor_link::(actor.clone().into_id())?; - Follow::accept_follow(conn, &actor, &self, follow, actor.id, self.id) - } -} - impl AsObject07 for User { type Error = Error; type Output = Follow; @@ -312,27 +296,6 @@ impl FromId for Follow { } } -impl AsObject for Follow { - type Error = Error; - type Output = (); - - fn activity(self, conn: &DbConn, actor: User, _id: &str) -> Result<()> { - let conn = conn; - if self.follower_id == actor.id { - diesel::delete(&self).execute(&**conn)?; - - // delete associated notification if any - if let Ok(notif) = Notification::find(conn, notification_kind::FOLLOW, self.id) { - diesel::delete(¬if).execute(&**conn)?; - } - - Ok(()) - } else { - Err(Error::Unauthorized) - } - } -} - impl AsObject07 for Follow { type Error = Error; type Output = (); diff --git a/plume-models/src/likes.rs b/plume-models/src/likes.rs index a4959978..07760edf 100644 --- a/plume-models/src/likes.rs +++ b/plume-models/src/likes.rs @@ -12,7 +12,7 @@ use activitystreams::{ use chrono::NaiveDateTime; use diesel::{self, ExpressionMethods, QueryDsl, RunQueryDsl}; use plume_common::activity_pub::{ - inbox::{AsActor, AsObject, AsObject07, FromId}, + inbox::{AsActor, AsObject07, FromId}, sign::Signer, Id, IntoId, PUBLIC_VISIBILITY, }; @@ -118,26 +118,6 @@ impl Like { } } -impl AsObject for Post { - type Error = Error; - type Output = Like; - - fn activity(self, conn: &DbConn, actor: User, id: &str) -> Result { - let res = Like::insert( - conn, - NewLike { - post_id: self.id, - user_id: actor.id, - ap_url: id.to_string(), - }, - )?; - res.notify(conn)?; - - Timeline::add_to_all_timelines(conn, &self, Kind::Like(&actor))?; - Ok(res) - } -} - impl AsObject07 for Post { type Error = Error; type Output = Like; @@ -207,25 +187,6 @@ impl FromId for Like { } } -impl AsObject for Like { - type Error = Error; - type Output = (); - - fn activity(self, conn: &DbConn, actor: User, _id: &str) -> Result<()> { - if actor.id == self.user_id { - diesel::delete(&self).execute(&**conn)?; - - // delete associated notification if any - if let Ok(notif) = Notification::find(conn, notification_kind::LIKE, self.id) { - diesel::delete(¬if).execute(&**conn)?; - } - Ok(()) - } else { - Err(Error::Unauthorized) - } - } -} - impl AsObject07 for Like { type Error = Error; type Output = (); diff --git a/plume-models/src/posts.rs b/plume-models/src/posts.rs index 1a2b5520..4cd6c648 100644 --- a/plume-models/src/posts.rs +++ b/plume-models/src/posts.rs @@ -26,7 +26,7 @@ use diesel::{self, BelongingToDsl, ExpressionMethods, QueryDsl, RunQueryDsl}; use once_cell::sync::Lazy; use plume_common::{ activity_pub::{ - inbox::{AsActor, AsObject, AsObject07, FromId}, + inbox::{AsActor, AsObject07, FromId}, sign::Signer, Hashtag, Hashtag07, HashtagType07, Id, IntoId, Licensed, Licensed07, LicensedArticle as LicensedArticle07, Source, SourceProperty, ToAsString, ToAsUri, @@ -1054,16 +1054,6 @@ impl FromId for Post { } } -impl AsObject for Post { - type Error = Error; - type Output = Post; - - fn activity(self, _conn: &DbConn, _actor: User, _id: &str) -> Result { - // TODO: check that _actor is actually one of the author? - Ok(self) - } -} - impl AsObject07 for Post { type Error = Error; type Output = Self; @@ -1074,23 +1064,6 @@ impl AsObject07 for Post { } } -impl AsObject for Post { - type Error = Error; - type Output = (); - - fn activity(self, conn: &DbConn, actor: User, _id: &str) -> Result<()> { - let can_delete = self - .get_authors(conn)? - .into_iter() - .any(|a| actor.id == a.id); - if can_delete { - self.delete(conn).map(|_| ()) - } else { - Err(Error::Unauthorized) - } - } -} - impl AsObject07 for Post { type Error = Error; type Output = (); @@ -1176,78 +1149,6 @@ impl FromId for PostUpdate { } } -impl AsObject for PostUpdate { - type Error = Error; - type Output = (); - - fn activity(self, conn: &DbConn, actor: User, _id: &str) -> Result<()> { - let mut post = - Post::from_id07(conn, &self.ap_url, None, CONFIG.proxy()).map_err(|(_, e)| e)?; - - if !post.is_author(conn, actor.id)? { - // TODO: maybe the author was added in the meantime - return Err(Error::Unauthorized); - } - - if let Some(title) = self.title { - post.slug = Post::slug(&title).to_string(); - post.title = title; - } - - if let Some(content) = self.content { - post.content = SafeString::new(&content); - } - - if let Some(subtitle) = self.subtitle { - post.subtitle = subtitle; - } - - post.cover_id = self.cover; - - if let Some(source) = self.source { - post.source = source; - } - - if let Some(license) = self.license { - post.license = license; - } - - let mut txt_hashtags = md_to_html(&post.source, None, false, None) - .2 - .into_iter() - .collect::>(); - if let Some(serde_json::Value::Array(mention_tags)) = self.tags { - let mut mentions = vec![]; - let mut tags = vec![]; - let mut hashtags = vec![]; - for tag in mention_tags { - serde_json::from_value::(tag.clone()) - .map(|m| mentions.push(m)) - .ok(); - - serde_json::from_value::(tag.clone()) - .map_err(Error::from) - .and_then(|t| { - let tag_name = t.name_string()?; - if txt_hashtags.remove(&tag_name) { - hashtags.push(t); - } else { - tags.push(t); - } - Ok(()) - }) - .ok(); - } - post.update_mentions(conn, mentions)?; - post.update_tags(conn, tags)?; - post.update_hashtags(conn, hashtags)?; - } - - post.update(conn)?; - Ok(()) - } -} - impl AsObject07 for PostUpdate { type Error = Error; type Output = (); diff --git a/plume-models/src/reshares.rs b/plume-models/src/reshares.rs index bfd89575..419e19d3 100644 --- a/plume-models/src/reshares.rs +++ b/plume-models/src/reshares.rs @@ -12,7 +12,7 @@ use activitystreams::{ use chrono::NaiveDateTime; use diesel::{self, ExpressionMethods, QueryDsl, RunQueryDsl}; use plume_common::activity_pub::{ - inbox::{AsActor, AsObject, AsObject07, FromId}, + inbox::{AsActor, AsObject07, FromId}, sign::Signer, Id, IntoId, PUBLIC_VISIBILITY, }; @@ -144,27 +144,6 @@ impl Reshare { } } -impl AsObject for Post { - type Error = Error; - type Output = Reshare; - - fn activity(self, conn: &DbConn, actor: User, id: &str) -> Result { - let conn = conn; - let reshare = Reshare::insert( - conn, - NewReshare { - post_id: self.id, - user_id: actor.id, - ap_url: id.to_string(), - }, - )?; - reshare.notify(conn)?; - - Timeline::add_to_all_timelines(conn, &self, Kind::Reshare(&actor))?; - Ok(reshare) - } -} - impl AsObject07 for Post { type Error = Error; type Output = Reshare; @@ -235,26 +214,6 @@ impl FromId for Reshare { } } -impl AsObject for Reshare { - type Error = Error; - type Output = (); - - fn activity(self, conn: &DbConn, actor: User, _id: &str) -> Result<()> { - if actor.id == self.user_id { - diesel::delete(&self).execute(&**conn)?; - - // delete associated notification if any - if let Ok(notif) = Notification::find(conn, notification_kind::RESHARE, self.id) { - diesel::delete(¬if).execute(&**conn)?; - } - - Ok(()) - } else { - Err(Error::Unauthorized) - } - } -} - impl AsObject07 for Reshare { type Error = Error; type Output = (); diff --git a/plume-models/src/users.rs b/plume-models/src/users.rs index fa20fb71..09345c98 100644 --- a/plume-models/src/users.rs +++ b/plume-models/src/users.rs @@ -35,7 +35,7 @@ use openssl::{ }; use plume_common::{ activity_pub::{ - inbox::{AsActor, AsObject, AsObject07, FromId}, + inbox::{AsActor, AsObject07, FromId}, request::get, sign::{gen_keypair, Error as SignError, Result as SignResult, Signer}, ActivityStream, ApSignature, ApSignature07, CustomPerson as CustomPerson07, Id, IntoId, @@ -1248,19 +1248,6 @@ impl AsActor<&DbConn> for User { } } -impl AsObject for User { - type Error = Error; - type Output = (); - - fn activity(self, conn: &DbConn, actor: User, _id: &str) -> Result<()> { - if self.id == actor.id { - self.delete(conn).map(|_| ()) - } else { - Err(Error::Unauthorized) - } - } -} - impl AsObject07 for User { type Error = Error; type Output = ();