oauth2_types/
webfinger.rs

1// Copyright 2022 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Types for provider discovery using [Webfinger].
16//!
17//! [Webfinger]: https://www.rfc-editor.org/rfc/rfc7033
18
19use serde::{Deserialize, Serialize};
20use url::Url;
21
22/// The response of the Webfinger endpoint.
23#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
24pub struct WebFingerResponse {
25    /// A URI that identifies the entity described by the response.
26    subject: String,
27
28    /// Links that describe the subject.
29    links: Vec<WebFingerLink>,
30}
31
32impl WebFingerResponse {
33    /// Creates a new `WebFingerResponse` with the given subject.
34    #[must_use]
35    pub const fn new(subject: String) -> Self {
36        Self {
37            subject,
38            links: Vec::new(),
39        }
40    }
41
42    /// Adds the given link to this `WebFingerResponse`.
43    #[must_use]
44    pub fn with_link(mut self, link: WebFingerLink) -> Self {
45        self.links.push(link);
46        self
47    }
48
49    /// Adds the given issuer to this `WebFingerResponse`.
50    #[must_use]
51    pub fn with_issuer(self, issuer: Url) -> Self {
52        self.with_link(WebFingerLink::issuer(issuer))
53    }
54}
55
56/// A link in a Webfinger response.
57#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
58#[serde(tag = "rel")]
59pub enum WebFingerLink {
60    /// An OpenID Connect issuer.
61    #[serde(rename = "http://openid.net/specs/connect/1.0/issuer")]
62    OidcIssuer {
63        /// The URL of the issuer.
64        href: Url,
65    },
66}
67
68impl WebFingerLink {
69    /// Creates a new `WebFingerLink` for an OpenID Connect issuer.
70    #[must_use]
71    pub const fn issuer(href: Url) -> Self {
72        Self::OidcIssuer { href }
73    }
74}
75
76#[cfg(test)]
77mod tests {
78    use serde_json::json;
79
80    use super::*;
81
82    #[test]
83    fn serialize_webfinger_response_test() {
84        let res = WebFingerResponse::new("acct:john@example.com".to_owned())
85            .with_issuer(Url::parse("https://account.example.com/").unwrap());
86
87        let res = serde_json::to_value(res).unwrap();
88
89        assert_eq!(
90            res,
91            json!({
92                "subject": "acct:john@example.com",
93                "links": [{
94                    "rel": "http://openid.net/specs/connect/1.0/issuer",
95                    "href": "https://account.example.com/",
96                }]
97            })
98        );
99    }
100}