]> Untitled Git - lemmy.git/blob - crates/apub/src/fetcher/mod.rs
Only allow authenticated users to fetch remote objects (#2493)
[lemmy.git] / crates / apub / src / fetcher / mod.rs
1 use crate::{fetcher::webfinger::webfinger_resolve_actor, ActorType};
2 use activitypub_federation::traits::ApubObject;
3 use itertools::Itertools;
4 use lemmy_api_common::utils::blocking;
5 use lemmy_db_schema::traits::ApubActor;
6 use lemmy_utils::error::LemmyError;
7 use lemmy_websocket::LemmyContext;
8
9 pub mod post_or_comment;
10 pub mod search;
11 pub mod user_or_community;
12 pub mod webfinger;
13
14 /// Resolve actor identifier (eg `!news@example.com`) from local database to avoid network requests.
15 /// This only works for local actors, and remote actors which were previously fetched (so it doesnt
16 /// trigger any new fetch).
17 #[tracing::instrument(skip_all)]
18 pub async fn resolve_actor_identifier<Actor, DbActor>(
19   identifier: &str,
20   context: &LemmyContext,
21   include_deleted: bool,
22 ) -> Result<DbActor, LemmyError>
23 where
24   Actor: ApubObject<DataType = LemmyContext, Error = LemmyError>
25     + ApubObject<DbType = DbActor>
26     + ActorType
27     + Send
28     + 'static,
29   for<'de2> <Actor as ApubObject>::ApubType: serde::Deserialize<'de2>,
30   DbActor: ApubActor + Send + 'static,
31 {
32   // remote actor
33   if identifier.contains('@') {
34     let (name, domain) = identifier
35       .splitn(2, '@')
36       .collect_tuple()
37       .expect("invalid query");
38     let name = name.to_string();
39     let domain = format!("{}://{}", context.settings().get_protocol_string(), domain);
40     let actor = blocking(context.pool(), move |conn| {
41       DbActor::read_from_name_and_domain(conn, &name, &domain)
42     })
43     .await?;
44     if actor.is_ok() {
45       Ok(actor?)
46     } else {
47       // Fetch the actor from its home instance using webfinger
48       let id = webfinger_resolve_actor::<Actor>(identifier, true, context, &mut 0).await?;
49       let actor: DbActor = blocking(context.pool(), move |conn| {
50         DbActor::read_from_apub_id(conn, &id)
51       })
52       .await??
53       .expect("actor exists as we fetched just before");
54       Ok(actor)
55     }
56   }
57   // local actor
58   else {
59     let identifier = identifier.to_string();
60     Ok(
61       blocking(context.pool(), move |conn| {
62         DbActor::read_from_name(conn, &identifier, include_deleted)
63       })
64       .await??,
65     )
66   }
67 }