From 9d4299aaac16b92b8c9180506535d733ef8e3df8 Mon Sep 17 00:00:00 2001 From: Nutomic Date: Fri, 15 Mar 2024 13:42:09 +0100 Subject: [PATCH] Dont require leading ! or @ for webfinger resolve (#4513) * Dont require leading ! or @ for webfinger resolve * fmt * clippy --- api_tests/src/user.spec.ts | 6 +-- crates/apub/src/api/resolve_object.rs | 27 +++++------ crates/apub/src/fetcher/search.rs | 65 ++++++++++++--------------- 3 files changed, 46 insertions(+), 52 deletions(-) diff --git a/api_tests/src/user.spec.ts b/api_tests/src/user.spec.ts index ccfc5e1fe..4846d60f7 100644 --- a/api_tests/src/user.spec.ts +++ b/api_tests/src/user.spec.ts @@ -45,7 +45,7 @@ test("Create user", async () => { if (!site.my_user) { throw "Missing site user"; } - apShortname = `@${site.my_user.local_user_view.person.name}@lemmy-alpha:8541`; + apShortname = `${site.my_user.local_user_view.person.name}@lemmy-alpha:8541`; }); test("Set some user settings, check that they are federated", async () => { @@ -68,7 +68,7 @@ test("Delete user", async () => { let user = await registerUser(alpha, alphaUrl); // make a local post and comment - let alphaCommunity = (await resolveCommunity(user, "!main@lemmy-alpha:8541")) + let alphaCommunity = (await resolveCommunity(user, "main@lemmy-alpha:8541")) .community; if (!alphaCommunity) { throw "Missing alpha community"; @@ -134,7 +134,7 @@ test("Create user with Arabic name", async () => { if (!site.my_user) { throw "Missing site user"; } - apShortname = `@${site.my_user.local_user_view.person.name}@lemmy-alpha:8541`; + apShortname = `${site.my_user.local_user_view.person.name}@lemmy-alpha:8541`; let alphaPerson = (await resolvePerson(alpha, apShortname)).person; expect(alphaPerson).toBeDefined(); diff --git a/crates/apub/src/api/resolve_object.rs b/crates/apub/src/api/resolve_object.rs index e081377f6..6d672a8cd 100644 --- a/crates/apub/src/api/resolve_object.rs +++ b/crates/apub/src/api/resolve_object.rs @@ -1,7 +1,6 @@ -use crate::fetcher::search::{ - search_query_to_object_id, - search_query_to_object_id_local, - SearchableObjects, +use crate::fetcher::{ + search::{search_query_to_object_id, search_query_to_object_id_local, SearchableObjects}, + user_or_community::UserOrCommunity, }; use activitypub_federation::config::Data; use actix_web::web::{Json, Query}; @@ -31,7 +30,7 @@ pub async fn resolve_object( let res = if is_authenticated { // user is fully authenticated; allow remote lookups as well. - search_query_to_object_id(&data.q, &context).await + search_query_to_object_id(data.q.clone(), &context).await } else { // user isn't authenticated only allow a local search. search_query_to_object_id_local(&data.q, &context).await @@ -52,14 +51,6 @@ async fn convert_response( let removed_or_deleted; let mut res = ResolveObjectResponse::default(); match object { - Person(p) => { - removed_or_deleted = p.deleted; - res.person = Some(PersonView::read(pool, p.id).await?) - } - Community(c) => { - removed_or_deleted = c.deleted || c.removed; - res.community = Some(CommunityView::read(pool, c.id, user_id, false).await?) - } Post(p) => { removed_or_deleted = p.deleted || p.removed; res.post = Some(PostView::read(pool, p.id, user_id, false).await?) @@ -68,6 +59,16 @@ async fn convert_response( removed_or_deleted = c.deleted || c.removed; res.comment = Some(CommentView::read(pool, c.id, user_id).await?) } + PersonOrCommunity(p) => match *p { + UserOrCommunity::User(u) => { + removed_or_deleted = u.deleted; + res.person = Some(PersonView::read(pool, u.id).await?) + } + UserOrCommunity::Community(c) => { + removed_or_deleted = c.deleted || c.removed; + res.community = Some(CommunityView::read(pool, c.id, user_id, false).await?) + } + }, }; // if the object was deleted from database, dont return it if removed_or_deleted { diff --git a/crates/apub/src/fetcher/search.rs b/crates/apub/src/fetcher/search.rs index 54951edd9..74d755da0 100644 --- a/crates/apub/src/fetcher/search.rs +++ b/crates/apub/src/fetcher/search.rs @@ -1,6 +1,7 @@ use crate::{ + fetcher::user_or_community::{PersonOrGroup, UserOrCommunity}, objects::{comment::ApubComment, community::ApubCommunity, person::ApubPerson, post::ApubPost}, - protocol::objects::{group::Group, note::Note, page::Page, person::Person}, + protocol::objects::{note::Note, page::Page}, }; use activitypub_federation::{ config::Data, @@ -9,7 +10,7 @@ use activitypub_federation::{ }; use chrono::{DateTime, Utc}; use lemmy_api_common::context::LemmyContext; -use lemmy_utils::error::{LemmyError, LemmyErrorType}; +use lemmy_utils::error::LemmyError; use serde::Deserialize; use url::Url; @@ -18,28 +19,22 @@ use url::Url; /// which gets resolved to an URL. #[tracing::instrument(skip_all)] pub(crate) async fn search_query_to_object_id( - query: &str, + mut query: String, context: &Data, ) -> Result { - Ok(match Url::parse(query) { + Ok(match Url::parse(&query) { Ok(url) => { // its already an url, just go with it ObjectId::from(url).dereference(context).await? } 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 { - Some('@') => SearchableObjects::Person( - webfinger_resolve_actor::(identifier, context).await?, - ), - Some('!') => SearchableObjects::Community( - webfinger_resolve_actor::(identifier, context).await?, - ), - _ => return Err(LemmyErrorType::InvalidQuery)?, + if query.starts_with('!') || query.starts_with('@') { + query.remove(0); } + SearchableObjects::PersonOrCommunity(Box::new( + webfinger_resolve_actor::(&query, context).await?, + )) } }) } @@ -59,19 +54,17 @@ pub(crate) async fn search_query_to_object_id_local( /// The types of ActivityPub objects that can be fetched directly by searching for their ID. #[derive(Debug)] pub(crate) enum SearchableObjects { - Person(ApubPerson), - Community(ApubCommunity), Post(ApubPost), Comment(ApubComment), + PersonOrCommunity(Box), } #[derive(Deserialize)] #[serde(untagged)] pub(crate) enum SearchableKinds { - Group(Group), - Person(Person), - Page(Page), + Page(Box), Note(Note), + PersonOrGroup(Box), } #[async_trait::async_trait] @@ -82,10 +75,9 @@ impl Object for SearchableObjects { fn last_refreshed_at(&self) -> Option> { match self { - SearchableObjects::Person(p) => p.last_refreshed_at(), - SearchableObjects::Community(c) => c.last_refreshed_at(), SearchableObjects::Post(p) => p.last_refreshed_at(), SearchableObjects::Comment(c) => c.last_refreshed_at(), + SearchableObjects::PersonOrCommunity(p) => p.last_refreshed_at(), } } @@ -99,13 +91,9 @@ impl Object for SearchableObjects { object_id: Url, context: &Data, ) -> Result, LemmyError> { - let c = ApubCommunity::read_from_id(object_id.clone(), context).await?; - if let Some(c) = c { - return Ok(Some(SearchableObjects::Community(c))); - } - let p = ApubPerson::read_from_id(object_id.clone(), context).await?; - if let Some(p) = p { - return Ok(Some(SearchableObjects::Person(p))); + let uc = UserOrCommunity::read_from_id(object_id.clone(), context).await?; + if let Some(uc) = uc { + return Ok(Some(SearchableObjects::PersonOrCommunity(Box::new(uc)))); } let p = ApubPost::read_from_id(object_id.clone(), context).await?; if let Some(p) = p { @@ -121,10 +109,12 @@ impl Object for SearchableObjects { #[tracing::instrument(skip_all)] async fn delete(self, data: &Data) -> Result<(), LemmyError> { match self { - SearchableObjects::Person(p) => p.delete(data).await, - SearchableObjects::Community(c) => c.delete(data).await, SearchableObjects::Post(p) => p.delete(data).await, SearchableObjects::Comment(c) => c.delete(data).await, + SearchableObjects::PersonOrCommunity(pc) => match *pc { + UserOrCommunity::User(p) => p.delete(data).await, + UserOrCommunity::Community(c) => c.delete(data).await, + }, } } @@ -139,10 +129,12 @@ impl Object for SearchableObjects { data: &Data, ) -> Result<(), LemmyError> { match apub { - SearchableKinds::Group(a) => ApubCommunity::verify(a, expected_domain, data).await, - SearchableKinds::Person(a) => ApubPerson::verify(a, expected_domain, data).await, SearchableKinds::Page(a) => ApubPost::verify(a, expected_domain, data).await, SearchableKinds::Note(a) => ApubComment::verify(a, expected_domain, data).await, + SearchableKinds::PersonOrGroup(pg) => match pg.as_ref() { + PersonOrGroup::Person(a) => ApubPerson::verify(a, expected_domain, data).await, + PersonOrGroup::Group(a) => ApubCommunity::verify(a, expected_domain, data).await, + }, } } @@ -151,10 +143,11 @@ impl Object for SearchableObjects { use SearchableKinds as SAT; use SearchableObjects as SO; Ok(match apub { - SAT::Group(g) => SO::Community(ApubCommunity::from_json(g, context).await?), - SAT::Person(p) => SO::Person(ApubPerson::from_json(p, context).await?), - SAT::Page(p) => SO::Post(ApubPost::from_json(p, context).await?), + SAT::Page(p) => SO::Post(ApubPost::from_json(*p, context).await?), SAT::Note(n) => SO::Comment(ApubComment::from_json(n, context).await?), + SAT::PersonOrGroup(pg) => { + SO::PersonOrCommunity(Box::new(UserOrCommunity::from_json(*pg, context).await?)) + } }) } }