Skip to content

Commit

Permalink
nostr: add NostrSigner::backend
Browse files Browse the repository at this point in the history
Closes rust-nostr#617

Signed-off-by: Yuki Kishimoto <[email protected]>
  • Loading branch information
yukibtc committed Nov 13, 2024
1 parent 5ea4eb1 commit a252976
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 5 deletions.
6 changes: 5 additions & 1 deletion bindings/nostr-sdk-ffi/src/connect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use uniffi::Object;

use crate::error::Result;
use crate::protocol::nips::nip46::{Nip46Request, NostrConnectURI};
use crate::protocol::signer::NostrSigner;
use crate::protocol::signer::{NostrSigner, SignerBackend};
use crate::protocol::{Event, Keys, PublicKey, SecretKey, UnsignedEvent};
use crate::relay::RelayOptions;

Expand Down Expand Up @@ -74,6 +74,10 @@ impl NostrConnect {
#[uniffi::export]
#[async_trait::async_trait]
impl NostrSigner for NostrConnect {
fn backend(&self) -> SignerBackend {
self.inner.backend().into()
}

async fn get_public_key(&self) -> Result<Option<Arc<PublicKey>>> {
Ok(Some(Arc::new(self.inner.get_public_key().await?.into())))
}
Expand Down
6 changes: 5 additions & 1 deletion bindings/nostr-sdk-ffi/src/protocol/key/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ mod secret_key;

pub use self::public_key::PublicKey;
pub use self::secret_key::SecretKey;
use super::signer::{NostrSigner, SignerBackend};
use crate::error::Result;
use crate::protocol::signer::NostrSigner;
use crate::protocol::{Event, UnsignedEvent};

/// Nostr keys
Expand Down Expand Up @@ -117,6 +117,10 @@ impl Keys {
#[uniffi::export]
#[async_trait::async_trait]
impl NostrSigner for Keys {
fn backend(&self) -> SignerBackend {
self.inner.backend().into()
}

async fn get_public_key(&self) -> Result<Option<Arc<PublicKey>>> {
Ok(Some(Arc::new(self.inner.get_public_key().await?.into())))
}
Expand Down
54 changes: 54 additions & 0 deletions bindings/nostr-sdk-ffi/src/protocol/signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,65 @@
// Copyright (c) 2023-2024 Rust Nostr Developers
// Distributed under the MIT software license

use std::borrow::Cow;
use std::fmt;
use std::ops::Deref;
use std::sync::Arc;

use nostr::signer;
use uniffi::Enum;

use super::event::{Event, UnsignedEvent};
use super::key::PublicKey;
use crate::error::Result;

#[derive(Enum)]
pub enum SignerBackend {
/// Secret key
Keys,
/// Browser extension (NIP07)
///
/// <https://github.com/nostr-protocol/nips/blob/master/07.md>
BrowserExtension,
/// Nostr Connect (NIP46)
///
/// <https://github.com/nostr-protocol/nips/blob/master/46.md>
NostrConnect,
/// Custom
Custom { backend: String },
}

impl<'a> From<signer::SignerBackend<'a>> for SignerBackend {
fn from(backend: signer::SignerBackend<'a>) -> Self {
match backend {
signer::SignerBackend::Keys => Self::Keys,
signer::SignerBackend::BrowserExtension => Self::BrowserExtension,
signer::SignerBackend::NostrConnect => Self::NostrConnect,
signer::SignerBackend::Custom(backend) => Self::Custom {
backend: backend.into_owned(),
},
}
}
}

impl<'a> From<SignerBackend> for signer::SignerBackend<'a> {
fn from(backend: SignerBackend) -> Self {
match backend {
SignerBackend::Keys => Self::Keys,
SignerBackend::BrowserExtension => Self::BrowserExtension,
SignerBackend::NostrConnect => Self::NostrConnect,
SignerBackend::Custom { backend } => Self::Custom(Cow::Owned(backend)),
}
}
}

// NOTE: for some weird reason the `Arc<T>` as output must be wrapped inside a `Vec<T>` or an `Option<T>`
// otherwise compilation will fail.
#[uniffi::export(with_foreign)]
#[async_trait::async_trait]
pub trait NostrSigner: Send + Sync {
fn backend(&self) -> SignerBackend;

/// Get signer public key
async fn get_public_key(&self) -> Result<Option<Arc<PublicKey>>>;

Expand Down Expand Up @@ -66,6 +112,10 @@ impl NostrSignerRust2FFI {

#[async_trait::async_trait]
impl NostrSigner for NostrSignerRust2FFI {
fn backend(&self) -> SignerBackend {
self.inner.backend().into()
}

async fn get_public_key(&self) -> Result<Option<Arc<PublicKey>>> {
Ok(Some(Arc::new(self.inner.get_public_key().await?.into())))
}
Expand Down Expand Up @@ -124,6 +174,10 @@ mod inner {

#[async_trait]
impl NostrSigner for NostrSignerFFI2Rust {
fn backend(&self) -> SignerBackend {
self.inner.backend().into()
}

async fn get_public_key(&self) -> Result<PublicKey, SignerError> {
let public_key = self
.inner
Expand Down
4 changes: 4 additions & 0 deletions crates/nostr-connect/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,10 @@ where
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl NostrSigner for NostrConnect {
fn backend(&self) -> SignerBackend {
SignerBackend::NostrConnect
}

async fn get_public_key(&self) -> Result<PublicKey, SignerError> {
self._get_public_key()
.await
Expand Down
8 changes: 7 additions & 1 deletion crates/nostr/src/key/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ pub mod vanity;
pub use self::public_key::PublicKey;
pub use self::secret_key::SecretKey;
#[cfg(feature = "std")]
use crate::{Event, NostrSigner, SignerError, UnsignedEvent, SECP256K1};
use crate::signer::{NostrSigner, SignerBackend, SignerError};
#[cfg(feature = "std")]
use crate::{Event, UnsignedEvent, SECP256K1};

/// [`Keys`] error
#[derive(Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -264,6 +266,10 @@ impl FromStr for Keys {
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl NostrSigner for Keys {
fn backend(&self) -> SignerBackend {
SignerBackend::Keys
}

async fn get_public_key(&self) -> Result<PublicKey, SignerError> {
Ok(self.public_key)
}
Expand Down
6 changes: 5 additions & 1 deletion crates/nostr/src/nips/nip07.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use wasm_bindgen_futures::JsFuture;
use web_sys::Window;

use crate::event::{self, unsigned};
use crate::signer::{NostrSigner, SignerError};
use crate::signer::{NostrSigner, SignerBackend, SignerError};
use crate::{key, Event, PublicKey, UnsignedEvent};

/// NIP07 error
Expand Down Expand Up @@ -315,6 +315,10 @@ impl Nip07Signer {

#[async_trait(?Send)]
impl NostrSigner for Nip07Signer {
fn backend(&self) -> SignerBackend {
SignerBackend::BrowserExtension
}

async fn get_public_key(&self) -> Result<PublicKey, SignerError> {
self._get_public_key().await.map_err(SignerError::backend)
}
Expand Down
33 changes: 32 additions & 1 deletion crates/nostr/src/signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

//! Nostr Signer
use alloc::borrow::Cow;
use alloc::boxed::Box;
#[cfg(any(not(feature = "std"), feature = "nip04", feature = "nip44"))]
use alloc::string::String;
Expand Down Expand Up @@ -68,11 +69,30 @@ where
}
}

/// Signer backend
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum SignerBackend<'a> {
/// Secret key
Keys,
/// Browser extension (NIP07)
///
/// <https://github.com/nostr-protocol/nips/blob/master/07.md>
BrowserExtension,
/// Nostr Connect (NIP46)
///
/// <https://github.com/nostr-protocol/nips/blob/master/46.md>
NostrConnect,
/// Custom
Custom(Cow<'a, str>),
}

/// Nostr signer abstraction
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait NostrSigner: AsyncTraitDeps {
// TODO: use `Cow<'a, PublicKey>`?
/// Signer backend
fn backend(&self) -> SignerBackend;

/// Get signer public key
async fn get_public_key(&self) -> Result<PublicKey, SignerError>;

Expand Down Expand Up @@ -115,14 +135,22 @@ pub trait NostrSigner: AsyncTraitDeps {
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl NostrSigner for Arc<dyn NostrSigner> {
#[inline]
fn backend(&self) -> SignerBackend {
self.as_ref().backend()
}

#[inline]
async fn get_public_key(&self) -> Result<PublicKey, SignerError> {
self.as_ref().get_public_key().await
}

#[inline]
async fn sign_event(&self, unsigned: UnsignedEvent) -> Result<Event, SignerError> {
self.as_ref().sign_event(unsigned).await
}

#[inline]
#[cfg(feature = "nip04")]
async fn nip04_encrypt(
&self,
Expand All @@ -132,6 +160,7 @@ impl NostrSigner for Arc<dyn NostrSigner> {
self.as_ref().nip04_encrypt(public_key, content).await
}

#[inline]
#[cfg(feature = "nip04")]
async fn nip04_decrypt(
&self,
Expand All @@ -143,6 +172,7 @@ impl NostrSigner for Arc<dyn NostrSigner> {
.await
}

#[inline]
#[cfg(feature = "nip44")]
async fn nip44_encrypt(
&self,
Expand All @@ -152,6 +182,7 @@ impl NostrSigner for Arc<dyn NostrSigner> {
self.as_ref().nip44_encrypt(public_key, content).await
}

#[inline]
#[cfg(feature = "nip44")]
async fn nip44_decrypt(
&self,
Expand Down

0 comments on commit a252976

Please sign in to comment.