1use secp256k1::Secp256k1;
2use std::str::FromStr;
3
4use log::debug;
5use serde::{Deserialize, Serialize};
6use std::fmt::Write;
7
8#[derive(Serialize, Deserialize)]
9pub struct Message {
10 pub msg_type: String,
11 pub subscription_id: String,
12 pub content: Event,
13}
14
15pub struct EventNonSigned {
18 pub created_at: u64,
19 pub kind: u64,
20 pub tags: Vec<Vec<String>>,
21 pub content: String,
22}
23
24impl EventNonSigned {
25 pub fn sign(self, keypair: &secp256k1::KeyPair) -> Event {
27 Event::new(keypair, self.created_at, self.kind, self.tags, self.content)
28 }
29}
30
31#[derive(Serialize, Deserialize)]
34pub struct Event {
35 pub id: String,
36 pub pubkey: String,
37 pub created_at: u64,
38 pub kind: u64,
39 pub tags: Vec<Vec<String>>,
40 pub content: String,
41 pub sig: String,
42}
43
44impl Event {
45 pub fn new(
47 keypair: &secp256k1::KeyPair,
48 created_at: u64,
49 kind: u64,
50 tags: Vec<Vec<String>>,
51 content: String,
52 ) -> Self {
53 let content = escape(content);
54
55 let secp = Secp256k1::new();
56
57 let (pubkey, _parity) = keypair.x_only_public_key();
58
59 let id = Self::get_id(pubkey, created_at, kind, &tags, &content);
60 let signature = secp.sign_schnorr(&id, keypair);
61
62 Event {
63 id: id.to_string(),
64 pubkey: pubkey.to_string(),
65 created_at,
66 kind,
67 content,
68 sig: signature.to_string(),
69 tags,
70 }
71 }
72
73 pub fn format(&self) -> String {
75 format!(
76 r#"["EVENT",{{"id": "{}", "pubkey": "{}", "created_at": {}, "kind": {}, "tags": [{}], "content": "{}", "sig": "{}"}}]"#,
77 self.id,
78 self.pubkey,
79 self.created_at,
80 self.kind,
81 Self::format_tags(&self.tags),
82 &self.content,
83 self.sig
84 )
85 }
86
87 pub fn has_valid_sig(&self) -> bool {
89 let secp = secp256k1::Secp256k1::verification_only();
90 let pubkey = match secp256k1::XOnlyPublicKey::from_str(&self.pubkey) {
92 Ok(pubkey) => pubkey,
93 Err(_) => return false,
94 };
95
96 let signature = match secp256k1::schnorr::Signature::from_str(&self.sig) {
97 Ok(signature) => signature,
98 Err(_) => return false,
99 };
100
101 let message = Event::get_id(
102 pubkey,
103 self.created_at,
104 self.kind,
105 &self.tags,
106 &self.content,
107 );
108
109 if message.to_string() != self.id {
110 return false;
111 }
112
113 secp.verify_schnorr(&signature, &message, &pubkey).is_ok()
114 }
115
116 fn format_tags(tags: &Vec<Vec<String>>) -> String {
117 let mut formatted = String::new();
118
119 for i in 0..tags.len() {
120 let tag = &tags[i];
121 write!(formatted, r#"["{}"]"#, tag.join(r#"",""#)).unwrap();
122 if i + 1 < tags.len() {
123 formatted.push(',');
124 }
125 }
126 formatted
127 }
128
129 fn get_id(
130 pubkey: secp256k1::XOnlyPublicKey,
131 created_at: u64,
132 kind: u64,
133 tags: &Vec<Vec<String>>,
134 content: &String,
135 ) -> secp256k1::Message {
136 let formatted_tags = Self::format_tags(tags);
137
138 let msg = format!(r#"[0,"{pubkey}",{created_at},{kind},[{formatted_tags}],"{content}"]"#);
139 secp256k1::Message::from_hashed_data::<secp256k1::hashes::sha256::Hash>(msg.as_bytes())
140 }
141}
142
143pub fn tags_for_reply(event: Event) -> Vec<Vec<String>> {
148 let mut e_tags = vec![];
149 let mut p_tags = vec![];
150
151 for t in event.tags {
152 if t[0] == "e" {
153 e_tags.push(t);
154 } else if t[0] == "p" {
155 p_tags.push(t);
156 }
157 }
158
159 let mut tags = vec![vec!["p".to_string(), event.pubkey]];
161
162 if !e_tags.is_empty() {
164 tags.push(e_tags[0].clone());
165 }
166 tags.push(vec!["e".to_string(), event.id]);
167
168 debug!("Returning these tags: {:?}", tags);
169 tags
170}
171
172pub fn get_profile_event(
173 name: Option<String>,
174 about: Option<String>,
175 picture_url: Option<String>,
176) -> EventNonSigned {
177 let name = if let Some(name) = name {
178 name
179 } else {
180 "".to_string()
181 };
182 let about = if let Some(about) = about {
183 about
184 } else {
185 "".to_string()
186 };
187 let picture_url = if let Some(picture_url) = picture_url {
188 picture_url
189 } else {
190 "".to_string()
191 };
192
193 EventNonSigned {
194 created_at: crate::utils::unix_timestamp(),
195 kind: 0,
196 tags: vec![],
197 content: format!(
198 r#"{{"name":"{}","about":"{}","picture":"{}"}}"#,
199 name,
200 escape(about),
201 escape(picture_url)
202 ),
203 }
204}
205
206pub fn get_reply(reply_to: Event, content: String) -> EventNonSigned {
208 EventNonSigned {
209 content,
210 created_at: crate::utils::unix_timestamp(),
211 kind: 1,
212 tags: tags_for_reply(reply_to),
213 }
214}
215
216fn escape(text: String) -> String {
217 let mut escaped = String::new();
219 for c in text.chars() {
220 match c {
221 '"' => escaped.push_str("\\\""),
222 '\\' => escaped.push_str("\\\\"),
223 '\n' => escaped.push_str("\\n"),
224 '\r' => escaped.push_str("\\r"),
225 '\t' => escaped.push_str("\\t"),
226 _ => escaped.push(c),
227 }
228 }
229
230 escaped
231}
232
233#[cfg(test)]
234mod tests {
235 use super::*;
236 const TEST_SECRET: &str = "67c497012395ded1448b06f4bc55abaa74e1fe8d60c3f635c980547171fb24f9";
237
238 const NOPE_SIG: &str = "af372c8cb342d27d0c2363040b676aa7d68a0d028f09e73b567675f1beb15c29f07c970c7b65e3451f4fcc31e9c855534ad3d4e1a3af0d6bcdbab85c340df8bd";
241
242 fn test_keypair(secret: &str) -> secp256k1::KeyPair {
243 let secp = secp256k1::Secp256k1::new();
244 secp256k1::KeyPair::from_seckey_str(&secp, secret).unwrap()
245 }
246
247 fn get_test_event(keypair: secp256k1::KeyPair) -> Event {
248 Event::new(
249 &keypair,
250 1660656918,
251 1,
252 vec![
253 vec![
254 "e".to_string(),
255 "012df9baa5377d7f2b29922249fe36e2fde5daab3060342b93235c9b6db444dc".to_string(),
256 ],
257 vec![
258 "p".to_string(),
259 "8b5a3bd6143fc0ad19c80886628097140b8dafd7adc1302444dff8d8645540f8".to_string(),
260 ],
261 vec!["random_tag".to_string(), "just testing here".to_string()],
262 ],
263 "Testing nostr-bot.".to_string(),
264 )
265 }
266
267 #[test]
268 fn new_event() {
269 let keypair = test_keypair(TEST_SECRET);
270 let event = get_test_event(keypair);
271
272 assert_eq!(
274 event.id,
275 "90ce185727fed0c5695e9e20d9c2130bd1d4b8776078016423420d6110d353fe"
276 );
277
278 let signature = secp256k1::schnorr::Signature::from_str(&event.sig).unwrap();
279 let (x_only_public_key, _parity) = keypair.x_only_public_key();
280 let message = Event::get_id(
281 x_only_public_key,
282 event.created_at,
283 event.kind,
284 &event.tags,
285 &event.content,
286 );
287
288 assert_eq!(message.to_string(), event.id);
290
291 let secp = secp256k1::Secp256k1::verification_only();
293 assert!(secp
294 .verify_schnorr(&signature, &message, &x_only_public_key)
295 .is_ok());
296
297 let mut event = event;
299 event.sig = NOPE_SIG.to_string();
300 let signature = secp256k1::schnorr::Signature::from_str(&event.sig).unwrap();
301
302 assert!(secp
304 .verify_schnorr(&signature, &message, &x_only_public_key)
305 .is_err());
306 }
307
308 #[test]
309 fn valid_event() {
310 let keypair = test_keypair(TEST_SECRET);
311 let event = get_test_event(keypair);
312
313 assert!(event.has_valid_sig());
314
315 let mut event = get_test_event(keypair);
317 event.sig = NOPE_SIG.to_string();
318 assert!(!event.has_valid_sig());
319
320 let mut event = get_test_event(keypair);
325 event.id = "9892364de48ac0e02cf2fc3c4ddb58f29721bd0024db06495a8f9396710dbe36".to_string();
326 assert!(!event.has_valid_sig());
327
328 let mut event = get_test_event(keypair);
329 event.created_at = 123456789;
330 assert!(!event.has_valid_sig());
331
332 let mut event = get_test_event(keypair);
334 event.tags = vec![vec!["random_tag".to_string(), "hohoho".to_string()]];
335 assert!(!event.has_valid_sig());
336
337 let mut event = get_test_event(keypair);
339 event.tags = vec![vec!["random_tag".to_string(), "hohoho".to_string()]];
340 assert!(!event.has_valid_sig());
341
342 let mut event = get_test_event(keypair);
344 event.content = "Difference content".to_string();
345 assert!(!event.has_valid_sig());
346 }
347}