1use std::fmt;
6use std::str::FromStr;
7
8use serde::de::{self, Deserializer, SeqAccess, Visitor};
9use serde::ser::SerializeTuple;
10use serde::{Deserialize, Serialize, Serializer};
11use thiserror::Error;
12
13#[derive(Debug, Error)]
15pub enum Error {
16 #[error(transparent)]
18 Secret(#[from] crate::secret::Error),
19 #[error(transparent)]
21 SerdeJsonError(#[from] serde_json::Error),
22}
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
26pub enum Kind {
27 P2PK,
29 HTLC,
31}
32
33#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
35pub struct SecretData {
36 nonce: String,
38 data: String,
40 #[serde(skip_serializing_if = "Option::is_none")]
42 tags: Option<Vec<Vec<String>>>,
43}
44
45impl SecretData {
46 pub fn new<S, V>(data: S, tags: Option<V>) -> Self
48 where
49 S: Into<String>,
50 V: Into<Vec<Vec<String>>>,
51 {
52 let nonce = crate::secret::Secret::generate().to_string();
53
54 Self {
55 nonce,
56 data: data.into(),
57 tags: tags.map(|v| v.into()),
58 }
59 }
60
61 pub fn nonce(&self) -> &str {
63 &self.nonce
64 }
65
66 pub fn data(&self) -> &str {
68 &self.data
69 }
70
71 pub fn tags(&self) -> Option<&Vec<Vec<String>>> {
73 self.tags.as_ref()
74 }
75}
76
77#[derive(Debug, Clone, PartialEq, Eq, Hash)]
79pub struct Secret {
80 kind: Kind,
82 secret_data: SecretData,
84}
85
86impl Secret {
87 pub fn new<S, V>(kind: Kind, data: S, tags: Option<V>) -> Self
89 where
90 S: Into<String>,
91 V: Into<Vec<Vec<String>>>,
92 {
93 let secret_data = SecretData::new(data, tags);
94 Self { kind, secret_data }
95 }
96
97 pub fn kind(&self) -> Kind {
99 self.kind
100 }
101
102 pub fn secret_data(&self) -> &SecretData {
104 &self.secret_data
105 }
106}
107
108impl Serialize for Secret {
109 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
110 where
111 S: Serializer,
112 {
113 let secret_tuple = (&self.kind, &self.secret_data);
115
116 let mut s = serializer.serialize_tuple(2)?;
118
119 s.serialize_element(&secret_tuple.0)?;
120 s.serialize_element(&secret_tuple.1)?;
121 s.end()
122 }
123}
124
125impl TryFrom<Secret> for crate::secret::Secret {
126 type Error = Error;
127 fn try_from(secret: Secret) -> Result<crate::secret::Secret, Self::Error> {
128 Ok(crate::secret::Secret::from_str(&serde_json::to_string(
129 &secret,
130 )?)?)
131 }
132}
133
134struct SecretVisitor;
136
137impl<'de> Visitor<'de> for SecretVisitor {
138 type Value = Secret;
139
140 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
141 formatter.write_str("a tuple with two elements: [Kind, SecretData]")
142 }
143
144 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
145 where
146 A: SeqAccess<'de>,
147 {
148 let kind = seq
150 .next_element()?
151 .ok_or_else(|| de::Error::invalid_length(0, &self))?;
152
153 let secret_data = seq
155 .next_element()?
156 .ok_or_else(|| de::Error::invalid_length(1, &self))?;
157
158 if seq.next_element::<serde::de::IgnoredAny>()?.is_some() {
160 return Err(de::Error::invalid_length(3, &self));
161 }
162
163 Ok(Secret { kind, secret_data })
164 }
165}
166
167impl<'de> Deserialize<'de> for Secret {
168 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
169 where
170 D: Deserializer<'de>,
171 {
172 deserializer.deserialize_seq(SecretVisitor)
173 }
174}
175
176#[cfg(test)]
177mod tests {
178 use std::assert_eq;
179 use std::str::FromStr;
180
181 use super::*;
182
183 #[test]
184 fn test_secret_serialize() {
185 let secret = Secret {
186 kind: Kind::P2PK,
187 secret_data: SecretData {
188 nonce: "5d11913ee0f92fefdc82a6764fd2457a".to_string(),
189 data: "026562efcfadc8e86d44da6a8adf80633d974302e62c850774db1fb36ff4cc7198"
190 .to_string(),
191 tags: Some(vec![vec![
192 "key".to_string(),
193 "value1".to_string(),
194 "value2".to_string(),
195 ]]),
196 },
197 };
198
199 let secret_str = r#"["P2PK",{"nonce":"5d11913ee0f92fefdc82a6764fd2457a","data":"026562efcfadc8e86d44da6a8adf80633d974302e62c850774db1fb36ff4cc7198","tags":[["key","value1","value2"]]}]"#;
200
201 assert_eq!(serde_json::to_string(&secret).unwrap(), secret_str);
202 }
203
204 #[test]
205 fn test_secret_round_trip_serialization() {
206 let original_secret = Secret {
208 kind: Kind::P2PK,
209 secret_data: SecretData {
210 nonce: "5d11913ee0f92fefdc82a6764fd2457a".to_string(),
211 data: "026562efcfadc8e86d44da6a8adf80633d974302e62c850774db1fb36ff4cc7198"
212 .to_string(),
213 tags: None,
214 },
215 };
216
217 let serialized = serde_json::to_string(&original_secret).unwrap();
219
220 let deserialized_secret: Secret = serde_json::from_str(&serialized).unwrap();
222
223 assert_eq!(original_secret, deserialized_secret);
225
226 let cashu_secret = crate::secret::Secret::from_str(&serialized).unwrap();
228 let deserialized_from_cashu: Secret = TryFrom::try_from(&cashu_secret).unwrap();
229 assert_eq!(original_secret, deserialized_from_cashu);
230 }
231
232 #[test]
233 fn test_htlc_secret_round_trip() {
234 let payment_hash = "5c23fc3aec9d985bd5fc88ca8bceaccc52cf892715dd94b42b84f1b43350751e";
239
240 let original_secret = Secret {
242 kind: Kind::HTLC,
243 secret_data: SecretData {
244 nonce: "7a9128b3f9612549f9278958337a5d7f".to_string(),
245 data: payment_hash.to_string(),
246 tags: None,
247 },
248 };
249
250 let serialized = serde_json::to_string(&original_secret).unwrap();
252
253 let expected_json = format!(
255 r#"["HTLC",{{"nonce":"7a9128b3f9612549f9278958337a5d7f","data":"{}"}}]"#,
256 payment_hash
257 );
258 assert_eq!(serialized, expected_json);
259
260 let deserialized_secret: Secret = serde_json::from_str(&serialized).unwrap();
262
263 assert_eq!(original_secret, deserialized_secret);
265 assert_eq!(deserialized_secret.kind, Kind::HTLC);
266 assert_eq!(deserialized_secret.secret_data.data, payment_hash);
267 }
268}