1use crate::AuthMaterialType;
2use crate::constants::{
3 AUTH_SIG_BLS_NETWORK_SIG_ALGO, AUTH_SIG_DERIVED_VIA_BLS_NETWORK_SIG,
4 AUTH_SIG_DERIVED_VIA_CONTRACT_SIG, AUTH_SIG_DERIVED_VIA_CONTRACT_SIG_SHA256,
5 AUTH_SIG_DERIVED_VIA_SESSION_SIG, AUTH_SIG_SESSION_SIG_ALGO, Chain,
6};
7use serde::de::{MapAccess, Visitor};
8use serde::{Deserialize, Deserializer, Serialize};
9use std::fmt;
10
11#[derive(Serialize, Clone, Default, PartialEq, Eq)]
14#[cfg_attr(test, derive(Debug))]
15#[serde(rename_all = "camelCase")]
16pub struct JsonAuthSig {
17 pub sig: String,
18 pub derived_via: String,
19 pub signed_message: String,
20
21 pub address: String,
23 pub algo: Option<String>,
24
25 #[serde(skip)]
26 pub auth_material_type: AuthMaterialType,
27
28 #[serde(skip)]
32 pub chain: Option<Chain>,
33}
34
35#[cfg(not(test))]
36impl fmt::Debug for JsonAuthSig {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 f.debug_struct("JsonAuthSig")
39 .field("sig", &"****filtered****")
40 .field("derived_via", &self.derived_via)
41 .field("signed_message", &self.signed_message)
42 .field("address", &self.address)
43 .field("algo", &self.algo)
44 .field("auth_material_type", &self.auth_material_type)
45 .field("chain", &self.chain)
46 .finish()
47 }
48}
49
50impl fmt::Display for JsonAuthSig {
51 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52 write!(
53 f,
54 "JsonAuthSig {{ sig: ****filtered****, derived_via: {}, signed_message: {}, address: {}, algo: {:?}, auth_material_type: {:?}, chain: {:?} }}",
55 self.derived_via,
56 self.signed_message,
57 self.address,
58 self.algo,
59 self.auth_material_type,
60 self.chain
61 )
62 }
63}
64
65impl JsonAuthSig {
66 pub fn new(
67 sig: String,
68 derived_via: String,
69 signed_message: String,
70 address: String,
71 algo: Option<String>,
72 ) -> Self {
73 JsonAuthSig {
74 sig,
75 derived_via,
76 signed_message,
77 address,
78 algo,
79 auth_material_type: AuthMaterialType::default(),
80 chain: None,
81 }
82 }
83
84 pub fn new_with_type(
85 sig: String,
86 derived_via: String,
87 signed_message: String,
88 address: String,
89 algo: Option<String>,
90 auth_material_type: AuthMaterialType,
91 chain: Option<Chain>,
92 ) -> Self {
93 JsonAuthSig {
94 sig,
95 derived_via,
96 signed_message,
97 address,
98 algo,
99 auth_material_type,
100 chain,
101 }
102 }
103
104 #[allow(clippy::collapsible_if)]
110 pub fn determine_auth_material_type(
111 derived_via: &str,
112 algo: &Option<String>,
113 ) -> AuthMaterialType {
114 if let Some(algo) = algo {
115 if derived_via == AUTH_SIG_DERIVED_VIA_SESSION_SIG && algo == AUTH_SIG_SESSION_SIG_ALGO
116 {
117 return AuthMaterialType::SessionSig;
118 }
119 }
120
121 if derived_via == AUTH_SIG_DERIVED_VIA_CONTRACT_SIG
122 || derived_via == AUTH_SIG_DERIVED_VIA_CONTRACT_SIG_SHA256
123 {
124 return AuthMaterialType::ContractSig;
125 }
126
127 if let Some(algo) = algo {
128 if derived_via == AUTH_SIG_DERIVED_VIA_BLS_NETWORK_SIG
129 && algo == AUTH_SIG_BLS_NETWORK_SIG_ALGO
130 {
131 return AuthMaterialType::BLSNetworkSig;
132 }
133 }
134
135 AuthMaterialType::WalletSig
136 }
137}
138
139#[derive(Deserialize)]
142#[serde(field_identifier, rename_all = "camelCase")]
143enum JsonAuthSigField {
144 Sig,
145 DerivedVia,
146 SignedMessage,
147 Address,
148 Algo,
149}
150
151impl<'de> Deserialize<'de> for JsonAuthSig {
152 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
153 where
154 D: Deserializer<'de>,
155 {
156 deserializer.deserialize_map(JsonAuthSigVisitor)
157 }
158}
159
160struct JsonAuthSigVisitor;
161
162impl<'de> Visitor<'de> for JsonAuthSigVisitor {
163 type Value = JsonAuthSig;
164
165 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
166 write!(
167 formatter,
168 "a map with keys sig, derivedVia, signedMessage, address, and optionally algo"
169 )
170 }
171
172 fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
173 where
174 M: MapAccess<'de>,
175 {
176 let mut sig = None;
177 let mut derived_via = None;
178 let mut signed_message = None;
179 let mut address = None;
180 let mut algo = None;
181
182 while let Some(key) = map.next_key()? {
183 match key {
184 JsonAuthSigField::Sig => {
185 if sig.is_some() {
186 return Err(serde::de::Error::duplicate_field("sig"));
187 }
188 sig = Some(map.next_value()?);
189 }
190 JsonAuthSigField::DerivedVia => {
191 if derived_via.is_some() {
192 return Err(serde::de::Error::duplicate_field("derived_via"));
193 }
194 derived_via = Some(map.next_value()?);
195 }
196 JsonAuthSigField::SignedMessage => {
197 if signed_message.is_some() {
198 return Err(serde::de::Error::duplicate_field("signed_message"));
199 }
200 signed_message = Some(map.next_value()?);
201 }
202 JsonAuthSigField::Address => {
203 if address.is_some() {
204 return Err(serde::de::Error::duplicate_field("address"));
205 }
206 address = Some(map.next_value()?);
207 }
208 JsonAuthSigField::Algo => {
209 if algo.is_some() {
210 return Err(serde::de::Error::duplicate_field("algo"));
211 }
212 algo = map.next_value()?;
213 }
214 }
215 }
216
217 let sig: String = sig.ok_or_else(|| serde::de::Error::missing_field("sig"))?;
218 let derived_via: String =
219 derived_via.ok_or_else(|| serde::de::Error::missing_field("derived_via"))?;
220 let signed_message: String =
221 signed_message.ok_or_else(|| serde::de::Error::missing_field("signed_message"))?;
222 let address: String = address.ok_or_else(|| serde::de::Error::missing_field("address"))?;
223
224 let auth_material_type = JsonAuthSig::determine_auth_material_type(&derived_via, &algo);
226
227 Ok(JsonAuthSig::new_with_type(
228 sig,
229 derived_via,
230 signed_message,
231 address,
232 algo,
233 auth_material_type,
234 None,
235 ))
236 }
237}
238
239#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
241#[serde(rename_all = "camelCase")]
242pub struct AdminAuthSig {
243 pub auth_sig: JsonAuthSig,
245}