From 568233b06243d58e5ceaa3c9f8487bc0c19d5463 Mon Sep 17 00:00:00 2001 From: Nutomic Date: Wed, 25 Oct 2023 13:14:59 +0200 Subject: [PATCH] Resolve federated objects from other instances via redirect (fixes #3129) (#4073) * Resolve federated objects from other instances via redirect (fixes #3129) * restore domain check using library change * add test case, update apub lib --------- Co-authored-by: Dessalines --- api_tests/src/post.spec.ts | 25 +++++++++++++++++++- crates/apub/src/http/comment.rs | 4 ++-- crates/apub/src/http/mod.rs | 12 ++++++---- crates/apub/src/http/post.rs | 4 ++-- docker/federation/docker-compose.yml | 2 +- docker/federation/start-local-instances.bash | 2 +- 6 files changed, 37 insertions(+), 12 deletions(-) diff --git a/api_tests/src/post.spec.ts b/api_tests/src/post.spec.ts index 8c1f22226..1d6e90c72 100644 --- a/api_tests/src/post.spec.ts +++ b/api_tests/src/post.spec.ts @@ -39,7 +39,7 @@ import { loginUser, } from "./shared"; import { PostView } from "lemmy-js-client/dist/types/PostView"; -import { LemmyHttp } from "lemmy-js-client"; +import { LemmyHttp, ResolveObject } from "lemmy-js-client"; let betaCommunity: CommunityView | undefined; @@ -556,3 +556,26 @@ test("Report a post", async () => { expect(betaReport.original_post_body).toBe(alphaReport.original_post_body); expect(betaReport.reason).toBe(alphaReport.reason); }); + +test("Fetch post via redirect", async () => { + let alphaPost = await createPost(alpha, betaCommunity!.community.id); + expect(alphaPost.post_view.post).toBeDefined(); + // Make sure that post is liked on beta + const betaPost = await waitForPost( + beta, + alphaPost.post_view.post, + res => res?.counts.score === 1, + ); + + expect(betaPost).toBeDefined(); + expect(betaPost.post?.ap_id).toBe(alphaPost.post_view.post.ap_id); + + // Fetch post from url on beta instance instead of ap_id + let q = `http://lemmy-beta:8551/post/${betaPost.post.id}`; + let form: ResolveObject = { + q, + }; + let gammaPost = await gamma.resolveObject(form); + expect(gammaPost).toBeDefined(); + expect(gammaPost.post?.post.ap_id).toBe(alphaPost.post_view.post.ap_id); +}); diff --git a/crates/apub/src/http/comment.rs b/crates/apub/src/http/comment.rs index 931caaee4..1704066aa 100644 --- a/crates/apub/src/http/comment.rs +++ b/crates/apub/src/http/comment.rs @@ -1,5 +1,5 @@ use crate::{ - http::{create_apub_response, create_apub_tombstone_response, err_object_not_local}, + http::{create_apub_response, create_apub_tombstone_response, redirect_remote_object}, objects::comment::ApubComment, }; use activitypub_federation::{config::Data, traits::Object}; @@ -23,7 +23,7 @@ pub(crate) async fn get_apub_comment( let id = CommentId(info.comment_id.parse::()?); let comment: ApubComment = Comment::read(&mut context.pool(), id).await?.into(); if !comment.local { - Err(err_object_not_local()) + Ok(redirect_remote_object(&comment.ap_id)) } else if !comment.deleted && !comment.removed { create_apub_response(&comment.into_json(&context).await?) } else { diff --git a/crates/apub/src/http/mod.rs b/crates/apub/src/http/mod.rs index c261d9e49..7c1d8529a 100644 --- a/crates/apub/src/http/mod.rs +++ b/crates/apub/src/http/mod.rs @@ -11,10 +11,10 @@ use activitypub_federation::{ FEDERATION_CONTENT_TYPE, }; use actix_web::{web, web::Bytes, HttpRequest, HttpResponse}; -use http::StatusCode; +use http::{header::LOCATION, StatusCode}; use lemmy_api_common::context::LemmyContext; -use lemmy_db_schema::source::activity::SentActivity; -use lemmy_utils::error::{LemmyError, LemmyErrorType, LemmyResult}; +use lemmy_db_schema::{newtypes::DbUrl, source::activity::SentActivity}; +use lemmy_utils::error::{LemmyError, LemmyResult}; use serde::{Deserialize, Serialize}; use std::ops::Deref; use url::Url; @@ -64,8 +64,10 @@ fn create_apub_tombstone_response>(id: T) -> LemmyResult LemmyError { - LemmyErrorType::ObjectNotLocal.into() +fn redirect_remote_object(url: &DbUrl) -> HttpResponse { + let mut res = HttpResponse::PermanentRedirect(); + res.insert_header((LOCATION, url.as_str())); + res.finish() } #[derive(Deserialize)] diff --git a/crates/apub/src/http/post.rs b/crates/apub/src/http/post.rs index f65968f15..084637c5b 100644 --- a/crates/apub/src/http/post.rs +++ b/crates/apub/src/http/post.rs @@ -1,5 +1,5 @@ use crate::{ - http::{create_apub_response, create_apub_tombstone_response, err_object_not_local}, + http::{create_apub_response, create_apub_tombstone_response, redirect_remote_object}, objects::post::ApubPost, }; use activitypub_federation::{config::Data, traits::Object}; @@ -23,7 +23,7 @@ pub(crate) async fn get_apub_post( let id = PostId(info.post_id.parse::()?); let post: ApubPost = Post::read(&mut context.pool(), id).await?.into(); if !post.local { - Err(err_object_not_local()) + Ok(redirect_remote_object(&post.ap_id)) } else if !post.deleted && !post.removed { create_apub_response(&post.into_json(&context).await?) } else { diff --git a/docker/federation/docker-compose.yml b/docker/federation/docker-compose.yml index 634a97449..142267596 100644 --- a/docker/federation/docker-compose.yml +++ b/docker/federation/docker-compose.yml @@ -2,7 +2,7 @@ version: "3.7" x-ui-default: &ui-default init: true - image: dessalines/lemmy-ui:0.18.4 + image: dessalines/lemmy-ui:0.19.0-rc.3 # assuming lemmy-ui is cloned besides lemmy directory # build: # context: ../../../lemmy-ui diff --git a/docker/federation/start-local-instances.bash b/docker/federation/start-local-instances.bash index 716f4d45c..615790764 100755 --- a/docker/federation/start-local-instances.bash +++ b/docker/federation/start-local-instances.bash @@ -8,4 +8,4 @@ for Item in alpha beta gamma delta epsilon ; do sudo chown -R 991:991 volumes/pictrs_$Item done -sudo docker compose up +sudo docker compose up --build