acme_types/v2/
error.rs

1#[cfg(feature = "json")]
2use serde::{Deserialize, Deserializer, Serialize, Serializer};
3
4/// Defines an ACME error object
5///
6/// For more information, refer to [RFC 8555 § 6.7](https://datatracker.ietf.org/doc/html/rfc8555#section-6.7)
7#[derive(Clone, Debug)]
8#[cfg_attr(feature = "json", derive(Serialize, Deserialize))]
9pub struct Error {
10    /// Error type
11    #[cfg_attr(feature = "json", serde(rename = "type"))]
12    #[cfg_attr(feature = "json", serde(serialize_with = "error_type_serialize"))]
13    #[cfg_attr(feature = "json", serde(deserialize_with = "error_type_deserialize"))]
14    pub type_: ErrorType,
15    /// Error description
16    pub detail: String,
17    /// Optional sub-problem documents
18    #[cfg_attr(feature = "json", serde(skip_serializing_if = "Option::is_none"))]
19    #[cfg_attr(feature = "json", serde(rename = "subproblems"))]
20    pub sub_problems: Option<Vec<ProblemDocument>>,
21}
22
23#[cfg(feature = "json")]
24impl Error {
25    /// Deserializes an Error object from a JSON str
26    pub fn from_str(s: &str) -> Result<Error, serde_json::error::Error> {
27        serde_json::from_str(s)
28    }
29
30    /// Serializes an Error object to a JSON String
31    pub fn to_string(&self) -> Result<String, serde_json::error::Error> {
32        serde_json::to_string(self)
33    }
34}
35
36/// Defines an ACME error problem document object
37///
38/// For more information, refer to [RFC 8555 § 6.7.1](https://datatracker.ietf.org/doc/html/rfc8555#section-6.7.1)
39#[derive(Clone, Debug)]
40#[cfg_attr(feature = "json", derive(Serialize, Deserialize))]
41pub struct ProblemDocument {
42    /// Error type
43    #[cfg_attr(feature = "json", serde(rename = "type"))]
44    #[cfg_attr(feature = "json", serde(serialize_with = "error_type_serialize"))]
45    #[cfg_attr(feature = "json", serde(deserialize_with = "error_type_deserialize"))]
46    pub type_: ErrorType,
47    /// Error description
48    pub detail: String,
49    /// Optional order identifier associated with the error
50    #[cfg_attr(feature = "json", serde(skip_serializing_if = "Option::is_none"))]
51    pub identifier: Option<super::Identifier>,
52}
53
54/// Non-exhaustive list of ACME error types
55///
56/// For more information, refer to [RFC 8555 § 6.7](https://datatracker.ietf.org/doc/html/rfc8555#section-6.7)
57#[derive(Clone, Debug)]
58pub enum ErrorType {
59    AccountDoesNotExist,
60    AlreadyRevoked,
61    BadCertificateSigningRequest,
62    BadNonce,
63    BadPublicKey,
64    BadRevocationReason,
65    BadSignatureAlgorithm,
66    CertificationAuthorityAuthorization,
67    Compound,
68    Connection,
69    Dns,
70    ExternalAccountRequired,
71    IncorrectResponse,
72    InvalidContact,
73    Malformed,
74    OrderNotReady,
75    RateLimited,
76    RejectedIdentifier,
77    ServerInternal,
78    Tls,
79    Unauthorized,
80    UnsupportedContact,
81    UnsupportedIdentifier,
82    UserActionRequired,
83    Other(String),
84}
85
86#[cfg(feature = "json")]
87fn error_type_deserialize<'de, D>(deserializer: D) -> Result<ErrorType, D::Error>
88where
89    D: Deserializer<'de>,
90{
91    use self::ErrorType::*;
92    let s = String::deserialize(deserializer)?;
93
94    match s.starts_with("urn:ietf:params:acme:error:") {
95        true => match s.strip_prefix("urn:ietf:params:acme:error:").unwrap() {
96            "accountDoesNotExist" => Ok(AccountDoesNotExist),
97            "alreadyRevoked" => Ok(AccountDoesNotExist),
98            "badCSR" => Ok(AccountDoesNotExist),
99            "badNonce" => Ok(AccountDoesNotExist),
100            "badPublicKey" => Ok(AccountDoesNotExist),
101            "badRevocationReason" => Ok(AccountDoesNotExist),
102            "badSignatureAlgorithm" => Ok(AccountDoesNotExist),
103            "caa" => Ok(AccountDoesNotExist),
104            "compound" => Ok(AccountDoesNotExist),
105            "connection" => Ok(AccountDoesNotExist),
106            "dns" => Ok(AccountDoesNotExist),
107            "externalAccountRequired" => Ok(AccountDoesNotExist),
108            "incorrectResponse" => Ok(AccountDoesNotExist),
109            "invalidContact" => Ok(AccountDoesNotExist),
110            "malformed" => Ok(AccountDoesNotExist),
111            "orderNotReady" => Ok(AccountDoesNotExist),
112            "rateLimited" => Ok(AccountDoesNotExist),
113            "rejectedIdentifier" => Ok(AccountDoesNotExist),
114            "serverInternal" => Ok(AccountDoesNotExist),
115            "tls" => Ok(AccountDoesNotExist),
116            "unauthorized" => Ok(AccountDoesNotExist),
117            "unsupportedContact" => Ok(AccountDoesNotExist),
118            "unsupportedIdentifier" => Ok(AccountDoesNotExist),
119            "userActionRequired" => Ok(AccountDoesNotExist),
120            _ => Ok(Other(s)),
121        },
122        false => Ok(Other(s)),
123    }
124}
125
126#[cfg(feature = "json")]
127fn error_type_serialize<S>(type_: &ErrorType, serializer: S) -> Result<S::Ok, S::Error>
128where
129    S: Serializer,
130{
131    use self::ErrorType::*;
132
133    serializer.serialize_str(&match type_ {
134        Other(s) => s.to_string(),
135        _ => {
136            format!(
137                "urn:ietf:params:acme:error:{}",
138                match type_ {
139                    AccountDoesNotExist => "accountDoesNotExist",
140                    AlreadyRevoked => "alreadyRevoked",
141                    BadCertificateSigningRequest => "badCSR",
142                    BadNonce => "badNonce",
143                    BadPublicKey => "badPublicKey",
144                    BadRevocationReason => "badRevocationReason",
145                    BadSignatureAlgorithm => "badSignatureAlgorithm",
146                    CertificationAuthorityAuthorization => "caa",
147                    Compound => "compound",
148                    Connection => "connection",
149                    Dns => "dns",
150                    ExternalAccountRequired => "externalAccountRequired",
151                    IncorrectResponse => "incorrectResponse",
152                    InvalidContact => "invalidContact",
153                    Malformed => "malformed",
154                    OrderNotReady => "orderNotReady",
155                    RateLimited => "rateLimited",
156                    RejectedIdentifier => "rejectedIdentifier",
157                    ServerInternal => "serverInternal",
158                    Tls => "tls",
159                    Unauthorized => "unauthorized",
160                    UnsupportedContact => "unsupportedContact",
161                    UnsupportedIdentifier => "unsupportedIdentifier",
162                    UserActionRequired => "userActionRequired",
163                    _ => {
164                        panic!("I've truly fucked up")
165                    }
166                }
167            )
168        }
169    })
170}