Skip to content
This repository has been archived by the owner on Feb 3, 2025. It is now read-only.

Commit

Permalink
Allow overriding derived nsec
Browse files Browse the repository at this point in the history
  • Loading branch information
benthecarman committed Jan 17, 2024
1 parent 8c204ee commit fa04ce9
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 9 deletions.
9 changes: 8 additions & 1 deletion mutiny-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ use crate::{
subscription::MutinySubscriptionClient,
};
use crate::{nostr::NostrManager, utils::sleep};
use ::nostr::key::XOnlyPublicKey;
use ::nostr::key::{SecretKey, XOnlyPublicKey};
use ::nostr::{EventBuilder, JsonUtil, Keys, Kind, Tag};
use async_lock::RwLock;
use bdk_chain::ConfirmationTime;
Expand Down Expand Up @@ -397,6 +397,7 @@ pub struct MutinyWalletConfig {

pub struct MutinyWalletBuilder<S: MutinyStorage> {
xprivkey: ExtendedPrivKey,
nsec_override: Option<SecretKey>,
storage: S,
glue_db: Option<GlueDB>,
config: Option<MutinyWalletConfig>,
Expand All @@ -415,6 +416,7 @@ impl<S: MutinyStorage> MutinyWalletBuilder<S> {
MutinyWalletBuilder::<S> {
xprivkey,
storage,
nsec_override: None,
glue_db: None,
config: None,
session_id: None,
Expand All @@ -440,6 +442,10 @@ impl<S: MutinyStorage> MutinyWalletBuilder<S> {
self
}

pub fn with_nsec(&mut self, nsec: SecretKey) {
self.nsec_override = Some(nsec)
}

pub fn with_glue_db(&mut self, glue_db: GlueDB) {
self.glue_db = Some(glue_db);
}
Expand Down Expand Up @@ -517,6 +523,7 @@ impl<S: MutinyStorage> MutinyWalletBuilder<S> {
// create nostr manager
let nostr = Arc::new(NostrManager::from_mnemonic(
self.xprivkey,
self.nsec_override,
self.storage.clone(),
logger.clone(),
stop.clone(),
Expand Down
17 changes: 14 additions & 3 deletions mutiny-core/src/nostr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,13 @@ impl<S: MutinyStorage> NostrManager<S> {
Ok(None)
}

/// Decrypts a DM using the primary key
pub fn decrypt_dm(&self, pubkey: XOnlyPublicKey, message: &str) -> Result<String, MutinyError> {
let secret = self.primary_key.secret_key().expect("must have");
let decrypted = decrypt(&secret, &pubkey, message)?;
Ok(decrypted)
}

/// Derives the client and server keys for Nostr Wallet Connect given a profile index
/// The left key is the client key and the right key is the server key
pub(crate) fn derive_nwc_keys<C: Signing>(
Expand Down Expand Up @@ -1137,14 +1144,18 @@ impl<S: MutinyStorage> NostrManager<S> {
/// Creates a new NostrManager
pub fn from_mnemonic(
xprivkey: ExtendedPrivKey,
nsec_override: Option<SecretKey>,
storage: S,
logger: Arc<MutinyLogger>,
stop: Arc<AtomicBool>,
) -> Result<Self, MutinyError> {
let context = Secp256k1::new();

// generate the default primary key
let primary_key = Self::derive_nostr_key(&context, xprivkey, 0, None, None)?;
// use provided nsec, otherwise generate it from seed
let primary_key = match nsec_override {
Some(nsec) => Keys::new(nsec),
None => Self::derive_nostr_key(&context, xprivkey, 0, None, None)?,
};

// get from storage
let profiles: Vec<Profile> = storage.get_data(NWC_STORAGE_KEY)?.unwrap_or_default();
Expand Down Expand Up @@ -1220,7 +1231,7 @@ mod test {

let stop = Arc::new(AtomicBool::new(false));

NostrManager::from_mnemonic(xprivkey, storage, logger, stop).unwrap()
NostrManager::from_mnemonic(xprivkey, None, storage, logger, stop).unwrap()
}

#[test]
Expand Down
10 changes: 6 additions & 4 deletions mutiny-core/src/nostr/nwc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1217,7 +1217,7 @@ mod wasm_test {
let xprivkey = ExtendedPrivKey::new_master(Network::Regtest, &[0; 64]).unwrap();
let stop = Arc::new(AtomicBool::new(false));
let nostr_manager =
NostrManager::from_mnemonic(xprivkey, storage.clone(), mw.logger.clone(), stop)
NostrManager::from_mnemonic(xprivkey, None, storage.clone(), mw.logger.clone(), stop)
.unwrap();

let profile = nostr_manager
Expand Down Expand Up @@ -1266,7 +1266,8 @@ mod wasm_test {
let xprivkey = ExtendedPrivKey::new_master(Network::Regtest, &[0; 64]).unwrap();
let stop = Arc::new(AtomicBool::new(false));
let nostr_manager =
NostrManager::from_mnemonic(xprivkey, storage.clone(), logger.clone(), stop).unwrap();
NostrManager::from_mnemonic(xprivkey, None, storage.clone(), logger.clone(), stop)
.unwrap();

let profile = nostr_manager
.create_new_profile(
Expand Down Expand Up @@ -1444,6 +1445,7 @@ mod wasm_test {
let stop = Arc::new(AtomicBool::new(false));
let nostr_manager = NostrManager::from_mnemonic(
xprivkey,
None,
storage.clone(),
Arc::new(MutinyLogger::default()),
stop,
Expand Down Expand Up @@ -1494,7 +1496,7 @@ mod wasm_test {
let xprivkey = ExtendedPrivKey::new_master(Network::Regtest, &[0; 64]).unwrap();
let stop = Arc::new(AtomicBool::new(false));
let nostr_manager =
NostrManager::from_mnemonic(xprivkey, storage.clone(), mw.logger.clone(), stop)
NostrManager::from_mnemonic(xprivkey, None, storage.clone(), mw.logger.clone(), stop)
.unwrap();

let budget = 10_000;
Expand Down Expand Up @@ -1576,7 +1578,7 @@ mod wasm_test {
let xprivkey = ExtendedPrivKey::new_master(Network::Regtest, &[0; 64]).unwrap();
let stop = Arc::new(AtomicBool::new(false));
let nostr_manager =
NostrManager::from_mnemonic(xprivkey, storage.clone(), logger, stop).unwrap();
NostrManager::from_mnemonic(xprivkey, None, storage.clone(), logger, stop).unwrap();

let budget = 10_000;
let profile = nostr_manager
Expand Down
2 changes: 2 additions & 0 deletions mutiny-core/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use uuid::Uuid;

pub const KEYCHAIN_STORE_KEY: &str = "bdk_keychain";
pub const MNEMONIC_KEY: &str = "mnemonic";
pub const NSEC_KEY: &str = "nsec";
pub(crate) const NEED_FULL_SYNC_KEY: &str = "needs_full_sync";
pub const NODES_KEY: &str = "nodes";
pub const FEDERATIONS_KEY: &str = "federations";
Expand All @@ -34,6 +35,7 @@ pub const LAST_DM_SYNC_TIME_KEY: &str = "last_dm_sync_time";
fn needs_encryption(key: &str) -> bool {
match key {
MNEMONIC_KEY => true,
NSEC_KEY => true,
str if str.starts_with(CHANNEL_MANAGER_KEY) => true,
_ => false,
}
Expand Down
52 changes: 51 additions & 1 deletion mutiny-wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ use mutiny_core::{
nodemanager::{create_lsp_config, NodeManager},
};
use mutiny_core::{logging::MutinyLogger, nostr::ProfileType};
use nostr::ToBech32;
use nostr::key::{Secp256k1, SecretKey};
use nostr::{FromBech32, ToBech32};
use std::str::FromStr;
use std::sync::Arc;
use std::{
Expand Down Expand Up @@ -99,6 +100,7 @@ impl MutinyWallet {
skip_device_lock: Option<bool>,
safe_mode: Option<bool>,
skip_hodl_invoices: Option<bool>,
nsec_override: Option<String>,
) -> Result<MutinyWallet, MutinyJsError> {
utils::set_panic_hook();
let mut init = INITIALIZED.lock().await;
Expand Down Expand Up @@ -126,6 +128,7 @@ impl MutinyWallet {
skip_device_lock,
safe_mode,
skip_hodl_invoices,
nsec_override,
)
.await
{
Expand Down Expand Up @@ -157,6 +160,7 @@ impl MutinyWallet {
skip_device_lock: Option<bool>,
safe_mode: Option<bool>,
skip_hodl_invoices: Option<bool>,
nsec_override: Option<String>,
) -> Result<MutinyWallet, MutinyJsError> {
let safe_mode = safe_mode.unwrap_or(false);
let logger = Arc::new(MutinyLogger::default());
Expand Down Expand Up @@ -266,7 +270,13 @@ impl MutinyWallet {

let mut mw_builder = MutinyWalletBuilder::new(xprivkey, storage).with_config(config);
mw_builder.with_session_id(logger.session_id.clone());
if let Some(nsec) = nsec_override {
let nsec =
SecretKey::from_bech32(nsec).map_err(|_| MutinyJsError::InvalidArgumentsError)?;
mw_builder.with_nsec(nsec);
}
let inner = mw_builder.build().await?;

Ok(MutinyWallet { mnemonic, inner })
}

Expand Down Expand Up @@ -389,6 +399,17 @@ impl MutinyWallet {
self.mnemonic.to_string()
}

/// Returns the npub for receiving dms
#[wasm_bindgen]
pub fn get_npub(&self) -> String {
self.inner
.nostr
.primary_key
.public_key()
.to_bech32()
.expect("bech32")
}

/// Returns the network of the wallet.
#[wasm_bindgen]
pub fn get_network(&self) -> String {
Expand Down Expand Up @@ -1579,6 +1600,12 @@ impl MutinyWallet {
Ok(())
}

/// Decrypts a DM using the primary key
pub fn decrypt_dm(&self, pubkey: String, message: String) -> Result<String, MutinyJsError> {
let pubkey = parse_npub(&pubkey)?;
Ok(self.inner.nostr.decrypt_dm(pubkey, &message)?)
}

/// Resets the scorer and network graph. This can be useful if you get stuck in a bad state.
#[wasm_bindgen]
pub async fn reset_router(&self) -> Result<(), MutinyJsError> {
Expand Down Expand Up @@ -1690,6 +1717,18 @@ impl MutinyWallet {
bitcoin::Amount::from_sat(sats).to_btc()
}

/// Convert an npub string to a hex string
#[wasm_bindgen]
pub async fn nsec_to_npub(nsec: String) -> Result<String, MutinyJsError> {
let nsec =
SecretKey::from_bech32(nsec).map_err(|_| MutinyJsError::InvalidArgumentsError)?;
Ok(nsec
.x_only_public_key(&Secp256k1::new())
.0
.to_bech32()
.expect("bech32"))
}

/// Convert an npub string to a hex string
#[wasm_bindgen]
pub async fn npub_to_hexpub(npub: String) -> Result<String, MutinyJsError> {
Expand Down Expand Up @@ -1745,6 +1784,7 @@ mod tests {
None,
None,
None,
None,
)
.await
.expect("mutiny wallet should initialize");
Expand Down Expand Up @@ -1777,6 +1817,7 @@ mod tests {
None,
None,
None,
None,
)
.await
.expect("mutiny wallet should initialize");
Expand All @@ -1803,6 +1844,7 @@ mod tests {
None,
None,
None,
None,
)
.await;

Expand Down Expand Up @@ -1842,6 +1884,7 @@ mod tests {
None,
None,
None,
None,
)
.await
.expect("mutiny wallet should initialize");
Expand All @@ -1867,6 +1910,7 @@ mod tests {
None,
None,
None,
None,
)
.await;

Expand Down Expand Up @@ -1913,6 +1957,7 @@ mod tests {
None,
None,
None,
None,
)
.await
.unwrap();
Expand Down Expand Up @@ -1957,6 +2002,7 @@ mod tests {
None,
None,
None,
None,
)
.await
.unwrap();
Expand Down Expand Up @@ -1988,6 +2034,7 @@ mod tests {
None,
None,
None,
None,
)
.await;

Expand Down Expand Up @@ -2023,6 +2070,7 @@ mod tests {
None,
None,
None,
None,
)
.await
.expect("mutiny wallet should initialize");
Expand Down Expand Up @@ -2088,6 +2136,7 @@ mod tests {
None,
None,
None,
None,
)
.await
.expect("mutiny wallet should initialize");
Expand Down Expand Up @@ -2142,6 +2191,7 @@ mod tests {
None,
None,
None,
None,
)
.await
.expect("mutiny wallet should initialize");
Expand Down

0 comments on commit fa04ce9

Please sign in to comment.