2020-03-16 04:15:50 +00:00
|
|
|
use crate::{
|
|
|
|
apub::{AcceptedActors, AcceptedObjects, ValidTypes},
|
2020-03-17 17:15:16 +00:00
|
|
|
db::{add_listener, remove_listener},
|
2020-03-16 04:15:50 +00:00
|
|
|
db_actor::{DbActor, DbQuery, Pool},
|
|
|
|
error::MyError,
|
2020-03-17 17:15:16 +00:00
|
|
|
requests::{deliver, deliver_many, fetch_actor},
|
|
|
|
response,
|
2020-03-16 04:15:50 +00:00
|
|
|
state::{State, UrlKind},
|
|
|
|
};
|
2020-03-15 17:49:27 +00:00
|
|
|
use activitystreams::{
|
2020-03-15 22:37:53 +00:00
|
|
|
activity::apub::{Accept, Announce, Follow, Undo},
|
|
|
|
context,
|
2020-03-15 17:49:27 +00:00
|
|
|
primitives::XsdAnyUri,
|
|
|
|
};
|
2020-03-15 02:05:40 +00:00
|
|
|
use actix::Addr;
|
2020-03-16 03:36:46 +00:00
|
|
|
use actix_web::{client::Client, web, HttpResponse};
|
2020-03-15 17:49:27 +00:00
|
|
|
use futures::join;
|
2020-03-17 19:52:33 +00:00
|
|
|
use http_signature_normalization_actix::middleware::SignatureVerified;
|
2020-03-15 22:37:53 +00:00
|
|
|
use log::error;
|
2020-03-15 02:05:40 +00:00
|
|
|
|
|
|
|
pub async fn inbox(
|
|
|
|
db_actor: web::Data<Addr<DbActor>>,
|
|
|
|
state: web::Data<State>,
|
|
|
|
client: web::Data<Client>,
|
|
|
|
input: web::Json<AcceptedObjects>,
|
2020-03-17 19:52:33 +00:00
|
|
|
verified: SignatureVerified,
|
2020-03-15 22:37:53 +00:00
|
|
|
) -> Result<HttpResponse, MyError> {
|
2020-03-15 02:05:40 +00:00
|
|
|
let input = input.into_inner();
|
|
|
|
|
2020-03-17 20:52:26 +00:00
|
|
|
let actor = fetch_actor(
|
|
|
|
state.clone().into_inner(),
|
|
|
|
client.clone().into_inner(),
|
|
|
|
&input.actor,
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
|
2020-03-18 02:16:09 +00:00
|
|
|
let (is_blocked, is_whitelisted) =
|
|
|
|
join!(state.is_blocked(&actor.id), state.is_whitelisted(&actor.id),);
|
|
|
|
|
|
|
|
if is_blocked {
|
|
|
|
return Err(MyError::Blocked(actor.id.to_string()));
|
|
|
|
}
|
|
|
|
|
|
|
|
if !is_whitelisted {
|
|
|
|
return Err(MyError::Whitelist(actor.id.to_string()));
|
|
|
|
}
|
|
|
|
|
2020-03-17 20:52:26 +00:00
|
|
|
if actor.public_key.id.as_str() != verified.key_id() {
|
2020-03-18 02:16:09 +00:00
|
|
|
return Err(MyError::BadActor(
|
|
|
|
actor.public_key.id.to_string(),
|
|
|
|
verified.key_id().to_owned(),
|
|
|
|
));
|
2020-03-17 19:52:33 +00:00
|
|
|
}
|
|
|
|
|
2020-03-15 02:05:40 +00:00
|
|
|
match input.kind {
|
2020-03-15 22:37:53 +00:00
|
|
|
ValidTypes::Announce | ValidTypes::Create => {
|
|
|
|
handle_relay(state, client, input, actor).await
|
|
|
|
}
|
|
|
|
ValidTypes::Follow => handle_follow(db_actor, state, client, input, actor).await,
|
|
|
|
ValidTypes::Delete | ValidTypes::Update => {
|
|
|
|
handle_forward(state, client, input, actor).await
|
|
|
|
}
|
|
|
|
ValidTypes::Undo => handle_undo(db_actor, state, client, input, actor).await,
|
2020-03-15 02:05:40 +00:00
|
|
|
}
|
2020-03-15 22:37:53 +00:00
|
|
|
}
|
2020-03-15 02:05:40 +00:00
|
|
|
|
2020-03-15 22:37:53 +00:00
|
|
|
async fn handle_undo(
|
|
|
|
db_actor: web::Data<Addr<DbActor>>,
|
|
|
|
state: web::Data<State>,
|
|
|
|
client: web::Data<Client>,
|
|
|
|
input: AcceptedObjects,
|
|
|
|
actor: AcceptedActors,
|
|
|
|
) -> Result<HttpResponse, MyError> {
|
|
|
|
if !input.object.is_kind("Follow") {
|
2020-03-16 03:36:46 +00:00
|
|
|
return Err(MyError::Kind);
|
2020-03-15 22:37:53 +00:00
|
|
|
}
|
|
|
|
|
2020-03-18 02:16:09 +00:00
|
|
|
let my_id: XsdAnyUri = state.generate_url(UrlKind::Actor).parse()?;
|
|
|
|
|
|
|
|
if !input.object.child_object_is(&my_id) {
|
|
|
|
return Err(MyError::WrongActor(input.object.id().to_string()));
|
|
|
|
}
|
|
|
|
|
2020-03-15 22:37:53 +00:00
|
|
|
let inbox = actor.inbox().to_owned();
|
|
|
|
|
|
|
|
db_actor.do_send(DbQuery(move |pool: Pool| {
|
|
|
|
let inbox = inbox.clone();
|
|
|
|
|
|
|
|
async move {
|
|
|
|
let conn = pool.get().await?;
|
|
|
|
|
2020-03-17 17:15:16 +00:00
|
|
|
remove_listener(&conn, &inbox).await.map_err(|e| {
|
|
|
|
error!("Error removing listener, {}", e);
|
|
|
|
e
|
|
|
|
})
|
2020-03-15 22:37:53 +00:00
|
|
|
}
|
|
|
|
}));
|
|
|
|
|
2020-03-18 02:16:09 +00:00
|
|
|
let actor_inbox = actor.inbox().clone();
|
|
|
|
let undo = generate_undo_follow(&state, &actor.id, &my_id)?;
|
|
|
|
let undo2 = undo.clone();
|
|
|
|
actix::Arbiter::spawn(async move {
|
|
|
|
let _ = deliver(
|
|
|
|
&state.into_inner(),
|
|
|
|
&client.into_inner(),
|
|
|
|
actor_inbox,
|
|
|
|
&undo2,
|
|
|
|
)
|
|
|
|
.await;
|
|
|
|
});
|
2020-03-15 22:37:53 +00:00
|
|
|
|
|
|
|
Ok(response(undo))
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn handle_forward(
|
|
|
|
state: web::Data<State>,
|
|
|
|
client: web::Data<Client>,
|
|
|
|
input: AcceptedObjects,
|
|
|
|
actor: AcceptedActors,
|
|
|
|
) -> Result<HttpResponse, MyError> {
|
|
|
|
let object_id = input.object.id();
|
|
|
|
|
|
|
|
let inboxes = get_inboxes(&state, &actor, &object_id).await?;
|
2020-03-18 02:16:09 +00:00
|
|
|
deliver_many(&state, &client, inboxes, input.clone());
|
2020-03-15 22:37:53 +00:00
|
|
|
|
2020-03-15 22:49:40 +00:00
|
|
|
Ok(response(input))
|
2020-03-15 22:37:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async fn handle_relay(
|
|
|
|
state: web::Data<State>,
|
|
|
|
client: web::Data<Client>,
|
|
|
|
input: AcceptedObjects,
|
|
|
|
actor: AcceptedActors,
|
|
|
|
) -> Result<HttpResponse, MyError> {
|
|
|
|
let object_id = input.object.id();
|
|
|
|
|
|
|
|
if state.is_cached(object_id).await {
|
2020-03-16 03:36:46 +00:00
|
|
|
return Err(MyError::Duplicate);
|
2020-03-15 22:37:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let activity_id: XsdAnyUri = state.generate_url(UrlKind::Activity).parse()?;
|
|
|
|
|
2020-03-18 02:16:09 +00:00
|
|
|
let announce = generate_announce(&state, &activity_id, object_id)?;
|
2020-03-15 22:37:53 +00:00
|
|
|
let inboxes = get_inboxes(&state, &actor, &object_id).await?;
|
2020-03-18 02:16:09 +00:00
|
|
|
deliver_many(&state, &client, inboxes, announce.clone());
|
2020-03-15 22:37:53 +00:00
|
|
|
|
|
|
|
state.cache(object_id.to_owned(), activity_id).await;
|
|
|
|
|
2020-03-15 22:49:40 +00:00
|
|
|
Ok(response(announce))
|
2020-03-15 17:49:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async fn handle_follow(
|
|
|
|
db_actor: web::Data<Addr<DbActor>>,
|
|
|
|
state: web::Data<State>,
|
2020-03-15 22:37:53 +00:00
|
|
|
client: web::Data<Client>,
|
2020-03-15 17:49:27 +00:00
|
|
|
input: AcceptedObjects,
|
|
|
|
actor: AcceptedActors,
|
2020-03-15 22:37:53 +00:00
|
|
|
) -> Result<HttpResponse, MyError> {
|
2020-03-18 02:16:09 +00:00
|
|
|
let my_id: XsdAnyUri = state.generate_url(UrlKind::Actor).parse()?;
|
2020-03-15 17:49:27 +00:00
|
|
|
|
2020-03-18 02:16:09 +00:00
|
|
|
if !input.object.is(&my_id) {
|
|
|
|
return Err(MyError::WrongActor(input.object.id().to_string()));
|
2020-03-15 17:49:27 +00:00
|
|
|
}
|
|
|
|
|
2020-03-18 02:16:09 +00:00
|
|
|
let is_listener = state.is_listener(&actor.id).await;
|
2020-03-15 17:49:27 +00:00
|
|
|
|
|
|
|
if !is_listener {
|
2020-03-15 22:37:53 +00:00
|
|
|
let inbox = actor.inbox().to_owned();
|
2020-03-15 17:49:27 +00:00
|
|
|
db_actor.do_send(DbQuery(move |pool: Pool| {
|
2020-03-15 22:37:53 +00:00
|
|
|
let inbox = inbox.clone();
|
2020-03-15 17:49:27 +00:00
|
|
|
|
|
|
|
async move {
|
|
|
|
let conn = pool.get().await?;
|
|
|
|
|
2020-03-17 17:15:16 +00:00
|
|
|
add_listener(&conn, &inbox).await.map_err(|e| {
|
2020-03-15 22:37:53 +00:00
|
|
|
error!("Error adding listener, {}", e);
|
|
|
|
e
|
|
|
|
})
|
2020-03-15 17:49:27 +00:00
|
|
|
}
|
|
|
|
}));
|
2020-03-18 02:16:09 +00:00
|
|
|
|
|
|
|
let actor_inbox = actor.inbox().clone();
|
|
|
|
let follow = generate_follow(&state, &actor.id, &my_id)?;
|
|
|
|
let state2 = state.clone();
|
|
|
|
let client2 = client.clone();
|
|
|
|
actix::Arbiter::spawn(async move {
|
|
|
|
let _ = deliver(
|
|
|
|
&state2.into_inner(),
|
|
|
|
&client2.into_inner(),
|
|
|
|
actor_inbox,
|
|
|
|
&follow,
|
|
|
|
)
|
|
|
|
.await;
|
|
|
|
});
|
2020-03-15 17:49:27 +00:00
|
|
|
}
|
|
|
|
|
2020-03-15 22:37:53 +00:00
|
|
|
let actor_inbox = actor.inbox().clone();
|
2020-03-18 02:16:09 +00:00
|
|
|
let accept = generate_accept_follow(&state, &actor.id, &input.id, &my_id)?;
|
|
|
|
let accept2 = accept.clone();
|
|
|
|
actix::Arbiter::spawn(async move {
|
|
|
|
let _ = deliver(
|
|
|
|
&state.into_inner(),
|
|
|
|
&client.into_inner(),
|
|
|
|
actor_inbox,
|
|
|
|
&accept2,
|
|
|
|
)
|
|
|
|
.await;
|
|
|
|
});
|
|
|
|
|
|
|
|
Ok(response(accept))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate a type that says "I want to stop following you"
|
|
|
|
fn generate_undo_follow(
|
|
|
|
state: &web::Data<State>,
|
|
|
|
actor_id: &XsdAnyUri,
|
|
|
|
my_id: &XsdAnyUri,
|
|
|
|
) -> Result<Undo, MyError> {
|
|
|
|
let mut undo = Undo::default();
|
|
|
|
let mut follow = Follow::default();
|
|
|
|
|
|
|
|
follow
|
|
|
|
.object_props
|
|
|
|
.set_id(state.generate_url(UrlKind::Activity))?;
|
|
|
|
follow
|
|
|
|
.follow_props
|
|
|
|
.set_actor_xsd_any_uri(actor_id.clone())?
|
|
|
|
.set_object_xsd_any_uri(actor_id.clone())?;
|
|
|
|
|
|
|
|
undo.object_props
|
|
|
|
.set_id(state.generate_url(UrlKind::Activity))?
|
|
|
|
.set_many_to_xsd_any_uris(vec![actor_id.clone()])?
|
|
|
|
.set_context_xsd_any_uri(context())?;
|
|
|
|
undo.undo_props
|
|
|
|
.set_object_object_box(follow)?
|
|
|
|
.set_actor_xsd_any_uri(my_id.clone())?;
|
|
|
|
|
|
|
|
Ok(undo)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate a type that says "Look at this object"
|
|
|
|
fn generate_announce(
|
|
|
|
state: &web::Data<State>,
|
|
|
|
activity_id: &XsdAnyUri,
|
|
|
|
object_id: &XsdAnyUri,
|
|
|
|
) -> Result<Announce, MyError> {
|
|
|
|
let mut announce = Announce::default();
|
|
|
|
|
|
|
|
announce
|
|
|
|
.object_props
|
|
|
|
.set_context_xsd_any_uri(context())?
|
|
|
|
.set_many_to_xsd_any_uris(vec![state.generate_url(UrlKind::Followers)])?
|
|
|
|
.set_id(activity_id.clone())?;
|
2020-03-15 22:37:53 +00:00
|
|
|
|
2020-03-18 02:16:09 +00:00
|
|
|
announce
|
|
|
|
.announce_props
|
|
|
|
.set_object_xsd_any_uri(object_id.clone())?
|
|
|
|
.set_actor_xsd_any_uri(state.generate_url(UrlKind::Actor))?;
|
|
|
|
|
|
|
|
Ok(announce)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate a type that says "I want to follow you"
|
|
|
|
fn generate_follow(
|
|
|
|
state: &web::Data<State>,
|
|
|
|
actor_id: &XsdAnyUri,
|
|
|
|
my_id: &XsdAnyUri,
|
|
|
|
) -> Result<Follow, MyError> {
|
|
|
|
let mut follow = Follow::default();
|
|
|
|
|
|
|
|
follow
|
|
|
|
.object_props
|
|
|
|
.set_id(state.generate_url(UrlKind::Activity))?
|
|
|
|
.set_many_to_xsd_any_uris(vec![actor_id.clone()])?
|
|
|
|
.set_context_xsd_any_uri(context())?;
|
|
|
|
|
|
|
|
follow
|
|
|
|
.follow_props
|
|
|
|
.set_object_xsd_any_uri(actor_id.clone())?
|
|
|
|
.set_actor_xsd_any_uri(my_id.clone())?;
|
|
|
|
|
|
|
|
Ok(follow)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate a type that says "I accept your follow request"
|
|
|
|
fn generate_accept_follow(
|
|
|
|
state: &web::Data<State>,
|
|
|
|
actor_id: &XsdAnyUri,
|
|
|
|
input_id: &XsdAnyUri,
|
|
|
|
my_id: &XsdAnyUri,
|
|
|
|
) -> Result<Accept, MyError> {
|
2020-03-15 17:49:27 +00:00
|
|
|
let mut accept = Accept::default();
|
|
|
|
let mut follow = Follow::default();
|
2020-03-18 02:16:09 +00:00
|
|
|
|
|
|
|
follow.object_props.set_id(input_id.clone())?;
|
2020-03-15 17:49:27 +00:00
|
|
|
follow
|
|
|
|
.follow_props
|
2020-03-18 02:16:09 +00:00
|
|
|
.set_object_xsd_any_uri(my_id.clone())?
|
|
|
|
.set_actor_xsd_any_uri(actor_id.clone())?;
|
2020-03-15 17:49:27 +00:00
|
|
|
|
|
|
|
accept
|
|
|
|
.object_props
|
2020-03-15 22:37:53 +00:00
|
|
|
.set_id(state.generate_url(UrlKind::Activity))?
|
2020-03-18 02:16:09 +00:00
|
|
|
.set_many_to_xsd_any_uris(vec![actor_id.clone()])?;
|
2020-03-15 17:49:27 +00:00
|
|
|
accept
|
|
|
|
.accept_props
|
|
|
|
.set_object_object_box(follow)?
|
2020-03-18 02:16:09 +00:00
|
|
|
.set_actor_xsd_any_uri(my_id.clone())?;
|
2020-03-15 17:49:27 +00:00
|
|
|
|
2020-03-18 02:16:09 +00:00
|
|
|
Ok(accept)
|
2020-03-15 02:05:40 +00:00
|
|
|
}
|
|
|
|
|
2020-03-15 22:37:53 +00:00
|
|
|
async fn get_inboxes(
|
|
|
|
state: &web::Data<State>,
|
|
|
|
actor: &AcceptedActors,
|
|
|
|
object_id: &XsdAnyUri,
|
|
|
|
) -> Result<Vec<XsdAnyUri>, MyError> {
|
2020-03-16 03:36:46 +00:00
|
|
|
let domain = object_id
|
|
|
|
.as_url()
|
|
|
|
.host()
|
|
|
|
.ok_or(MyError::Domain)?
|
|
|
|
.to_string();
|
2020-03-15 22:37:53 +00:00
|
|
|
|
|
|
|
let inbox = actor.inbox();
|
|
|
|
|
|
|
|
Ok(state.listeners_without(&inbox, &domain).await)
|
|
|
|
}
|