Use the activitypub crate

This commit is contained in:
Bat 2018-06-10 12:13:07 +01:00
parent 40d87e746d
commit 78362feffb
13 changed files with 88 additions and 75 deletions

30
Cargo.lock generated
View File

@ -1,3 +1,16 @@
[[package]]
name = "activitypub"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"activitystreams-derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"activitystreams-traits 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"activitystreams-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "activitystreams" name = "activitystreams"
version = "0.1.1" version = "0.1.1"
@ -41,6 +54,20 @@ dependencies = [
"serde_json 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "activitystreams-types"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"activitystreams-derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"activitystreams-traits 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"mime 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "adler32" name = "adler32"
version = "1.0.2" version = "1.0.2"
@ -936,6 +963,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
name = "plume" name = "plume"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"activitypub 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"activitystreams 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "activitystreams 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"activitystreams-derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "activitystreams-derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"activitystreams-traits 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "activitystreams-traits 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1811,10 +1839,12 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata] [metadata]
"checksum activitypub 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c87040997a45d9da90327a11191bda4f2b1812d8c3e2062ea8d539eb8e2bfde7"
"checksum activitystreams 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "638541e5169c839f6581302c50e38876312389475cd911ecc7c446c7491004cc" "checksum activitystreams 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "638541e5169c839f6581302c50e38876312389475cd911ecc7c446c7491004cc"
"checksum activitystreams-derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "48db826c588a009960d74530e7c215e21fae130f585362504dc6b6357e5ce86b" "checksum activitystreams-derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "48db826c588a009960d74530e7c215e21fae130f585362504dc6b6357e5ce86b"
"checksum activitystreams-traits 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "670ef03168e704b0cae242e7a5d8b40506772b339687e01a3496fc4afe2e8542" "checksum activitystreams-traits 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "670ef03168e704b0cae242e7a5d8b40506772b339687e01a3496fc4afe2e8542"
"checksum activitystreams-types 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aff9aa0c3412fe4da72a1f6e4b1c2e9792bfdf1308b709389192f17aa8e2b3cd" "checksum activitystreams-types 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aff9aa0c3412fe4da72a1f6e4b1c2e9792bfdf1308b709389192f17aa8e2b3cd"
"checksum activitystreams-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "14806b3c88c439e1670fdc99d9b18bf1a47d4fa7152fe8a3bd7da08b6ced3e95"
"checksum adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6cbd0b9af8587c72beadc9f72d35b9fbb070982c9e6203e46e93f10df25f8f45" "checksum adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6cbd0b9af8587c72beadc9f72d35b9fbb070982c9e6203e46e93f10df25f8f45"
"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4" "checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"

View File

@ -3,6 +3,7 @@ authors = ["Bat' <baptiste@gelez.xyz>"]
name = "plume" name = "plume"
version = "0.1.0" version = "0.1.0"
[dependencies] [dependencies]
activitypub = "0.1"
activitystreams = "0.1" activitystreams = "0.1"
activitystreams-derive = "0.1" activitystreams-derive = "0.1"
activitystreams-traits = "0.1" activitystreams-traits = "0.1"

View File

@ -1,9 +1,10 @@
use activitystreams_traits::Actor; use activitypub::{
use activitystreams_types::{ Actor,
actor::Person, actor::Person,
activity::{Accept, Announce, Create, Follow, Like, Undo}, activity::{Accept, Announce, Create, Follow, Like, Undo},
object::{Article, Note} object::Note
}; };
use activitystreams_types::object::Article;
use diesel::PgConnection; use diesel::PgConnection;
use failure::Error; use failure::Error;
use serde_json; use serde_json;
@ -67,11 +68,11 @@ pub trait Inbox {
} }
fn follow(&self, conn: &PgConnection, follow: Follow) -> Result<(), Error> { fn follow(&self, conn: &PgConnection, follow: Follow) -> Result<(), Error> {
let from = User::from_url(conn, follow.actor.as_str().unwrap().to_string()).unwrap(); let from = User::from_url(conn, follow.follow_props.actor.as_str().unwrap().to_string()).unwrap();
match User::from_url(conn, follow.object.as_str().unwrap().to_string()) { match User::from_url(conn, follow.follow_props.object.as_str().unwrap().to_string()) {
Some(u) => self.accept_follow(conn, &from, &u, follow, from.id, u.id), Some(u) => self.accept_follow(conn, &from, &u, follow, from.id, u.id),
None => { None => {
let blog = Blog::from_url(conn, follow.object.as_str().unwrap().to_string()).unwrap(); let blog = Blog::from_url(conn, follow.follow_props.object.as_str().unwrap().to_string()).unwrap();
self.accept_follow(conn, &from, &blog, follow, from.id, blog.id) self.accept_follow(conn, &from, &blog, follow, from.id, blog.id)
} }
}; };
@ -79,8 +80,8 @@ pub trait Inbox {
} }
fn like(&self, conn: &PgConnection, like: Like) -> Result<(), Error> { fn like(&self, conn: &PgConnection, like: Like) -> Result<(), Error> {
let liker = User::from_url(conn, like.actor.as_str().unwrap().to_string()); let liker = User::from_url(conn, like.like_props.actor.as_str().unwrap().to_string());
let post = Post::find_by_ap_url(conn, like.object.as_str().unwrap().to_string()); let post = Post::find_by_ap_url(conn, like.like_props.object.as_str().unwrap().to_string());
likes::Like::insert(conn, likes::NewLike { likes::Like::insert(conn, likes::NewLike {
post_id: post.unwrap().id, post_id: post.unwrap().id,
user_id: liker.unwrap().id, user_id: liker.unwrap().id,
@ -90,14 +91,14 @@ pub trait Inbox {
} }
fn unlike(&self, conn: &PgConnection, undo: Undo) -> Result<(), Error> { fn unlike(&self, conn: &PgConnection, undo: Undo) -> Result<(), Error> {
let like = likes::Like::find_by_ap_url(conn, undo.object_object::<Like>()?.object_props.id_string()?).unwrap(); let like = likes::Like::find_by_ap_url(conn, undo.undo_props.object_object::<Like>()?.object_props.id_string()?).unwrap();
like.delete(conn); like.delete(conn);
Ok(()) Ok(())
} }
fn announce(&self, conn: &PgConnection, announce: Announce) -> Result<(), Error> { fn announce(&self, conn: &PgConnection, announce: Announce) -> Result<(), Error> {
let user = User::from_url(conn, announce.actor.as_str().unwrap().to_string()); let user = User::from_url(conn, announce.announce_props.actor.as_str().unwrap().to_string());
let post = Post::find_by_ap_url(conn, announce.object.as_str().unwrap().to_string()); let post = Post::find_by_ap_url(conn, announce.announce_props.object.as_str().unwrap().to_string());
Reshare::insert(conn, NewReshare { Reshare::insert(conn, NewReshare {
post_id: post.unwrap().id, post_id: post.unwrap().id,
user_id: user.unwrap().id, user_id: user.unwrap().id,
@ -113,9 +114,9 @@ pub trait Inbox {
"Announce" => self.announce(conn, serde_json::from_value(act.clone())?), "Announce" => self.announce(conn, serde_json::from_value(act.clone())?),
"Create" => { "Create" => {
let act: Create = serde_json::from_value(act.clone())?; let act: Create = serde_json::from_value(act.clone())?;
match act.object["type"].as_str().unwrap() { match act.create_props.object["type"].as_str().unwrap() {
"Article" => self.new_article(conn, act.object_object()?), "Article" => self.new_article(conn, act.create_props.object_object()?),
"Note" => self.new_comment(conn, act.object_object()?, act.actor_object::<Person>()?.object_props.id_string()?), "Note" => self.new_comment(conn, act.create_props.object_object()?, act.create_props.actor_object::<Person>()?.object_props.id_string()?),
_ => Err(InboxError::InvalidType)? _ => Err(InboxError::InvalidType)?
} }
}, },
@ -123,7 +124,7 @@ pub trait Inbox {
"Like" => self.like(conn, serde_json::from_value(act.clone())?), "Like" => self.like(conn, serde_json::from_value(act.clone())?),
"Undo" => { "Undo" => {
let act: Undo = serde_json::from_value(act.clone())?; let act: Undo = serde_json::from_value(act.clone())?;
match act.object["type"].as_str().unwrap() { match act.undo_props.object["type"].as_str().unwrap() {
"Like" => self.unlike(conn, act), "Like" => self.unlike(conn, act),
_ => Err(InboxError::CantUndo)? _ => Err(InboxError::CantUndo)?
} }
@ -150,8 +151,8 @@ pub trait Inbox {
}); });
let mut accept = Accept::default(); let mut accept = Accept::default();
accept.set_actor_link::<Id>(from.clone().into_id()).unwrap(); accept.accept_props.set_actor_link::<Id>(from.clone().into_id()).unwrap();
accept.set_object_object(follow).unwrap(); accept.accept_props.set_object_object(follow).unwrap();
broadcast(conn, &*from, accept, vec![target.clone()]); broadcast(conn, &*from, accept, vec![target.clone()]);
} }
} }

View File

@ -1,4 +1,4 @@
use activitystreams_traits::{Activity, Actor, Object, Link}; use activitypub::{Activity, Actor, Object, Link};
use array_tool::vec::Uniq; use array_tool::vec::Uniq;
use diesel::PgConnection; use diesel::PgConnection;
use reqwest::Client; use reqwest::Client;

View File

@ -1,10 +1,7 @@
#![feature(plugin, custom_derive, iterator_find_map)] #![feature(plugin, custom_derive, iterator_find_map)]
#![plugin(rocket_codegen)] #![plugin(rocket_codegen)]
extern crate activitystreams; extern crate activitypub;
#[macro_use]
extern crate activitystreams_derive;
extern crate activitystreams_traits;
extern crate activitystreams_types; extern crate activitystreams_types;
extern crate array_tool; extern crate array_tool;
extern crate base64; extern crate base64;

View File

@ -1,5 +1,4 @@
use activitystreams_traits::{Actor, Object}; use activitypub::{Actor, Object, collection::OrderedCollection};
use activitystreams_types::collection::OrderedCollection;
use reqwest::{ use reqwest::{
Client, Client,
header::{Accept, qitem}, header::{Accept, qitem},

View File

@ -1,4 +1,4 @@
use activitystreams_types::{ use activitypub::{
activity::Create, activity::Create,
object::{Note, properties::ObjectProperties} object::{Note, properties::ObjectProperties}
}; };
@ -105,8 +105,8 @@ impl Comment {
pub fn create_activity(&self, conn: &PgConnection) -> Create { pub fn create_activity(&self, conn: &PgConnection) -> Create {
let mut act = Create::default(); let mut act = Create::default();
act.set_actor_link(self.get_author(conn).into_id()).unwrap(); act.create_props.set_actor_link(self.get_author(conn).into_id()).unwrap();
act.set_object_object(self.into_activity(conn)).unwrap(); act.create_props.set_object_object(self.into_activity(conn)).unwrap();
act.object_props.set_id_string(format!("{}/activity", self.ap_url.clone().unwrap())).unwrap(); act.object_props.set_id_string(format!("{}/activity", self.ap_url.clone().unwrap())).unwrap();
act act
} }

View File

@ -1,4 +1,4 @@
use activitystreams_types::activity; use activitypub::activity;
use chrono; use chrono;
use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods}; use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods};
use serde_json; use serde_json;
@ -76,15 +76,15 @@ impl Like {
diesel::delete(self).execute(conn).unwrap(); diesel::delete(self).execute(conn).unwrap();
let mut act = activity::Undo::default(); let mut act = activity::Undo::default();
act.set_actor_link(User::get(conn, self.user_id).unwrap().into_id()).unwrap(); act.undo_props.set_actor_link(User::get(conn, self.user_id).unwrap().into_id()).unwrap();
act.set_object_object(self.into_activity(conn)).unwrap(); act.undo_props.set_object_object(self.into_activity(conn)).unwrap();
act act
} }
pub fn into_activity(&self, conn: &PgConnection) -> activity::Like { pub fn into_activity(&self, conn: &PgConnection) -> activity::Like {
let mut act = activity::Like::default(); let mut act = activity::Like::default();
act.set_actor_link(User::get(conn, self.user_id).unwrap().into_id()).unwrap(); act.like_props.set_actor_link(User::get(conn, self.user_id).unwrap().into_id()).unwrap();
act.set_object_link(Post::get(conn, self.post_id).unwrap().into_id()).unwrap(); act.like_props.set_object_link(Post::get(conn, self.post_id).unwrap().into_id()).unwrap();
act.object_props.set_id_string(format!("{}/like/{}", act.object_props.set_id_string(format!("{}/like/{}",
User::get(conn, self.user_id).unwrap().ap_url, User::get(conn, self.user_id).unwrap().ap_url,
Post::get(conn, self.post_id).unwrap().ap_url Post::get(conn, self.post_id).unwrap().ap_url

View File

@ -1,7 +1,5 @@
use activitystreams_types::{ use activitypub::activity::Create;
activity::Create, use activitystreams_types::object::{Article, properties::ObjectProperties};
object::{Article, properties::ObjectProperties}
};
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use diesel::{self, PgConnection, RunQueryDsl, QueryDsl, ExpressionMethods, BelongingToDsl}; use diesel::{self, PgConnection, RunQueryDsl, QueryDsl, ExpressionMethods, BelongingToDsl};
use diesel::dsl::any; use diesel::dsl::any;
@ -177,8 +175,8 @@ impl Post {
pub fn create_activity(&self, conn: &PgConnection) -> Create { pub fn create_activity(&self, conn: &PgConnection) -> Create {
let mut act = Create::default(); let mut act = Create::default();
act.object_props.set_id_string(format!("{}/activity", self.ap_url)).unwrap(); act.object_props.set_id_string(format!("{}/activity", self.ap_url)).unwrap();
act.set_actor_link(Id::new(self.get_authors(conn)[0].clone().ap_url)).unwrap(); act.create_props.set_actor_link(Id::new(self.get_authors(conn)[0].clone().ap_url)).unwrap();
act.set_object_object(self.into_activity(conn)).unwrap(); act.create_props.set_object_object(self.into_activity(conn)).unwrap();
act act
} }
} }

View File

@ -1,4 +1,4 @@
use activitystreams_types::activity; use activitypub::activity;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods}; use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods};
@ -84,15 +84,15 @@ impl Reshare {
diesel::delete(self).execute(conn).unwrap(); diesel::delete(self).execute(conn).unwrap();
let mut act = activity::Undo::default(); let mut act = activity::Undo::default();
act.set_actor_link(User::get(conn, self.user_id).unwrap().into_id()).unwrap(); act.undo_props.set_actor_link(User::get(conn, self.user_id).unwrap().into_id()).unwrap();
act.set_object_object(self.into_activity(conn)).unwrap(); act.undo_props.set_object_object(self.into_activity(conn)).unwrap();
act act
} }
pub fn into_activity(&self, conn: &PgConnection) -> activity::Announce { pub fn into_activity(&self, conn: &PgConnection) -> activity::Announce {
let mut act = activity::Announce::default(); let mut act = activity::Announce::default();
act.set_actor_link(User::get(conn, self.user_id).unwrap().into_id()).unwrap(); act.announce_props.set_actor_link(User::get(conn, self.user_id).unwrap().into_id()).unwrap();
act.set_object_link(Post::get(conn, self.post_id).unwrap().into_id()).unwrap(); act.announce_props.set_object_link(Post::get(conn, self.post_id).unwrap().into_id()).unwrap();
act.object_props.set_id_string(self.ap_url.clone()).unwrap(); act.object_props.set_id_string(self.ap_url.clone()).unwrap();
act act

View File

@ -1,9 +1,8 @@
use activitystreams_traits::{Actor, Object, Link}; use activitypub::{
use activitystreams_types::{ Actor, Object,
actor::Person, actor::{Person, properties::ApActorProperties},
collection::OrderedCollection, collection::OrderedCollection,
object::properties::ObjectProperties, object::properties::ObjectProperties
CustomObject
}; };
use bcrypt; use bcrypt;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
@ -302,7 +301,7 @@ impl User {
PKey::from_rsa(Rsa::private_key_from_pem(self.private_key.clone().unwrap().as_ref()).unwrap()).unwrap() PKey::from_rsa(Rsa::private_key_from_pem(self.private_key.clone().unwrap().as_ref()).unwrap()).unwrap()
} }
pub fn into_activity(&self, conn: &PgConnection) -> CustomObject<ApProps, Person> { pub fn into_activity(&self, conn: &PgConnection) -> Person {
let mut actor = Person::default(); let mut actor = Person::default();
actor.object_props = ObjectProperties { actor.object_props = ObjectProperties {
id: Some(serde_json::to_value(self.compute_id(conn)).unwrap()), id: Some(serde_json::to_value(self.compute_id(conn)).unwrap()),
@ -311,34 +310,22 @@ impl User {
url: Some(serde_json::to_value(self.compute_id(conn)).unwrap()), url: Some(serde_json::to_value(self.compute_id(conn)).unwrap()),
..ObjectProperties::default() ..ObjectProperties::default()
}; };
actor.ap_actor_props = ApActorProperties {
CustomObject::new(actor, ApProps { inbox: serde_json::to_value(self.compute_inbox(conn)).unwrap(),
inbox: Some(serde_json::to_value(self.compute_inbox(conn)).unwrap()), outbox: serde_json::to_value(self.compute_outbox(conn)).unwrap(),
outbox: Some(serde_json::to_value(self.compute_outbox(conn)).unwrap()),
preferred_username: Some(serde_json::to_value(self.get_actor_id()).unwrap()), preferred_username: Some(serde_json::to_value(self.get_actor_id()).unwrap()),
endpoints: Some(json!({ endpoints: Some(json!({
"sharedInbox": ap_url(format!("{}/inbox", BASE_URL.as_str())) "sharedInbox": ap_url(format!("{}/inbox", BASE_URL.as_str()))
})) })),
}) followers: None,
following: None,
liked: None,
streams: None
};
actor
} }
} }
#[derive(Serialize, Deserialize, Default, Properties)]
#[serde(rename_all = "camelCase")]
pub struct ApProps {
#[activitystreams(ab(Object, Link))]
inbox: Option<serde_json::Value>,
#[activitystreams(ab(Object, Link))]
outbox: Option<serde_json::Value>,
#[activitystreams(ab(Object, Link))]
preferred_username: Option<serde_json::Value>,
#[activitystreams(ab(Object))]
endpoints: Option<serde_json::Value>
}
impl<'a, 'r> FromRequest<'a, 'r> for User { impl<'a, 'r> FromRequest<'a, 'r> for User {
type Error = (); type Error = ();

View File

@ -1,4 +1,4 @@
use activitystreams_types::collection::OrderedCollection; use activitypub::collection::OrderedCollection;
use rocket::{ use rocket::{
request::Form, request::Form,
response::{Redirect, Flash} response::{Redirect, Flash}

View File

@ -1,4 +1,4 @@
use activitystreams_types::{ use activitypub::{
activity::Follow, activity::Follow,
collection::OrderedCollection collection::OrderedCollection
}; };
@ -82,8 +82,8 @@ fn follow(name: String, conn: DbConn, user: User) -> Redirect {
following_id: target.id following_id: target.id
}); });
let mut act = Follow::default(); let mut act = Follow::default();
act.set_actor_link::<Id>(user.clone().into_id()).unwrap(); act.follow_props.set_actor_link::<Id>(user.clone().into_id()).unwrap();
act.set_object_object(user.into_activity(&*conn)).unwrap(); act.follow_props.set_object_object(user.into_activity(&*conn)).unwrap();
act.object_props.set_id_string(format!("{}/follow/{}", user.ap_url, target.ap_url)).unwrap(); act.object_props.set_id_string(format!("{}/follow/{}", user.ap_url, target.ap_url)).unwrap();
broadcast(&*conn, &user, act, vec![target]); broadcast(&*conn, &user, act, vec![target]);
Redirect::to(format!("/@/{}/", name).as_ref()) Redirect::to(format!("/@/{}/", name).as_ref())