Skip to content

Commit 3da5490

Browse files
committed
signer: add NostrSigner::unwrap_gift_wrap method
Signed-off-by: Yuki Kishimoto <[email protected]>
1 parent bc24daf commit 3da5490

File tree

10 files changed

+88
-11
lines changed

10 files changed

+88
-11
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
* nostr: add `EventBuilder::interest_set` ([Yuki Kishimoto])
4141
* nostr: add `title`, `image` and `description` constructors to `Tag` ([Yuki Kishimoto])
4242
* pool: add `SendOutput` and `SendEventOutput` structs ([Yuki Kishimoto])
43+
* signer: add `NostrSigner::unwrap_gift_wrap` method ([Yuki Kishimoto])
4344
* js(sdk): partially expose `JsRelayPool` ([Yuki Kishimoto])
4445
* book: add some python examples ([RydalWater])
4546

bindings/nostr-ffi/src/nips/nip59.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ pub struct UnwrappedGift {
5454
inner: nip59::UnwrappedGift,
5555
}
5656

57+
impl From<nip59::UnwrappedGift> for UnwrappedGift {
58+
fn from(inner: nostr::prelude::UnwrappedGift) -> Self {
59+
Self { inner }
60+
}
61+
}
62+
5763
#[uniffi::export]
5864
impl UnwrappedGift {
5965
/// Unwrap Gift Wrap event

bindings/nostr-js/src/nips/nip59.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ pub struct JsUnwrappedGift {
1919
inner: UnwrappedGift,
2020
}
2121

22+
impl From<UnwrappedGift> for JsUnwrappedGift {
23+
fn from(inner: UnwrappedGift) -> Self {
24+
Self { inner }
25+
}
26+
}
27+
2228
#[wasm_bindgen(js_class = UnwrappedGift)]
2329
impl JsUnwrappedGift {
2430
/// Unwrap Gift Wrap event

bindings/nostr-sdk-ffi/src/client/signer/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use std::ops::Deref;
66

7+
use nostr_ffi::nips::nip59::UnwrappedGift;
78
use nostr_ffi::{Event, EventBuilder, Keys, PublicKey, UnsignedEvent};
89
use nostr_sdk::signer;
910
use uniffi::Object;
@@ -91,4 +92,13 @@ impl NostrSigner {
9192
pub async fn nip44_decrypt(&self, public_key: &PublicKey, content: String) -> Result<String> {
9293
Ok(self.inner.nip44_decrypt(**public_key, content).await?)
9394
}
95+
96+
/// Unwrap Gift Wrap event
97+
///
98+
/// Internally verify the `seal` event
99+
///
100+
/// <https://github.com/nostr-protocol/nips/blob/master/59.md>
101+
pub async fn unwrap_gift_wrap(&self, gift_wrap: &Event) -> Result<UnwrappedGift> {
102+
Ok(self.inner.unwrap_gift_wrap(gift_wrap.deref()).await?.into())
103+
}
94104
}

bindings/nostr-sdk-js/src/client/signer/mod.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use nostr_js::error::{into_err, Result};
88
use nostr_js::event::{JsEvent, JsEventBuilder, JsUnsignedEvent};
99
use nostr_js::key::{JsKeys, JsPublicKey};
1010
use nostr_js::nips::nip07::JsNip07Signer;
11+
use nostr_js::nips::nip59::JsUnwrappedGift;
1112
use nostr_sdk::NostrSigner;
1213
use wasm_bindgen::prelude::*;
1314

@@ -118,4 +119,19 @@ impl JsNostrSigner {
118119
.await
119120
.map_err(into_err)
120121
}
122+
123+
/// Unwrap Gift Wrap event
124+
///
125+
/// Internally verify the `seal` event
126+
///
127+
/// <https://github.com/nostr-protocol/nips/blob/master/59.md>
128+
#[wasm_bindgen(js_name = unwrapGiftWrap)]
129+
pub async fn unwrap_gift_wrap(&self, gift_wrap: &JsEvent) -> Result<JsUnwrappedGift> {
130+
Ok(self
131+
.inner
132+
.unwrap_gift_wrap(gift_wrap.deref())
133+
.await
134+
.map_err(into_err)?
135+
.into())
136+
}
121137
}

crates/nostr-sdk/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ nip46 = ["nostr/nip46", "nostr-signer/nip46"]
3434
nip47 = ["nostr/nip47", "dep:nwc"]
3535
nip49 = ["nostr/nip49"]
3636
nip57 = ["nostr/nip57", "dep:nostr-zapper", "dep:lnurl-pay"]
37-
nip59 = ["nostr/nip59"]
37+
nip59 = ["nostr/nip59", "nostr-signer/nip59"]
3838

3939
[dependencies]
4040
async-utility.workspace = true

crates/nostr-signer/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@ rust-version.workspace = true
1212
keywords = ["nostr", "signer"]
1313

1414
[features]
15-
default = ["nip04", "nip07", "nip44", "nip46"]
15+
default = ["nip04", "nip07", "nip44", "nip46", "nip59"]
1616
nip04 = ["nostr/nip04"]
1717
nip07 = ["nostr/nip07"]
1818
nip44 = ["nostr/nip44"]
1919
nip46 = ["nostr/nip46", "dep:nostr-relay-pool", "dep:tracing"]
20+
nip59 = ["nostr/nip59"]
2021

2122
[dependencies]
2223
async-utility.workspace = true

crates/nostr-signer/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ The following crate feature flags are available:
1212
| `nip07` | Yes | Enable NIP-07: `window.nostr` capability for web browsers (**available only for `wasm32`!**) |
1313
| `nip44` | Yes | Enable NIP-44: Encrypted Payloads (Versioned) |
1414
| `nip46` | Yes | Enable NIP-46: Nostr Connect |
15+
| `nip59` | Yes | Enable NIP-59: Gift Wrap |
1516

1617
## State
1718

crates/nostr-signer/src/lib.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
use std::fmt;
1212

13-
use nostr::key;
1413
use nostr::prelude::*;
1514
use thiserror::Error;
1615

@@ -46,6 +45,14 @@ pub enum Error {
4645
#[cfg(feature = "nip46")]
4746
#[error(transparent)]
4847
NIP46(#[from] nip46::Error),
48+
/// NIP59 error
49+
#[cfg(feature = "nip59")]
50+
#[error(transparent)]
51+
NIP59(#[from] nip59::Error),
52+
/// Event error
53+
#[cfg(feature = "nip59")]
54+
#[error(transparent)]
55+
Event(#[from] event::Error),
4956
}
5057

5158
/// Nostr Signer Type
@@ -217,6 +224,35 @@ impl NostrSigner {
217224
Self::NIP46(signer) => Ok(signer.nip44_decrypt(public_key, payload).await?),
218225
}
219226
}
227+
228+
/// Unwrap Gift Wrap event
229+
///
230+
/// Internally verify the `seal` event
231+
///
232+
/// <https://github.com/nostr-protocol/nips/blob/master/59.md>
233+
// TODO: find a way to merge this with the `Keys` implementation in `nostr` crate
234+
#[cfg(feature = "nip59")]
235+
pub async fn unwrap_gift_wrap(&self, gift_wrap: &Event) -> Result<UnwrappedGift, Error> {
236+
// Check event kind
237+
if gift_wrap.kind != Kind::GiftWrap {
238+
return Err(Error::NIP59(nip59::Error::NotGiftWrap));
239+
}
240+
241+
// Decrypt and verify seal
242+
let seal: String = self
243+
.nip44_decrypt(gift_wrap.author(), gift_wrap.content())
244+
.await?;
245+
let seal: Event = Event::from_json(seal)?;
246+
seal.verify()?;
247+
248+
// Decrypt rumor
249+
let rumor: String = self.nip44_decrypt(seal.author(), seal.content()).await?;
250+
251+
Ok(UnwrappedGift {
252+
sender: seal.author(),
253+
rumor: UnsignedEvent::from_json(rumor)?,
254+
})
255+
}
220256
}
221257

222258
impl From<Keys> for NostrSigner {

crates/nostr/src/prelude.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ pub use negentropy::Negentropy;
1717
pub use serde_json::Value;
1818

1919
// Internal modules
20-
pub use crate::event::builder::*;
21-
pub use crate::event::id::*;
22-
pub use crate::event::kind::*;
23-
pub use crate::event::tag::*;
24-
pub use crate::event::unsigned::*;
25-
pub use crate::event::*;
26-
pub use crate::key::*;
27-
pub use crate::message::*;
20+
pub use crate::event::builder::{self, *};
21+
pub use crate::event::id::{self, *};
22+
pub use crate::event::kind::{self, *};
23+
pub use crate::event::tag::{self, *};
24+
pub use crate::event::unsigned::{self, *};
25+
pub use crate::event::{self, *};
26+
pub use crate::key::{self, *};
27+
pub use crate::message::{self, *};
2828
// NIPs
2929
pub use crate::nips::nip01::{self, *};
3030
#[cfg(feature = "nip04")]

0 commit comments

Comments
 (0)