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