Only allow authenticated users to fetch remote objects (#2493)
* Only allow authenticated users to fetch remote objects * try to fix api tests
This commit is contained in:
parent
cb559178bd
commit
6c3e984ad1
10 changed files with 53 additions and 48 deletions
|
@ -30,6 +30,7 @@ import {
|
|||
unfollows,
|
||||
getComments,
|
||||
getCommentParentId,
|
||||
resolveCommunity,
|
||||
} from './shared';
|
||||
|
||||
let postRes: PostResponse;
|
||||
|
@ -293,8 +294,8 @@ test('Comment Search', async () => {
|
|||
|
||||
test('A and G subscribe to B (center) A posts, G mentions B, it gets announced to A', async () => {
|
||||
// Create a local post
|
||||
let alphaCommunity = await createCommunity(alpha, "main");
|
||||
let alphaPost = await createPost(alpha, alphaCommunity.community_view.community.id);
|
||||
let alphaCommunity = (await resolveCommunity(alpha, "!main@lemmy-alpha:8541")).community.unwrap();
|
||||
let alphaPost = await createPost(alpha, alphaCommunity.community.id);
|
||||
expect(alphaPost.post_view.community.local).toBe(true);
|
||||
|
||||
// Make sure gamma sees it
|
||||
|
|
|
@ -37,7 +37,7 @@ test('Follow federated community', async () => {
|
|||
c => c.community.local == false
|
||||
).community.id;
|
||||
expect(remoteCommunityId).toBeDefined();
|
||||
expect(site.my_user.unwrap().follows.length).toBe(1);
|
||||
expect(site.my_user.unwrap().follows.length).toBe(2);
|
||||
|
||||
// Test an unfollow
|
||||
let unfollow = await followCommunity(alpha, false, remoteCommunityId);
|
||||
|
@ -45,5 +45,5 @@ test('Follow federated community', async () => {
|
|||
|
||||
// Make sure you are unsubbed locally
|
||||
let siteUnfollowCheck = await getSite(alpha);
|
||||
expect(siteUnfollowCheck.my_user.unwrap().follows.length).toBe(0);
|
||||
expect(siteUnfollowCheck.my_user.unwrap().follows.length).toBe(1);
|
||||
});
|
||||
|
|
|
@ -32,7 +32,8 @@ import {
|
|||
registerUser,
|
||||
API,
|
||||
getSite,
|
||||
unfollows
|
||||
unfollows,
|
||||
resolveCommunity
|
||||
} from './shared';
|
||||
|
||||
let betaCommunity: CommunityView;
|
||||
|
@ -226,7 +227,8 @@ test('Delete a post', async () => {
|
|||
});
|
||||
|
||||
test('Remove a post from admin and community on different instance', async () => {
|
||||
let postRes = await createPost(gamma, betaCommunity.community.id);
|
||||
let gammaCommunity = await resolveCommunity(gamma, betaCommunity.community.actor_id);
|
||||
let postRes = await createPost(gamma, gammaCommunity.community.unwrap().community.id);
|
||||
|
||||
let alphaPost = (await resolvePost(alpha, postRes.post_view.post)).post.unwrap();
|
||||
let removedPost = await removePost(alpha, true, alphaPost.post);
|
||||
|
|
|
@ -174,9 +174,9 @@ export async function setupLogins() {
|
|||
editSiteForm.auth = epsilon.auth.unwrap();
|
||||
await epsilon.client.editSite(editSiteForm);
|
||||
|
||||
// Create the main beta community, follow it
|
||||
// Create the main alpha/beta communities
|
||||
await createCommunity(alpha, "main");
|
||||
await createCommunity(beta, "main");
|
||||
await followBeta(beta);
|
||||
}
|
||||
|
||||
export async function createPost(
|
||||
|
|
|
@ -19,8 +19,13 @@ import {
|
|||
API,
|
||||
resolveComment,
|
||||
saveUserSettingsFederated,
|
||||
setupLogins,
|
||||
} from './shared';
|
||||
|
||||
beforeAll(async () => {
|
||||
await setupLogins();
|
||||
});
|
||||
|
||||
let apShortname: string;
|
||||
|
||||
function assertUserFederation(userOne: PersonViewSafe, userTwo: PersonViewSafe) {
|
||||
|
|
|
@ -5,7 +5,7 @@ use lemmy_api_common::{
|
|||
site::{ResolveObject, ResolveObjectResponse},
|
||||
utils::{blocking, check_private_instance, get_local_user_view_from_jwt_opt},
|
||||
};
|
||||
use lemmy_apub::fetcher::search::{search_by_apub_id, SearchableObjects};
|
||||
use lemmy_apub::fetcher::search::{search_query_to_object_id, SearchableObjects};
|
||||
use lemmy_db_schema::{newtypes::PersonId, utils::DbPool};
|
||||
use lemmy_db_views::structs::{CommentView, PostView};
|
||||
use lemmy_db_views_actor::structs::{CommunityView, PersonViewSafe};
|
||||
|
@ -27,7 +27,7 @@ impl Perform for ResolveObject {
|
|||
.await?;
|
||||
check_private_instance(&local_user_view, context.pool()).await?;
|
||||
|
||||
let res = search_by_apub_id(&self.q, context)
|
||||
let res = search_query_to_object_id(&self.q, local_user_view.is_none(), context)
|
||||
.await
|
||||
.map_err(|e| e.with_message("couldnt_find_object"))?;
|
||||
convert_response(res, local_user_view.map(|l| l.person.id), context.pool())
|
||||
|
|
|
@ -45,7 +45,7 @@ where
|
|||
Ok(actor?)
|
||||
} else {
|
||||
// Fetch the actor from its home instance using webfinger
|
||||
let id = webfinger_resolve_actor::<Actor>(identifier, context, &mut 0).await?;
|
||||
let id = webfinger_resolve_actor::<Actor>(identifier, true, context, &mut 0).await?;
|
||||
let actor: DbActor = blocking(context.pool(), move |conn| {
|
||||
DbActor::read_from_apub_id(conn, &id)
|
||||
})
|
||||
|
|
|
@ -11,52 +11,44 @@ use lemmy_websocket::LemmyContext;
|
|||
use serde::Deserialize;
|
||||
use url::Url;
|
||||
|
||||
/// Attempt to parse the query as URL, and fetch an ActivityPub object from it.
|
||||
///
|
||||
/// Some working examples for use with the `docker/federation/` setup:
|
||||
/// http://lemmy_alpha:8541/c/main, or !main@lemmy_alpha:8541
|
||||
/// http://lemmy_beta:8551/u/lemmy_alpha, or @lemmy_beta@lemmy_beta:8551
|
||||
/// http://lemmy_gamma:8561/post/3
|
||||
/// http://lemmy_delta:8571/comment/2
|
||||
/// Converts search query to object id. The query can either be an URL, which will be treated as
|
||||
/// ObjectId directly, or a webfinger identifier (@user@example.com or !community@example.com)
|
||||
/// which gets resolved to an URL.
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub async fn search_by_apub_id(
|
||||
pub async fn search_query_to_object_id(
|
||||
query: &str,
|
||||
local_only: bool,
|
||||
context: &LemmyContext,
|
||||
) -> Result<SearchableObjects, LemmyError> {
|
||||
let request_counter = &mut 0;
|
||||
let instance = local_instance(context);
|
||||
match Url::parse(query) {
|
||||
Ok(url) => {
|
||||
ObjectId::new(url)
|
||||
.dereference(context, instance, request_counter)
|
||||
.await
|
||||
}
|
||||
let object_id = match Url::parse(query) {
|
||||
// its already an url, just go with it
|
||||
Ok(url) => ObjectId::new(url),
|
||||
Err(_) => {
|
||||
// not an url, try to resolve via webfinger
|
||||
let mut chars = query.chars();
|
||||
let kind = chars.next();
|
||||
let identifier = chars.as_str();
|
||||
match kind {
|
||||
let id = match kind {
|
||||
Some('@') => {
|
||||
let id =
|
||||
webfinger_resolve_actor::<ApubPerson>(identifier, context, request_counter).await?;
|
||||
Ok(SearchableObjects::Person(
|
||||
ObjectId::new(id)
|
||||
.dereference(context, instance, request_counter)
|
||||
.await?,
|
||||
))
|
||||
webfinger_resolve_actor::<ApubPerson>(identifier, local_only, context, request_counter)
|
||||
.await?
|
||||
}
|
||||
Some('!') => {
|
||||
let id =
|
||||
webfinger_resolve_actor::<ApubCommunity>(identifier, context, request_counter).await?;
|
||||
Ok(SearchableObjects::Community(
|
||||
ObjectId::new(id)
|
||||
.dereference(context, instance, request_counter)
|
||||
.await?,
|
||||
))
|
||||
webfinger_resolve_actor::<ApubCommunity>(identifier, local_only, context, request_counter)
|
||||
.await?
|
||||
}
|
||||
_ => Err(LemmyError::from_message("invalid query")),
|
||||
}
|
||||
_ => return Err(LemmyError::from_message("invalid query")),
|
||||
};
|
||||
ObjectId::new(id)
|
||||
}
|
||||
};
|
||||
if local_only {
|
||||
object_id.dereference_local(context).await
|
||||
} else {
|
||||
object_id
|
||||
.dereference(context, local_instance(context), request_counter)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ pub struct WebfingerResponse {
|
|||
#[tracing::instrument(skip_all)]
|
||||
pub(crate) async fn webfinger_resolve_actor<Kind>(
|
||||
identifier: &str,
|
||||
local_only: bool,
|
||||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<DbUrl, LemmyError>
|
||||
|
@ -68,9 +69,14 @@ where
|
|||
.filter_map(|l| l.href.clone())
|
||||
.collect();
|
||||
for l in links {
|
||||
let object = ObjectId::<Kind>::new(l)
|
||||
.dereference(context, local_instance(context), request_counter)
|
||||
.await;
|
||||
let object_id = ObjectId::<Kind>::new(l);
|
||||
let object = if local_only {
|
||||
object_id.dereference_local(context).await
|
||||
} else {
|
||||
object_id
|
||||
.dereference(context, local_instance(context), request_counter)
|
||||
.await
|
||||
};
|
||||
if object.is_ok() {
|
||||
return object.map(|o| o.actor_id().into());
|
||||
}
|
||||
|
|
|
@ -73,10 +73,9 @@ pub async fn collect_non_local_mentions(
|
|||
.collect::<Vec<MentionData>>();
|
||||
|
||||
for mention in &mentions {
|
||||
// TODO should it be fetching it every time?
|
||||
let identifier = format!("{}@{}", mention.name, mention.domain);
|
||||
let actor_id =
|
||||
webfinger_resolve_actor::<ApubPerson>(&identifier, context, request_counter).await;
|
||||
webfinger_resolve_actor::<ApubPerson>(&identifier, true, context, request_counter).await;
|
||||
if let Ok(actor_id) = actor_id {
|
||||
let actor_id: ObjectId<ApubPerson> = ObjectId::new(actor_id);
|
||||
addressed_ccs.push(actor_id.to_string().parse()?);
|
||||
|
|
Loading…
Reference in a new issue