]> Untitled Git - lemmy.git/blob - crates/apub_lib/src/webfinger.rs
Merge branch 'remove_settings_and_secret_singletons_squashed'
[lemmy.git] / crates / apub_lib / src / webfinger.rs
1 use anyhow::anyhow;
2 use lemmy_utils::{
3   request::{retry, RecvError},
4   LemmyError,
5 };
6 use log::debug;
7 use reqwest::Client;
8 use serde::{Deserialize, Serialize};
9 use url::Url;
10
11 #[derive(Serialize, Deserialize, Debug)]
12 pub struct WebfingerLink {
13   pub rel: Option<String>,
14   #[serde(rename(serialize = "type", deserialize = "type"))]
15   pub type_: Option<String>,
16   pub href: Option<Url>,
17   #[serde(skip_serializing_if = "Option::is_none")]
18   pub template: Option<String>,
19 }
20
21 #[derive(Serialize, Deserialize, Debug)]
22 pub struct WebfingerResponse {
23   pub subject: String,
24   pub aliases: Vec<Url>,
25   pub links: Vec<WebfingerLink>,
26 }
27
28 pub enum WebfingerType {
29   Person,
30   Group,
31 }
32
33 /// Turns a person id like `@name@example.com` into an apub ID, like `https://example.com/user/name`,
34 /// using webfinger.
35 pub async fn webfinger_resolve_actor(
36   name: &str,
37   domain: &str,
38   webfinger_type: WebfingerType,
39   client: &Client,
40   protocol_string: &str,
41 ) -> Result<Url, LemmyError> {
42   let webfinger_type = match webfinger_type {
43     WebfingerType::Person => "acct",
44     WebfingerType::Group => "group",
45   };
46   let fetch_url = format!(
47     "{}://{}/.well-known/webfinger?resource={}:{}@{}",
48     protocol_string, domain, webfinger_type, name, domain
49   );
50   debug!("Fetching webfinger url: {}", &fetch_url);
51
52   let response = retry(|| client.get(&fetch_url).send()).await?;
53
54   let res: WebfingerResponse = response
55     .json()
56     .await
57     .map_err(|e| RecvError(e.to_string()))?;
58
59   let link = res
60     .links
61     .iter()
62     .find(|l| l.type_.eq(&Some("application/activity+json".to_string())))
63     .ok_or_else(|| anyhow!("No application/activity+json link found."))?;
64   link
65     .href
66     .to_owned()
67     .ok_or_else(|| anyhow!("No href found.").into())
68 }