2018-06-10 13:13:07 +02:00
|
|
|
use activitypub::{Activity, Actor, Object, Link};
|
2018-05-16 20:20:44 +02:00
|
|
|
use array_tool::vec::Uniq;
|
|
|
|
use diesel::PgConnection;
|
|
|
|
use reqwest::Client;
|
2018-05-19 09:39:59 +02:00
|
|
|
use rocket::{
|
|
|
|
http::{ContentType, Status},
|
|
|
|
response::{Response, Responder, Content},
|
|
|
|
request::Request
|
|
|
|
};
|
2018-04-24 14:31:02 +02:00
|
|
|
use rocket_contrib::Json;
|
|
|
|
use serde_json;
|
|
|
|
|
2018-05-16 20:20:44 +02:00
|
|
|
use self::sign::Signable;
|
|
|
|
|
2018-04-24 11:21:39 +02:00
|
|
|
pub mod actor;
|
2018-05-01 16:00:29 +02:00
|
|
|
pub mod inbox;
|
2018-05-04 17:18:00 +02:00
|
|
|
pub mod request;
|
2018-04-29 19:49:56 +02:00
|
|
|
pub mod sign;
|
2018-04-24 14:31:02 +02:00
|
|
|
|
2018-06-16 19:39:22 +02:00
|
|
|
pub type ActivityPub = Content<Json<serde_json::Value>>;
|
2018-04-24 16:52:47 +02:00
|
|
|
|
|
|
|
pub const CONTEXT_URL: &'static str = "https://www.w3.org/ns/activitystreams";
|
2018-04-30 18:50:35 +02:00
|
|
|
pub const PUBLIC_VISIBILTY: &'static str = "https://www.w3.org/ns/activitystreams#Public";
|
2018-04-24 14:31:02 +02:00
|
|
|
|
2018-05-02 14:47:46 +02:00
|
|
|
#[cfg(debug_assertions)]
|
|
|
|
pub fn ap_url(url: String) -> String {
|
|
|
|
format!("http://{}", url)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(debug_assertions))]
|
|
|
|
pub fn ap_url(url: String) -> String {
|
|
|
|
format!("https://{}", url)
|
|
|
|
}
|
|
|
|
|
2018-04-24 14:31:02 +02:00
|
|
|
pub fn context() -> serde_json::Value {
|
|
|
|
json!([
|
2018-04-29 19:49:56 +02:00
|
|
|
CONTEXT_URL,
|
2018-04-24 14:31:02 +02:00
|
|
|
"https://w3id.org/security/v1",
|
|
|
|
{
|
|
|
|
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
|
|
|
|
"sensitive": "as:sensitive",
|
|
|
|
"movedTo": "as:movedTo",
|
|
|
|
"Hashtag": "as:Hashtag",
|
|
|
|
"ostatus":"http://ostatus.org#",
|
|
|
|
"atomUri":"ostatus:atomUri",
|
|
|
|
"inReplyToAtomUri":"ostatus:inReplyToAtomUri",
|
|
|
|
"conversation":"ostatus:conversation",
|
|
|
|
"toot":"http://joinmastodon.org/ns#",
|
|
|
|
"Emoji":"toot:Emoji",
|
|
|
|
"focalPoint": {
|
|
|
|
"@container":"@list",
|
|
|
|
"@id":"toot:focalPoint"
|
|
|
|
},
|
|
|
|
"featured":"toot:featured"
|
|
|
|
}
|
|
|
|
])
|
|
|
|
}
|
|
|
|
|
2018-04-24 16:52:47 +02:00
|
|
|
pub fn activity_pub(json: serde_json::Value) -> ActivityPub {
|
2018-04-24 14:31:02 +02:00
|
|
|
Content(ContentType::new("application", "activity+json"), Json(json))
|
|
|
|
}
|
2018-05-16 20:20:44 +02:00
|
|
|
|
|
|
|
pub struct ActivityStream<T> (T);
|
|
|
|
|
|
|
|
impl<T> ActivityStream<T> {
|
|
|
|
pub fn new(t: T) -> ActivityStream<T> {
|
|
|
|
ActivityStream(t)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'r, O: Object> Responder<'r> for ActivityStream<O> {
|
|
|
|
fn respond_to(self, request: &Request) -> Result<Response<'r>, Status> {
|
|
|
|
serde_json::to_string(&self.0).respond_to(request)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-18 17:16:18 +02:00
|
|
|
pub fn broadcast<A: Activity, S: sign::Signer, T: inbox::WithInbox + Actor>(conn: &PgConnection, sender: &S, act: A, to: Vec<T>) {
|
2018-05-16 20:20:44 +02:00
|
|
|
let boxes = to.into_iter()
|
|
|
|
.map(|u| u.get_shared_inbox_url().unwrap_or(u.get_inbox_url()))
|
|
|
|
.collect::<Vec<String>>()
|
|
|
|
.unique();
|
2018-06-18 17:16:18 +02:00
|
|
|
|
|
|
|
let mut act = serde_json::to_value(act).unwrap();
|
|
|
|
act["@context"] = context();
|
|
|
|
let signed = act.sign(sender, conn);
|
|
|
|
|
2018-05-16 20:20:44 +02:00
|
|
|
for inbox in boxes {
|
|
|
|
// TODO: run it in Sidekiq or something like that
|
|
|
|
let res = Client::new()
|
|
|
|
.post(&inbox[..])
|
|
|
|
.headers(request::headers())
|
|
|
|
.header(request::signature(sender, request::headers(), conn))
|
|
|
|
.header(request::digest(signed.to_string()))
|
|
|
|
.body(signed.to_string())
|
|
|
|
.send();
|
|
|
|
match res {
|
|
|
|
Ok(mut r) => println!("Successfully sent activity to inbox ({})\n\n{:?}", inbox, r.text().unwrap()),
|
|
|
|
Err(e) => println!("Error while sending to inbox ({:?})", e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-19 00:04:30 +02:00
|
|
|
#[derive(Clone, Serialize, Deserialize)]
|
2018-05-19 11:50:56 +02:00
|
|
|
pub struct Id(String);
|
2018-05-16 20:20:44 +02:00
|
|
|
|
|
|
|
impl Id {
|
|
|
|
pub fn new<T: Into<String>>(id: T) -> Id {
|
2018-05-19 11:50:56 +02:00
|
|
|
Id(id.into())
|
2018-05-16 20:20:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-12 21:10:08 +02:00
|
|
|
impl Into<String> for Id {
|
|
|
|
fn into(self) -> String {
|
|
|
|
self.0.clone()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-18 10:04:40 +02:00
|
|
|
pub trait IntoId {
|
2018-05-19 00:04:30 +02:00
|
|
|
fn into_id(self) -> Id;
|
2018-05-18 10:04:40 +02:00
|
|
|
}
|
|
|
|
|
2018-05-16 20:20:44 +02:00
|
|
|
impl Link for Id {}
|