1#![allow(non_snake_case)]
5#![allow(non_camel_case_types)]
6
7use serde::{
8 ser::{SerializeMap, Serializer},
9 Deserialize, Serialize,
10};
11
12pub struct ApiEmptyString;
14impl Serialize for ApiEmptyString {
15 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
16 where
17 S: Serializer,
18 {
19 serializer.serialize_str("")
20 }
21}
22
23pub struct ApiEmptyObject;
25impl Serialize for ApiEmptyObject {
26 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
27 where
28 S: Serializer,
29 {
30 let m = serializer.serialize_map(Some(0))?;
31 m.end()
32 }
33}
34
35#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
36pub struct ApiProblem {
37 #[serde(rename = "type")]
38 pub _type: String,
39 #[serde(skip_serializing_if = "Option::is_none")]
40 pub detail: Option<String>,
41 #[serde(skip_serializing_if = "Option::is_none")]
42 pub subproblems: Option<Vec<ApiSubproblem>>,
43}
44
45impl ApiProblem {
46 pub fn is_bad_nonce(&self) -> bool {
47 self._type == "badNonce"
48 }
49 pub fn is_jwt_verification_error(&self) -> bool {
50 (self._type == "urn:acme:error:malformed"
51 || self._type == "urn:ietf:params:acme:error:malformed")
52 && self
53 .detail
54 .as_ref()
55 .map(|s| s == "JWS verification error")
56 .unwrap_or(false)
57 }
58}
59
60impl std::fmt::Display for ApiProblem {
61 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
62 if let Some(detail) = &self.detail {
63 write!(f, "{}: {}", self._type, detail)
64 } else {
65 write!(f, "{}", self._type)
66 }
67 }
68}
69
70#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
71pub struct ApiSubproblem {
72 #[serde(rename = "type")]
73 pub _type: String,
74 pub detail: Option<String>,
75 pub identifier: Option<ApiIdentifier>,
76}
77
78#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
79pub struct ApiDirectory {
80 pub newNonce: String,
81 pub newAccount: String,
82 pub newOrder: String,
83 #[serde(skip_serializing_if = "Option::is_none")]
84 pub newAuthz: Option<String>,
85 pub revokeCert: String,
86 pub keyChange: String,
87 #[serde(skip_serializing_if = "Option::is_none")]
88 pub meta: Option<ApiDirectoryMeta>,
89}
90
91#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
92pub struct ApiDirectoryMeta {
93 #[serde(skip_serializing_if = "Option::is_none")]
94 pub termsOfService: Option<String>,
95 #[serde(skip_serializing_if = "Option::is_none")]
96 pub website: Option<String>,
97 #[serde(skip_serializing_if = "Option::is_none")]
98 pub caaIdentities: Option<Vec<String>>,
99 #[serde(skip_serializing_if = "Option::is_none")]
100 pub externalAccountRequired: Option<bool>,
101}
102
103impl ApiDirectoryMeta {
104 pub fn externalAccountRequired(&self) -> bool {
105 self.externalAccountRequired.unwrap_or(false)
106 }
107}
108
109#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
119pub struct ApiAccount {
120 #[serde(skip_serializing_if = "Option::is_none")]
121 pub status: Option<String>,
122 #[serde(skip_serializing_if = "Option::is_none")]
123 pub contact: Option<Vec<String>>,
124 #[serde(skip_serializing_if = "Option::is_none")]
125 pub termsOfServiceAgreed: Option<bool>,
126 #[serde(skip_serializing_if = "Option::is_none")]
127 pub orders: Option<String>,
128}
129
130impl ApiAccount {
131 pub fn is_status_valid(&self) -> bool {
132 self.status.as_ref().map(|s| s.as_ref()) == Some("valid")
133 }
134 pub fn is_status_deactivated(&self) -> bool {
135 self.status.as_ref().map(|s| s.as_ref()) == Some("deactivated")
136 }
137 pub fn is_status_revoked(&self) -> bool {
138 self.status.as_ref().map(|s| s.as_ref()) == Some("revoked")
139 }
140 pub fn termsOfServiceAgreed(&self) -> bool {
141 self.termsOfServiceAgreed.unwrap_or(false)
142 }
143}
144
145#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
160pub struct ApiOrder {
161 #[serde(skip_serializing_if = "Option::is_none")]
162 pub status: Option<String>,
163 #[serde(skip_serializing_if = "Option::is_none")]
164 pub expires: Option<String>,
165 pub identifiers: Vec<ApiIdentifier>,
166 pub notBefore: Option<String>,
167 pub notAfter: Option<String>,
168 pub error: Option<ApiProblem>,
169 pub authorizations: Option<Vec<String>>,
170 pub finalize: String,
171 pub certificate: Option<String>,
172}
173
174impl ApiOrder {
175 pub fn is_status_pending(&self) -> bool {
177 self.status.as_ref().map(|s| s.as_ref()) == Some("pending")
178 }
179 pub fn is_status_ready(&self) -> bool {
182 self.status.as_ref().map(|s| s.as_ref()) == Some("ready")
183 }
184 pub fn is_status_processing(&self) -> bool {
186 self.status.as_ref().map(|s| s.as_ref()) == Some("processing")
187 }
188 pub fn is_status_valid(&self) -> bool {
190 self.status.as_ref().map(|s| s.as_ref()) == Some("valid")
191 }
192 pub fn is_status_invalid(&self) -> bool {
194 self.status.as_ref().map(|s| s.as_ref()) == Some("invalid")
195 }
196 pub fn domains(&self) -> Vec<&str> {
198 self.identifiers.iter().map(|i| i.value.as_ref()).collect()
199 }
200}
201
202#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
203pub struct ApiIdentifier {
204 #[serde(rename = "type")]
205 pub _type: String,
206 pub value: String,
207}
208
209impl ApiIdentifier {
210 pub fn is_type_dns(&self) -> bool {
211 self._type == "dns"
212 }
213}
214
215#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
260pub struct ApiAuth {
261 pub identifier: ApiIdentifier,
262 pub status: Option<String>,
263 pub expires: Option<String>,
264 pub challenges: Vec<ApiChallenge>,
265 pub wildcard: Option<bool>,
266}
267
268impl ApiAuth {
269 pub fn is_status_pending(&self) -> bool {
270 self.status.as_ref().map(|s| s.as_ref()) == Some("pending")
271 }
272 pub fn is_status_valid(&self) -> bool {
273 self.status.as_ref().map(|s| s.as_ref()) == Some("valid")
274 }
275 pub fn is_status_invalid(&self) -> bool {
276 self.status.as_ref().map(|s| s.as_ref()) == Some("invalid")
277 }
278 pub fn is_status_deactivated(&self) -> bool {
279 self.status.as_ref().map(|s| s.as_ref()) == Some("deactivated")
280 }
281 pub fn is_status_expired(&self) -> bool {
282 self.status.as_ref().map(|s| s.as_ref()) == Some("expired")
283 }
284 pub fn is_status_revoked(&self) -> bool {
285 self.status.as_ref().map(|s| s.as_ref()) == Some("revoked")
286 }
287 pub fn wildcard(&self) -> bool {
288 self.wildcard.unwrap_or(false)
289 }
290 pub fn http_challenge(&self) -> Option<&ApiChallenge> {
291 self.challenges.iter().find(|c| c._type == "http-01")
292 }
293 pub fn dns_challenge(&self) -> Option<&ApiChallenge> {
294 self.challenges.iter().find(|c| c._type == "dns-01")
295 }
296 pub fn tls_alpn_challenge(&self) -> Option<&ApiChallenge> {
297 self.challenges.iter().find(|c| c._type == "tls-alpn-01")
298 }
299}
300
301#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
302pub struct ApiChallenge {
303 pub url: String,
304 #[serde(rename = "type")]
305 pub _type: String,
306 pub status: String,
307 pub token: String,
308 pub validated: Option<String>,
309 pub error: Option<ApiProblem>,
310}
311
312impl ApiChallenge {
319 pub fn is_status_pending(&self) -> bool {
320 &self.status == "pending"
321 }
322 pub fn is_status_processing(&self) -> bool {
323 &self.status == "processing"
324 }
325 pub fn is_status_valid(&self) -> bool {
326 &self.status == "valid"
327 }
328 pub fn is_status_invalid(&self) -> bool {
329 &self.status == "invalid"
330 }
331}
332
333#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
334pub struct ApiFinalize {
335 pub csr: String,
336}
337
338#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
339pub struct ApiRevocation {
340 pub certificate: String,
341 pub reason: usize,
342}
343
344#[cfg(test)]
345mod test {
346 use super::*;
347
348 #[test]
349 fn test_api_empty_string() {
350 let x = serde_json::to_string(&ApiEmptyString).unwrap();
351 assert_eq!("\"\"", x);
352 }
353
354 #[test]
355 fn test_api_empty_object() {
356 let x = serde_json::to_string(&ApiEmptyObject).unwrap();
357 assert_eq!("{}", x);
358 }
359}