1use crate::{
2 json_rpc::{
3 JsonRpcError, JsonRpcErrorCode, JsonRpcRequest, JsonRpcResponse, JsonRpcResponseData,
4 SingleOrBatch,
5 },
6 stream_helper::map_sender,
7 KeyManager, Nip55Client, Nip55ServerStream, UdsClientError,
8};
9use futures::StreamExt;
10use nostr_sdk::{nips::nip46, Keys, PublicKey};
11use nostr_sdk::{Kind, SecretKey};
12use serde_json::Value;
13use std::{
14 pin::Pin,
15 sync::Arc,
16 task::{Context, Poll},
17};
18
19pub struct Nip46OverNip55Client {
21 client: Nip55Client,
22}
23
24impl Nip46OverNip55Client {
25 pub fn new(uds_address: impl Into<String>) -> Self {
27 Self {
28 client: Nip55Client::new(uds_address),
29 }
30 }
31
32 pub async fn sign_event(
34 &self,
35 unsigned_event: nostr_sdk::UnsignedEvent,
36 user_pubkey: PublicKey,
37 ) -> Result<nostr_sdk::Event, Nip46OverNip55ClientError> {
38 let request = nip46::Request::SignEvent(unsigned_event);
39 let response = self.send_request(&request, user_pubkey).await?;
40 match response {
41 nip46::ResponseResult::SignEvent(signed_event) => Ok(*signed_event),
42 _ => Err(Nip46OverNip55ClientError::UdsClientError(
43 UdsClientError::MalformedResponse(anyhow::anyhow!(
44 "Expected SignEvent response, but got {:?}",
45 response
46 )),
47 )),
48 }
49 }
50
51 async fn send_request(
52 &self,
53 request: &nip46::Request,
54 user_pubkey: PublicKey,
55 ) -> Result<nip46::ResponseResult, Nip46OverNip55ClientError> {
56 let json_rpc_request = request.try_into().map_err(|_| {
57 Nip46OverNip55ClientError::UdsClientError(UdsClientError::RequestSerializationError)
58 })?;
59
60 let SingleOrBatch::Single(response) = self
61 .client
62 .send_request(
63 Kind::NostrConnect,
64 &SingleOrBatch::Single(json_rpc_request),
65 user_pubkey,
66 )
67 .await
68 .map_err(Nip46OverNip55ClientError::UdsClientError)?
69 else {
70 return Err(Nip46OverNip55ClientError::UdsClientError(
71 UdsClientError::MalformedResponse(anyhow::anyhow!(
72 "Expected single response, but got batch response"
73 )),
74 ));
75 };
76
77 if let JsonRpcResponseData::Error { error } = response.data() {
78 return Err(Nip46OverNip55ClientError::JsonRpcError(error.clone()));
79 }
80
81 (&response).try_into().map_err(|e| {
82 Nip46OverNip55ClientError::UdsClientError(UdsClientError::MalformedResponse(e))
83 })
84 }
85}
86
87#[derive(Debug)]
89pub enum Nip46OverNip55ClientError {
90 UdsClientError(UdsClientError),
92
93 JsonRpcError(JsonRpcError),
95}
96
97pub struct Nip46OverNip55ServerStream {
98 #[allow(clippy::type_complexity)]
99 stream: Pin<
100 Box<
101 dyn futures::Stream<
102 Item = (
103 (Vec<nip46::Request>, PublicKey),
104 futures::channel::oneshot::Sender<Nip46RequestApproval>,
105 ),
106 > + Send,
107 >,
108 >,
109}
110
111impl futures::Stream for Nip46OverNip55ServerStream {
112 type Item = (
113 Vec<nip46::Request>,
114 PublicKey,
115 futures::channel::oneshot::Sender<Nip46RequestApproval>,
116 );
117
118 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
119 self.stream.poll_next_unpin(cx).map(|next_item_or| {
120 next_item_or.map(|next_item| (next_item.0 .0, next_item.0 .1, next_item.1))
121 })
122 }
123}
124
125impl Nip46OverNip55ServerStream {
126 pub fn start(
128 uds_address: impl Into<String>,
129 key_manager: Arc<dyn KeyManager>,
130 ) -> std::io::Result<Self> {
131 Ok(Self {
132 stream: Box::pin(
133 Nip55ServerStream::start::<(SingleOrBatch<JsonRpcRequest>, SecretKey)>(
134 uds_address,
135 key_manager,
136 )?
137 .map(|(request, secret_key, response_sender)| {
138 (
139 match request.clone() {
140 SingleOrBatch::Single(request) =>
141 {
144 handle_request_array((vec![request], secret_key.clone()))
145 }
146
147 SingleOrBatch::Batch(requests) =>
148 {
150 handle_request_array((requests, secret_key.clone()))
151 }
152 },
153 map_sender(response_sender, move |nip_46_request_approval| {
154 match nip_46_request_approval {
155 Nip46RequestApproval::Approve => request.map(|json_rpc_request| {
156 let (nip46_request, id): (nip46::Request, String) =
157 (&json_rpc_request).try_into().unwrap();
158
159 let nip46_response = match nip46_request {
160 nip46::Request::SignEvent(unsigned_event) => {
161 nip46::ResponseResult::SignEvent(Box::from(
162 unsigned_event
163 .sign(&Keys::new(secret_key.clone()))
164 .unwrap(),
165 ))
166 }
167 _ => {
169 return JsonRpcResponseData::Error {
170 error: JsonRpcError::new(
171 JsonRpcErrorCode::MethodNotFound,
172 "Method not implemented".to_string(),
173 None,
174 ),
175 };
176 }
177 };
178
179 (&nip46_response, &id).try_into().unwrap()
180 }),
181 Nip46RequestApproval::Reject => {
182 request.map(|_| JsonRpcResponseData::Error {
183 error: JsonRpcError::new(
184 JsonRpcErrorCode::InternalError,
185 "Batch request rejected".to_string(),
186 None,
187 ),
188 })
189 }
190 }
191 }),
192 )
193 }),
194 ),
195 })
196 }
197}
198
199#[derive(Debug, Clone, Copy, PartialEq, Eq)]
201pub enum Nip46RequestApproval {
202 Approve,
203 Reject,
204}
205
206fn handle_request_array(
207 requests: (Vec<JsonRpcRequest>, SecretKey),
208) -> (Vec<nostr_sdk::nips::nip46::Request>, PublicKey) {
209 let nip46_requests: Vec<nostr_sdk::nips::nip46::Request> = requests
210 .0
211 .into_iter()
212 .filter_map(|request| (&request).try_into().ok())
213 .map(|(nip46_request, _nip46_request_id)| nip46_request)
214 .collect();
215
216 let secp = nostr_sdk::secp256k1::Secp256k1::new();
217
218 let public_key: PublicKey = requests.1.x_only_public_key(&secp).0.into();
219
220 (nip46_requests, public_key)
221}
222
223impl TryInto<JsonRpcRequest> for &nip46::Request {
224 type Error = anyhow::Error;
225
226 fn try_into(self) -> Result<JsonRpcRequest, Self::Error> {
227 let object_json = match serde_json::json!(nip46::Message::request(self.clone())) {
229 Value::Object(mut object) => {
230 object.insert("jsonrpc".to_string(), "2.0".into());
231 object
232 }
233 _ => {
234 return Err(anyhow::anyhow!(
235 "Failed to convert NIP-46 request to JSON-RPC request"
236 ));
237 }
238 };
239
240 Ok(serde_json::from_value(Value::Object(object_json))?)
241 }
242}
243
244impl TryFrom<&JsonRpcRequest> for (nip46::Request, String) {
245 type Error = anyhow::Error;
246
247 fn try_from(value: &JsonRpcRequest) -> Result<Self, Self::Error> {
248 let message: nip46::Message = serde_json::from_value(serde_json::json!(value))?;
249 let request_id = message.id().to_string();
250 Ok((message.to_request()?, request_id))
251 }
252}
253
254impl TryInto<JsonRpcResponseData> for (&nip46::ResponseResult, &String) {
255 type Error = anyhow::Error;
256
257 fn try_into(self) -> Result<JsonRpcResponseData, anyhow::Error> {
258 Ok(serde_json::from_value(serde_json::json!(
260 nip46::Message::response(self.1, Some(self.0.clone()), None)
261 ))?)
262 }
263}
264
265impl TryFrom<&JsonRpcResponse> for nip46::ResponseResult {
266 type Error = anyhow::Error;
267
268 fn try_from(value: &JsonRpcResponse) -> Result<Self, anyhow::Error> {
269 let message: nip46::Message = serde_json::from_value(serde_json::json!(value))?;
270 match message {
271 nip46::Message::Response { result, error, .. } => match (result, error) {
272 (Some(result), None) => Ok(result),
273 (None, Some(error)) => Err(anyhow::anyhow!(error)),
274 _ => Err(anyhow::anyhow!("Invalid NIP-46 response")),
275 },
276 nip46::Message::Request { .. } => Err(anyhow::anyhow!("Invalid NIP-46 response")),
277 }
278 }
279}
280
281#[cfg(test)]
283mod tests {
284 use super::*;
285 use crate::KeyManager;
286 use async_trait::async_trait;
287 use nostr_sdk::Keys;
288 use std::collections::HashMap;
289 use std::sync::Arc;
290 use std::sync::Mutex;
291
292 fn get_random_uds_address() -> String {
293 format!("/tmp/test-{}.sock", uuid::Uuid::new_v4())
294 }
295
296 struct MockKeyManager {
297 keys: Arc<Mutex<HashMap<PublicKey, SecretKey>>>,
298 }
299
300 impl Default for MockKeyManager {
301 fn default() -> Self {
302 Self {
303 keys: Arc::new(Mutex::new(HashMap::new())),
304 }
305 }
306 }
307
308 #[async_trait]
309 impl KeyManager for MockKeyManager {
310 fn get_secret_key(&self, public_key: &PublicKey) -> Option<SecretKey> {
311 self.keys.lock().unwrap().get(public_key).cloned()
312 }
313 }
314
315 impl MockKeyManager {
316 fn new() -> Self {
317 Self::default()
318 }
319
320 fn new_with_single_key(secret_key: SecretKey) -> Self {
321 let key_manager = Self::new();
322 key_manager.add_key(secret_key);
323 key_manager
324 }
325
326 fn add_key(&self, secret_key: SecretKey) {
327 self.keys.lock().unwrap().insert(
328 PublicKey::from(
329 secret_key
330 .x_only_public_key(&nostr_sdk::secp256k1::Secp256k1::new())
331 .0,
332 ),
333 secret_key,
334 );
335 }
336 }
337
338 #[tokio::test]
339 async fn test_nip46_over_nip55_registered_key() {
340 let keypair = Keys::generate();
341 let key_manager = MockKeyManager::new_with_single_key(keypair.secret_key().clone());
342
343 let (server_started_sender, server_started_receiver) = futures::channel::oneshot::channel();
345
346 let uds_address = get_random_uds_address();
347 let uds_address_clone = uds_address.clone();
348
349 let server_handle = tokio::task::spawn(async {
350 let mut foo =
351 Nip46OverNip55ServerStream::start(uds_address_clone, Arc::new(key_manager))
352 .expect("Failed to start NIP-46 over NIP-55 server");
353
354 server_started_sender.send(()).unwrap();
355
356 while let Some((_request_list, _public_key, response_sender)) = foo.next().await {
357 response_sender.send(Nip46RequestApproval::Approve).unwrap();
358 }
359 });
360
361 server_started_receiver.await.unwrap();
362
363 let client = Nip46OverNip55Client::new(uds_address);
364
365 for _ in 0..10 {
367 let unsigned_event = nostr_sdk::EventBuilder::new(Kind::TextNote, "example text", None)
368 .to_unsigned_event(keypair.public_key());
369
370 let signed_event = client
371 .sign_event(unsigned_event, keypair.public_key())
372 .await
373 .expect("Failed to send NIP-46 request");
374
375 signed_event
376 .verify()
377 .expect("Failed to verify signed event");
378 assert_eq!(signed_event.kind, Kind::TextNote);
379 assert_eq!(signed_event.content, "example text");
380 }
381
382 server_handle.abort();
383 }
384
385 #[tokio::test]
386 async fn test_nip46_over_nip55_unregistered_key() {
387 let key_manager = MockKeyManager::new();
388
389 let (server_started_sender, server_started_receiver) = futures::channel::oneshot::channel();
391
392 let uds_address = get_random_uds_address();
393 let uds_address_clone = uds_address.clone();
394
395 let server_handle = tokio::task::spawn(async {
396 let mut foo =
397 Nip46OverNip55ServerStream::start(uds_address_clone, Arc::new(key_manager))
398 .expect("Failed to start NIP-46 over NIP-55 server");
399
400 server_started_sender.send(()).unwrap();
401
402 while let Some((_request_list, _public_key, response_sender)) = foo.next().await {
403 response_sender.send(Nip46RequestApproval::Approve).unwrap();
404 }
405 });
406
407 server_started_receiver.await.unwrap();
408
409 let client = Nip46OverNip55Client::new(uds_address);
410
411 for _ in 0..10 {
413 let unregistered_keypair = Keys::generate();
414
415 let unsigned_event = nostr_sdk::EventBuilder::new(Kind::TextNote, "example text", None)
416 .to_unsigned_event(unregistered_keypair.public_key());
417
418 let signed_event_error = client
419 .sign_event(unsigned_event.clone(), unregistered_keypair.public_key())
420 .await
421 .unwrap_err();
422
423 assert!(matches!(
424 signed_event_error,
425 Nip46OverNip55ClientError::UdsClientError(UdsClientError::MalformedResponse(_))
426 ));
427 }
428
429 server_handle.abort();
430 }
431
432 #[tokio::test]
433 async fn test_nip46_over_nip55_no_server() {
434 let keypair = Keys::generate();
435
436 let client = Nip46OverNip55Client::new(get_random_uds_address());
437
438 let unsigned_event = nostr_sdk::EventBuilder::new(Kind::TextNote, "example text", None)
439 .to_unsigned_event(keypair.public_key());
440
441 assert!(matches!(
442 client
443 .sign_event(unsigned_event, keypair.public_key())
444 .await,
445 Err(Nip46OverNip55ClientError::UdsClientError(
446 UdsClientError::ServerNotRunning
447 ))
448 ));
449 }
450}