chore: simplify mnemonic zeroize story (#3165)
* updated bip39 dependency to simplify our zeroize story * Replaced UserPassword wrapper with Zeroizing type alias * fixed wallet-types cosmwasm-std dependency version
This commit is contained in:
committed by
GitHub
parent
6de829163d
commit
54287666e8
Generated
+31
-30
@@ -302,22 +302,23 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bip39"
|
||||
version = "1.0.1"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e89470017230c38e52b82b3ee3f530db1856ba1d434e3a67a3456a8a8dec5f"
|
||||
checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f"
|
||||
dependencies = [
|
||||
"bitcoin_hashes",
|
||||
"rand 0.6.5",
|
||||
"rand_core 0.4.2",
|
||||
"rand 0.8.5",
|
||||
"rand_core 0.6.4",
|
||||
"serde",
|
||||
"unicode-normalization",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitcoin_hashes"
|
||||
version = "0.9.7"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ce18265ec2324ad075345d5814fbeed4f41f0a660055dc78840b74d19b874b1"
|
||||
checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
@@ -2845,12 +2846,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "maybe-uninit"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
@@ -4171,7 +4166,7 @@ dependencies = [
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec 1.10.0",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
@@ -4184,7 +4179,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec 1.10.0",
|
||||
"smallvec",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
@@ -5057,7 +5052,7 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
"ref-cast",
|
||||
"serde",
|
||||
"smallvec 1.10.0",
|
||||
"smallvec",
|
||||
"stable-pattern",
|
||||
"state",
|
||||
"time 0.3.17",
|
||||
@@ -5552,15 +5547,6 @@ dependencies = [
|
||||
"autocfg 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "0.6.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0"
|
||||
dependencies = [
|
||||
"maybe-uninit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.10.0"
|
||||
@@ -5725,7 +5711,7 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
"rustls 0.19.1",
|
||||
"sha2 0.10.6",
|
||||
"smallvec 1.10.0",
|
||||
"smallvec",
|
||||
"sqlformat 0.1.8",
|
||||
"sqlx-rt 0.5.13",
|
||||
"stringprep",
|
||||
@@ -5773,7 +5759,7 @@ dependencies = [
|
||||
"rustls 0.20.8",
|
||||
"rustls-pemfile",
|
||||
"sha2 0.10.6",
|
||||
"smallvec 1.10.0",
|
||||
"smallvec",
|
||||
"sqlformat 0.2.1",
|
||||
"sqlx-rt 0.6.2",
|
||||
"stringprep",
|
||||
@@ -6198,6 +6184,21 @@ dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec_macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.25.0"
|
||||
@@ -6495,7 +6496,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"regex",
|
||||
"sharded-slab",
|
||||
"smallvec 1.10.0",
|
||||
"smallvec",
|
||||
"thread_local",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
@@ -6661,11 +6662,11 @@ checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.9"
|
||||
version = "0.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09c8070a9942f5e7cfccd93f490fdebd230ee3c3c9f107cb25bad5351ef671cf"
|
||||
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
|
||||
dependencies = [
|
||||
"smallvec 0.6.14",
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -105,6 +105,7 @@ license = "Apache-2.0"
|
||||
|
||||
[workspace.dependencies]
|
||||
async-trait = "0.1.64"
|
||||
bip39 = { version = "2.0.0", features = ["zeroize"] }
|
||||
cfg-if = "1.0.0"
|
||||
dotenvy = "0.15.6"
|
||||
lazy_static = "1.4.0"
|
||||
|
||||
@@ -6,7 +6,7 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
bip39 = "1.0.1"
|
||||
bip39 = { workspace = true }
|
||||
clap = { version = "4.0", features = ["cargo", "derive"] }
|
||||
log = "0.4"
|
||||
rand = "0.7.3"
|
||||
|
||||
@@ -37,7 +37,7 @@ nym-execute = { path = "../../execute" }
|
||||
# at some point it might be possible to make it wasm-compatible
|
||||
# perhaps after https://github.com/cosmos/cosmos-rust/pull/97 is resolved (and tendermint-rs is updated)
|
||||
async-trait = { workspace = true, optional = true }
|
||||
bip39 = { version = "1", features = ["rand"], optional = true }
|
||||
bip39 = { workspace = true, features = ["rand"], optional = true }
|
||||
nym-config = { path = "../../config", optional = true }
|
||||
cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support", features = ["rpc", "bip32", "cosmwasm"], optional = true}
|
||||
cw3 = { version = "0.13.4", optional = true }
|
||||
@@ -47,7 +47,7 @@ flate2 = { version = "1.0.20", optional = true }
|
||||
sha2 = { version = "0.9.5", optional = true }
|
||||
itertools = { version = "0.10", optional = true }
|
||||
cosmwasm-std = { version = "1.0.0", optional = true }
|
||||
zeroize = { version = "1.5.7", optional = true }
|
||||
zeroize = { version = "1.5.7", optional = true, features = ["zeroize_derive"] }
|
||||
|
||||
[dev-dependencies]
|
||||
ts-rs = "6.1.2"
|
||||
|
||||
@@ -8,7 +8,7 @@ use cosmrs::crypto::PublicKey;
|
||||
use cosmrs::tx::SignDoc;
|
||||
use cosmrs::{tx, AccountId};
|
||||
use nym_config::defaults;
|
||||
use zeroize::Zeroize;
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
|
||||
/// Derivation information required to derive a keypair and an address from a mnemonic.
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -41,7 +41,7 @@ impl AccountData {
|
||||
|
||||
type Secp256k1Keypair = (SigningKey, PublicKey);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Zeroize, ZeroizeOnDrop)]
|
||||
pub struct DirectSecp256k1HdWallet {
|
||||
/// Base secret
|
||||
secret: bip39::Mnemonic,
|
||||
@@ -54,30 +54,10 @@ pub struct DirectSecp256k1HdWallet {
|
||||
// that would include the secret key which is a dyn EcdsaSigner and hence not Sync making the wallet
|
||||
// not Sync and if used on the signing client in an async trait, it wouldn't be Send
|
||||
/// Derivation instructions
|
||||
#[zeroize(skip)]
|
||||
accounts: Vec<Secp256k1Derivation>,
|
||||
}
|
||||
|
||||
impl Zeroize for DirectSecp256k1HdWallet {
|
||||
fn zeroize(&mut self) {
|
||||
// in ideal world, Mnemonic would have had zeroize defined on it (there's an almost year old PR that introduces it)
|
||||
// and the memory would have been filled with zeroes.
|
||||
//
|
||||
// we really don't want to keep our real mnemonic in memory, so let's do the semi-nasty thing
|
||||
// of overwriting it with a fresh mnemonic that was never used before
|
||||
//
|
||||
// note: this function can only fail on an invalid word count, which clearly is not the case here
|
||||
self.secret = bip39::Mnemonic::generate(self.secret.word_count()).unwrap();
|
||||
self.seed.zeroize();
|
||||
// there's nothing secret about derivation paths
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DirectSecp256k1HdWallet {
|
||||
fn drop(&mut self) {
|
||||
self.zeroize()
|
||||
}
|
||||
}
|
||||
|
||||
impl DirectSecp256k1HdWallet {
|
||||
pub fn builder(prefix: &str) -> DirectSecp256k1HdWalletBuilder {
|
||||
DirectSecp256k1HdWalletBuilder::new(prefix)
|
||||
|
||||
@@ -6,7 +6,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
base64 = "0.13.0"
|
||||
bip39 = "1.0.1"
|
||||
bip39 = { workspace = true }
|
||||
bs58 = "0.4"
|
||||
comfy-table = "6.0.0"
|
||||
cfg-if = "1.0.0"
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ rust-version = "1.56"
|
||||
[dependencies]
|
||||
anyhow = "1.0.53"
|
||||
async-trait = { workspace = true }
|
||||
bip39 = "1.0.1"
|
||||
bip39 = { workspace = true }
|
||||
bs58 = "0.4.0"
|
||||
clap = { version = "4.0", features = ["cargo", "derive"] }
|
||||
colored = "2.0"
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ rust-version = "1.56"
|
||||
[dependencies]
|
||||
async-trait = { workspace = true }
|
||||
bs58 = {version = "0.4.0" }
|
||||
bip39 = "1"
|
||||
bip39 = { workspace = true }
|
||||
cfg-if = "1.0"
|
||||
clap = { version = "4.0", features = ["cargo", "derive"] }
|
||||
console-subscriber = { version = "0.1.1", optional = true } # validator-api needs to be built with RUSTFLAGS="--cfg tokio_unstable"
|
||||
|
||||
@@ -20,7 +20,7 @@ tauri-macros = "^1.2.1"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
bip39 = "1.0"
|
||||
bip39 = { version = "2.0.0", features = ["zeroize"] }
|
||||
dirs = "4.0"
|
||||
eyre = "0.6.5"
|
||||
fix-path-env = { git = "https://github.com/tauri-apps/fix-path-env-rs", branch = "release"}
|
||||
|
||||
@@ -21,7 +21,7 @@ tauri-build = { version = "2.0.0-alpha.1", features = [] }
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
bip39 = "1.0"
|
||||
bip39 = { version = "2.0.0", features = ["zeroize"] }
|
||||
chrono = "0.4"
|
||||
dirs = "4.0"
|
||||
eyre = "0.6.5"
|
||||
|
||||
Generated
+59
-197
@@ -181,15 +181,6 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78"
|
||||
dependencies = [
|
||||
"autocfg 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
@@ -240,22 +231,23 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bip39"
|
||||
version = "1.0.1"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e89470017230c38e52b82b3ee3f530db1856ba1d434e3a67a3456a8a8dec5f"
|
||||
checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f"
|
||||
dependencies = [
|
||||
"bitcoin_hashes",
|
||||
"rand 0.6.5",
|
||||
"rand_core 0.4.2",
|
||||
"rand 0.8.5",
|
||||
"rand_core 0.6.4",
|
||||
"serde",
|
||||
"unicode-normalization",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitcoin_hashes"
|
||||
version = "0.9.7"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ce18265ec2324ad075345d5814fbeed4f41f0a660055dc78840b74d19b874b1"
|
||||
checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
@@ -476,7 +468,7 @@ version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3431df59f28accaf4cb4eed4a9acc66bea3f3c3753aa6cdc2f024174ef232af7"
|
||||
dependencies = [
|
||||
"smallvec 1.10.0",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -485,7 +477,7 @@ version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0357a6402b295ca3a86bc148e84df46c02e41f41fef186bda662557ef6328aa"
|
||||
dependencies = [
|
||||
"smallvec 1.10.0",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -569,15 +561,6 @@ dependencies = [
|
||||
"os_str_bytes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cloudabi"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cocoa"
|
||||
version = "0.24.1"
|
||||
@@ -869,7 +852,7 @@ dependencies = [
|
||||
"phf 0.8.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"smallvec 1.10.0",
|
||||
"smallvec",
|
||||
"syn",
|
||||
]
|
||||
|
||||
@@ -1431,12 +1414,6 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e"
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-cprng"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
||||
|
||||
[[package]]
|
||||
name = "funty"
|
||||
version = "2.0.0"
|
||||
@@ -1762,7 +1739,7 @@ dependencies = [
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"smallvec 1.10.0",
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
@@ -2248,7 +2225,7 @@ version = "1.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
|
||||
dependencies = [
|
||||
"autocfg 1.1.0",
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
"serde",
|
||||
]
|
||||
@@ -2508,7 +2485,7 @@ version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
|
||||
dependencies = [
|
||||
"autocfg 1.1.0",
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
@@ -2581,12 +2558,6 @@ version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
|
||||
|
||||
[[package]]
|
||||
name = "maybe-uninit"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
@@ -2599,7 +2570,7 @@ version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
|
||||
dependencies = [
|
||||
"autocfg 1.1.0",
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2729,7 +2700,7 @@ version = "0.1.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
||||
dependencies = [
|
||||
"autocfg 1.1.0",
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
@@ -2739,7 +2710,7 @@ version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
|
||||
dependencies = [
|
||||
"autocfg 1.1.0",
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
@@ -2750,7 +2721,7 @@ version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||
dependencies = [
|
||||
"autocfg 1.1.0",
|
||||
"autocfg",
|
||||
"libm",
|
||||
]
|
||||
|
||||
@@ -2878,6 +2849,20 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-crypto"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"ed25519-dalek",
|
||||
"nym-pemstore",
|
||||
"nym-sphinx-types",
|
||||
"rand 0.7.3",
|
||||
"subtle-encoding",
|
||||
"thiserror",
|
||||
"x25519-dalek",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-dkg"
|
||||
version = "0.1.0"
|
||||
@@ -2899,20 +2884,6 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-crypto"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"ed25519-dalek",
|
||||
"nym-pemstore",
|
||||
"nym-sphinx-types",
|
||||
"rand 0.7.3",
|
||||
"subtle-encoding",
|
||||
"thiserror",
|
||||
"x25519-dalek",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-execute"
|
||||
version = "0.1.0"
|
||||
@@ -2984,7 +2955,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-sphinx-types"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"sphinx-packet",
|
||||
]
|
||||
@@ -3110,7 +3081,6 @@ dependencies = [
|
||||
"nym-wallet-types",
|
||||
"once_cell",
|
||||
"pretty_env_logger",
|
||||
"rand 0.6.5",
|
||||
"rand_chacha 0.2.2",
|
||||
"reqwest",
|
||||
"serde",
|
||||
@@ -3258,7 +3228,7 @@ version = "0.9.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23bbbf7854cd45b83958ebe919f0e8e516793727652e27fda10a8384cfc790b7"
|
||||
dependencies = [
|
||||
"autocfg 1.1.0",
|
||||
"autocfg",
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
@@ -3330,7 +3300,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec 1.10.0",
|
||||
"smallvec",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
@@ -3790,25 +3760,6 @@ version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
|
||||
dependencies = [
|
||||
"autocfg 0.1.8",
|
||||
"libc",
|
||||
"rand_chacha 0.1.1",
|
||||
"rand_core 0.4.2",
|
||||
"rand_hc 0.1.0",
|
||||
"rand_isaac",
|
||||
"rand_jitter",
|
||||
"rand_os",
|
||||
"rand_pcg 0.1.2",
|
||||
"rand_xorshift",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.3"
|
||||
@@ -3819,8 +3770,8 @@ dependencies = [
|
||||
"libc",
|
||||
"rand_chacha 0.2.2",
|
||||
"rand_core 0.5.1",
|
||||
"rand_hc 0.2.0",
|
||||
"rand_pcg 0.2.1",
|
||||
"rand_hc",
|
||||
"rand_pcg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3834,16 +3785,6 @@ dependencies = [
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
|
||||
dependencies = [
|
||||
"autocfg 0.1.8",
|
||||
"rand_core 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.2.2"
|
||||
@@ -3864,21 +3805,6 @@ dependencies = [
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
||||
dependencies = [
|
||||
"rand_core 0.4.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.5.1"
|
||||
@@ -3907,15 +3833,6 @@ dependencies = [
|
||||
"rand 0.7.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
|
||||
dependencies = [
|
||||
"rand_core 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.2.0"
|
||||
@@ -3925,50 +3842,6 @@ dependencies = [
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_isaac"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
|
||||
dependencies = [
|
||||
"rand_core 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_jitter"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_core 0.4.2",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_os"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
|
||||
dependencies = [
|
||||
"cloudabi",
|
||||
"fuchsia-cprng",
|
||||
"libc",
|
||||
"rand_core 0.4.2",
|
||||
"rdrand",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_pcg"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
|
||||
dependencies = [
|
||||
"autocfg 0.1.8",
|
||||
"rand_core 0.4.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_pcg"
|
||||
version = "0.2.1"
|
||||
@@ -3978,15 +3851,6 @@ dependencies = [
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_xorshift"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
|
||||
dependencies = [
|
||||
"rand_core 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "raw-window-handle"
|
||||
version = "0.5.0"
|
||||
@@ -3996,15 +3860,6 @@ dependencies = [
|
||||
"cty",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rdrand"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
|
||||
dependencies = [
|
||||
"rand_core 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.16"
|
||||
@@ -4350,7 +4205,7 @@ dependencies = [
|
||||
"phf_codegen",
|
||||
"precomputed-hash",
|
||||
"servo_arc",
|
||||
"smallvec 1.10.0",
|
||||
"smallvec",
|
||||
"thin-slice",
|
||||
]
|
||||
|
||||
@@ -4605,16 +4460,7 @@ version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef"
|
||||
dependencies = [
|
||||
"autocfg 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "0.6.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0"
|
||||
dependencies = [
|
||||
"maybe-uninit",
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5281,13 +5127,28 @@ dependencies = [
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec_macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af"
|
||||
dependencies = [
|
||||
"autocfg 1.1.0",
|
||||
"autocfg",
|
||||
"bytes",
|
||||
"libc",
|
||||
"memchr",
|
||||
@@ -5434,7 +5295,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"regex",
|
||||
"sharded-slab",
|
||||
"smallvec 1.10.0",
|
||||
"smallvec",
|
||||
"thread_local",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
@@ -5517,11 +5378,11 @@ checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.9"
|
||||
version = "0.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09c8070a9942f5e7cfccd93f490fdebd230ee3c3c9f107cb25bad5351ef671cf"
|
||||
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
|
||||
dependencies = [
|
||||
"smallvec 0.6.14",
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6228,6 +6089,7 @@ version = "1.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"zeroize_derive",
|
||||
]
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ aes-gcm = "0.9"
|
||||
anyhow = "1.0"
|
||||
argon2 = "0.4"
|
||||
base64 = "0.13"
|
||||
bip39 = "1.0"
|
||||
bip39 = { version = "2.0.0", features = ["zeroize"] }
|
||||
clap = { version = "4.0", features = ["derive"] }
|
||||
log = "0.4"
|
||||
pretty_env_logger = "0.4"
|
||||
|
||||
@@ -11,7 +11,7 @@ serde_json = "1.0"
|
||||
strum = { version = "0.23", features = ["derive"] }
|
||||
ts-rs = "6.1.2"
|
||||
|
||||
cosmwasm-std = "1.0.0-beta8"
|
||||
cosmwasm-std = "1.0.0"
|
||||
cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support" }
|
||||
|
||||
nym-config = { path = "../../common/config" }
|
||||
|
||||
@@ -20,7 +20,7 @@ tauri-macros = "=1.2.1"
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1.64"
|
||||
bip39 = "1.0"
|
||||
bip39 = { version = "2.0.0", features = ["zeroize", "rand"] }
|
||||
cfg-if = "1.0.0"
|
||||
colored = "2.0"
|
||||
dirs = "4.0"
|
||||
@@ -32,7 +32,6 @@ itertools = "0.10"
|
||||
log = { version = "0.4", features = ["serde"] }
|
||||
once_cell = "1.7.2"
|
||||
pretty_env_logger = "0.4"
|
||||
rand = "0.6.5"
|
||||
reqwest = {version = "0.11.9", features = ["json"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
@@ -50,7 +49,7 @@ k256 = { version = "0.10", features = ["ecdsa", "sha256"] }
|
||||
aes-gcm = "0.9.4"
|
||||
argon2 = { version = "0.3.2", features = ["std"] }
|
||||
base64 = "0.13"
|
||||
zeroize = "1.4.3"
|
||||
zeroize = { version = "1.5", features = ["zeroize_derive", "serde"] }
|
||||
|
||||
cosmwasm-std = "1.0.0"
|
||||
cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support" }
|
||||
|
||||
@@ -2,15 +2,14 @@ use crate::config::{Config, CUSTOM_SIMULATED_GAS_MULTIPLIER};
|
||||
use crate::error::BackendError;
|
||||
use crate::network_config;
|
||||
use crate::state::{WalletAccountIds, WalletState};
|
||||
use crate::utils::{SensitiveStringWrapper, ZeroizeMnemonicWrapper};
|
||||
use crate::wallet_storage::{self, UserPassword, DEFAULT_LOGIN_ID};
|
||||
use bip39::rand::{self, seq::SliceRandom};
|
||||
use bip39::{Language, Mnemonic};
|
||||
use cosmrs::bip32::DerivationPath;
|
||||
use itertools::Itertools;
|
||||
use nym_config::defaults::{NymNetworkDetails, COSMOS_DERIVATION_PATH};
|
||||
use nym_types::account::{Account, AccountEntry, Balance};
|
||||
use nym_wallet_types::network::Network as WalletNetwork;
|
||||
use rand::seq::SliceRandom;
|
||||
use std::collections::HashMap;
|
||||
use strum::IntoEnumIterator;
|
||||
use url::Url;
|
||||
@@ -19,10 +18,9 @@ use validator_client::{nyxd::SigningNyxdClient, Client};
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn connect_with_mnemonic(
|
||||
mnemonic: SensitiveStringWrapper,
|
||||
mnemonic: Mnemonic,
|
||||
state: tauri::State<'_, WalletState>,
|
||||
) -> Result<Account, BackendError> {
|
||||
let mnemonic = ZeroizeMnemonicWrapper::try_from_string(mnemonic)?;
|
||||
_connect_with_mnemonic(mnemonic, state).await
|
||||
}
|
||||
|
||||
@@ -48,13 +46,13 @@ pub async fn get_balance(state: tauri::State<'_, WalletState>) -> Result<Balance
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn create_new_mnemonic() -> SensitiveStringWrapper {
|
||||
random_mnemonic().into_string()
|
||||
pub fn create_new_mnemonic() -> Mnemonic {
|
||||
random_mnemonic()
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn validate_mnemonic(mnemonic: SensitiveStringWrapper) -> bool {
|
||||
ZeroizeMnemonicWrapper::try_from_string(mnemonic).is_ok()
|
||||
pub fn validate_mnemonic(_mnemonic: Mnemonic) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -82,15 +80,13 @@ pub async fn logout(state: tauri::State<'_, WalletState>) -> Result<(), BackendE
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn random_mnemonic() -> ZeroizeMnemonicWrapper {
|
||||
fn random_mnemonic() -> Mnemonic {
|
||||
let mut rng = rand::thread_rng();
|
||||
Mnemonic::generate_in_with(&mut rng, Language::English, 24)
|
||||
.unwrap()
|
||||
.into()
|
||||
Mnemonic::generate_in_with(&mut rng, Language::English, 24).unwrap()
|
||||
}
|
||||
|
||||
async fn _connect_with_mnemonic(
|
||||
mnemonic: ZeroizeMnemonicWrapper,
|
||||
mnemonic: Mnemonic,
|
||||
state: tauri::State<'_, WalletState>,
|
||||
) -> Result<Account, BackendError> {
|
||||
{
|
||||
@@ -141,7 +137,7 @@ async fn _connect_with_mnemonic(
|
||||
&default_nyxd_urls,
|
||||
&default_api_urls,
|
||||
&config,
|
||||
mnemonic.as_ref(),
|
||||
&mnemonic,
|
||||
)?;
|
||||
|
||||
// Set the default account
|
||||
@@ -298,16 +294,12 @@ pub fn does_password_file_exist() -> Result<bool, BackendError> {
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn create_password(
|
||||
mnemonic: SensitiveStringWrapper,
|
||||
password: UserPassword,
|
||||
) -> Result<(), BackendError> {
|
||||
pub fn create_password(mnemonic: Mnemonic, password: UserPassword) -> Result<(), BackendError> {
|
||||
if does_password_file_exist()? {
|
||||
return Err(BackendError::WalletFileAlreadyExists);
|
||||
}
|
||||
log::info!("Creating password");
|
||||
|
||||
let mnemonic = ZeroizeMnemonicWrapper::try_from_string(mnemonic)?;
|
||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
// Currently we only support a single, default, login id in the wallet
|
||||
let login_id = wallet_storage::LoginId::new(DEFAULT_LOGIN_ID.to_string());
|
||||
@@ -330,7 +322,7 @@ pub async fn sign_in_with_password(
|
||||
set_state_with_all_accounts(stored_login, first_login_id_when_converting, state.clone())
|
||||
.await?;
|
||||
|
||||
_connect_with_mnemonic(mnemonic.into(), state).await
|
||||
_connect_with_mnemonic(mnemonic, state).await
|
||||
}
|
||||
|
||||
fn extract_first_mnemonic(
|
||||
@@ -370,7 +362,7 @@ pub async fn sign_in_with_password_and_account_id(
|
||||
set_state_with_all_accounts(stored_login, first_login_id_when_converting, state.clone())
|
||||
.await?;
|
||||
|
||||
_connect_with_mnemonic(mnemonic.into(), state).await
|
||||
_connect_with_mnemonic(mnemonic, state).await
|
||||
}
|
||||
|
||||
fn extract_mnemonic(
|
||||
@@ -404,13 +396,12 @@ pub fn archive_wallet_file() -> Result<(), BackendError> {
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn add_account_for_password(
|
||||
mnemonic: SensitiveStringWrapper,
|
||||
mnemonic: Mnemonic,
|
||||
password: UserPassword,
|
||||
account_id: &str,
|
||||
state: tauri::State<'_, WalletState>,
|
||||
) -> Result<AccountEntry, BackendError> {
|
||||
log::info!("Adding account for the current password: {account_id}");
|
||||
let mnemonic = ZeroizeMnemonicWrapper::try_from_string(mnemonic)?;
|
||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
// Currently we only support a single, default, login id in the wallet
|
||||
let login_id = wallet_storage::LoginId::new(DEFAULT_LOGIN_ID.to_string());
|
||||
@@ -427,13 +418,7 @@ pub async fn add_account_for_password(
|
||||
let address = {
|
||||
let state = state.read().await;
|
||||
let network: NymNetworkDetails = state.current_network().into();
|
||||
// safety: the call to `clone_inner` is fine here as the raw mnemonic will get immediately
|
||||
// passed to `DirectSecp256k1HdWallet` which will zeroize it on drop
|
||||
derive_address(
|
||||
mnemonic.into_cloned_inner(),
|
||||
&network.chain_details.bech32_account_prefix,
|
||||
)?
|
||||
.to_string()
|
||||
derive_address(mnemonic, &network.chain_details.bech32_account_prefix)?.to_string()
|
||||
};
|
||||
|
||||
// Re-read all the acccounts from the wallet to reset the state, rather than updating it
|
||||
@@ -553,19 +538,19 @@ pub async fn list_accounts(
|
||||
pub fn show_mnemonic_for_account_in_password(
|
||||
account_id: String,
|
||||
password: UserPassword,
|
||||
) -> Result<SensitiveStringWrapper, BackendError> {
|
||||
) -> Result<Mnemonic, BackendError> {
|
||||
log::info!("Getting mnemonic for: {account_id}");
|
||||
let login_id = wallet_storage::LoginId::new(DEFAULT_LOGIN_ID.to_string());
|
||||
let account_id = wallet_storage::AccountId::new(account_id);
|
||||
let mnemonic = _show_mnemonic_for_account_in_password(&login_id, &account_id, &password)?;
|
||||
Ok(mnemonic.into_string())
|
||||
Ok(mnemonic)
|
||||
}
|
||||
|
||||
fn _show_mnemonic_for_account_in_password(
|
||||
login_id: &wallet_storage::LoginId,
|
||||
account_id: &wallet_storage::AccountId,
|
||||
password: &wallet_storage::UserPassword,
|
||||
) -> Result<ZeroizeMnemonicWrapper, BackendError> {
|
||||
) -> Result<Mnemonic, BackendError> {
|
||||
let stored_account = wallet_storage::load_existing_login(login_id, password)?;
|
||||
let mnemonic = match stored_account {
|
||||
wallet_storage::StoredLogin::Mnemonic(ref account) => account.mnemonic().clone(),
|
||||
@@ -575,7 +560,7 @@ fn _show_mnemonic_for_account_in_password(
|
||||
.mnemonic()
|
||||
.clone(),
|
||||
};
|
||||
Ok(mnemonic.into())
|
||||
Ok(mnemonic)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -590,8 +575,8 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
// This decryptes a stored wallet file using the same procedure as when signing in. Most tests
|
||||
// related to the encryped wallet storage is in `wallet_storage`.
|
||||
// This decrypts a stored wallet file using the same procedure as when signing in. Most tests
|
||||
// related to the encrypted wallet storage is in `wallet_storage`.
|
||||
#[test]
|
||||
fn decrypt_stored_wallet_for_sign_in() {
|
||||
const SAVED_WALLET: &str = "src/wallet_storage/test-data/saved-wallet.json";
|
||||
|
||||
@@ -4,16 +4,14 @@
|
||||
use crate::error::BackendError;
|
||||
use crate::nyxd_client;
|
||||
use crate::state::WalletState;
|
||||
use bip39::Mnemonic;
|
||||
use cosmwasm_std::Decimal;
|
||||
use nym_mixnet_contract_common::{IdentityKey, MixId, Percent};
|
||||
use nym_types::currency::DecCoin;
|
||||
use nym_types::mixnode::MixNodeCostParams;
|
||||
use nym_wallet_types::app::AppEnv;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use validator_client::nyxd::traits::MixnetQueryClient;
|
||||
use validator_client::nyxd::{tx, Coin, CosmosCoin, Gas, GasPrice};
|
||||
use zeroize::Zeroize;
|
||||
|
||||
fn get_env_as_option(key: &str) -> Option<String> {
|
||||
match ::std::env::var(key) {
|
||||
@@ -194,94 +192,3 @@ pub async fn get_old_and_incorrect_hardcoded_fee(
|
||||
log::info!("hardcoded fee for {:?} is {:?}", operation, coin);
|
||||
guard.attempt_convert_to_display_dec_coin(coin)
|
||||
}
|
||||
|
||||
#[derive(Zeroize)]
|
||||
#[zeroize(drop)]
|
||||
pub struct SensitiveStringWrapper(String);
|
||||
|
||||
impl<'de> Deserialize<'de> for SensitiveStringWrapper {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Ok(SensitiveStringWrapper(String::deserialize(deserializer)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for SensitiveStringWrapper {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
// unfortunately this serialized value will live on...
|
||||
self.0.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for SensitiveStringWrapper {
|
||||
fn from(value: String) -> Self {
|
||||
SensitiveStringWrapper(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for SensitiveStringWrapper {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
// can't do it natively until https://github.com/rust-bitcoin/rust-bip39/pull/32 gets merged and released...
|
||||
pub(crate) struct ZeroizeMnemonicWrapper(bip39::Mnemonic);
|
||||
|
||||
impl From<bip39::Mnemonic> for ZeroizeMnemonicWrapper {
|
||||
fn from(value: Mnemonic) -> Self {
|
||||
ZeroizeMnemonicWrapper(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Zeroize for ZeroizeMnemonicWrapper {
|
||||
fn zeroize(&mut self) {
|
||||
// overwrite the mnemonic value with a completely random one
|
||||
// (a poor man's zeroize until bip39 crate does it properly...)
|
||||
self.0 = Mnemonic::generate(self.0.word_count()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ZeroizeMnemonicWrapper {
|
||||
fn drop(&mut self) {
|
||||
self.zeroize()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<bip39::Mnemonic> for ZeroizeMnemonicWrapper {
|
||||
fn as_ref(&self) -> &Mnemonic {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl ZeroizeMnemonicWrapper {
|
||||
pub(crate) fn into_string(self) -> SensitiveStringWrapper {
|
||||
SensitiveStringWrapper(self.0.to_string())
|
||||
}
|
||||
|
||||
pub(crate) fn try_from_string(string: SensitiveStringWrapper) -> Result<Self, bip39::Error> {
|
||||
let res = string.as_ref().parse()?;
|
||||
Ok(ZeroizeMnemonicWrapper(res))
|
||||
}
|
||||
|
||||
// special care must be taken when calling this method as the mnemonic will no longer get zeroized!
|
||||
pub(crate) fn into_cloned_inner(self) -> bip39::Mnemonic {
|
||||
self.0.clone()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn unchecked_clone_inner(&self) -> bip39::Mnemonic {
|
||||
self.0.clone()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn generate_random() -> Self {
|
||||
ZeroizeMnemonicWrapper(Mnemonic::generate(24).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,16 +14,14 @@
|
||||
// In the future we might want to simplify by dropping the support for a single account entry,
|
||||
// instead treating as muliple accounts with one entry.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use validator_client::nyxd::bip32::DerivationPath;
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use crate::error::BackendError;
|
||||
use crate::utils::ZeroizeMnemonicWrapper;
|
||||
|
||||
use super::encryption::EncryptedData;
|
||||
use super::password::{AccountId, LoginId};
|
||||
use super::UserPassword;
|
||||
use crate::error::BackendError;
|
||||
use bip39::Mnemonic;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use validator_client::nyxd::bip32::DerivationPath;
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
|
||||
const CURRENT_WALLET_FILE_VERSION: u32 = 1;
|
||||
|
||||
@@ -153,9 +151,8 @@ impl EncryptedLogin {
|
||||
|
||||
/// A stored login is either a account, such as a mnemonic, or a list of multiple accounts where
|
||||
/// each has an inner id. Future proofed for having private key backed accounts.
|
||||
#[derive(Serialize, Deserialize, Debug, Zeroize)]
|
||||
#[derive(Serialize, Deserialize, Debug, Zeroize, ZeroizeOnDrop)]
|
||||
#[serde(untagged)]
|
||||
#[zeroize(drop)]
|
||||
pub(crate) enum StoredLogin {
|
||||
Mnemonic(MnemonicAccount),
|
||||
// PrivateKey(PrivateKeyAccount)
|
||||
@@ -193,8 +190,7 @@ impl StoredLogin {
|
||||
}
|
||||
|
||||
/// Multiple stored accounts, each entry having an id and a data field.
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Zeroize, PartialEq, Eq)]
|
||||
#[zeroize(drop)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Zeroize, ZeroizeOnDrop, PartialEq, Eq)]
|
||||
pub(crate) struct MultipleAccounts {
|
||||
accounts: Vec<WalletAccount>,
|
||||
}
|
||||
@@ -238,19 +234,17 @@ impl MultipleAccounts {
|
||||
pub(crate) fn add(
|
||||
&mut self,
|
||||
id: AccountId,
|
||||
mnemonic: ZeroizeMnemonicWrapper,
|
||||
mnemonic: Mnemonic,
|
||||
hd_path: DerivationPath,
|
||||
) -> Result<(), BackendError> {
|
||||
if self.get_account(&id).is_some() {
|
||||
Err(BackendError::WalletAccountIdAlreadyExistsInWalletLogin)
|
||||
} else if self.get_account_with_mnemonic(mnemonic.as_ref()).is_some() {
|
||||
} else if self.get_account_with_mnemonic(&mnemonic).is_some() {
|
||||
Err(BackendError::WalletMnemonicAlreadyExistsInWalletLogin)
|
||||
} else {
|
||||
self.accounts.push(WalletAccount::new(
|
||||
id,
|
||||
// safety: the call to `clone_inner` is fine here as the raw mnemonic will get immediately
|
||||
// passed to `MnemonicAccount` which will zeroize it on drop
|
||||
MnemonicAccount::new(mnemonic.into_cloned_inner(), hd_path),
|
||||
MnemonicAccount::new(mnemonic, hd_path),
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
@@ -272,8 +266,7 @@ impl From<Vec<WalletAccount>> for MultipleAccounts {
|
||||
}
|
||||
|
||||
/// An entry in the list of stored accounts
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Zeroize, PartialEq, Eq)]
|
||||
#[zeroize(drop)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Zeroize, ZeroizeOnDrop, PartialEq, Eq)]
|
||||
pub(crate) struct WalletAccount {
|
||||
id: AccountId,
|
||||
account: AccountData,
|
||||
@@ -307,19 +300,20 @@ impl WalletAccount {
|
||||
|
||||
/// An account usually is a mnemonic account, but in the future it might be backed by a private
|
||||
/// key.
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Zeroize, PartialEq, Eq)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Zeroize, ZeroizeOnDrop, PartialEq, Eq)]
|
||||
#[serde(untagged)]
|
||||
#[zeroize(drop)]
|
||||
enum AccountData {
|
||||
Mnemonic(MnemonicAccount),
|
||||
// PrivateKey(PrivateKeyAccount)
|
||||
}
|
||||
|
||||
/// An account backed by a unique mnemonic.
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Zeroize, ZeroizeOnDrop, PartialEq, Eq)]
|
||||
pub(crate) struct MnemonicAccount {
|
||||
mnemonic: bip39::Mnemonic,
|
||||
#[serde(with = "display_hd_path")]
|
||||
// there's nothing secret about our derivation path
|
||||
#[zeroize(skip)]
|
||||
hd_path: DerivationPath,
|
||||
}
|
||||
|
||||
@@ -338,27 +332,6 @@ impl MnemonicAccount {
|
||||
}
|
||||
}
|
||||
|
||||
impl Zeroize for MnemonicAccount {
|
||||
fn zeroize(&mut self) {
|
||||
// in ideal world, Mnemonic would have had zeroize defined on it (there's an almost year old PR that introduces it)
|
||||
// and the memory would have been filled with zeroes.
|
||||
//
|
||||
// we really don't want to keep our real mnemonic in memory, so let's do the semi-nasty thing
|
||||
// of overwriting it with a fresh mnemonic that was never used before
|
||||
//
|
||||
// note: this function can only fail on an invalid word count, which clearly is not the case here
|
||||
self.mnemonic = bip39::Mnemonic::generate(self.mnemonic.word_count()).unwrap();
|
||||
|
||||
// further note: we don't really care about the hd_path, there's nothing secret about it.
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for MnemonicAccount {
|
||||
fn drop(&mut self) {
|
||||
self.zeroize()
|
||||
}
|
||||
}
|
||||
|
||||
mod display_hd_path {
|
||||
use serde::{Deserialize, Deserializer, Serializer};
|
||||
use validator_client::nyxd::bip32::DerivationPath;
|
||||
|
||||
@@ -14,7 +14,7 @@ pub(crate) use crate::wallet_storage::password::{AccountId, LoginId, UserPasswor
|
||||
|
||||
use crate::error::BackendError;
|
||||
use crate::platform_constants::{STORAGE_DIR_NAME, WALLET_INFO_FILENAME};
|
||||
use crate::utils::ZeroizeMnemonicWrapper;
|
||||
use bip39::Mnemonic;
|
||||
use std::ffi::OsString;
|
||||
use std::fs::{self, create_dir_all, OpenOptions};
|
||||
use std::path::{Path, PathBuf};
|
||||
@@ -139,7 +139,7 @@ fn store_login_at_file(
|
||||
}
|
||||
|
||||
pub(crate) fn store_login_with_multiple_accounts(
|
||||
mnemonic: ZeroizeMnemonicWrapper,
|
||||
mnemonic: Mnemonic,
|
||||
hd_path: DerivationPath,
|
||||
id: LoginId,
|
||||
password: &UserPassword,
|
||||
@@ -154,7 +154,7 @@ pub(crate) fn store_login_with_multiple_accounts(
|
||||
|
||||
fn store_login_with_multiple_accounts_at_file(
|
||||
filepath: &Path,
|
||||
mnemonic: ZeroizeMnemonicWrapper,
|
||||
mnemonic: Mnemonic,
|
||||
hd_path: DerivationPath,
|
||||
id: LoginId,
|
||||
password: &UserPassword,
|
||||
@@ -185,7 +185,7 @@ fn store_login_with_multiple_accounts_at_file(
|
||||
/// account in the list of accounts associated with the encrypted entry. The inner id for this
|
||||
/// entry will be set to the same as the outer, unencrypted, id.
|
||||
pub(crate) fn append_account_to_login(
|
||||
mnemonic: ZeroizeMnemonicWrapper,
|
||||
mnemonic: Mnemonic,
|
||||
hd_path: DerivationPath,
|
||||
id: LoginId,
|
||||
inner_id: AccountId,
|
||||
@@ -201,7 +201,7 @@ pub(crate) fn append_account_to_login(
|
||||
|
||||
fn append_account_to_login_at_file(
|
||||
filepath: &Path,
|
||||
mnemonic: ZeroizeMnemonicWrapper,
|
||||
mnemonic: Mnemonic,
|
||||
hd_path: DerivationPath,
|
||||
id: LoginId,
|
||||
inner_id: AccountId,
|
||||
@@ -422,19 +422,12 @@ mod tests {
|
||||
fn store_single_login() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet_file = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let account1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account1 = Mnemonic::generate(24).unwrap();
|
||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
let id1 = LoginId::new("first".to_string());
|
||||
|
||||
store_login_at_file(
|
||||
&wallet_file,
|
||||
account1.into_cloned_inner(),
|
||||
hd_path,
|
||||
id1.clone(),
|
||||
&password,
|
||||
)
|
||||
.unwrap();
|
||||
store_login_at_file(&wallet_file, account1, hd_path, id1.clone(), &password).unwrap();
|
||||
|
||||
let stored_wallet = load_existing_wallet_at_file(&wallet_file).unwrap();
|
||||
assert_eq!(stored_wallet.len(), 1);
|
||||
@@ -450,7 +443,7 @@ mod tests {
|
||||
fn store_single_login_with_multi() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet_file = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let account1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account1 = Mnemonic::generate(24).unwrap();
|
||||
let cosmos_hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
let id1 = LoginId::new("first".to_string());
|
||||
@@ -478,7 +471,7 @@ mod tests {
|
||||
fn store_twice_for_the_same_id_fails() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet_file = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let account1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account1 = Mnemonic::generate(24).unwrap();
|
||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
let id1 = LoginId::new("first".to_string());
|
||||
@@ -486,7 +479,7 @@ mod tests {
|
||||
// Store the first login
|
||||
store_login_at_file(
|
||||
&wallet_file,
|
||||
account1.unchecked_clone_inner(),
|
||||
account1.clone(),
|
||||
hd_path.clone(),
|
||||
id1.clone(),
|
||||
&password,
|
||||
@@ -495,13 +488,7 @@ mod tests {
|
||||
|
||||
// and storing the same id again fails
|
||||
assert!(matches!(
|
||||
store_login_at_file(
|
||||
&wallet_file,
|
||||
account1.into_cloned_inner(),
|
||||
hd_path,
|
||||
id1,
|
||||
&password,
|
||||
),
|
||||
store_login_at_file(&wallet_file, account1, hd_path, id1, &password,),
|
||||
Err(BackendError::WalletLoginIdAlreadyExists),
|
||||
));
|
||||
}
|
||||
@@ -510,7 +497,7 @@ mod tests {
|
||||
fn store_twice_for_the_same_id_fails_with_multiple() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet_file = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let account1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account1 = Mnemonic::generate(24).unwrap();
|
||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
let id1 = LoginId::new("first".to_string());
|
||||
@@ -542,20 +529,13 @@ mod tests {
|
||||
fn load_with_wrong_password_fails() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet_file = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let account1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account1 = Mnemonic::generate(24).unwrap();
|
||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
let bad_password = UserPassword::new("bad-password".to_string());
|
||||
let id1 = LoginId::new("first".to_string());
|
||||
|
||||
store_login_at_file(
|
||||
&wallet_file,
|
||||
account1.into_cloned_inner(),
|
||||
hd_path,
|
||||
id1.clone(),
|
||||
&password,
|
||||
)
|
||||
.unwrap();
|
||||
store_login_at_file(&wallet_file, account1, hd_path, id1.clone(), &password).unwrap();
|
||||
|
||||
// Trying to load it with wrong password now fails
|
||||
assert!(matches!(
|
||||
@@ -568,7 +548,7 @@ mod tests {
|
||||
fn load_with_wrong_password_fails_with_multi() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet_file = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let account1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account1 = Mnemonic::generate(24).unwrap();
|
||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
let bad_password = UserPassword::new("bad-password".to_string());
|
||||
@@ -594,20 +574,13 @@ mod tests {
|
||||
fn load_with_wrong_id_fails() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet_file = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let account1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account1 = Mnemonic::generate(24).unwrap();
|
||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
let id1 = LoginId::new("first".to_string());
|
||||
let id2 = LoginId::new("second".to_string());
|
||||
|
||||
store_login_at_file(
|
||||
&wallet_file,
|
||||
account1.into_cloned_inner(),
|
||||
hd_path,
|
||||
id1,
|
||||
&password,
|
||||
)
|
||||
.unwrap();
|
||||
store_login_at_file(&wallet_file, account1, hd_path, id1, &password).unwrap();
|
||||
|
||||
// Trying to load with the wrong id
|
||||
assert!(matches!(
|
||||
@@ -620,7 +593,7 @@ mod tests {
|
||||
fn load_with_wrong_id_fails_with_multi() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet_file = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let account1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account1 = Mnemonic::generate(24).unwrap();
|
||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
let id1 = LoginId::new("first".to_string());
|
||||
@@ -640,14 +613,14 @@ mod tests {
|
||||
fn store_and_load_a_single_login() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet_file = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let account1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account1 = Mnemonic::generate(24).unwrap();
|
||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
let id1 = LoginId::new("first".to_string());
|
||||
|
||||
store_login_at_file(
|
||||
&wallet_file,
|
||||
account1.unchecked_clone_inner(),
|
||||
account1.clone(),
|
||||
hd_path.clone(),
|
||||
id1.clone(),
|
||||
&password,
|
||||
@@ -656,7 +629,7 @@ mod tests {
|
||||
|
||||
let loaded_login = load_existing_login_at_file(&wallet_file, &id1, &password).unwrap();
|
||||
let acc = loaded_login.as_mnemonic_account().unwrap();
|
||||
assert_eq!(account1.as_ref(), acc.mnemonic());
|
||||
assert_eq!(&account1, acc.mnemonic());
|
||||
assert_eq!(&hd_path, acc.hd_path());
|
||||
}
|
||||
|
||||
@@ -664,7 +637,7 @@ mod tests {
|
||||
fn store_and_load_a_single_login_with_multi() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet_file = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let acc1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let acc1 = Mnemonic::generate(24).unwrap();
|
||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
let id1 = LoginId::new("first".to_string());
|
||||
@@ -685,7 +658,7 @@ mod tests {
|
||||
.get_account(&DEFAULT_FIRST_ACCOUNT_NAME.into())
|
||||
.unwrap();
|
||||
assert_eq!(account.id().as_ref(), DEFAULT_FIRST_ACCOUNT_NAME);
|
||||
assert_eq!(account.mnemonic(), acc1.as_ref());
|
||||
assert_eq!(account.mnemonic(), &acc1);
|
||||
assert_eq!(account.hd_path(), &hd_path);
|
||||
}
|
||||
|
||||
@@ -693,8 +666,8 @@ mod tests {
|
||||
fn store_a_second_login_with_a_different_password_fails() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet_file = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let account1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account2 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account1 = Mnemonic::generate(24).unwrap();
|
||||
let account2 = Mnemonic::generate(24).unwrap();
|
||||
let cosmos_hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
let bad_password = UserPassword::new("bad-password".to_string());
|
||||
@@ -703,7 +676,7 @@ mod tests {
|
||||
|
||||
store_login_at_file(
|
||||
&wallet_file,
|
||||
account1.into_cloned_inner(),
|
||||
account1,
|
||||
cosmos_hd_path.clone(),
|
||||
id1,
|
||||
&password,
|
||||
@@ -712,13 +685,7 @@ mod tests {
|
||||
|
||||
// Can't store a second login if you use different password
|
||||
assert!(matches!(
|
||||
store_login_at_file(
|
||||
&wallet_file,
|
||||
account2.into_cloned_inner(),
|
||||
cosmos_hd_path,
|
||||
id2,
|
||||
&bad_password
|
||||
),
|
||||
store_login_at_file(&wallet_file, account2, cosmos_hd_path, id2, &bad_password),
|
||||
Err(BackendError::WalletDifferentPasswordDetected),
|
||||
));
|
||||
}
|
||||
@@ -727,8 +694,8 @@ mod tests {
|
||||
fn store_a_second_login_with_a_different_password_fails_with_multi() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet_file = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let account1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account2 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account1 = Mnemonic::generate(24).unwrap();
|
||||
let account2 = Mnemonic::generate(24).unwrap();
|
||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
let bad_password = UserPassword::new("bad-password".to_string());
|
||||
@@ -761,8 +728,8 @@ mod tests {
|
||||
fn store_two_mnemonic_accounts_gives_different_salts_and_iv() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet_file = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let account1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account2 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account1 = Mnemonic::generate(24).unwrap();
|
||||
let account2 = Mnemonic::generate(24).unwrap();
|
||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let different_hd_path: DerivationPath = "m".parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
@@ -770,14 +737,7 @@ mod tests {
|
||||
let id2 = LoginId::new("second".to_string());
|
||||
|
||||
// Store the first account
|
||||
store_login_at_file(
|
||||
&wallet_file,
|
||||
account1.into_cloned_inner(),
|
||||
hd_path,
|
||||
id1,
|
||||
&password,
|
||||
)
|
||||
.unwrap();
|
||||
store_login_at_file(&wallet_file, account1, hd_path, id1, &password).unwrap();
|
||||
|
||||
let stored_wallet = load_existing_wallet_at_file(&wallet_file).unwrap();
|
||||
let encrypted_blob = &stored_wallet
|
||||
@@ -790,14 +750,7 @@ mod tests {
|
||||
let original_salt = encrypted_blob.salt().to_vec();
|
||||
|
||||
// Add an extra account
|
||||
store_login_at_file(
|
||||
&wallet_file,
|
||||
account2.into_cloned_inner(),
|
||||
different_hd_path,
|
||||
id2,
|
||||
&password,
|
||||
)
|
||||
.unwrap();
|
||||
store_login_at_file(&wallet_file, account2, different_hd_path, id2, &password).unwrap();
|
||||
|
||||
let loaded_accounts = load_existing_wallet_at_file(&wallet_file).unwrap();
|
||||
assert_eq!(loaded_accounts.len(), 2);
|
||||
@@ -815,8 +768,8 @@ mod tests {
|
||||
fn store_two_mnemonic_accounts_using_two_logins() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let account1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account2 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account1 = Mnemonic::generate(24).unwrap();
|
||||
let account2 = Mnemonic::generate(24).unwrap();
|
||||
let cosmos_hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let different_hd_path: DerivationPath = "m".parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
@@ -826,7 +779,7 @@ mod tests {
|
||||
// Store the first account
|
||||
store_login_at_file(
|
||||
&wallet,
|
||||
account1.unchecked_clone_inner(),
|
||||
account1.clone(),
|
||||
cosmos_hd_path.clone(),
|
||||
id1.clone(),
|
||||
&password,
|
||||
@@ -835,13 +788,13 @@ mod tests {
|
||||
|
||||
let login = load_existing_login_at_file(&wallet, &id1, &password).unwrap();
|
||||
let acc = login.as_mnemonic_account().unwrap();
|
||||
assert_eq!(account1.as_ref(), acc.mnemonic());
|
||||
assert_eq!(&account1, acc.mnemonic());
|
||||
assert_eq!(&cosmos_hd_path, acc.hd_path());
|
||||
|
||||
// Add an extra account
|
||||
store_login_at_file(
|
||||
&wallet,
|
||||
account2.unchecked_clone_inner(),
|
||||
account2.clone(),
|
||||
different_hd_path.clone(),
|
||||
id2.clone(),
|
||||
&password,
|
||||
@@ -851,12 +804,12 @@ mod tests {
|
||||
// first account should be unchanged
|
||||
let loaded_login = load_existing_login_at_file(&wallet, &id1, &password).unwrap();
|
||||
let acc1 = loaded_login.as_mnemonic_account().unwrap();
|
||||
assert_eq!(account1.as_ref(), acc1.mnemonic());
|
||||
assert_eq!(&account1, acc1.mnemonic());
|
||||
assert_eq!(&cosmos_hd_path, acc1.hd_path());
|
||||
|
||||
let loaded_login = load_existing_login_at_file(&wallet, &id2, &password).unwrap();
|
||||
let acc2 = loaded_login.as_mnemonic_account().unwrap();
|
||||
assert_eq!(account2.as_ref(), acc2.mnemonic());
|
||||
assert_eq!(&account2, acc2.mnemonic());
|
||||
assert_eq!(&different_hd_path, acc2.hd_path());
|
||||
}
|
||||
|
||||
@@ -864,8 +817,8 @@ mod tests {
|
||||
fn store_one_mnemonic_account_and_one_multi_account() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet_file = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let account1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account2 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account1 = Mnemonic::generate(24).unwrap();
|
||||
let account2 = Mnemonic::generate(24).unwrap();
|
||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let different_hd_path: DerivationPath = "m".parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
@@ -875,7 +828,7 @@ mod tests {
|
||||
// Store the first account
|
||||
store_login_at_file(
|
||||
&wallet_file,
|
||||
account1.unchecked_clone_inner(),
|
||||
account1.clone(),
|
||||
hd_path.clone(),
|
||||
id1.clone(),
|
||||
&password,
|
||||
@@ -884,7 +837,7 @@ mod tests {
|
||||
|
||||
let loaded_login = load_existing_login_at_file(&wallet_file, &id1, &password).unwrap();
|
||||
let acc = loaded_login.as_mnemonic_account().unwrap();
|
||||
assert_eq!(account1.as_ref(), acc.mnemonic());
|
||||
assert_eq!(&account1, acc.mnemonic());
|
||||
assert_eq!(&hd_path, acc.hd_path());
|
||||
|
||||
// Add an extra account
|
||||
@@ -900,7 +853,7 @@ mod tests {
|
||||
// first account should be unchanged
|
||||
let loaded_login = load_existing_login_at_file(&wallet_file, &id1, &password).unwrap();
|
||||
let acc1 = loaded_login.as_mnemonic_account().unwrap();
|
||||
assert_eq!(account1.as_ref(), acc1.mnemonic());
|
||||
assert_eq!(&account1, acc1.mnemonic());
|
||||
assert_eq!(&hd_path, acc1.hd_path());
|
||||
|
||||
let loaded_login = load_existing_login_at_file(&wallet_file, &id2, &password).unwrap();
|
||||
@@ -910,7 +863,7 @@ mod tests {
|
||||
.get_account(&DEFAULT_FIRST_ACCOUNT_NAME.into())
|
||||
.unwrap();
|
||||
assert_eq!(account.id().as_ref(), DEFAULT_FIRST_ACCOUNT_NAME);
|
||||
assert_eq!(account.mnemonic(), account2.as_ref());
|
||||
assert_eq!(account.mnemonic(), &account2);
|
||||
assert_eq!(account.hd_path(), &different_hd_path);
|
||||
}
|
||||
|
||||
@@ -918,7 +871,7 @@ mod tests {
|
||||
fn remove_non_existent_id_fails() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet_file = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let account1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account1 = Mnemonic::generate(24).unwrap();
|
||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
let id1 = LoginId::new("first".to_string());
|
||||
@@ -938,8 +891,8 @@ mod tests {
|
||||
fn store_and_remove_wallet_login_information() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet_file = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let account1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account2 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account1 = Mnemonic::generate(24).unwrap();
|
||||
let account2 = Mnemonic::generate(24).unwrap();
|
||||
let cosmos_hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let different_hd_path: DerivationPath = "m".parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
@@ -949,7 +902,7 @@ mod tests {
|
||||
// Store two accounts with two different passwords
|
||||
store_login_at_file(
|
||||
&wallet_file,
|
||||
account1.unchecked_clone_inner(),
|
||||
account1.clone(),
|
||||
cosmos_hd_path.clone(),
|
||||
id1.clone(),
|
||||
&password,
|
||||
@@ -957,7 +910,7 @@ mod tests {
|
||||
.unwrap();
|
||||
store_login_at_file(
|
||||
&wallet_file,
|
||||
account2.unchecked_clone_inner(),
|
||||
account2.clone(),
|
||||
different_hd_path.clone(),
|
||||
id2.clone(),
|
||||
&password,
|
||||
@@ -967,12 +920,12 @@ mod tests {
|
||||
// Load and compare
|
||||
let loaded_login = load_existing_login_at_file(&wallet_file, &id1, &password).unwrap();
|
||||
let acc1 = loaded_login.as_mnemonic_account().unwrap();
|
||||
assert_eq!(account1.as_ref(), acc1.mnemonic());
|
||||
assert_eq!(&account1, acc1.mnemonic());
|
||||
assert_eq!(&cosmos_hd_path, acc1.hd_path());
|
||||
|
||||
let loaded_login = load_existing_login_at_file(&wallet_file, &id2, &password).unwrap();
|
||||
let acc2 = loaded_login.as_mnemonic_account().unwrap();
|
||||
assert_eq!(account2.as_ref(), acc2.mnemonic());
|
||||
assert_eq!(&account2, acc2.mnemonic());
|
||||
assert_eq!(&different_hd_path, acc2.hd_path());
|
||||
|
||||
// Delete the second account
|
||||
@@ -981,7 +934,7 @@ mod tests {
|
||||
// The first account should be unchanged
|
||||
let loaded_login = load_existing_login_at_file(&wallet_file, &id1, &password).unwrap();
|
||||
let acc1 = loaded_login.as_mnemonic_account().unwrap();
|
||||
assert_eq!(account1.as_ref(), acc1.mnemonic());
|
||||
assert_eq!(&account1, acc1.mnemonic());
|
||||
assert_eq!(&cosmos_hd_path, acc1.hd_path());
|
||||
|
||||
// And we can't load the second one anymore
|
||||
@@ -1008,8 +961,8 @@ mod tests {
|
||||
fn append_account_converts_the_type() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet_file = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let account1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account2 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account1 = Mnemonic::generate(24).unwrap();
|
||||
let account2 = Mnemonic::generate(24).unwrap();
|
||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
let id1 = LoginId::new("first".to_string());
|
||||
@@ -1017,7 +970,7 @@ mod tests {
|
||||
|
||||
store_login_at_file(
|
||||
&wallet_file,
|
||||
account1.unchecked_clone_inner(),
|
||||
account1.clone(),
|
||||
hd_path.clone(),
|
||||
id1.clone(),
|
||||
&password,
|
||||
@@ -1027,7 +980,7 @@ mod tests {
|
||||
// Check that it's there as the correct non-multiple type
|
||||
let loaded_login = load_existing_login_at_file(&wallet_file, &id1, &password).unwrap();
|
||||
let acc = loaded_login.as_mnemonic_account().unwrap();
|
||||
assert_eq!(acc.mnemonic(), account1.as_ref());
|
||||
assert_eq!(acc.mnemonic(), &account1);
|
||||
assert_eq!(acc.hd_path(), &hd_path);
|
||||
|
||||
append_account_to_login_at_file(
|
||||
@@ -1044,14 +997,8 @@ mod tests {
|
||||
let loaded_login = load_existing_login_at_file(&wallet_file, &id1, &password).unwrap();
|
||||
let loaded_accounts = loaded_login.as_multiple_accounts().unwrap();
|
||||
let expected = vec![
|
||||
WalletAccount::new(
|
||||
id1.into(),
|
||||
MnemonicAccount::new(account1.into_cloned_inner(), hd_path.clone()),
|
||||
),
|
||||
WalletAccount::new(
|
||||
id2,
|
||||
MnemonicAccount::new(account2.into_cloned_inner(), hd_path),
|
||||
),
|
||||
WalletAccount::new(id1.into(), MnemonicAccount::new(account1, hd_path.clone())),
|
||||
WalletAccount::new(id2, MnemonicAccount::new(account2, hd_path)),
|
||||
]
|
||||
.into();
|
||||
assert_eq!(loaded_accounts, &expected);
|
||||
@@ -1061,10 +1008,10 @@ mod tests {
|
||||
fn append_accounts_to_existing_login() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet_file = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let account1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account2 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account3 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account4 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account1 = Mnemonic::generate(24).unwrap();
|
||||
let account2 = Mnemonic::generate(24).unwrap();
|
||||
let account3 = Mnemonic::generate(24).unwrap();
|
||||
let account4 = Mnemonic::generate(24).unwrap();
|
||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
let id1 = LoginId::new("first".to_string());
|
||||
@@ -1074,7 +1021,7 @@ mod tests {
|
||||
|
||||
store_login_at_file(
|
||||
&wallet_file,
|
||||
account1.unchecked_clone_inner(),
|
||||
account1.clone(),
|
||||
hd_path.clone(),
|
||||
id1.clone(),
|
||||
&password,
|
||||
@@ -1083,7 +1030,7 @@ mod tests {
|
||||
|
||||
store_login_at_file(
|
||||
&wallet_file,
|
||||
account2.unchecked_clone_inner(),
|
||||
account2.clone(),
|
||||
hd_path.clone(),
|
||||
id2.clone(),
|
||||
&password,
|
||||
@@ -1093,7 +1040,7 @@ mod tests {
|
||||
// Check that it's there as the correct non-multiple type
|
||||
let loaded_login = load_existing_login_at_file(&wallet_file, &id2, &password).unwrap();
|
||||
let acc2 = loaded_login.as_mnemonic_account().unwrap();
|
||||
assert_eq!(acc2.mnemonic(), account2.as_ref());
|
||||
assert_eq!(acc2.mnemonic(), &account2);
|
||||
assert_eq!(acc2.hd_path(), &hd_path);
|
||||
|
||||
// Add a third and fourth mnenonic grouped together with the second one
|
||||
@@ -1119,24 +1066,15 @@ mod tests {
|
||||
// Check that we can load all four
|
||||
let loaded_login = load_existing_login_at_file(&wallet_file, &id1, &password).unwrap();
|
||||
let acc1 = loaded_login.as_mnemonic_account().unwrap();
|
||||
assert_eq!(acc1.mnemonic(), account1.as_ref());
|
||||
assert_eq!(acc1.mnemonic(), &account1);
|
||||
assert_eq!(acc1.hd_path(), &hd_path);
|
||||
|
||||
let loaded_login = load_existing_login_at_file(&wallet_file, &id2, &password).unwrap();
|
||||
let loaded_accounts = loaded_login.as_multiple_accounts().unwrap();
|
||||
let expected = vec![
|
||||
WalletAccount::new(
|
||||
id2.into(),
|
||||
MnemonicAccount::new(account2.into_cloned_inner(), hd_path.clone()),
|
||||
),
|
||||
WalletAccount::new(
|
||||
id3,
|
||||
MnemonicAccount::new(account3.into_cloned_inner(), hd_path.clone()),
|
||||
),
|
||||
WalletAccount::new(
|
||||
id4,
|
||||
MnemonicAccount::new(account4.into_cloned_inner(), hd_path),
|
||||
),
|
||||
WalletAccount::new(id2.into(), MnemonicAccount::new(account2, hd_path.clone())),
|
||||
WalletAccount::new(id3, MnemonicAccount::new(account3, hd_path.clone())),
|
||||
WalletAccount::new(id4, MnemonicAccount::new(account4, hd_path)),
|
||||
]
|
||||
.into();
|
||||
assert_eq!(loaded_accounts, &expected);
|
||||
@@ -1146,10 +1084,10 @@ mod tests {
|
||||
fn append_accounts_to_existing_login_with_multi() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet_file = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let account1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account2 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account3 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account4 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account1 = Mnemonic::generate(24).unwrap();
|
||||
let account2 = Mnemonic::generate(24).unwrap();
|
||||
let account3 = Mnemonic::generate(24).unwrap();
|
||||
let account4 = Mnemonic::generate(24).unwrap();
|
||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
let id1 = LoginId::new("first".to_string());
|
||||
@@ -1200,7 +1138,7 @@ mod tests {
|
||||
let loaded_accounts = loaded_login.as_multiple_accounts().unwrap();
|
||||
let expected = vec![WalletAccount::new(
|
||||
DEFAULT_FIRST_ACCOUNT_NAME.into(),
|
||||
MnemonicAccount::new(account1.into_cloned_inner(), hd_path.clone()),
|
||||
MnemonicAccount::new(account1, hd_path.clone()),
|
||||
)]
|
||||
.into();
|
||||
assert_eq!(loaded_accounts, &expected);
|
||||
@@ -1210,16 +1148,10 @@ mod tests {
|
||||
let expected = vec![
|
||||
WalletAccount::new(
|
||||
DEFAULT_FIRST_ACCOUNT_NAME.into(),
|
||||
MnemonicAccount::new(account2.into_cloned_inner(), hd_path.clone()),
|
||||
),
|
||||
WalletAccount::new(
|
||||
id3,
|
||||
MnemonicAccount::new(account3.into_cloned_inner(), hd_path.clone()),
|
||||
),
|
||||
WalletAccount::new(
|
||||
id4,
|
||||
MnemonicAccount::new(account4.into_cloned_inner(), hd_path),
|
||||
MnemonicAccount::new(account2, hd_path.clone()),
|
||||
),
|
||||
WalletAccount::new(id3, MnemonicAccount::new(account3, hd_path.clone())),
|
||||
WalletAccount::new(id4, MnemonicAccount::new(account4, hd_path)),
|
||||
]
|
||||
.into();
|
||||
assert_eq!(loaded_accounts, &expected);
|
||||
@@ -1229,7 +1161,7 @@ mod tests {
|
||||
fn append_the_same_mnemonic_twice_fails() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet_file = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let account1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account1 = Mnemonic::generate(24).unwrap();
|
||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
let id1 = LoginId::new("first".to_string());
|
||||
@@ -1254,21 +1186,14 @@ mod tests {
|
||||
fn delete_the_same_account_twice_for_a_login_fails() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let account1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account2 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account1 = Mnemonic::generate(24).unwrap();
|
||||
let account2 = Mnemonic::generate(24).unwrap();
|
||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
let id1 = LoginId::new("first".to_string());
|
||||
let id2 = AccountId::new("second".to_string());
|
||||
|
||||
store_login_at_file(
|
||||
&wallet,
|
||||
account1.into_cloned_inner(),
|
||||
hd_path.clone(),
|
||||
id1.clone(),
|
||||
&password,
|
||||
)
|
||||
.unwrap();
|
||||
store_login_at_file(&wallet, account1, hd_path.clone(), id1.clone(), &password).unwrap();
|
||||
|
||||
append_account_to_login_at_file(
|
||||
&wallet,
|
||||
@@ -1292,8 +1217,8 @@ mod tests {
|
||||
fn delete_the_same_account_twice_for_a_login_fails_with_multi() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet_file = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let account1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account2 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account1 = Mnemonic::generate(24).unwrap();
|
||||
let account2 = Mnemonic::generate(24).unwrap();
|
||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
let id1 = LoginId::new("first".to_string());
|
||||
@@ -1330,9 +1255,9 @@ mod tests {
|
||||
fn delete_appended_account_doesnt_affect_others() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet_file = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let account1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account2 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account3 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account1 = Mnemonic::generate(24).unwrap();
|
||||
let account2 = Mnemonic::generate(24).unwrap();
|
||||
let account3 = Mnemonic::generate(24).unwrap();
|
||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
let id1 = LoginId::new("first".to_string());
|
||||
@@ -1341,7 +1266,7 @@ mod tests {
|
||||
|
||||
store_login_at_file(
|
||||
&wallet_file,
|
||||
account1.into_cloned_inner(),
|
||||
account1,
|
||||
hd_path.clone(),
|
||||
id1.clone(),
|
||||
&password,
|
||||
@@ -1350,7 +1275,7 @@ mod tests {
|
||||
|
||||
store_login_at_file(
|
||||
&wallet_file,
|
||||
account2.unchecked_clone_inner(),
|
||||
account2.clone(),
|
||||
hd_path.clone(),
|
||||
id2.clone(),
|
||||
&password,
|
||||
@@ -1373,14 +1298,8 @@ mod tests {
|
||||
let loaded_login = load_existing_login_at_file(&wallet_file, &id2, &password).unwrap();
|
||||
let loaded_accounts = loaded_login.as_multiple_accounts().unwrap();
|
||||
let expected = vec![
|
||||
WalletAccount::new(
|
||||
id2.into(),
|
||||
MnemonicAccount::new(account2.into_cloned_inner(), hd_path.clone()),
|
||||
),
|
||||
WalletAccount::new(
|
||||
id3,
|
||||
MnemonicAccount::new(account3.into_cloned_inner(), hd_path),
|
||||
),
|
||||
WalletAccount::new(id2.into(), MnemonicAccount::new(account2, hd_path.clone())),
|
||||
WalletAccount::new(id3, MnemonicAccount::new(account3, hd_path)),
|
||||
]
|
||||
.into();
|
||||
assert_eq!(loaded_accounts, &expected);
|
||||
@@ -1390,8 +1309,8 @@ mod tests {
|
||||
fn remove_all_accounts_for_a_login_removes_the_file_when_empty() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let account1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account2 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account1 = Mnemonic::generate(24).unwrap();
|
||||
let account2 = Mnemonic::generate(24).unwrap();
|
||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
let id1 = LoginId::new("first".to_string());
|
||||
@@ -1439,9 +1358,9 @@ mod tests {
|
||||
fn remove_all_accounts_for_a_login_removes_that_login() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let account1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account2 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account3 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let account1 = Mnemonic::generate(24).unwrap();
|
||||
let account2 = Mnemonic::generate(24).unwrap();
|
||||
let account3 = Mnemonic::generate(24).unwrap();
|
||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
let id1 = LoginId::new("first".to_string());
|
||||
@@ -1496,7 +1415,7 @@ mod tests {
|
||||
let acc3 = loaded_login.as_multiple_accounts().unwrap();
|
||||
let expected = vec![WalletAccount::new(
|
||||
DEFAULT_FIRST_ACCOUNT_NAME.into(),
|
||||
MnemonicAccount::new(account3.into_cloned_inner(), hd_path),
|
||||
MnemonicAccount::new(account3, hd_path),
|
||||
)]
|
||||
.into();
|
||||
assert_eq!(acc3, &expected);
|
||||
@@ -1506,10 +1425,10 @@ mod tests {
|
||||
fn append_accounts_and_remove_appended_accounts() {
|
||||
let store_dir = tempdir().unwrap();
|
||||
let wallet = store_dir.path().join(WALLET_INFO_FILENAME);
|
||||
let acc1 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let acc2 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let acc3 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let acc4 = ZeroizeMnemonicWrapper::generate_random();
|
||||
let acc1 = Mnemonic::generate(24).unwrap();
|
||||
let acc2 = Mnemonic::generate(24).unwrap();
|
||||
let acc3 = Mnemonic::generate(24).unwrap();
|
||||
let acc4 = Mnemonic::generate(24).unwrap();
|
||||
let hd_path: DerivationPath = COSMOS_DERIVATION_PATH.parse().unwrap();
|
||||
let password = UserPassword::new("password".to_string());
|
||||
let id1 = LoginId::new("first".to_string());
|
||||
@@ -1519,7 +1438,7 @@ mod tests {
|
||||
|
||||
store_login_at_file(
|
||||
&wallet,
|
||||
acc1.unchecked_clone_inner(),
|
||||
acc1.clone(),
|
||||
hd_path.clone(),
|
||||
id1.clone(),
|
||||
&password,
|
||||
@@ -1528,7 +1447,7 @@ mod tests {
|
||||
|
||||
store_login_at_file(
|
||||
&wallet,
|
||||
acc2.unchecked_clone_inner(),
|
||||
acc2.clone(),
|
||||
hd_path.clone(),
|
||||
id2.clone(),
|
||||
&password,
|
||||
@@ -1564,12 +1483,9 @@ mod tests {
|
||||
let expected = vec![
|
||||
WalletAccount::new(
|
||||
id2.clone().into(),
|
||||
MnemonicAccount::new(acc2.into_cloned_inner(), hd_path.clone()),
|
||||
),
|
||||
WalletAccount::new(
|
||||
id4.clone(),
|
||||
MnemonicAccount::new(acc4.into_cloned_inner(), hd_path.clone()),
|
||||
MnemonicAccount::new(acc2, hd_path.clone()),
|
||||
),
|
||||
WalletAccount::new(id4.clone(), MnemonicAccount::new(acc4, hd_path.clone())),
|
||||
]
|
||||
.into();
|
||||
assert_eq!(loaded_accounts, &expected);
|
||||
@@ -1585,7 +1501,7 @@ mod tests {
|
||||
// The first login is still available
|
||||
let loaded_login = load_existing_login_at_file(&wallet, &id1, &password).unwrap();
|
||||
let account = loaded_login.as_mnemonic_account().unwrap();
|
||||
assert_eq!(account.mnemonic(), acc1.as_ref());
|
||||
assert_eq!(account.mnemonic(), &acc1);
|
||||
assert_eq!(account.hd_path(), &hd_path);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use zeroize::Zeroize;
|
||||
use zeroize::{Zeroize, Zeroizing};
|
||||
|
||||
// The `LoginId` is the top level id in the wallet file, and is not stored encrypted
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub(crate) struct LoginId(String);
|
||||
|
||||
impl LoginId {
|
||||
@@ -81,26 +80,4 @@ impl fmt::Display for AccountId {
|
||||
}
|
||||
|
||||
// simple wrapper for String that will get zeroized on drop
|
||||
#[derive(Zeroize)]
|
||||
#[zeroize(drop)]
|
||||
pub struct UserPassword(String);
|
||||
|
||||
impl UserPassword {
|
||||
#[cfg(test)]
|
||||
pub(crate) fn new(inner: String) -> Self {
|
||||
UserPassword(inner)
|
||||
}
|
||||
|
||||
pub(crate) fn as_bytes(&self) -> &[u8] {
|
||||
self.0.as_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for UserPassword {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Ok(UserPassword(String::deserialize(deserializer)?))
|
||||
}
|
||||
}
|
||||
pub type UserPassword = Zeroizing<String>;
|
||||
|
||||
@@ -16,7 +16,7 @@ pretty_env_logger = "0.4"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
tokio = { version = "1.11", features = [ "net", "rt-multi-thread", "macros", "signal"] }
|
||||
bip39 = "1.0.1"
|
||||
bip39 = { workspace = true }
|
||||
anyhow = "1"
|
||||
tap = "1"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user