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