nostr_types/nip46/
prebunk.rs1use crate::client::Client;
2use crate::nip46::{BunkerClient, Nip46ConnectionParameters, Nip46Request, Nip46Response};
3use crate::{Error, EventKind, Filter, KeySigner, LockableSigner, PublicKey, RelayUrl, Signer};
4use serde::{Deserialize, Serialize};
5use std::sync::Arc;
6use std::time::Duration;
7use tracing::{event, span, Level};
8
9#[derive(Debug, Serialize, Deserialize)]
12pub struct PreBunkerClient {
13 pub remote_signer_pubkey: PublicKey,
15
16 pub relay_url: RelayUrl,
18
19 pub connect_secret: Option<String>,
21
22 pub local_signer: Arc<KeySigner>,
24
25 pub timeout: Duration,
27}
28
29impl PreBunkerClient {
30 pub fn new(
32 remote_signer_pubkey: PublicKey,
33 relay_url: RelayUrl,
34 connect_secret: Option<String>,
35 new_password: &str,
36 timeout: Duration,
37 ) -> Result<PreBunkerClient, Error> {
38 let local_signer = Arc::new(KeySigner::generate(new_password, 18)?);
39
40 Ok(PreBunkerClient {
41 remote_signer_pubkey,
42 relay_url,
43 connect_secret,
44 local_signer,
45 timeout,
46 })
47 }
48
49 pub fn new_from_url(
54 url: &str,
55 new_password: &str,
56 timeout: Duration,
57 ) -> Result<PreBunkerClient, Error> {
58 let Nip46ConnectionParameters {
59 remote_signer_pubkey,
60 relays,
61 secret,
62 } = Nip46ConnectionParameters::from_str(url)?;
63
64 let local_signer = Arc::new(KeySigner::generate(new_password, 18)?);
65
66 Ok(PreBunkerClient {
67 remote_signer_pubkey,
68 relay_url: relays[0].clone(),
69 connect_secret: secret,
70 local_signer,
71 timeout,
72 })
73 }
74
75 pub fn is_locked(&self) -> bool {
77 self.local_signer.is_locked()
78 }
79
80 pub fn unlock(&mut self, password: &str) -> Result<(), Error> {
82 self.local_signer.unlock(password)
83 }
84
85 pub async fn initialize(&mut self) -> Result<BunkerClient, Error> {
88 let span = span!(Level::DEBUG, "nip46 Prebunk initializing");
89 let _enter = span.enter();
90
91 let client = Client::new(self.relay_url.as_str());
92
93 let connect_response = {
94 let connect_request = {
95 let params = {
96 let mut params = vec![self.remote_signer_pubkey.as_hex_string()];
97 if let Some(secret) = &self.connect_secret {
98 params.push(secret.to_owned());
99 }
100 params
101 };
102
103 Nip46Request::new("connect".to_string(), params)
104 };
105
106 event!(Level::DEBUG, "Calling with connect request event");
107 self.call(&client, connect_request).await?
108 };
109
110 if let Some(error) = connect_response.error {
111 if !error.is_empty() {
112 return Err(Error::Nip46Error(error));
113 }
114 }
115
116 let pubkey_response = {
118 let pubkey_request = {
119 let params = vec![];
120 Nip46Request::new("get_public_key".to_string(), params)
121 };
122
123 event!(Level::DEBUG, "Calling with pubkey request event");
124 self.call(&client, pubkey_request).await?
125 };
126
127 if let Some(error) = pubkey_response.error {
129 if !error.is_empty() {
130 return Err(Error::Nip46Error(error));
131 }
132 }
133
134 let public_key = PublicKey::try_from_hex_string(&pubkey_response.result, true)?;
135
136 Ok(BunkerClient {
137 remote_signer_pubkey: self.remote_signer_pubkey,
138 relay_url: self.relay_url.clone(),
139 local_signer: self.local_signer.clone(),
140 public_key,
141 timeout: self.timeout,
142 client,
143 })
144 }
145
146 async fn call(&self, client: &Client, request: Nip46Request) -> Result<Nip46Response, Error> {
147 let span = span!(Level::DEBUG, "nip46 Prebunk callfn");
148 let _enter = span.enter();
149
150 let event = request
151 .to_event(self.remote_signer_pubkey, self.local_signer.clone())
152 .await?;
153
154 let mut filter = Filter::new();
156 filter.add_author(self.remote_signer_pubkey);
157 filter.add_event_kind(EventKind::NostrConnect);
158 filter.add_tag_value('p', self.local_signer.public_key().as_hex_string());
159 filter.limit = Some(1);
160 event!(
161 Level::DEBUG,
162 "calling client subscribe to subscribe to responses from the remote signer"
163 );
164 let sub_id = client.subscribe(filter.clone(), self.timeout).await?;
165
166 let event_id = event.id;
168 event!(Level::DEBUG, "posting our event");
169 client.post_event(event, self.timeout).await?;
170 event!(Level::DEBUG, "waiting for OK response");
171 let (ok, msg) = client.wait_for_ok(event_id, self.timeout).await?;
172 if !ok {
173 return Err(Error::Nip46FailedToPost(msg));
174 }
175
176 event!(
178 Level::DEBUG,
179 "waiting for a response event on the remote signer subscription"
180 );
181 let event = client
182 .wait_for_subscribed_event(sub_id, self.timeout)
183 .await?;
184 let contents = self.local_signer.decrypt_event_contents(&event).await?;
185
186 let response: Nip46Response = serde_json::from_str(&contents)?;
188
189 Ok(response)
190 }
191}