From a2e2b762d748a00185f5d62f7272ac580443dcb8 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Wed, 17 Jun 2020 17:09:57 +0200 Subject: [PATCH] WIP: Verify permissions in shared inbox --- server/src/apub/fetcher.rs | 17 +++++++++++ server/src/apub/shared_inbox.rs | 50 +++++++++++++++++++++++++++------ 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/server/src/apub/fetcher.rs b/server/src/apub/fetcher.rs index 05b7492ee..bd8aa3dda 100644 --- a/server/src/apub/fetcher.rs +++ b/server/src/apub/fetcher.rs @@ -38,6 +38,7 @@ use crate::{ }, db::user_view::UserView, }; +use crate::apub::ActorType; // Fetch nodeinfo metadata from a remote instance. fn _fetch_node_info(domain: &str) -> Result { @@ -245,6 +246,22 @@ pub fn get_or_fetch_and_upsert_remote_community( } } +pub fn get_or_fetch_and_upsert_remote_actor( + apub_id: &str, + conn: &PgConnection, +) -> Result, Error> { + let user = get_or_fetch_and_upsert_remote_user(apub_id, &conn); + if user.is_ok() { + return Ok(Box::new(user?)); + } + let community = get_or_fetch_and_upsert_remote_community(apub_id, &conn); + if community.is_ok() { + return Ok(Box::new(community?)); + } else { + todo!() // need proper error handling + } +} + fn upsert_post(post_form: &PostForm, conn: &PgConnection) -> Result { let existing = Post::read_from_apub_id(conn, &post_form.ap_id); match existing { diff --git a/server/src/apub/shared_inbox.rs b/server/src/apub/shared_inbox.rs index 1ada6ad1d..736219ed8 100644 --- a/server/src/apub/shared_inbox.rs +++ b/server/src/apub/shared_inbox.rs @@ -9,7 +9,6 @@ use crate::{ fetcher::{ get_or_fetch_and_insert_remote_comment, get_or_fetch_and_insert_remote_post, - get_or_fetch_and_upsert_remote_community, get_or_fetch_and_upsert_remote_user, }, FromApub, @@ -47,6 +46,10 @@ use diesel::PgConnection; use failure::{Error, _core::fmt::Debug}; use log::debug; use serde::{Deserialize, Serialize}; +use http::Uri; +use crate::apub::ActorType; +use crate::apub::fetcher::get_or_fetch_and_upsert_remote_actor; +use activitystreams::primitives::XsdAnyUri; #[serde(untagged)] #[derive(Serialize, Deserialize, Debug)] @@ -127,14 +130,8 @@ pub async fn shared_inbox( // TODO: this is hacky, we should probably send the community id directly somehow let to = cc.replace("/followers", ""); - // TODO: this is ugly - match get_or_fetch_and_upsert_remote_user(&sender.to_string(), &conn) { - Ok(u) => verify(&request, &u), - Err(_) => { - let c = get_or_fetch_and_upsert_remote_community(&sender.to_string(), &conn)?; - verify(&request, &c) - } - }?; + let actor = get_or_fetch_and_upsert_remote_actor(&sender.to_string(), &conn)?; + verify(&request, actor.as_ref())?; match (activity, object.kind()) { (SharedAcceptedObjects::Create(c), Some("Page")) => { @@ -142,6 +139,9 @@ pub async fn shared_inbox( announce_activity_if_valid::(*c, &to, sender, conn) } (SharedAcceptedObjects::Update(u), Some("Page")) => { + // TODO: need to get the object::attributed_to here + // (ideally from the database in case we received malicious data) + verify_update_valid(actor, object)?; receive_update_post(&u, &conn, chat_server)?; announce_activity_if_valid::(*u, &to, sender, conn) } @@ -154,10 +154,12 @@ pub async fn shared_inbox( announce_activity_if_valid::(*d, &to, sender, conn) } (SharedAcceptedObjects::Delete(d), Some("Page")) => { + //verify_delete_valid()?; receive_delete_post(&d, &conn, chat_server)?; announce_activity_if_valid::(*d, &to, sender, conn) } (SharedAcceptedObjects::Remove(r), Some("Page")) => { + //verify_remove_valid()?; receive_remove_post(&r, &conn, chat_server)?; announce_activity_if_valid::(*r, &to, sender, conn) } @@ -166,6 +168,7 @@ pub async fn shared_inbox( announce_activity_if_valid::(*c, &to, sender, conn) } (SharedAcceptedObjects::Update(u), Some("Note")) => { + verify_update_valid(actor, u.object_props.get_id().unwrap())?; receive_update_comment(&u, &conn, chat_server)?; announce_activity_if_valid::(*u, &to, sender, conn) } @@ -178,26 +181,33 @@ pub async fn shared_inbox( announce_activity_if_valid::(*d, &to, sender, conn) } (SharedAcceptedObjects::Delete(d), Some("Note")) => { + //verify_delete_valid()?; receive_delete_comment(&d, &conn, chat_server)?; announce_activity_if_valid::(*d, &to, sender, conn) } (SharedAcceptedObjects::Remove(r), Some("Note")) => { + //verify_remove_valid()?; receive_remove_comment(&r, &conn, chat_server)?; announce_activity_if_valid::(*r, &to, sender, conn) } (SharedAcceptedObjects::Delete(d), Some("Group")) => { + //verify_delete_valid()?; receive_delete_community(&d, &conn, chat_server)?; announce_activity_if_valid::(*d, &to, sender, conn) } (SharedAcceptedObjects::Remove(r), Some("Group")) => { + //verify_remove_valid()?; receive_remove_community(&r, &conn, chat_server)?; announce_activity_if_valid::(*r, &to, sender, conn) } + // TODO: for any undo, we should check if the activity to be undone exists (SharedAcceptedObjects::Undo(u), Some("Delete")) => { + //verify_delete_valid()?; receive_undo_delete(&u, &conn, chat_server)?; announce_activity_if_valid::(*u, &to, sender, conn) } (SharedAcceptedObjects::Undo(u), Some("Remove")) => { + //verify_remove_valid()?; receive_undo_remove(&u, &conn, chat_server)?; announce_activity_if_valid::(*u, &to, sender, conn) } @@ -221,6 +231,12 @@ where A: Activity + Base + Serialize + Debug, { let community = Community::read_from_actor_id(conn, &community_uri)?; + // TODO: only allow specific types of activities here: + // - create/like/dislike page/note + // - update only from the same user that created a page/note + // - undo for the activities above + // - delete or undo delete only from the user that created the object + // - remove only for local admins or local mods of the community if community.local { let sending_user = get_or_fetch_and_upsert_remote_user(&sender.to_string(), &conn)?; Community::do_announce(activity, &community, &sending_user, conn) @@ -1613,3 +1629,19 @@ fn receive_undo_like_post( Ok(HttpResponse::Ok().finish()) } + +fn verify_update_valid(actor_id: Box, object: &BaseBox) -> Result<(), Error> { + + todo!() + // can only come from the user that created the object +} + +fn verify_delete_valid(actor_id: Box, object_id: Uri) -> Result<(), Error> { + todo!() + // can only come from the user that created the object +} + +fn verify_remove_valid(actor_id: Box, object_id: Uri, community: &Community) -> Result<(), Error> { + todo!() + // can only come from admins or mods on the instance of the community +}