Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make resolve_object not require auth #3685 #3716

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/api_common/src/site.rs
Expand Up @@ -84,7 +84,7 @@ pub struct SearchResponse {
pub struct ResolveObject {
/// Can be the full url, or a shortened version like: !fediverse@lemmy.ml
pub q: String,
pub auth: Sensitive<String>,
pub auth: Option<Sensitive<String>>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API change, but it shouldn't be breaking.

}

#[skip_serializing_none]
Expand Down
37 changes: 25 additions & 12 deletions crates/apub/src/api/resolve_object.rs
@@ -1,11 +1,15 @@
use crate::fetcher::search::{search_query_to_object_id, SearchableObjects};
use crate::fetcher::search::{
search_query_to_object_id,
search_query_to_object_id_local,
SearchableObjects,
};
use activitypub_federation::config::Data;
use actix_web::web::{Json, Query};
use diesel::NotFound;
use lemmy_api_common::{
context::LemmyContext,
site::{ResolveObject, ResolveObjectResponse},
utils::{check_private_instance, local_user_view_from_jwt},
utils::{check_private_instance, local_user_view_from_jwt_opt},
};
use lemmy_db_schema::{newtypes::PersonId, source::local_site::LocalSite, utils::DbPool};
use lemmy_db_views::structs::{CommentView, PostView};
Expand All @@ -17,22 +21,31 @@ pub async fn resolve_object(
data: Query<ResolveObject>,
context: Data<LemmyContext>,
) -> Result<Json<ResolveObjectResponse>, LemmyError> {
let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?;
let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), &context).await;
let local_site = LocalSite::read(&mut context.pool()).await?;
let person_id = local_user_view.person.id;
check_private_instance(&Some(local_user_view), &local_site)?;
check_private_instance(&local_user_view, &local_site)?;
let person_id = local_user_view.map(|v| v.person.id);
// If we get a valid personId back we can safely assume that the user is authenticated,
// if there's no personId then the JWT was missing or invalid.
let is_authenticated = person_id.is_some();

let res = if is_authenticated {
// user is fully authenticated; allow remote lookups as well.
search_query_to_object_id(&data.q, &context).await
} else {
// user isn't authenticated only allow a local search.
search_query_to_object_id_local(&data.q, &context).await
}
.with_lemmy_type(LemmyErrorType::CouldntFindObject)?;

let res = search_query_to_object_id(&data.q, &context)
.await
.with_lemmy_type(LemmyErrorType::CouldntFindObject)?;
convert_response(res, person_id, &mut context.pool())
.await
.with_lemmy_type(LemmyErrorType::CouldntFindObject)
}

async fn convert_response(
object: SearchableObjects,
user_id: PersonId,
user_id: Option<PersonId>,
pool: &mut DbPool<'_>,
) -> Result<Json<ResolveObjectResponse>, LemmyError> {
use SearchableObjects::*;
Expand All @@ -45,15 +58,15 @@ async fn convert_response(
}
Community(c) => {
removed_or_deleted = c.deleted || c.removed;
res.community = Some(CommunityView::read(pool, c.id, Some(user_id), None).await?)
res.community = Some(CommunityView::read(pool, c.id, user_id, None).await?)
}
Post(p) => {
removed_or_deleted = p.deleted || p.removed;
res.post = Some(PostView::read(pool, p.id, Some(user_id), None).await?)
res.post = Some(PostView::read(pool, p.id, user_id, None).await?)
}
Comment(c) => {
removed_or_deleted = c.deleted || c.removed;
res.comment = Some(CommentView::read(pool, c.id, Some(user_id)).await?)
res.comment = Some(CommentView::read(pool, c.id, user_id).await?)
}
};
// if the object was deleted from database, dont return it
Expand Down
12 changes: 12 additions & 0 deletions crates/apub/src/fetcher/search.rs
Expand Up @@ -44,6 +44,18 @@ pub(crate) async fn search_query_to_object_id(
})
}

/// Converts a search query to an object id. The query MUST bbe a URL which will bbe treated
/// as the ObjectId directly. If the query is a webfinger identifier (@user@example.com or
/// !community@example.com) this method will return an error.
#[tracing::instrument(skip_all)]
pub(crate) async fn search_query_to_object_id_local(
query: &str,
context: &Data<LemmyContext>,
) -> Result<SearchableObjects, LemmyError> {
let url = Url::parse(query)?;
ObjectId::from(url).dereference_local(context).await
Copy link
Member

@Nutomic Nutomic Jul 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can directly call ObjectId::parse which calls Url::parse internally. And in fact it doesnt make much sense to have a separate function for this single line. Otherwise looks good.

}

/// The types of ActivityPub objects that can be fetched directly by searching for their ID.
#[derive(Debug)]
pub(crate) enum SearchableObjects {
Expand Down