From 99cdbb5d585da721e6d61b39a0ff0c59394bb5fb Mon Sep 17 00:00:00 2001 From: Grafcube Date: Wed, 5 Apr 2023 01:26:34 +0530 Subject: [PATCH] Multi webfinger response (#33) * Add support for building webfinger for multiple URLs with type Update `build_webfinger_response` to accept `Vec<(Url, Option<&str>)>` where `Url` is the ActivityPub ID and `&str` is the optional type. * Update docs for `build_webfinger_response` * Update tests to use new `build_webfinger_response` Tests and docs don't cover usage with some `kind` value. * Run formatter with nightly * Revert "Add support for building webfinger for multiple URLs with type" This reverts commits until 3f70586e63d6f5ae6a9c329ae9e9981da4e2eaaf. This was a breaking change and should be made into a separate function. * Add `build_webfinger_response_with_type` * Construct links separately and update `build_webfinger_response` - `build_webfinger_response` calls `build_webfinger_response_with_type`. - Links are constructed in a separate variable. - Update docs for `build_webfinger_response_with_type` to be clearer about usage. - TODO: Use `derive_builder` to simplify function. * Extract properties into variable * Remove `other` from docs --- src/fetch/webfinger.rs | 67 +++++++++++++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 14 deletions(-) diff --git a/src/fetch/webfinger.rs b/src/fetch/webfinger.rs index 655598b..936485a 100644 --- a/src/fetch/webfinger.rs +++ b/src/fetch/webfinger.rs @@ -101,22 +101,61 @@ where /// # Ok::<(), anyhow::Error>(()) /// ``` pub fn build_webfinger_response(subject: String, url: Url) -> Webfinger { + build_webfinger_response_with_type(subject, vec![(url, None)]) +} + +/// Builds a webfinger response similar to `build_webfinger_response`. Use this when you want to +/// return multiple actors who share the same namespace and to specify the type of the actor. +/// +/// `urls` takes a vector of tuples. The first item of the tuple is the URL while the second +/// item is the type, such as `"Person"` or `"Group"`. If `None` is passed for the type, the field +/// will be empty. +/// +/// ``` +/// # use url::Url; +/// # use activitypub_federation::fetch::webfinger::build_webfinger_response_with_type; +/// let subject = "acct:nutomic@lemmy.ml".to_string(); +/// let user = Url::parse("https://lemmy.ml/u/nutomic")?; +/// let group = Url::parse("https://lemmy.ml/c/asklemmy")?; +/// build_webfinger_response_with_type(subject, vec![ +/// (user, Some("Person")), +/// (group, Some("Group"))]); +/// # Ok::<(), anyhow::Error>(()) +/// ``` +pub fn build_webfinger_response_with_type( + subject: String, + urls: Vec<(Url, Option<&str>)>, +) -> Webfinger { Webfinger { subject, - links: vec![ - WebfingerLink { - rel: Some("http://webfinger.net/rel/profile-page".to_string()), - kind: Some("text/html".to_string()), - href: Some(url.clone()), - properties: Default::default(), - }, - WebfingerLink { - rel: Some("self".to_string()), - kind: Some(FEDERATION_CONTENT_TYPE.to_string()), - href: Some(url), - properties: Default::default(), - }, - ], + links: urls.iter().fold(vec![], |mut acc, (url, kind)| { + let properties: HashMap = kind + .map(|kind| { + HashMap::from([( + "https://www.w3.org/ns/activitystreams#type" + .parse() + .expect("parse url"), + kind.to_string(), + )]) + }) + .unwrap_or_default(); + let mut links = vec![ + WebfingerLink { + rel: Some("http://webfinger.net/rel/profile-page".to_string()), + kind: Some("text/html".to_string()), + href: Some(url.clone()), + properties: Default::default(), + }, + WebfingerLink { + rel: Some("self".to_string()), + kind: Some(FEDERATION_CONTENT_TYPE.to_string()), + href: Some(url.clone()), + properties, + }, + ]; + acc.append(&mut links); + acc + }), aliases: vec![], properties: Default::default(), }