Skip to main content

acme/api/
authorization.rs

1use serde::{Deserialize, Serialize};
2
3use crate::api;
4
5/// The status of an [`api::Order`].
6///
7/// See [RFC 8555 §7.1.4].
8///
9/// [RFC 8555 §7.1.4]: https://datatracker.ietf.org/doc/html/rfc8555#section-7.1.4
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
11#[serde(rename_all = "lowercase")]
12pub enum AuthorizationStatus {
13    Pending,
14    Valid,
15    Invalid,
16    Deactivated,
17    Expired,
18    Revoked,
19}
20
21// {
22//   "identifier": {
23//     "type": "dns",
24//     "value": "acmetest.algesten.se"
25//   },
26//   "status": "pending",
27//   "expires": "2019-01-09T08:26:43Z",
28//   "challenges": [
29//     {
30//       "type": "http-01",
31//       "status": "pending",
32//       "url": "https://example.com/acme/challenge/YTqpYUthlVfwBncUufE8IRA2TkzZkN4eYWWLMSRqcSs/216789597",
33//       "token": "MUi-gqeOJdRkSb_YR2eaMxQBqf6al8dgt_dOttSWb0w"
34//     },
35//     {
36//       "type": "tls-alpn-01",
37//       "status": "pending",
38//       "url": "https://example.com/acme/challenge/YTqpYUthlVfwBncUufE8IRA2TkzZkN4eYWWLMSRqcSs/216789598",
39//       "token": "WCdRWkCy4THTD_j5IH4ISAzr59lFIg5wzYmKxuOJ1lU"
40//     },
41//     {
42//       "type": "dns-01",
43//       "status": "pending",
44//       "url": "https://example.com/acme/challenge/YTqpYUthlVfwBncUufE8IRA2TkzZkN4eYWWLMSRqcSs/216789599",
45//       "token": "RRo2ZcXAEqxKvMH8RGcATjSK1KknLEUmauwfQ5i3gG8"
46//     }
47//   ]
48// }
49//
50// on incorrect challenge, something like:
51//
52//   "challenges": [
53//     {
54//       "type": "dns-01",
55//       "status": "invalid",
56//       "error": {
57//         "type": "urn:ietf:params:acme:error:dns",
58//         "detail": "DNS problem: NXDOMAIN looking up TXT for _acme-challenge.martintest.foobar.com",
59//         "status": 400
60//       },
61//       "url": "https://example.com/acme/challenge/afyChhlFB8GLLmIqEnqqcXzX0Ss3GBw6oUlKAGDG6lY/221695600",
62//       "token": "YsNqBWZnyYjDun3aUC2CkCopOaqZRrI5hp3tUjxPLQU"
63//     },
64// "Incorrect TXT record \"caOh44dp9eqXNRkd0sYrKVF8dBl0L8h8-kFpIBje-2c\" found at _acme-challenge.martintest.foobar.com
65/// An ACME authorization object.
66///
67/// Represents a server's authorization for an account to represent an identifier.
68///
69/// See [RFC 8555 §7.1.4].
70///
71/// [RFC 8555 §7.1.4]: https://datatracker.ietf.org/doc/html/rfc8555#section-7.1.4
72#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
73pub struct Authorization {
74    /// Authorization identifier.
75    pub identifier: api::Identifier,
76
77    /// Authorization status.
78    pub status: AuthorizationStatus,
79
80    /// The timestamp after which the server will consider this authorization invalid.
81    ///
82    /// Uses RFC 3339 format.
83    ///
84    /// This field is required for objects with "valid" in the "status" field.
85    pub expires: Option<String>,
86
87    /// Returns the challenges related to the identifier.
88    ///
89    /// - For pending authorizations, the challenges that the client can fulfill in order to prove
90    ///   possession of the identifier.
91    /// - For valid authorizations, the challenge that was validated.
92    /// - For invalid authorizations, the challenge that was attempted and failed.
93    ///
94    /// Each array entry is an object with parameters required to validate the challenge. A client
95    /// should attempt to fulfill one of these challenges, and a server should consider any one of
96    /// the challenges sufficient to make the authorization valid.
97    pub challenges: Vec<api::Challenge>,
98
99    /// This field MUST be present and true for authorizations created as a result of a newOrder
100    /// request containing a DNS identifier with a value that was a wildcard domain name. For other
101    /// authorizations, it MUST be absent. Wildcard domain names are described in §7.1.3.
102    pub wildcard: Option<bool>,
103}
104
105impl Authorization {
106    /// Returns true if authorization was created for a wildcard domain.
107    pub fn is_wildcard(&self) -> bool {
108        self.wildcard.unwrap_or(false)
109    }
110
111    /// Returns an `http-01` challenge, if one is present.
112    pub fn http_challenge(&self) -> Option<&api::Challenge> {
113        self.challenges.iter().find(|c| c._type == "http-01")
114    }
115
116    /// Returns a `dns-01` challenge, if one is present.
117    pub fn dns_challenge(&self) -> Option<&api::Challenge> {
118        self.challenges.iter().find(|c| c._type == "dns-01")
119    }
120
121    /// Returns a `tls-alpn-01` challenge, if one is present.
122    pub fn tls_alpn_challenge(&self) -> Option<&api::Challenge> {
123        self.challenges.iter().find(|c| c._type == "tls-alpn-01")
124    }
125}