upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/utils.rs
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2023-05-21 11:18:29 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2023-05-21 11:18:29 +0000
commitfda0fdd81caab1ca92eb7ed601058e6c2fdc59f5 (patch)
treedd91fc1a7b41d02aead655ea2dc07463b3487d5d /src/utils.rs
parent0067804cc00e94ce2b7043e67f9ff50968525479 (diff)
helpers and utilities
Diffstat (limited to 'src/utils.rs')
-rw-r--r--src/utils.rs212
1 files changed, 212 insertions, 0 deletions
diff --git a/src/utils.rs b/src/utils.rs
new file mode 100644
index 0000000..48aafa9
--- /dev/null
+++ b/src/utils.rs
@@ -0,0 +1,212 @@
1use std::fs::File;
2use std::io::{Read, Write};
3use std::path::{Path};
4use std::time::Duration;
5
6use dialoguer::{Select, Input};
7use dialoguer::theme::ColorfulTheme;
8use nostr_sdk::blocking::Client;
9use nostr_sdk::prelude::*;
10
11use crate::config::{MyConfig, save_conifg};
12
13pub fn handle_keys(private_key: Option<String>, hex: bool) -> Result<Keys> {
14 // Parse and validate private key
15 let keys = match private_key {
16 Some(pk) => {
17 // create a new identity using the provided private key
18 Keys::from_sk_str(pk.as_str())?
19 }
20 None => {
21 // create a new identity with a new keypair
22 println!("No private key provided, creating new identity");
23 Keys::generate()
24 }
25 };
26
27 if !hex {
28 println!("Private key: {}", keys.secret_key()?.to_bech32()?);
29 println!("Public key: {}", keys.public_key().to_bech32()?);
30 } else {
31 println!("Private key: {}", keys.secret_key()?.display_secret());
32 println!("Public key: {}", keys.public_key());
33 }
34 Ok(keys)
35}
36
37// Creates the websocket client that is used for communicating with relays
38pub fn create_client(keys: &Keys, relays: Vec<String>) -> Result<Client> {
39 let opts = Options::new()
40 .wait_for_send(true)
41 .timeout(Some(Duration::from_secs(7)));
42 let client = Client::with_opts(keys, opts);
43 let relays = relays.iter().map(|url| (url, None)).collect();
44 client.add_relays(relays)?;
45 client.connect();
46 Ok(client)
47}
48
49// Accepts both hex and bech32 keys and returns the hex encoded key
50pub fn parse_key(key: String) -> Result<String> {
51 // Check if the key is a bech32 encoded key
52 let parsed_key = if key.starts_with("npub") {
53 XOnlyPublicKey::from_bech32(key)?.to_string()
54 } else if key.starts_with("nsec") {
55 SecretKey::from_bech32(key)?.display_secret().to_string()
56 } else if key.starts_with("note") {
57 EventId::from_bech32(key)?.to_hex()
58 } else if key.starts_with("nchannel") {
59 ChannelId::from_bech32(key)?.to_hex()
60 } else {
61 // If the key is not bech32 encoded, return it as is
62 key
63 };
64 Ok(parsed_key)
65}
66
67pub fn get_stored_keys(cfg:&mut MyConfig) -> Option<Keys> {
68 match &cfg.private_key {
69 None => None,
70 Some(k) => Some(Keys::new(*k)),
71 }
72}
73
74pub fn get_or_generate_keys(cfg:&mut MyConfig) -> Keys {
75 match cfg.private_key {
76 None => {
77 let selection = Select::with_theme(&ColorfulTheme::default())
78 .items(&vec!["enter existing private key", "generate new keys"])
79 .default(0)
80 .with_prompt("no keys are stored")
81 .interact().unwrap();
82 let key = match selection {
83 0 => {
84 let mut prompt = "secret key (nsec, hex, etc)";
85 loop {
86 let pk: String = Input::with_theme(&ColorfulTheme::default())
87 .with_prompt(prompt)
88 .interact_text()
89 .unwrap();
90 match Keys::from_sk_str(&pk) {
91 Ok(key) => { break key; },
92 Err(_e) => { prompt = "error interpeting secret key. try again with nsec, hex, etc"; },
93 }
94 }
95
96 }
97 _ => Keys::generate(),
98 };
99 cfg.private_key = Some(key.secret_key().unwrap());
100 save_conifg(&cfg);
101 key
102 }
103 Some(k) => Keys::new(k),
104 }
105}
106
107#[derive(clap::ValueEnum, Clone, Debug)]
108pub enum Prefix {
109 Npub,
110 Nsec,
111 Note,
112 Nchannel,
113}
114
115
116/// [`LoadFile`] error
117#[derive(Debug, thiserror::Error)]
118pub enum Error {
119 /// Error loading event file
120 #[error("cannot load event file.")]
121 // LoadFile(#[from] init::Error),
122 LoadFile(),
123}
124
125pub fn load_file<P: AsRef<Path>>(path: P) -> Result<String,Error> {
126 let mut buf = vec![];
127 match File::open(path) {
128 Ok(mut f) => {
129 f.read_to_end(&mut buf)
130 .expect("read_to_end not to error on file");
131 Ok(
132 std::str::from_utf8(&buf[..])
133 .expect("file contents u8 to convert to str")
134 .to_string(),
135 )
136 },
137 Err(_e) => { Err(Error::LoadFile()) },
138 }
139
140}
141
142pub fn load_event<P: AsRef<Path>>(path: P) -> Result<Event,Error> {
143 if let Ok(mut file) = File::open(path) {
144 let mut buf = vec![];
145 if file.read_to_end(&mut buf).is_ok() {
146 if let Ok(event) = Event::from_json(std::str::from_utf8(&buf[..]).unwrap()) {
147 return Ok(event)
148 }
149 }
150 }
151 Err(Error::LoadFile())
152}
153
154pub fn save_event<P: AsRef<Path>>(path: P, event: &Event) -> Result<()> {
155 let mut f = File::create(path)?;
156 f.write_all(&event.as_json().as_bytes())?;
157 Ok(())
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163
164 #[test]
165 fn test_parse_key_hex_input() {
166 let hex_key =
167 String::from("f4deaad98b61fa24d86ef315f1d5d57c1a6a533e1e87e777e5d0b48dcd332cdb");
168 let result = parse_key(hex_key.clone());
169
170 assert!(result.is_ok());
171 assert_eq!(result.unwrap(), hex_key);
172 }
173
174 #[test]
175 fn test_parse_key_bech32_note_input() {
176 let bech32_note_id =
177 String::from("note1h445ule4je70k7kvddate8kpsh2fd6n77esevww5hmgda2qwssjsw957wk");
178 let result = parse_key(bech32_note_id);
179
180 assert!(result.is_ok());
181 assert_eq!(
182 result.unwrap(),
183 String::from("bd6b4e7f35967cfb7acc6b7abc9ec185d496ea7ef6619639d4bed0dea80e8425")
184 );
185 }
186
187 #[test]
188 fn test_parse_bech32_public_key_input() {
189 let bech32_encoded_key =
190 String::from("npub1ktt8phjnkfmfrsxrgqpztdjuxk3x6psf80xyray0l3c7pyrln49qhkyhz0");
191 let result = parse_key(bech32_encoded_key);
192
193 assert!(result.is_ok());
194 assert_eq!(
195 result.unwrap(),
196 String::from("b2d670de53b27691c0c3400225b65c35a26d06093bcc41f48ffc71e0907f9d4a")
197 );
198 }
199
200 #[test]
201 fn test_parse_bech32_private_key() {
202 let bech32_encoded_key =
203 String::from("nsec1hdeqm0y8vgzuucqv4840h7rlpy4qfu928ulxh3dzj6s2nqupdtzqagtew3");
204 let result = parse_key(bech32_encoded_key);
205
206 assert!(result.is_ok());
207 assert_eq!(
208 result.unwrap(),
209 String::from("bb720dbc876205ce600ca9eafbf87f092a04f0aa3f3e6bc5a296a0a983816ac4")
210 );
211 }
212}