acme/api/
mod.rs

1//! JSON API payloads.
2//!
3//! Not intended to be used directly. Provided to aid debugging.
4
5use std::fmt;
6
7use serde::{
8    ser::{SerializeMap as _, Serializer},
9    Deserialize, Serialize,
10};
11
12mod account;
13mod authorization;
14mod challenge;
15mod directory;
16mod finalize;
17mod identifier;
18mod order;
19mod revocation;
20
21pub use self::{
22    account::Account,
23    authorization::{Authorization, AuthorizationStatus},
24    challenge::{Challenge, ChallengeStatus},
25    directory::{Directory, DirectoryMeta},
26    finalize::Finalize,
27    identifier::Identifier,
28    order::{Order, OrderStatus},
29    revocation::Revocation,
30};
31
32/// Serializes to `""`.
33pub struct EmptyString;
34
35impl Serialize for EmptyString {
36    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
37        serializer.serialize_str("")
38    }
39}
40
41/// Serializes to `{}`.
42pub struct EmptyObject;
43
44impl Serialize for EmptyObject {
45    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
46        serializer.serialize_map(Some(0))?.end()
47    }
48}
49
50#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
51pub struct Problem {
52    #[serde(rename = "type")]
53    pub _type: String,
54
55    #[serde(skip_serializing_if = "Option::is_none")]
56    pub detail: Option<String>,
57
58    #[serde(skip_serializing_if = "Option::is_none")]
59    pub subproblems: Option<Vec<Subproblem>>,
60}
61
62impl Problem {
63    /// Returns true if problem type is "badNonce".
64    pub fn is_bad_nonce(&self) -> bool {
65        self._type == "badNonce"
66    }
67
68    /// Returns true if problem details indicate that JWS verification failed.
69    pub fn is_jws_verification_error(&self) -> bool {
70        (self._type == "urn:ietf:params:acme:error:malformed"
71            || self._type == "urn:acme:error:malformed")
72            && self
73                .detail
74                .as_deref()
75                .is_some_and(|detail| detail == "JWS verification error")
76    }
77}
78
79impl fmt::Display for Problem {
80    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81        match &self.detail {
82            Some(detail) => write!(f, "{}: {detail}", self._type),
83            _ => write!(f, "{}", self._type),
84        }
85    }
86}
87
88#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
89pub struct Subproblem {
90    #[serde(rename = "type")]
91    pub _type: String,
92    pub detail: Option<String>,
93    pub identifier: Option<identifier::Identifier>,
94}
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99
100    #[test]
101    fn test_api_empty_string() {
102        let x = serde_json::to_string(&EmptyString).unwrap();
103        assert_eq!("\"\"", x);
104    }
105
106    #[test]
107    fn test_api_empty_object() {
108        let x = serde_json::to_string(&EmptyObject).unwrap();
109        assert_eq!("{}", x);
110    }
111}