oauth2_types/
webfinger.rs

1// Copyright 2024 New Vector Ltd.
2// Copyright 2022-2024 The Matrix.org Foundation C.I.C.
3//
4// SPDX-License-Identifier: AGPL-3.0-only
5// Please see LICENSE in the repository root for full details.
6
7//! Types for provider discovery using [Webfinger].
8//!
9//! [Webfinger]: https://www.rfc-editor.org/rfc/rfc7033
10
11use serde::{Deserialize, Serialize};
12use url::Url;
13
14/// The response of the Webfinger endpoint.
15#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
16pub struct WebFingerResponse {
17    /// A URI that identifies the entity described by the response.
18    subject: String,
19
20    /// Links that describe the subject.
21    links: Vec<WebFingerLink>,
22}
23
24impl WebFingerResponse {
25    /// Creates a new `WebFingerResponse` with the given subject.
26    #[must_use]
27    pub const fn new(subject: String) -> Self {
28        Self {
29            subject,
30            links: Vec::new(),
31        }
32    }
33
34    /// Adds the given link to this `WebFingerResponse`.
35    #[must_use]
36    pub fn with_link(mut self, link: WebFingerLink) -> Self {
37        self.links.push(link);
38        self
39    }
40
41    /// Adds the given issuer to this `WebFingerResponse`.
42    #[must_use]
43    pub fn with_issuer(self, issuer: Url) -> Self {
44        self.with_link(WebFingerLink::issuer(issuer))
45    }
46}
47
48/// A link in a Webfinger response.
49#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
50#[serde(tag = "rel")]
51pub enum WebFingerLink {
52    /// An OpenID Connect issuer.
53    #[serde(rename = "http://openid.net/specs/connect/1.0/issuer")]
54    OidcIssuer {
55        /// The URL of the issuer.
56        href: Url,
57    },
58}
59
60impl WebFingerLink {
61    /// Creates a new `WebFingerLink` for an OpenID Connect issuer.
62    #[must_use]
63    pub const fn issuer(href: Url) -> Self {
64        Self::OidcIssuer { href }
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use serde_json::json;
71
72    use super::*;
73
74    #[test]
75    fn serialize_webfinger_response_test() {
76        let res = WebFingerResponse::new("acct:john@example.com".to_owned())
77            .with_issuer(Url::parse("https://account.example.com/").unwrap());
78
79        let res = serde_json::to_value(res).unwrap();
80
81        assert_eq!(
82            res,
83            json!({
84                "subject": "acct:john@example.com",
85                "links": [{
86                    "rel": "http://openid.net/specs/connect/1.0/issuer",
87                    "href": "https://account.example.com/",
88                }]
89            })
90        );
91    }
92}