wire_e2e_identity/acme/
identifier.rs

1use rusty_jwt_tools::prelude::*;
2
3use crate::acme::prelude::*;
4
5/// Represent an identifier in an ACME Order
6#[derive(Debug, Clone, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
7#[serde(tag = "type", content = "value", rename_all = "kebab-case")]
8pub enum AcmeIdentifier {
9    WireappUser(String),
10    WireappDevice(String),
11}
12
13impl AcmeIdentifier {
14    pub fn try_new_device(
15        client_id: ClientId,
16        handle: QualifiedHandle,
17        display_name: String,
18        domain: String,
19    ) -> RustyAcmeResult<Self> {
20        let client_id = client_id.to_uri();
21        let identifier = WireIdentifier {
22            display_name,
23            handle,
24            domain,
25            client_id: Some(client_id),
26        };
27        let identifier = serde_json::to_string(&identifier)?;
28        Ok(Self::WireappDevice(identifier))
29    }
30
31    pub fn try_new_user(handle: QualifiedHandle, display_name: String, domain: String) -> RustyAcmeResult<Self> {
32        let identifier = WireIdentifier {
33            display_name,
34            handle,
35            domain,
36            client_id: None,
37        };
38        let identifier = serde_json::to_string(&identifier)?;
39        Ok(Self::WireappUser(identifier))
40    }
41
42    pub fn to_wire_identifier(&self) -> RustyAcmeResult<WireIdentifier> {
43        Ok(match self {
44            AcmeIdentifier::WireappDevice(id) => serde_json::from_str(id)?,
45            AcmeIdentifier::WireappUser(id) => serde_json::from_str(id)?,
46        })
47    }
48
49    /// ACME protocol imposes this to be a json string while we need it to be a json object so
50    /// we serialize it to json like this which is simpler than implementing a serde Visitor
51    pub fn to_json(&self) -> RustyAcmeResult<String> {
52        Ok(serde_json::to_string(self)?)
53    }
54}
55
56#[cfg(test)]
57impl AcmeIdentifier {
58    pub fn new_device() -> Self {
59        Self::try_new_device(
60            ClientId::default(),
61            QualifiedHandle::default(),
62            "Alice Smith".to_string(),
63            "wire.com".to_string(),
64        )
65        .unwrap()
66    }
67
68    pub fn new_user() -> Self {
69        Self::try_new_user(
70            QualifiedHandle::default(),
71            "Alice Smith".to_string(),
72            "wire.com".to_string(),
73        )
74        .unwrap()
75    }
76}
77
78/// Structure of the ACME identifier
79#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
80pub struct WireIdentifier {
81    /// Wire ClientId. Absent on [AcmeIdentifier::WireappUser]
82    #[serde(rename = "client-id", skip_serializing_if = "Option::is_none")]
83    pub client_id: Option<String>,
84    /// Wire client handle
85    #[serde(rename = "handle")]
86    pub handle: QualifiedHandle,
87    /// Wire display name
88    #[serde(rename = "name")]
89    pub display_name: String,
90    /// Wire domain of the federated backend
91    #[serde(rename = "domain")]
92    pub domain: String,
93}
94
95/// Internal view of 2 merged [WireIdentifier], one of type [AcmeIdentifier::WireappUser] and one of
96/// [AcmeIdentifier::WireappDevice]
97#[derive(Clone, Debug, Eq, PartialEq)]
98pub struct CanonicalIdentifier {
99    pub client_id: String,
100    pub handle: QualifiedHandle,
101    pub display_name: String,
102    pub domain: String,
103}
104
105impl TryFrom<WireIdentifier> for CanonicalIdentifier {
106    type Error = RustyAcmeError;
107
108    fn try_from(i: WireIdentifier) -> RustyAcmeResult<Self> {
109        Ok(Self {
110            client_id: i.client_id.ok_or(RustyAcmeError::ImplementationError)?,
111            handle: i.handle,
112            display_name: i.display_name,
113            domain: i.domain,
114        })
115    }
116}