Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(types)!: use Mnemonic type from crypto.rs #471

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
b2ec73b
add mnemonic type
Alex6323 May 22, 2023
b35b895
try from
Alex6323 May 23, 2023
215e6cd
Merge branch 'develop' into feat/types/zeroize-on-drop-mnemonic-type
Alex6323 May 23, 2023
4166575
update changelog
Alex6323 May 23, 2023
9d7e0fb
fix doc comment
Alex6323 May 23, 2023
c7ff0bb
move Mnemonic type to mnemonic module; introduce MnemonicLike trait
Alex6323 May 23, 2023
c558eca
format
Alex6323 May 24, 2023
b0640a7
fix ci
Alex6323 May 24, 2023
e1a845b
update changelog
Alex6323 May 24, 2023
fdf033e
Merge branch 'develop' into feat/types/zeroize-on-drop-mnemonic-type
Alex6323 May 25, 2023
2d69c33
impl MemonicLike for word list
Alex6323 May 25, 2023
a066603
add test
Alex6323 May 31, 2023
4d585b2
Merge branch 'develop' into feat/types/zeroize-on-drop-mnemonic-type
Alex6323 May 31, 2023
26e43d2
improve test
Alex6323 Jun 1, 2023
9d8b94a
Merge branch 'develop' into feat/types/zeroize-on-drop-mnemonic-type
Alex6323 Jun 1, 2023
1e60246
Mnemonic type in response
Alex6323 Jun 1, 2023
a8de867
giant dynamic museum toddler :sunglasses:
Alex6323 Jun 2, 2023
01477b1
Merge branch 'develop' into feat/types/zeroize-on-drop-mnemonic-type
Alex6323 Jun 2, 2023
8524c5e
Merge branch 'develop' into feat/types/zeroize-on-drop-mnemonic-type
Alex6323 Jun 5, 2023
4ccfe80
Merge branch 'develop' into feat/types/zeroize-on-drop-mnemonic-type
Alex6323 Jun 5, 2023
91ec56d
review suggestions
Alex6323 Jun 5, 2023
0c1c2f0
Merge branch 'develop' into feat/types/zeroize-on-drop-mnemonic-type
Alex6323 Jun 7, 2023
04a123a
Merge branch 'develop' into feat/types/zeroize-on-drop-mnemonic-type
Alex6323 Jun 29, 2023
8723e8b
Merge branch 'develop' into feat/types/zeroize-on-drop-mnemonic-type
Alex6323 Jul 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bindings/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ pub(crate) trait OmittedDebug {
f.write_str("<omitted>")
}
}
impl OmittedDebug for crypto::keys::bip39::Mnemonic {}
impl OmittedDebug for String {}
impl OmittedDebug for SecretManagerDto {}
impl<T: OmittedDebug> OmittedDebug for Option<T> {
Expand Down
8 changes: 5 additions & 3 deletions bindings/core/tests/secrets_debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,22 @@ fn method_interface_secrets_debug() {
);
}

let mnemonic = "giant dynamic museum toddler six deny defense ostrich bomb access mercy blood explain muscle shoot shallow glad autumn author calm heavy hawk abuse rally";

let client_method = UtilsMethod::MnemonicToHexSeed {
mnemonic: "mnemonic".to_string(),
mnemonic: mnemonic.to_string(),
};
assert_eq!(
format!("{:?}", client_method),
"MnemonicToHexSeed { mnemonic: <omitted> }"
);

let wallet_method = UtilsMethod::VerifyMnemonic {
mnemonic: "mnemonic".to_string(),
mnemonic: mnemonic.to_string(),
};
assert_eq!(format!("{:?}", wallet_method), "VerifyMnemonic { mnemonic: <omitted> }");

let response = Response::GeneratedMnemonic("mnemonic".to_string());
let response = Response::GeneratedMnemonic(mnemonic.to_owned());
assert_eq!(format!("{:?}", response), "GeneratedMnemonic(<omitted>)");

let wallet_options = WalletOptions {
Expand Down
4 changes: 2 additions & 2 deletions cli/src/helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,15 +201,15 @@ pub async fn import_mnemonic(path: &str) -> Result<Mnemonic, Error> {
}
}

async fn write_mnemonic_to_file(path: &str, mnemonic: &str) -> Result<(), Error> {
async fn write_mnemonic_to_file(path: &str, mnemonic: &Mnemonic) -> Result<(), Error> {
let mut open_options = OpenOptions::new();
open_options.create(true).append(true);

#[cfg(unix)]
open_options.mode(0o600);

let mut file = open_options.open(path).await?;
file.write_all(format!("{mnemonic}\n").as_bytes()).await?;
file.write_all(format!("{}\n", mnemonic.as_ref()).as_bytes()).await?;

Ok(())
}
Expand Down
131 changes: 131 additions & 0 deletions sdk/src/client/secret/mnemonic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,76 @@ impl MnemonicSecretManager {
}
}
DaughterOfMars marked this conversation as resolved.
Show resolved Hide resolved

// impl From<Mnemonic> for MnemonicSecretManager {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's up with all this ?

Copy link
Contributor Author

@Alex6323 Alex6323 Jul 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't think too much about it ... I merged develop into this branch to see in GH if there's something left of use and just out-commented this for the time being.

// fn from(m: Mnemonic) -> Self {
// Self(Client::mnemonic_to_seed(&m))
// }
// }

// /// A mnemonic (space separated list of words) that allows to create a seed from.
// #[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Zeroize, ZeroizeOnDrop)]
// pub struct Mnemonic(String);

// impl Mnemonic {
// pub fn as_str(&self) -> &str {
// self.0.as_str()
// }
// }

// impl TryFrom<String> for Mnemonic {
// type Error = Error;

// fn try_from(value: String) -> Result<Self, Self::Error> {
// let value: Zeroizing<String> = Zeroizing::new(value);
// // trim because empty spaces could create a different seed https://github.com/iotaledger/crypto.rs/issues/125
// let trimmed = value.as_str().trim();
// // first we check if the mnemonic is valid to give meaningful errors
// if let Err(err) = crypto::keys::bip39::wordlist::verify(trimmed, &crypto::keys::bip39::wordlist::ENGLISH) {
// Err(crate::client::Error::InvalidMnemonic(format!("{err:?}")))
// } else {
// Ok(Self(trimmed.to_string()))
// }
// }
// }

// pub trait MnemonicLike: Send {
// fn to_mnemonic(self) -> Result<Mnemonic, Error>;
// }

// impl MnemonicLike for Mnemonic {
// fn to_mnemonic(self) -> Result<Mnemonic, Error> {
// Ok(self)
// }
// }

// impl MnemonicLike for String {
// fn to_mnemonic(self) -> Result<Mnemonic, Error> {
// Mnemonic::try_from(self)
// }
// }

// impl MnemonicLike for Vec<String> {
// fn to_mnemonic(mut self) -> Result<Mnemonic, Error> {
// let m = self.join(" ");
// self.zeroize();
// Mnemonic::try_from(m)
// }
// }

// impl MnemonicLike for [&'static str; 24] {
// fn to_mnemonic(self) -> Result<Mnemonic, Error> {
// let m = self.join(" ");
// Mnemonic::try_from(m)
// }
// }

// // that's only necessary to use it in `assert!` macros
// impl core::fmt::Debug for Mnemonic {
// fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
// write!(f, "<mnemonic>")
// }
// }

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -194,4 +264,65 @@ mod tests {
"atoi1qzt0nhsf38nh6rs4p6zs5knqp6psgha9wsv74uajqgjmwc75ugupx3y7x0r"
);
}

// #[test]
// fn mnemonic_like() {
// // Mnemonic from a space-separated word list stored in a `String`
// let mnemonic1 = "giant dynamic museum toddler six deny defense ostrich bomb access mercy blood explain muscle
// shoot shallow glad autumn author calm heavy hawk abuse rally".to_owned().to_mnemonic().unwrap(); // Mnemonic
// from a word list stored in a `Vec<String>` let mnemonic2 = [
// "giant", "dynamic", "museum", "toddler", "six", "deny", "defense", "ostrich", "bomb", "access", "mercy",
// "blood", "explain", "muscle", "shoot", "shallow", "glad", "autumn", "author", "calm", "heavy", "hawk",
// "abuse", "rally",
// ]
// .into_iter()
// .map(|s| s.to_owned())
// .collect::<Vec<_>>()
// .to_mnemonic()
// .unwrap();
// // Mnemonic from a word list stored in a `[&'static str; 24]`
// let mnemonic3 = [
// "giant", "dynamic", "museum", "toddler", "six", "deny", "defense", "ostrich", "bomb", "access", "mercy",
// "blood", "explain", "muscle", "shoot", "shallow", "glad", "autumn", "author", "calm", "heavy", "hawk",
// "abuse", "rally",
// ]
// .to_mnemonic()
// .unwrap();

// assert_eq!(mnemonic1, mnemonic2);
// assert_eq!(mnemonic1, mnemonic3);
// assert_eq!(mnemonic2, mnemonic3);

// // Different mnemonic
// let mnemonic4 = [
// "endorse", "answer", "radar", "about", "source", "reunion", "marriage", "tag", "sausage", "weekend",
// "frost", "daring", "base", "attack", "because", "joke", "dream", "slender", "leisure", "group", "reason",
// "prepare", "broken", "river",
// ]
// .to_mnemonic()
// .unwrap();

// assert_ne!(mnemonic1, mnemonic4);
// assert_ne!(mnemonic2, mnemonic4);
// assert_ne!(mnemonic3, mnemonic4);

// // Incorrect mnemonic
// assert!(
// [
// "dynamic", "giant", "museum", "toddler", "six", "deny", "defense", "ostrich", "bomb", "access",
// "mercy", "blood", "explain", "muscle", "shoot", "shallow", "glad", "autumn", "author", "calm",
// "heavy", "hawk", "abuse", "rally"
// ]
// .to_mnemonic()
// .is_err()
// );
// }

// #[test]
// fn zeroize_mnemonic() {
// let mut mnemonic1 = "giant dynamic museum toddler six deny defense ostrich bomb access mercy blood explain
// muscle shoot shallow glad autumn author calm heavy hawk abuse rally".to_owned().to_mnemonic().unwrap();
// mnemonic1.zeroize();
// assert!(mnemonic1.as_str().is_empty());
// }
}
11 changes: 8 additions & 3 deletions sdk/src/client/secret/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,17 +194,22 @@ impl TryFrom<SecretManagerDto> for SecretManager {
Ok(match value {
#[cfg(feature = "stronghold")]
SecretManagerDto::Stronghold(stronghold_dto) => {
let StrongholdDto {
password,
snapshot_path,
timeout,
} = stronghold_dto;
let mut builder = StrongholdSecretManager::builder();

if let Some(password) = stronghold_dto.password {
if let Some(password) = password {
builder = builder.password(password);
}

if let Some(timeout) = stronghold_dto.timeout {
if let Some(timeout) = timeout {
builder = builder.timeout(Duration::from_secs(timeout));
}

Self::Stronghold(builder.build(&stronghold_dto.snapshot_path)?)
Self::Stronghold(builder.build(snapshot_path)?)
}

#[cfg(feature = "ledger_nano")]
Expand Down
2 changes: 1 addition & 1 deletion sdk/src/client/secret/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::{
utils::serde::bip44::option_bip44,
};

/// Stronghold DTO to allow the creation of a Stronghold secret manager from bindings
/// Stronghold DTO to allow the creation of a Stronghold secret manager from bindings.
#[cfg(feature = "stronghold")]
#[cfg_attr(docsrs, doc(cfg(feature = "stronghold")))]
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize)]
Expand Down
7 changes: 6 additions & 1 deletion sdk/tests/client/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@ pub async fn create_client_and_secret_manager_with_funds(
) -> Result<(Client, SecretManager)> {
let client = Client::builder().with_node(NODE_LOCAL)?.finish().await?;

let secret_manager = SecretManager::try_from_mnemonic(mnemonic.unwrap_or(Client::generate_mnemonic().unwrap()))?;
let mnemonic = if let Some(mnemonic) = mnemonic {
mnemonic
} else {
Client::generate_mnemonic()?
};
let secret_manager = SecretManager::try_from_mnemonic(mnemonic)?;

let address = secret_manager
.generate_ed25519_addresses(
Expand Down
9 changes: 2 additions & 7 deletions sdk/tests/wallet/account_recovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,7 @@
use std::time::Duration;

use iota_sdk::{
client::{
api::GetAddressesOptions,
constants::SHIMMER_COIN_TYPE,
secret::{mnemonic::MnemonicSecretManager, SecretManager},
Client,
},
client::{api::GetAddressesOptions, constants::SHIMMER_COIN_TYPE, secret::SecretManager, Client},
wallet::Result,
};

Expand Down Expand Up @@ -66,7 +61,7 @@ async fn account_recovery_with_balance_and_empty_addresses() -> Result<()> {
.finish()
.await?;

let secret_manager = SecretManager::Mnemonic(MnemonicSecretManager::try_from_mnemonic(mnemonic.clone())?);
let secret_manager = SecretManager::try_from_mnemonic(mnemonic.clone())?;

let addresses = secret_manager
.generate_ed25519_addresses(
Expand Down
3 changes: 1 addition & 2 deletions sdk/tests/wallet/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ pub use self::constants::*;
#[allow(dead_code, unused_variables)]
pub(crate) async fn make_wallet(storage_path: &str, mnemonic: Option<Mnemonic>, node: Option<&str>) -> Result<Wallet> {
let client_options = ClientOptions::new().with_node(node.unwrap_or(NODE_LOCAL))?;
let secret_manager =
MnemonicSecretManager::try_from_mnemonic(mnemonic.unwrap_or(Client::generate_mnemonic().unwrap()))?;
let secret_manager = MnemonicSecretManager::try_from_mnemonic(mnemonic.unwrap_or(Client::generate_mnemonic()?))?;

#[allow(unused_mut)]
let mut wallet_builder = Wallet::builder()
Expand Down
11 changes: 5 additions & 6 deletions sdk/tests/wallet/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ async fn different_seed() -> Result<()> {
#[cfg(feature = "storage")]
#[tokio::test]
async fn changed_coin_type() -> Result<()> {
use crypto::keys::bip39::Mnemonic;

let storage_path = "test-storage/changed_coin_type";
setup(storage_path)?;

Expand All @@ -92,10 +94,9 @@ async fn changed_coin_type() -> Result<()> {
drop(_account);
drop(wallet);

// Recreate Wallet with same mnemonic
let err = Wallet::builder()
.with_secret_manager(SecretManager::Mnemonic(MnemonicSecretManager::try_from_mnemonic(
mnemonic.clone(),
)?))
.with_secret_manager(SecretManager::try_from_mnemonic(mnemonic.clone())?)
.with_coin_type(IOTA_COIN_TYPE)
.with_storage_path(storage_path)
.finish()
Expand All @@ -113,9 +114,7 @@ async fn changed_coin_type() -> Result<()> {

// Building the wallet with the same coin type still works
let wallet = Wallet::builder()
.with_secret_manager(SecretManager::Mnemonic(MnemonicSecretManager::try_from_mnemonic(
mnemonic,
)?))
.with_secret_manager(SecretManager::try_from_mnemonic(mnemonic.clone())?)
.with_storage_path(storage_path)
.finish()
.await?;
Expand Down
Loading