2020-05-16 14:04:08 +00:00
|
|
|
use crate::{
|
|
|
|
apub::{
|
|
|
|
extensions::signatures::verify,
|
|
|
|
fetcher::{get_or_fetch_and_upsert_remote_community, get_or_fetch_and_upsert_remote_user},
|
|
|
|
ActorType,
|
|
|
|
},
|
|
|
|
db::{
|
|
|
|
activity::insert_activity,
|
|
|
|
community::{Community, CommunityFollower, CommunityFollowerForm},
|
|
|
|
user::User_,
|
|
|
|
Followable,
|
|
|
|
},
|
|
|
|
routes::{ChatServerParam, DbPoolParam},
|
|
|
|
};
|
2020-05-06 17:10:36 +00:00
|
|
|
use activitystreams::activity::{Follow, Undo, Update, Create, Delete, Remove};
|
2020-05-16 14:04:08 +00:00
|
|
|
use actix_web::{web, HttpRequest, HttpResponse, Result};
|
|
|
|
use diesel::PgConnection;
|
|
|
|
use failure::{Error, _core::fmt::Debug};
|
|
|
|
use log::debug;
|
2020-05-06 17:10:36 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use activitystreams::activity::{Activity, Announce};
|
|
|
|
use activitystreams::Base;
|
|
|
|
use crate::apub::activities::{populate_object_props, send_activity};
|
|
|
|
use activitystreams::BaseBox;
|
2020-04-15 18:12:25 +00:00
|
|
|
|
|
|
|
#[serde(untagged)]
|
2020-04-17 14:55:28 +00:00
|
|
|
#[derive(Deserialize, Debug)]
|
2020-04-15 18:12:25 +00:00
|
|
|
pub enum CommunityAcceptedObjects {
|
|
|
|
Follow(Follow),
|
2020-05-04 02:41:45 +00:00
|
|
|
Undo(Undo),
|
2020-05-06 17:10:36 +00:00
|
|
|
Create(Create),
|
|
|
|
Update(Update),
|
|
|
|
Delete(Delete),
|
|
|
|
Remove(Remove),
|
2020-04-15 18:12:25 +00:00
|
|
|
}
|
|
|
|
|
2020-05-14 15:44:01 +00:00
|
|
|
impl CommunityAcceptedObjects {
|
|
|
|
fn follow(&self) -> Result<Follow, Error> {
|
|
|
|
match self {
|
|
|
|
CommunityAcceptedObjects::Follow(f) => Ok(f.to_owned()),
|
|
|
|
CommunityAcceptedObjects::Undo(u) => Ok(
|
|
|
|
u.undo_props
|
|
|
|
.get_object_base_box()
|
|
|
|
.to_owned()
|
|
|
|
.unwrap()
|
|
|
|
.to_owned()
|
|
|
|
.into_concrete::<Follow>()?,
|
|
|
|
),
|
2020-05-06 17:10:36 +00:00
|
|
|
_ => todo!()
|
2020-05-14 15:44:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-17 15:33:55 +00:00
|
|
|
/// Handler for all incoming activities to community inboxes.
|
2020-04-15 18:12:25 +00:00
|
|
|
pub async fn community_inbox(
|
2020-04-19 17:35:40 +00:00
|
|
|
request: HttpRequest,
|
2020-04-15 18:12:25 +00:00
|
|
|
input: web::Json<CommunityAcceptedObjects>,
|
2020-04-17 17:34:18 +00:00
|
|
|
path: web::Path<String>,
|
2020-04-24 14:04:36 +00:00
|
|
|
db: DbPoolParam,
|
2020-05-06 17:10:36 +00:00
|
|
|
chat_server: ChatServerParam,
|
2020-04-15 18:12:25 +00:00
|
|
|
) -> Result<HttpResponse, Error> {
|
|
|
|
let input = input.into_inner();
|
2020-05-06 17:10:36 +00:00
|
|
|
let conn = db.get()?;
|
|
|
|
let community = Community::read_from_name(&conn, &path.into_inner())?;
|
|
|
|
if !community.local {
|
|
|
|
return Err(format_err!(
|
|
|
|
"Received activity is addressed to remote community {}",
|
|
|
|
&community.actor_id
|
|
|
|
));
|
|
|
|
}
|
2020-04-17 14:55:28 +00:00
|
|
|
debug!(
|
|
|
|
"Community {} received activity {:?}",
|
2020-05-06 17:10:36 +00:00
|
|
|
&community.name, &input
|
2020-04-17 14:55:28 +00:00
|
|
|
);
|
2020-05-14 15:44:01 +00:00
|
|
|
let follow = input.follow()?;
|
2020-04-19 17:35:40 +00:00
|
|
|
let user_uri = follow
|
|
|
|
.follow_props
|
|
|
|
.get_actor_xsd_any_uri()
|
|
|
|
.unwrap()
|
|
|
|
.to_string();
|
2020-05-14 15:44:01 +00:00
|
|
|
let community_uri = follow
|
2020-04-15 18:12:25 +00:00
|
|
|
.follow_props
|
|
|
|
.get_object_xsd_any_uri()
|
|
|
|
.unwrap()
|
|
|
|
.to_string();
|
2020-04-24 14:04:36 +00:00
|
|
|
|
|
|
|
let conn = db.get()?;
|
|
|
|
|
|
|
|
let user = get_or_fetch_and_upsert_remote_user(&user_uri, &conn)?;
|
2020-05-14 15:44:01 +00:00
|
|
|
let community = get_or_fetch_and_upsert_remote_community(&community_uri, &conn)?;
|
2020-04-24 14:04:36 +00:00
|
|
|
|
2020-05-14 13:38:07 +00:00
|
|
|
verify(&request, &user)?;
|
2020-04-24 14:04:36 +00:00
|
|
|
|
2020-05-14 15:44:01 +00:00
|
|
|
match input {
|
2020-05-06 17:10:36 +00:00
|
|
|
CommunityAcceptedObjects::Follow(f) => {
|
|
|
|
handle_follow(&f, &user, &community, &conn)
|
|
|
|
}
|
|
|
|
CommunityAcceptedObjects::Undo(u) => {
|
|
|
|
// TODO: if this is an undo<remove> or undo<delete>, we need to announce it instead
|
|
|
|
handle_undo_follow(&u, &user, &community, &conn)
|
|
|
|
}
|
|
|
|
// TODO: we should be able to handle all this with a single wildcard match, but i dont see how
|
|
|
|
// to get the value from that
|
|
|
|
CommunityAcceptedObjects::Create(c) => {
|
|
|
|
do_announce(c, &request, &community, &conn, chat_server)
|
|
|
|
}
|
|
|
|
CommunityAcceptedObjects::Update(u) => {
|
|
|
|
do_announce(u, &request, &community, &conn, chat_server)
|
|
|
|
}
|
|
|
|
CommunityAcceptedObjects::Delete(d) => {
|
|
|
|
do_announce(d, &request, &community, &conn, chat_server)
|
|
|
|
}
|
|
|
|
CommunityAcceptedObjects::Remove(r) => {
|
|
|
|
do_announce(r, &request, &community, &conn, chat_server)
|
|
|
|
}
|
2020-05-14 15:44:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Handle a follow request from a remote user, adding it to the local database and returning an
|
|
|
|
/// Accept activity.
|
|
|
|
fn handle_follow(
|
|
|
|
follow: &Follow,
|
|
|
|
user: &User_,
|
|
|
|
community: &Community,
|
|
|
|
conn: &PgConnection,
|
|
|
|
) -> Result<HttpResponse, Error> {
|
2020-05-14 12:26:44 +00:00
|
|
|
insert_activity(&conn, user.id, &follow, false)?;
|
2020-04-27 22:17:02 +00:00
|
|
|
|
2020-04-15 18:12:25 +00:00
|
|
|
let community_follower_form = CommunityFollowerForm {
|
|
|
|
community_id: community.id,
|
|
|
|
user_id: user.id,
|
|
|
|
};
|
2020-04-24 14:04:36 +00:00
|
|
|
|
2020-04-25 02:34:51 +00:00
|
|
|
// This will fail if they're already a follower, but ignore the error.
|
|
|
|
CommunityFollower::follow(&conn, &community_follower_form).ok();
|
2020-04-24 14:04:36 +00:00
|
|
|
|
2020-04-27 22:17:02 +00:00
|
|
|
community.send_accept_follow(&follow, &conn)?;
|
2020-04-26 17:20:42 +00:00
|
|
|
|
2020-04-15 18:12:25 +00:00
|
|
|
Ok(HttpResponse::Ok().finish())
|
|
|
|
}
|
2020-05-04 02:41:45 +00:00
|
|
|
|
|
|
|
fn handle_undo_follow(
|
|
|
|
undo: &Undo,
|
2020-05-14 15:44:01 +00:00
|
|
|
user: &User_,
|
|
|
|
community: &Community,
|
|
|
|
conn: &PgConnection,
|
2020-05-04 02:41:45 +00:00
|
|
|
) -> Result<HttpResponse, Error> {
|
2020-05-14 15:44:01 +00:00
|
|
|
insert_activity(&conn, user.id, &undo, false)?;
|
2020-05-04 02:41:45 +00:00
|
|
|
|
|
|
|
let community_follower_form = CommunityFollowerForm {
|
|
|
|
community_id: community.id,
|
|
|
|
user_id: user.id,
|
|
|
|
};
|
|
|
|
|
2020-05-04 18:26:16 +00:00
|
|
|
CommunityFollower::unfollow(&conn, &community_follower_form).ok();
|
2020-05-04 02:41:45 +00:00
|
|
|
|
|
|
|
Ok(HttpResponse::Ok().finish())
|
|
|
|
}
|
2020-05-06 17:10:36 +00:00
|
|
|
|
|
|
|
fn do_announce<A>(
|
|
|
|
activity: A,
|
|
|
|
_request: &HttpRequest,
|
|
|
|
community: &Community,
|
|
|
|
conn: &PgConnection,
|
|
|
|
_chat_server: ChatServerParam,
|
|
|
|
) -> Result<HttpResponse, Error>
|
|
|
|
where
|
|
|
|
A: Activity + Base + Serialize,
|
|
|
|
{
|
|
|
|
// TODO: checking the signature needs a lot of boilerplate, unless this gets implemented
|
|
|
|
// https://git.asonix.dog/Aardwolf/activitystreams/issues/4
|
|
|
|
/*
|
|
|
|
let user_uri = activity
|
|
|
|
.follow_props
|
|
|
|
.get_actor_xsd_any_uri()
|
|
|
|
.unwrap()
|
|
|
|
.to_string();
|
|
|
|
let user = get_or_fetch_and_upsert_remote_user(&user_uri, &conn)?;
|
|
|
|
verify(&request, &user.public_key.unwrap())?;
|
|
|
|
*/
|
|
|
|
|
|
|
|
insert_activity(&conn, -1, &activity, false)?;
|
|
|
|
|
|
|
|
// TODO: handle the sending in community.rs
|
|
|
|
let mut announce = Announce::default();
|
|
|
|
populate_object_props(
|
|
|
|
&mut announce.object_props,
|
|
|
|
vec!(community.get_followers_url()),
|
|
|
|
&format!("{}/announce/{}", community.actor_id, uuid::Uuid::new_v4()),
|
|
|
|
)?;
|
|
|
|
announce
|
|
|
|
.announce_props
|
|
|
|
.set_actor_xsd_any_uri(community.actor_id.to_owned())?
|
|
|
|
.set_object_base_box(BaseBox::from_concrete(activity)?)?;
|
|
|
|
|
|
|
|
insert_activity(&conn, -1, &announce, true)?;
|
|
|
|
|
|
|
|
send_activity(
|
|
|
|
&announce,
|
|
|
|
community,
|
|
|
|
community.get_follower_inboxes(&conn)?,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
Ok(HttpResponse::Ok().finish())
|
|
|
|
}
|