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 <dessalines@users.noreply.github.com>
This commit is contained in:
Nutomic 2023-10-25 13:14:59 +02:00 committed by GitHub
parent 45bed71c36
commit 568233b062
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 37 additions and 12 deletions

View file

@ -39,7 +39,7 @@ import {
loginUser, loginUser,
} from "./shared"; } from "./shared";
import { PostView } from "lemmy-js-client/dist/types/PostView"; 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; 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.original_post_body).toBe(alphaReport.original_post_body);
expect(betaReport.reason).toBe(alphaReport.reason); 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);
});

View file

@ -1,5 +1,5 @@
use crate::{ 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, objects::comment::ApubComment,
}; };
use activitypub_federation::{config::Data, traits::Object}; 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::<i32>()?); let id = CommentId(info.comment_id.parse::<i32>()?);
let comment: ApubComment = Comment::read(&mut context.pool(), id).await?.into(); let comment: ApubComment = Comment::read(&mut context.pool(), id).await?.into();
if !comment.local { if !comment.local {
Err(err_object_not_local()) Ok(redirect_remote_object(&comment.ap_id))
} else if !comment.deleted && !comment.removed { } else if !comment.deleted && !comment.removed {
create_apub_response(&comment.into_json(&context).await?) create_apub_response(&comment.into_json(&context).await?)
} else { } else {

View file

@ -11,10 +11,10 @@ use activitypub_federation::{
FEDERATION_CONTENT_TYPE, FEDERATION_CONTENT_TYPE,
}; };
use actix_web::{web, web::Bytes, HttpRequest, HttpResponse}; use actix_web::{web, web::Bytes, HttpRequest, HttpResponse};
use http::StatusCode; use http::{header::LOCATION, StatusCode};
use lemmy_api_common::context::LemmyContext; use lemmy_api_common::context::LemmyContext;
use lemmy_db_schema::source::activity::SentActivity; use lemmy_db_schema::{newtypes::DbUrl, source::activity::SentActivity};
use lemmy_utils::error::{LemmyError, LemmyErrorType, LemmyResult}; use lemmy_utils::error::{LemmyError, LemmyResult};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::ops::Deref; use std::ops::Deref;
use url::Url; use url::Url;
@ -64,8 +64,10 @@ fn create_apub_tombstone_response<T: Into<Url>>(id: T) -> LemmyResult<HttpRespon
) )
} }
fn err_object_not_local() -> LemmyError { fn redirect_remote_object(url: &DbUrl) -> HttpResponse {
LemmyErrorType::ObjectNotLocal.into() let mut res = HttpResponse::PermanentRedirect();
res.insert_header((LOCATION, url.as_str()));
res.finish()
} }
#[derive(Deserialize)] #[derive(Deserialize)]

View file

@ -1,5 +1,5 @@
use crate::{ 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, objects::post::ApubPost,
}; };
use activitypub_federation::{config::Data, traits::Object}; 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::<i32>()?); let id = PostId(info.post_id.parse::<i32>()?);
let post: ApubPost = Post::read(&mut context.pool(), id).await?.into(); let post: ApubPost = Post::read(&mut context.pool(), id).await?.into();
if !post.local { if !post.local {
Err(err_object_not_local()) Ok(redirect_remote_object(&post.ap_id))
} else if !post.deleted && !post.removed { } else if !post.deleted && !post.removed {
create_apub_response(&post.into_json(&context).await?) create_apub_response(&post.into_json(&context).await?)
} else { } else {

View file

@ -2,7 +2,7 @@ version: "3.7"
x-ui-default: &ui-default x-ui-default: &ui-default
init: true 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 # assuming lemmy-ui is cloned besides lemmy directory
# build: # build:
# context: ../../../lemmy-ui # context: ../../../lemmy-ui

View file

@ -8,4 +8,4 @@ for Item in alpha beta gamma delta epsilon ; do
sudo chown -R 991:991 volumes/pictrs_$Item sudo chown -R 991:991 volumes/pictrs_$Item
done done
sudo docker compose up sudo docker compose up --build