From 49b9e43665554e420135dc5af7330696048db25b Mon Sep 17 00:00:00 2001 From: XuNeal Date: Tue, 6 Feb 2024 15:45:36 +0800 Subject: [PATCH] feat: add biometric to more api --- token-core/tcx-btc-kin/src/signer.rs | 1 - token-core/tcx-crypto/src/crypto.rs | 2 + token-core/tcx-keystore/src/keystore/hd.rs | 27 +- token-core/tcx-keystore/src/keystore/mod.rs | 36 +- .../tcx-keystore/src/keystore/private.rs | 26 +- .../tcx-migration/src/keystore_upgrade.rs | 105 +++--- token-core/tcx-migration/src/migration.rs | 50 +-- token-core/tcx-primitive/src/ecc.rs | 3 +- token-core/tcx-proto/src/api.proto | 5 +- token-core/tcx-proto/src/params.proto | 14 +- token-core/tcx-substrate/src/address.rs | 1 - token-core/tcx/src/api.rs | 44 ++- token-core/tcx/src/handler.rs | 93 +++--- token-core/tcx/src/lib.rs | 315 +++++++++++++++--- 14 files changed, 489 insertions(+), 233 deletions(-) diff --git a/token-core/tcx-btc-kin/src/signer.rs b/token-core/tcx-btc-kin/src/signer.rs index 2f653da2..99f1e2bd 100644 --- a/token-core/tcx-btc-kin/src/signer.rs +++ b/token-core/tcx-btc-kin/src/signer.rs @@ -1153,7 +1153,6 @@ mod tests { } mod ltc { - //todo: test error use super::*; #[test] diff --git a/token-core/tcx-crypto/src/crypto.rs b/token-core/tcx-crypto/src/crypto.rs index c141210e..d8020903 100644 --- a/token-core/tcx-crypto/src/crypto.rs +++ b/token-core/tcx-crypto/src/crypto.rs @@ -304,6 +304,8 @@ impl Crypto { fn derive_key(&self, password: &str) -> Result> { let mut derived_key: Credential = [0u8; CREDENTIAL_LEN]; self.kdf.derive_key(password.as_bytes(), &mut derived_key); + + dbg!(hex::encode(derived_key)); Ok(derived_key.to_vec()) } diff --git a/token-core/tcx-keystore/src/keystore/hd.rs b/token-core/tcx-keystore/src/keystore/hd.rs index f2e2ac70..ee9f1c7e 100644 --- a/token-core/tcx-keystore/src/keystore/hd.rs +++ b/token-core/tcx-keystore/src/keystore/hd.rs @@ -7,7 +7,7 @@ use super::{transform_mnemonic_error, Account, Address, Error, Metadata, Result, use std::collections::{hash_map::Entry, HashMap}; -use tcx_common::ToHex; +use tcx_common::{FromHex, ToHex}; use tcx_constants::{coin_info::get_xpub_prefix, CoinInfo, CurveType}; use tcx_crypto::{Crypto, Key}; use tcx_primitive::{ @@ -224,8 +224,18 @@ impl HdKeystore { &self.store().identity } - pub(crate) fn verify_password(&self, password: &str) -> bool { - self.store.crypto.verify_password(password) + pub(crate) fn verify_password(&self, key: &Key) -> bool { + match key { + Key::Password(password) => { + return self.store.crypto.verify_password(password); + } + Key::DerivedKey(derived_key_hex) => { + let Ok(derived_key) = Vec::from_hex_auto(derived_key_hex) else { + return false; + }; + return self.store.crypto.verify_derived_key(&derived_key); + } + } } } @@ -235,7 +245,7 @@ mod tests { use crate::keystore::{metadata_default_time, IdentityNetwork}; use crate::keystore::tests::MockAddress; - use crate::Source; + use crate::{Keystore, Source}; use bitcoin_hashes::hex::ToHex; use std::string::ToString; use tcx_common::FromHex; @@ -258,8 +268,13 @@ mod tests { let keystore = HdKeystore::from_mnemonic(TEST_MNEMONIC, TEST_PASSWORD, Metadata::default()).unwrap(); - assert!(keystore.verify_password(TEST_PASSWORD)); - assert!(!keystore.verify_password("WrongPassword")); + let derived_key = Keystore::Hd(keystore.clone()) + .get_derived_key(TEST_PASSWORD) + .unwrap(); + assert!(keystore.verify_password(&Key::Password(TEST_PASSWORD.to_string()))); + assert!(keystore.verify_password(&Key::DerivedKey(derived_key.to_string()))); + assert!(!keystore.verify_password(&Key::Password("WRONG PASSWORD".to_string()))); + assert!(!keystore.verify_password(&Key::DerivedKey("731dd44109f9897eb39980907161b7531be44714352ddaa40542da22fb4fab7533678f2e132226389174faad4e653c542811a7b0c9391ae3cce4e75039a15adc".to_string()))); } #[test] diff --git a/token-core/tcx-keystore/src/keystore/mod.rs b/token-core/tcx-keystore/src/keystore/mod.rs index a84d029e..f3170d77 100644 --- a/token-core/tcx-keystore/src/keystore/mod.rs +++ b/token-core/tcx-keystore/src/keystore/mod.rs @@ -403,11 +403,8 @@ impl Keystore { } } - pub fn backup(&self, password: &str) -> Result { - let unlocker = self - .store() - .crypto - .use_key(&Key::Password(password.to_string()))?; + pub fn backup(&self, key: &Key) -> Result { + let unlocker = self.store().crypto.use_key(key)?; let decrypted = unlocker.decrypt_enc_pair(&self.store().enc_original)?; let original = String::from_utf8_lossy(&decrypted); Ok(original.to_string()) @@ -417,10 +414,10 @@ impl Keystore { &self.store().identity } - pub fn verify_password(&self, password: &str) -> bool { + pub fn verify_password(&self, key: &Key) -> bool { match self { - Keystore::PrivateKey(ks) => ks.verify_password(password), - Keystore::Hd(ks) => ks.verify_password(password), + Keystore::PrivateKey(ks) => ks.verify_password(key), + Keystore::Hd(ks) => ks.verify_password(key), } } @@ -773,8 +770,11 @@ pub(crate) mod tests { "password_incorrect" ); - assert!(keystore.verify_password(TEST_PASSWORD)); - assert!(!keystore.verify_password("WRONG PASSWORD")); + let derived_key = keystore.get_derived_key(TEST_PASSWORD).unwrap(); + assert!(keystore.verify_password(&Key::Password(TEST_PASSWORD.to_string()))); + assert!(keystore.verify_password(&Key::DerivedKey(derived_key.to_string()))); + assert!(!keystore.verify_password(&Key::Password("WRONG PASSWORD".to_string()))); + assert!(!keystore.verify_password(&Key::DerivedKey("731dd44109f9897eb39980907161b7531be44714352ddaa40542da22fb4fab7533678f2e132226389174faad4e653c542811a7b0c9391ae3cce4e75039a15adc".to_string()))); keystore.unlock_by_password(TEST_PASSWORD).unwrap(); assert_eq!( "inject kidney empty canal shadow pact comfort wife crush horse wife sketch", @@ -889,9 +889,11 @@ pub(crate) mod tests { assert!(keystore.identity().identifier.starts_with("im")); assert_eq!(keystore.meta().name, "Unknown"); assert_ne!(keystore.id(), ""); - - assert!(keystore.verify_password(&TEST_PASSWORD)); - assert!(!keystore.verify_password(&WRONG_PASSWORD)); + let derived_key = keystore.get_derived_key(TEST_PASSWORD).unwrap(); + assert!(keystore.verify_password(&Key::Password(TEST_PASSWORD.to_string()))); + assert!(keystore.verify_password(&Key::DerivedKey(derived_key.to_string()))); + assert!(!keystore.verify_password(&Key::Password("WRONG PASSWORD".to_string()))); + assert!(!keystore.verify_password(&Key::DerivedKey("731dd44109f9897eb39980907161b7531be44714352ddaa40542da22fb4fab7533678f2e132226389174faad4e653c542811a7b0c9391ae3cce4e75039a15adc".to_string()))); let coin_info = CoinInfo { coin: "BITCOIN".to_string(), @@ -959,9 +961,11 @@ pub(crate) mod tests { format!("0x{}", keystore.export().unwrap()), TEST_PRIVATE_KEY.to_string() ); - - assert!(keystore.verify_password(&TEST_PASSWORD)); - assert!(!keystore.verify_password(&WRONG_PASSWORD)); + let derived_key = keystore.get_derived_key(TEST_PASSWORD).unwrap(); + assert!(keystore.verify_password(&Key::Password(TEST_PASSWORD.to_string()))); + assert!(keystore.verify_password(&Key::DerivedKey(derived_key.to_string()))); + assert!(!keystore.verify_password(&Key::Password("WRONG PASSWORD".to_string()))); + assert!(!keystore.verify_password(&Key::DerivedKey("731dd44109f9897eb39980907161b7531be44714352ddaa40542da22fb4fab7533678f2e132226389174faad4e653c542811a7b0c9391ae3cce4e75039a15adc".to_string()))); let coin_info = CoinInfo { coin: "BITCOIN".to_string(), diff --git a/token-core/tcx-keystore/src/keystore/private.rs b/token-core/tcx-keystore/src/keystore/private.rs index 6630410e..329ee4d0 100644 --- a/token-core/tcx-keystore/src/keystore/private.rs +++ b/token-core/tcx-keystore/src/keystore/private.rs @@ -1,5 +1,6 @@ use super::Account; use super::{Address, Metadata}; +use bitcoin::util; use tcx_constants::{CoinInfo, CurveType}; use tcx_crypto::{Crypto, Key}; @@ -82,8 +83,18 @@ impl PrivateKeystore { Ok(account) } - pub(crate) fn verify_password(&self, password: &str) -> bool { - self.store.crypto.verify_password(password) + pub(crate) fn verify_password(&self, key: &Key) -> bool { + match key { + Key::Password(password) => { + return self.store.crypto.verify_password(password); + } + Key::DerivedKey(derived_key_hex) => { + let Ok(derived_key) = Vec::from_hex_auto(derived_key_hex) else { + return false; + }; + return self.store.crypto.verify_derived_key(&derived_key); + } + } } pub fn from_private_key( @@ -160,7 +171,7 @@ impl PrivateKeystore { mod tests { use crate::keystore::private::fingerprint_from_private_key; use crate::keystore::tests::MockAddress; - use crate::{Metadata, PrivateKeystore, Source}; + use crate::{Keystore, Metadata, PrivateKeystore, Source}; use tcx_common::FromHex; use tcx_constants::{CoinInfo, CurveType, TEST_PASSWORD, TEST_PRIVATE_KEY}; use tcx_crypto::Key; @@ -205,8 +216,13 @@ mod tests { ) .unwrap(); - assert!(keystore.verify_password(TEST_PASSWORD)); - assert!(!keystore.verify_password("WrongPassword")); + let derived_key = Keystore::PrivateKey(keystore.clone()) + .get_derived_key(TEST_PASSWORD) + .unwrap(); + assert!(keystore.verify_password(&Key::Password(TEST_PASSWORD.to_string()))); + assert!(keystore.verify_password(&Key::DerivedKey(derived_key.to_string()))); + assert!(!keystore.verify_password(&Key::Password("WRONG PASSWORD".to_string()))); + assert!(!keystore.verify_password(&Key::DerivedKey("731dd44109f9897eb39980907161b7531be44714352ddaa40542da22fb4fab7533678f2e132226389174faad4e653c542811a7b0c9391ae3cce4e75039a15adc".to_string()))); } #[test] diff --git a/token-core/tcx-migration/src/keystore_upgrade.rs b/token-core/tcx-migration/src/keystore_upgrade.rs index 1079d566..a0c6bac3 100644 --- a/token-core/tcx-migration/src/keystore_upgrade.rs +++ b/token-core/tcx-migration/src/keystore_upgrade.rs @@ -576,13 +576,15 @@ mod tests { ); let json = serde_json::from_str(json_str).unwrap(); let old_ks = KeystoreUpgrade::new(json); - let ks = old_ks - .upgrade( - &Key::Password(TEST_PASSWORD.to_string()), - &IdentityNetwork::Mainnet, - ) - .unwrap(); - let ori = ks.backup(TEST_PASSWORD).unwrap(); + let key = Key::Password(TEST_PASSWORD.to_string()); + let ks = old_ks.upgrade(&key, &IdentityNetwork::Mainnet).unwrap(); + let ori = ks.backup(&key).unwrap(); + assert_eq!( + ori, + "685634d212eabe016a1cb09d9f1ea1ea757ebe590b9a097d7b1c9379ad280171" + ); + + let ori = ks.backup(&Key::DerivedKey("1a60471067b6c6a3202e0014de2ce9b2d45fd73e2289b3cc3d8e5b58fe99ff242fd61e9fe63e75abbdc0ed87a50756cc10c57daf1d6297b99ec9a3b174eee017".to_string())).unwrap(); assert_eq!( ori, "685634d212eabe016a1cb09d9f1ea1ea757ebe590b9a097d7b1c9379ad280171" @@ -596,13 +598,15 @@ mod tests { ); let json = serde_json::from_str(json_str).unwrap(); let old_ks = KeystoreUpgrade::new(json); - let ks = old_ks - .upgrade( - &Key::Password(TEST_PASSWORD.to_string()), - &IdentityNetwork::Mainnet, - ) - .unwrap(); - let ori = ks.backup(TEST_PASSWORD).unwrap(); + let key = Key::Password(TEST_PASSWORD.to_string()); + let ks = old_ks.upgrade(&key, &IdentityNetwork::Mainnet).unwrap(); + let ori = ks.backup(&key).unwrap(); + assert_eq!( + ori, + "edskS3E5CLrkwHRYAbDvw5xC913C9GGseMcyNGeGbeaD57Yvvi2jqizpAAZyzUtRK626UvkKYdJwCYE9oKMcqFCtJeBpDYcrVH" + ); + + let ori = ks.backup(&Key::DerivedKey("b009d3c4e961411836028a9fffbea994e03c71f75589a571cd52125884537f2ac165b92e7bc49c7828d4be0c5c05263a306744f0b9dc785142c8562d45ce4345".to_string())).unwrap(); assert_eq!( ori, "edskS3E5CLrkwHRYAbDvw5xC913C9GGseMcyNGeGbeaD57Yvvi2jqizpAAZyzUtRK626UvkKYdJwCYE9oKMcqFCtJeBpDYcrVH" @@ -616,13 +620,13 @@ mod tests { ); let json = serde_json::from_str(json_str).unwrap(); let old_ks = KeystoreUpgrade::new(json); - let ks = old_ks - .upgrade( - &Key::Password(TEST_PASSWORD.to_string()), - &IdentityNetwork::Mainnet, - ) - .unwrap(); - let ori = ks.backup(TEST_PASSWORD).unwrap(); + let key = Key::Password(TEST_PASSWORD.to_string()); + let ks = old_ks.upgrade(&key, &IdentityNetwork::Mainnet).unwrap(); + let ori = ks.backup(&key).unwrap(); + + assert_eq!(ori, "TBRMznXcDf2HK2jBKJsqjBpsEdaiaZUBGKN8aKdwTMrPnMNB5UQM"); + let ori = ks.backup(&Key::DerivedKey("2e70651f06a28d2f6053a90ee55ab8cb14518ab82182cd922926b4239713286ac6746ad4448608fc1599e6f4e0af33c65f70bc5de13a376933e5e145681d0f80".to_string())).unwrap(); + assert_eq!(ori, "TBRMznXcDf2HK2jBKJsqjBpsEdaiaZUBGKN8aKdwTMrPnMNB5UQM"); } @@ -633,13 +637,14 @@ mod tests { ); let json = serde_json::from_str(json_str).unwrap(); let old_ks = KeystoreUpgrade::new(json); - let ks = old_ks - .upgrade( - &Key::Password(TEST_PASSWORD.to_string()), - &IdentityNetwork::Mainnet, - ) - .unwrap(); - let ori = ks.backup(TEST_PASSWORD).unwrap(); + let key = Key::Password(TEST_PASSWORD.to_string()); + let ks = old_ks.upgrade(&key, &IdentityNetwork::Mainnet).unwrap(); + let ori = ks.backup(&key).unwrap(); + + assert_eq!(ori, "L1xDTJYPqhofU8DQCiwjStEBr1X6dhiNfweUhxhoRSgYyMJPcZ6B"); + + let ori = ks.backup(&Key::DerivedKey("d175dad756f59a59b6a311f2b369802537d92011c8e3bf6dc2dfaf8df00d942648bf83133bd0204ebc43efcbd0ab79a8d5551c8dcf7ae1f67fc2d1d4aff33c06".to_string())).unwrap(); + assert_eq!(ori, "L1xDTJYPqhofU8DQCiwjStEBr1X6dhiNfweUhxhoRSgYyMJPcZ6B"); } @@ -650,13 +655,11 @@ mod tests { ); let json = serde_json::from_str(json_str).unwrap(); let old_ks = KeystoreUpgrade::new(json); - let ks = old_ks - .upgrade( - &Key::Password(TEST_PASSWORD.to_string()), - &IdentityNetwork::Mainnet, - ) - .unwrap(); - let ori = ks.backup(TEST_PASSWORD).unwrap(); + let key = Key::Password(TEST_PASSWORD.to_string()); + let ks = old_ks.upgrade(&key, &IdentityNetwork::Mainnet).unwrap(); + let ori = ks.backup(&key).unwrap(); + assert!(ori.contains("FDS7ZJpJg4R7Kd2hzfsEc6mtW5iknjZ3UazX76EsnbH74v8")); + let ori = ks.backup(&Key::DerivedKey("daa734e276c7420bd7eb6f9d59d39f3072d9ab0c4c0bda09eb410ab930c745302fb39714a2c4ca1935b18d1d216db11455a4c962daf8bf360ba41c65d872a5a8".to_string())).unwrap(); assert!(ori.contains("FDS7ZJpJg4R7Kd2hzfsEc6mtW5iknjZ3UazX76EsnbH74v8")); } @@ -667,13 +670,15 @@ mod tests { ); let json = serde_json::from_str(json_str).unwrap(); let old_ks = KeystoreUpgrade::new(json); - let ks = old_ks - .upgrade( - &Key::Password(TEST_PASSWORD.to_string()), - &IdentityNetwork::Mainnet, - ) - .unwrap(); - let ori = ks.backup(TEST_PASSWORD).unwrap(); + let key = Key::Password(TEST_PASSWORD.to_string()); + let ks = old_ks.upgrade(&key, &IdentityNetwork::Mainnet).unwrap(); + let ori = ks.backup(&key).unwrap(); + + let expected_ori = + r#"{"Type":"secp256k1","PrivateKey":"o5JgTvwvrZwLPaQ7X2mKLj8nDxcNhZkSvg1UdCJ1xfY="}"#; + assert_eq!(ori, expected_ori.as_bytes().to_hex()); + + let ori = ks.backup(&Key::DerivedKey("bee56a3cc9e6536dd22a695742ff1b4a00a797fa6c0ddd6f2c3bfd2ec25d05d61918ab3ceaf5c135f771d957889ee2b361c5d70f1911cc8857299d349a0d9ee6".to_string())).unwrap(); let expected_ori = r#"{"Type":"secp256k1","PrivateKey":"o5JgTvwvrZwLPaQ7X2mKLj8nDxcNhZkSvg1UdCJ1xfY="}"#; assert_eq!(ori, expected_ori.as_bytes().to_hex()); @@ -686,13 +691,15 @@ mod tests { ); let json = serde_json::from_str(json_str).unwrap(); let old_ks = KeystoreUpgrade::new(json); - let ks = old_ks - .upgrade( - &Key::Password(TEST_PASSWORD.to_string()), - &IdentityNetwork::Mainnet, - ) - .unwrap(); - let ori = ks.backup(TEST_PASSWORD).unwrap(); + let key = Key::Password(TEST_PASSWORD.to_string()); + let ks = old_ks.upgrade(&key, &IdentityNetwork::Mainnet).unwrap(); + let ori = ks.backup(&key).unwrap(); + + let expected_ori = + r#"{"Type":"bls","PrivateKey":"i7kO+zxc6QS+v7YygcmUYh7MUYSRes6anigiLhKF808="}"#; + assert_eq!(ori, expected_ori.as_bytes().to_hex()); + + let ori = ks.backup(&Key::DerivedKey("f3207a9f25adbdae5eff58bb13a9d9be4d763c6d47269fb14e4bd7a59ed667ba7282f1ba40746c60ae842c3f9dfeba91060f29f547ef2a94a66cfee93573ffaa".to_string())).unwrap(); let expected_ori = r#"{"Type":"bls","PrivateKey":"i7kO+zxc6QS+v7YygcmUYh7MUYSRes6anigiLhKF808="}"#; assert_eq!(ori, expected_ori.as_bytes().to_hex()); diff --git a/token-core/tcx-migration/src/migration.rs b/token-core/tcx-migration/src/migration.rs index 447b6de7..7d47e9b6 100644 --- a/token-core/tcx-migration/src/migration.rs +++ b/token-core/tcx-migration/src/migration.rs @@ -515,13 +515,9 @@ mod tests { let json_str = include_str!("../../test-data/wallets-ios-2_14_1/9f4acb4a-7431-4c7d-bd25-a19656a86ea0"); let old_ks = LegacyKeystore::from_json_str(json_str).unwrap(); - let ks = old_ks - .migrate( - &Key::Password(TEST_PASSWORD.to_string()), - &IdentityNetwork::Mainnet, - ) - .unwrap(); - let ori = ks.backup(TEST_PASSWORD).unwrap(); + let key = Key::Password(TEST_PASSWORD.to_string()); + let ks = old_ks.migrate(&key, &IdentityNetwork::Mainnet).unwrap(); + let ori = ks.backup(&key).unwrap(); assert_eq!(ori, "L1xDTJYPqhofU8DQCiwjStEBr1X6dhiNfweUhxhoRSgYyMJPcZ6B"); } @@ -531,13 +527,9 @@ mod tests { let json_str = include_str!("../../test-data/wallets-ios-2_14_1/60573d8d-8e83-45c3-85a5-34fbb2aad5e1"); let old_ks = LegacyKeystore::from_json_str(json_str).unwrap(); - let ks = old_ks - .migrate( - &Key::Password(TEST_PASSWORD.to_string()), - &IdentityNetwork::Mainnet, - ) - .unwrap(); - let ori = ks.backup(TEST_PASSWORD).unwrap(); + let key = Key::Password(TEST_PASSWORD.to_string()); + let ks = old_ks.migrate(&key, &IdentityNetwork::Mainnet).unwrap(); + let ori = ks.backup(&key).unwrap(); // ciphertext is 9b62... assert!(ori.contains("9b62a4c07c96ca9b0b82b5b5eae4e7c9b2b7db531a6d2991198eb6809a8c35ac")); } @@ -547,13 +539,9 @@ mod tests { let json_str = include_str!("../../test-data/wallets-ios-2_14_1/0597526e-105f-425b-bb44-086fc9dc9568"); let old_ks = LegacyKeystore::from_json_str(json_str).unwrap(); - let ks = old_ks - .migrate( - &Key::Password(TEST_PASSWORD.to_string()), - &IdentityNetwork::Mainnet, - ) - .unwrap(); - let ori = ks.backup(TEST_PASSWORD).unwrap(); + let key = Key::Password(TEST_PASSWORD.to_string()); + let ks = old_ks.migrate(&key, &IdentityNetwork::Mainnet).unwrap(); + let ori = ks.backup(&key).unwrap(); assert_eq!( ori, @@ -566,13 +554,9 @@ mod tests { let json_str = include_str!("../../test-data/wallets-ios-2_14_1/f3615a56-cb03-4aa4-a893-89944e49920d"); let old_ks = LegacyKeystore::from_json_str(json_str).unwrap(); - let ks = old_ks - .migrate( - &Key::DerivedKey("0x79c74b67fc73a255bc66afc1e7c25867a19e6d2afa5b8e3107a472de13201f1924fed05e811e7f5a4c3e72a8a6e047a80393c215412bde239ec7ded520896630".to_string()), - &IdentityNetwork::Mainnet, - ) - .unwrap(); - let ori = ks.backup(TEST_PASSWORD).unwrap(); + let key = Key::DerivedKey("0x79c74b67fc73a255bc66afc1e7c25867a19e6d2afa5b8e3107a472de13201f1924fed05e811e7f5a4c3e72a8a6e047a80393c215412bde239ec7ded520896630".to_string()); + let ks = old_ks.migrate(&key, &IdentityNetwork::Mainnet).unwrap(); + let ori = ks.backup(&key).unwrap(); assert_eq!( ori, @@ -585,13 +569,9 @@ mod tests { let json_str = include_str!("../../test-data/wallets-ios-2_14_1/ac59ccc1-285b-47a7-92f5-a6c432cee21a"); let old_ks = LegacyKeystore::from_json_str(json_str).unwrap(); - let ks = old_ks - .migrate( - &Key::Password(TEST_PASSWORD.to_string()), - &IdentityNetwork::Mainnet, - ) - .unwrap(); - let ori = ks.backup(TEST_PASSWORD).unwrap(); + let key = Key::Password(TEST_PASSWORD.to_string()); + let ks = old_ks.migrate(&key, &IdentityNetwork::Mainnet).unwrap(); + let ori = ks.backup(&key).unwrap(); assert_eq!( ori, diff --git a/token-core/tcx-primitive/src/ecc.rs b/token-core/tcx-primitive/src/ecc.rs index cd72609f..7cc2128a 100644 --- a/token-core/tcx-primitive/src/ecc.rs +++ b/token-core/tcx-primitive/src/ecc.rs @@ -29,8 +29,7 @@ pub enum KeyError { InvalidChildNumber, #[error("cannot_derive_from_hardened_key")] CannotDeriveFromHardenedKey, - // todo: why use this key? - #[error("cannot_derive_key")] + #[error("invalid_base58")] InvalidBase58, #[error("invalid_private_key")] InvalidPrivateKey, diff --git a/token-core/tcx-proto/src/api.proto b/token-core/tcx-proto/src/api.proto index d3c21443..8e796675 100644 --- a/token-core/tcx-proto/src/api.proto +++ b/token-core/tcx-proto/src/api.proto @@ -117,7 +117,10 @@ message ExportJsonParam { //// verify the password of the keystore message WalletKeyParam { string id = 1; - string password = 2; + oneof key { + string password = 2; + string derivedKey = 3; + } } message ExportMnemonicParam { diff --git a/token-core/tcx-proto/src/params.proto b/token-core/tcx-proto/src/params.proto index ac36982b..680557cf 100644 --- a/token-core/tcx-proto/src/params.proto +++ b/token-core/tcx-proto/src/params.proto @@ -192,15 +192,6 @@ message DeriveSubAccountsResult { repeated AccountResponse accounts = 1; } -message RemoveWalletParam { - string id = 1; - string password = 2; -} - -message RemoveWalletResult { - bool isSuccess = 1; -} - message EncryptDataToIpfsParam { string identifier = 1; string content = 2; @@ -225,7 +216,10 @@ message SignAuthenticationMessageParam { uint64 accessTime = 1; string identifier = 2 ; string deviceToken = 3; - string password = 4; + oneof key { + string password = 4; + string derivedKey = 5; + } } message SignAuthenticationMessageResult { diff --git a/token-core/tcx-substrate/src/address.rs b/token-core/tcx-substrate/src/address.rs index 83a0eabd..717ee436 100644 --- a/token-core/tcx-substrate/src/address.rs +++ b/token-core/tcx-substrate/src/address.rs @@ -12,7 +12,6 @@ pub struct SubstrateAddress(String); impl Address for SubstrateAddress { fn from_public_key(public_key: &TypedPublicKey, coin: &CoinInfo) -> Result { - // todo: TypedPublicKey to public key let sr_pk = Sr25519PublicKey::from_slice(&public_key.to_bytes())?; let address = match coin.coin.as_str() { "KUSAMA" => sr_pk diff --git a/token-core/tcx/src/api.rs b/token-core/tcx/src/api.rs index 0f80df8e..5a55d538 100644 --- a/token-core/tcx/src/api.rs +++ b/token-core/tcx/src/api.rs @@ -196,8 +196,19 @@ pub struct ExportJsonParam { pub struct WalletKeyParam { #[prost(string, tag = "1")] pub id: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub password: ::prost::alloc::string::String, + #[prost(oneof = "wallet_key_param::Key", tags = "2, 3")] + pub key: ::core::option::Option, +} +/// Nested message and enum types in `WalletKeyParam`. +pub mod wallet_key_param { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Key { + #[prost(string, tag = "2")] + Password(::prost::alloc::string::String), + #[prost(string, tag = "3")] + DerivedKey(::prost::alloc::string::String), + } } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -510,20 +521,6 @@ pub struct DeriveSubAccountsResult { } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct RemoveWalletParam { - #[prost(string, tag = "1")] - pub id: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub password: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct RemoveWalletResult { - #[prost(bool, tag = "1")] - pub is_success: bool, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] pub struct EncryptDataToIpfsParam { #[prost(string, tag = "1")] pub identifier: ::prost::alloc::string::String, @@ -563,8 +560,19 @@ pub struct SignAuthenticationMessageParam { pub identifier: ::prost::alloc::string::String, #[prost(string, tag = "3")] pub device_token: ::prost::alloc::string::String, - #[prost(string, tag = "4")] - pub password: ::prost::alloc::string::String, + #[prost(oneof = "sign_authentication_message_param::Key", tags = "4, 5")] + pub key: ::core::option::Option, +} +/// Nested message and enum types in `SignAuthenticationMessageParam`. +pub mod sign_authentication_message_param { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Key { + #[prost(string, tag = "4")] + Password(::prost::alloc::string::String), + #[prost(string, tag = "5")] + DerivedKey(::prost::alloc::string::String), + } } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/token-core/tcx/src/handler.rs b/token-core/tcx/src/handler.rs index f857c7af..1f90bc89 100644 --- a/token-core/tcx/src/handler.rs +++ b/token-core/tcx/src/handler.rs @@ -28,13 +28,13 @@ use tcx_filecoin::KeyInfo; use crate::api::derive_accounts_param::Derivation; use crate::api::{ - export_private_key_param, AccountResponse, BackupResult, CreateKeystoreParam, - DecryptDataFromIpfsParam, DecryptDataFromIpfsResult, DeriveAccountsParam, DeriveAccountsResult, - DeriveSubAccountsParam, DeriveSubAccountsResult, DerivedKeyResult, EncryptDataToIpfsParam, - EncryptDataToIpfsResult, ExistsJsonParam, ExistsKeystoreResult, ExistsMnemonicParam, - ExistsPrivateKeyParam, ExportJsonParam, ExportJsonResult, ExportMnemonicParam, - ExportMnemonicResult, ExportPrivateKeyParam, ExportPrivateKeyResult, GeneralResult, - GetExtendedPublicKeysParam, GetExtendedPublicKeysResult, GetPublicKeysParam, + self, export_private_key_param, wallet_key_param, AccountResponse, BackupResult, + CreateKeystoreParam, DecryptDataFromIpfsParam, DecryptDataFromIpfsResult, DeriveAccountsParam, + DeriveAccountsResult, DeriveSubAccountsParam, DeriveSubAccountsResult, DerivedKeyResult, + EncryptDataToIpfsParam, EncryptDataToIpfsResult, ExistsJsonParam, ExistsKeystoreResult, + ExistsMnemonicParam, ExistsPrivateKeyParam, ExportJsonParam, ExportJsonResult, + ExportMnemonicParam, ExportMnemonicResult, ExportPrivateKeyParam, ExportPrivateKeyResult, + GeneralResult, GetExtendedPublicKeysParam, GetExtendedPublicKeysResult, GetPublicKeysParam, GetPublicKeysResult, ImportJsonParam, ImportMnemonicParam, ImportPrivateKeyParam, ImportPrivateKeyResult, KeystoreResult, MnemonicToPublicKeyParam, MnemonicToPublicKeyResult, ScanKeystoresResult, SignAuthenticationMessageParam, SignAuthenticationMessageResult, @@ -132,10 +132,6 @@ fn fingerprint_from_any_format_pk(pk: &str) -> Result { fingerprint_from_private_key(&key_data) } -// fn fingerprint_from_tezos_format_pk(pk: &str) -> Result { -// fingerprint_from_private_key(&key_data) -// } - fn import_private_key_internal( param: &ImportPrivateKeyParam, source: Option, @@ -333,8 +329,8 @@ fn key_info_from_v3(keystore: &str, password: &str) -> Result<(Vec, String)> ks.validate_v3(password)?; let key = tcx_crypto::Key::Password(password.to_string()); let unlocker = ks.crypto.use_key(&key)?; - let pk = unlocker.plaintext()?; - Ok((pk, "Imported ETH".to_string())) + let private_key = unlocker.plaintext()?; + Ok((private_key, "Imported ETH".to_string())) } fn key_info_from_substrate_keystore(keystore: &str, password: &str) -> Result<(Vec, String)> { @@ -344,6 +340,24 @@ fn key_info_from_substrate_keystore(keystore: &str, password: &str) -> Result<(V Ok((pk, ks.meta.name)) } +fn curve_to_chain_type(curve: &CurveType) -> Vec { + match curve { + CurveType::SECP256k1 => vec![ + "BITCOIN".to_string(), + "BITCOINCASH".to_string(), + "LITECOIN".to_string(), + "FILECOIN".to_string(), + "EOS".to_string(), + "TRON".to_string(), + "COSMOS".to_string(), + ], + CurveType::ED25519 => vec!["TEZOS".to_string()], + CurveType::SR25519 => vec!["KUSAMA".to_string(), "POLKADOT".to_string()], + CurveType::BLS => vec!["FILECOIN".to_string()], + _ => vec![], + } +} + pub fn init_token_core_x(data: &[u8]) -> Result<()> { let InitTokenCoreXParam { file_dir, @@ -371,6 +385,7 @@ pub fn init_token_core_x(data: &[u8]) -> Result<()> { Ok(()) } + pub(crate) fn scan_keystores() -> Result { clean_keystore(); let file_dir = WALLET_FILE_DIR.read(); @@ -443,24 +458,6 @@ pub(crate) fn scan_keystores() -> Result { }) } -fn curve_to_chain_type(curve: &CurveType) -> Vec { - match curve { - CurveType::SECP256k1 => vec![ - "BITCOIN".to_string(), - "BITCOINCASH".to_string(), - "LITECOIN".to_string(), - "FILECOIN".to_string(), - "EOS".to_string(), - "TRON".to_string(), - "COSMOS".to_string(), - ], - CurveType::ED25519 => vec!["TEZOS".to_string()], - CurveType::SR25519 => vec!["KUSAMA".to_string(), "POLKADOT".to_string()], - CurveType::BLS => vec!["FILECOIN".to_string()], - _ => vec![], - } -} - pub(crate) fn create_keystore(data: &[u8]) -> Result> { let param: CreateKeystoreParam = CreateKeystoreParam::decode(data).expect("create_keystore param"); @@ -552,7 +549,6 @@ pub(crate) fn import_mnemonic(data: &[u8]) -> Result> { } impl_to_key!(crate::api::derive_accounts_param::Key); - pub(crate) fn derive_accounts(data: &[u8]) -> Result> { let param: DeriveAccountsParam = DeriveAccountsParam::decode(data).expect("derive_accounts param"); @@ -691,7 +687,7 @@ pub(crate) fn verify_password(data: &[u8]) -> Result> { _ => Err(anyhow!("{}", "wallet_not_found")), }?; - if keystore.verify_password(¶m.password) { + if keystore.verify_password(¶m.key.clone().unwrap().into()) { let rsp = GeneralResult { is_success: true, error: "".to_owned(), @@ -702,6 +698,7 @@ pub(crate) fn verify_password(data: &[u8]) -> Result> { } } +impl_to_key!(crate::api::wallet_key_param::Key); pub(crate) fn delete_keystore(data: &[u8]) -> Result> { let param: WalletKeyParam = WalletKeyParam::decode(data).expect("delete_keystore param"); let mut map = KEYSTORE_MAP.write(); @@ -710,7 +707,7 @@ pub(crate) fn delete_keystore(data: &[u8]) -> Result> { _ => Err(anyhow!("{}", "wallet_not_found")), }?; - if keystore.verify_password(¶m.password) { + if keystore.verify_password(¶m.key.clone().unwrap().into()) { delete_keystore_file(¶m.id)?; map.remove(¶m.id); @@ -891,7 +888,10 @@ pub(crate) fn get_derived_key(data: &[u8]) -> Result> { _ => Err(anyhow!("{}", "wallet_not_found")), }?; - let dk = keystore.get_derived_key(¶m.password)?; + let Some(api::wallet_key_param::Key::Password(password)) = param.key else { + return Err(anyhow!("{}", "get_derived_key need password")); + }; + let dk = keystore.get_derived_key(&password)?; let ret = DerivedKeyResult { id: param.id.to_owned(), @@ -1047,17 +1047,23 @@ pub(crate) fn backup(data: &[u8]) -> Result> { Some(keystore) => Ok(keystore), _ => Err(anyhow!("{}", "wallet_not_found")), }?; - let original = keystore.backup(¶m.password)?; + + let original = keystore.backup(¶m.key.clone().unwrap().into())?; let fingerprint = match keystore.meta().source { Source::Mnemonic | Source::NewMnemonic => fingerprint_from_mnemonic(&original)?, Source::KeystoreV3 => { - let (private_key_bytes, _) = key_info_from_v3(&original, ¶m.password)?; + let Some(api::wallet_key_param::Key::Password(password)) = param.key else { + return Err(anyhow!("{}", "backup_keystore_need_password")); + }; + let (private_key_bytes, _) = key_info_from_v3(&original, &password)?; let private_key = private_key_bytes.to_hex(); fingerprint_from_any_format_pk(&private_key)? } Source::SubstrateKeystore => { - let (private_key_bytes, _) = - key_info_from_substrate_keystore(&original, ¶m.password)?; + let Some(api::wallet_key_param::Key::Password(password)) = param.key else { + return Err(anyhow!("{}", "backup_keystore_need_password")); + }; + let (private_key_bytes, _) = key_info_from_substrate_keystore(&original, &password)?; let private_key = private_key_bytes.to_hex(); fingerprint_from_any_format_pk(&private_key)? } @@ -1078,7 +1084,7 @@ pub(crate) fn unlock_then_crash(data: &[u8]) -> Result> { _ => Err(anyhow!("{}", "wallet_not_found")), }?; - let _guard = KeystoreGuard::unlock_by_password(keystore, ¶m.password)?; + let _guard = keystore.unlock(¶m.key.unwrap().into()); panic!("test_unlock_then_crash"); } @@ -1118,6 +1124,7 @@ pub(crate) fn decrypt_data_from_ipfs(data: &[u8]) -> Result> { encode_message(output) } +impl_to_key!(crate::api::sign_authentication_message_param::Key); pub(crate) fn sign_authentication_message(data: &[u8]) -> Result> { let param = SignAuthenticationMessageParam::decode(data).expect("SignAuthenticationMessageParam"); @@ -1127,8 +1134,10 @@ pub(crate) fn sign_authentication_message(data: &[u8]) -> Result> { return Err(anyhow::anyhow!("identity_not_found")); }; - let key = tcx_crypto::Key::Password(param.password); - let unlocker = identity_ks.store().crypto.use_key(&key)?; + let unlocker = identity_ks + .store() + .crypto + .use_key(¶m.key.clone().unwrap().into())?; let signature = identity_ks.identity().sign_authentication_message( param.access_time, diff --git a/token-core/tcx/src/lib.rs b/token-core/tcx/src/lib.rs index 32a3474f..32f26dfd 100644 --- a/token-core/tcx/src/lib.rs +++ b/token-core/tcx/src/lib.rs @@ -529,7 +529,9 @@ mod tests { let param = WalletKeyParam { id: wallet.id.to_string(), - password: TEST_PASSWORD.to_string(), + key: Some(api::wallet_key_param::Key::Password( + TEST_PASSWORD.to_owned(), + )), }; let ret = call_api("export_mnemonic", param).unwrap(); let result: ExportMnemonicResult = @@ -541,7 +543,9 @@ mod tests { let param = WalletKeyParam { id: wallet.id.to_string(), - password: TEST_PASSWORD.to_string(), + key: Some(api::wallet_key_param::Key::Password( + TEST_PASSWORD.to_owned(), + )), }; unsafe { clear_err() }; let ret = call_api("export_mnemonic", param); @@ -1934,7 +1938,9 @@ mod tests { for id in wallet_id { let param: WalletKeyParam = WalletKeyParam { id: id.to_string(), - password: TEST_PASSWORD.to_string(), + key: Some(api::wallet_key_param::Key::Password( + TEST_PASSWORD.to_owned(), + )), }; let ret_bytes = call_api("verify_password", param).unwrap(); @@ -1943,7 +1949,9 @@ mod tests { let param: WalletKeyParam = WalletKeyParam { id: id.to_string(), - password: "WRONG PASSWORD".to_string(), + key: Some(api::wallet_key_param::Key::Password( + "WRONG PASSWORD".to_string(), + )), }; let ret = call_api("verify_password", param); @@ -1955,7 +1963,7 @@ mod tests { #[test] #[serial] - pub fn test_delete_keystore() { + pub fn test_delete_keystore_by_password() { run_test(|| { let param: ImportPrivateKeyParam = ImportPrivateKeyParam { private_key: "5JZc7wGRUr4J1RHDcM9ySWKLfQ2xjRUEo612qC4RLJ3G7jzJ4qx".to_string(), @@ -1969,10 +1977,11 @@ mod tests { let ret_bytes = import_private_key(&encode_message(param).unwrap()).unwrap(); let import_result: KeystoreResult = KeystoreResult::decode(ret_bytes.as_slice()).unwrap(); - let param: WalletKeyParam = WalletKeyParam { id: import_result.id.to_string(), - password: "WRONG PASSWORD".to_string(), + key: Some(api::wallet_key_param::Key::Password( + "WRONG PASSWORD".to_string(), + )), }; let ret = call_api("delete_keystore", param); @@ -1981,7 +1990,69 @@ mod tests { let param: WalletKeyParam = WalletKeyParam { id: import_result.id.to_string(), + key: Some(api::wallet_key_param::Key::Password( + TEST_PASSWORD.to_owned(), + )), + }; + + let ret_bytes = call_api("delete_keystore", param).unwrap(); + let ret: GeneralResult = GeneralResult::decode(ret_bytes.as_slice()).unwrap(); + assert!(ret.is_success); + + let param: ExistsPrivateKeyParam = ExistsPrivateKeyParam { + private_key: "5JZc7wGRUr4J1RHDcM9ySWKLfQ2xjRUEo612qC4RLJ3G7jzJ4qx".to_string(), + }; + + let ret_bytes = call_api("exists_private_key", param).unwrap(); + let ret: ExistsKeystoreResult = + ExistsKeystoreResult::decode(ret_bytes.as_slice()).unwrap(); + + assert_eq!(false, ret.is_exists); + }) + } + + #[test] + #[serial] + pub fn test_delete_keystore_by_derived_key() { + run_test(|| { + let param: ImportPrivateKeyParam = ImportPrivateKeyParam { + private_key: "5JZc7wGRUr4J1RHDcM9ySWKLfQ2xjRUEo612qC4RLJ3G7jzJ4qx".to_string(), password: TEST_PASSWORD.to_string(), + name: "test_delete_keystore".to_string(), + password_hint: "".to_string(), + network: "".to_string(), + overwrite: true, + }; + + let ret_bytes = import_private_key(&encode_message(param).unwrap()).unwrap(); + let import_result: KeystoreResult = + KeystoreResult::decode(ret_bytes.as_slice()).unwrap(); + let param = WalletKeyParam { + id: import_result.id.to_string(), + key: Some(api::wallet_key_param::Key::Password( + TEST_PASSWORD.to_owned(), + )), + }; + let ret_bytes = get_derived_key(&encode_message(param).unwrap()).unwrap(); + let derived_key_result: DerivedKeyResult = + DerivedKeyResult::decode(ret_bytes.as_slice()).unwrap(); + + let param: WalletKeyParam = WalletKeyParam { + id: import_result.id.to_string(), + key: Some(api::wallet_key_param::Key::DerivedKey( + "2de5cb10b712be587f31e428e22984bd9ee420d198ddd742f70d746fff27d19904629dd64246a0ce2dbb1484c193d51bb2fd47d5611def5b4db4531d7abed824".to_string(), + )), + }; + + let ret = call_api("delete_keystore", param); + assert!(ret.is_err()); + assert_eq!(format!("{}", ret.err().unwrap()), "password_incorrect"); + + let param: WalletKeyParam = WalletKeyParam { + id: import_result.id.to_string(), + key: Some(api::wallet_key_param::Key::DerivedKey( + derived_key_result.derived_key.to_owned(), + )), }; let ret_bytes = call_api("delete_keystore", param).unwrap(); @@ -2819,7 +2890,9 @@ mod tests { let param = WalletKeyParam { id: import_result.id.to_string(), - password: TEST_PASSWORD.to_string(), + key: Some(api::wallet_key_param::Key::Password( + TEST_PASSWORD.to_owned(), + )), }; let ret_bytes = get_derived_key(&encode_message(param).unwrap()).unwrap(); let ret: DerivedKeyResult = DerivedKeyResult::decode(ret_bytes.as_slice()).unwrap(); @@ -2925,7 +2998,9 @@ mod tests { let dk_param = WalletKeyParam { id: wallet.id.to_string(), - password: TEST_PASSWORD.to_string(), + key: Some(api::wallet_key_param::Key::Password( + TEST_PASSWORD.to_owned(), + )), }; let ret_bytes = get_derived_key(&encode_message(dk_param).unwrap()).unwrap(); @@ -3074,37 +3149,6 @@ mod tests { }) } - // #[test] - // fn test_get_derived_key() { - // let param = InitTokenCoreXParam { - // file_dir: "../test-data".to_string(), - // xpub_common_key: "B888D25EC8C12BD5043777B1AC49F872".to_string(), - // xpub_common_iv: "9C0C30889CBCC5E01AB5B2BB88715799".to_string(), - // is_debug: true, - // }; - - // handler::init_token_core_x(&encode_message(param).unwrap()).expect("should init tcx"); - - // let param = WalletKeyParam { - // id: "cb1ba2d7-7b89-4595-9753-d16b6e317c6b".to_string(), - // password: "WRONG PASSWORD".to_string(), - // }; - - // let ret = call_api("get_derived_key", param); - // assert!(ret.is_err()); - // assert_eq!(format!("{}", ret.err().unwrap()), "password_incorrect"); - - // let param = WalletKeyParam { - // id: "cb1ba2d7-7b89-4595-9753-d16b6e317c6b".to_string(), - // password: TEST_PASSWORD.to_string(), - // }; - - // let ret = call_api("get_derived_key", param).unwrap(); - // let dk_ret: DerivedKeyResult = DerivedKeyResult::decode(ret.as_slice()).unwrap(); - // assert_eq!(dk_ret.derived_key, "119a38ab626aaf8806e223833b29da7aa1d0623e282164d1dd73b0b5e0a88fb4b88937efadd9ca9d4ee931d7b2b33594d75ac4f4d651602819998237b27860fa"); - // } - // - #[test] #[serial] #[ignore = "this case is test panic"] @@ -3113,7 +3157,9 @@ mod tests { let wallet = import_default_wallet(); let param = WalletKeyParam { id: wallet.id.to_string(), - password: TEST_PASSWORD.to_string(), + key: Some(api::wallet_key_param::Key::Password( + TEST_PASSWORD.to_owned(), + )), }; let _ret = call_api("unlock_then_crash", param); let err = unsafe { _to_str(get_last_err_message()) }; @@ -4364,7 +4410,7 @@ mod tests { #[test] #[serial] - pub fn test_backup() { + pub fn test_backup_v3_keystore() { run_test(|| { let json = r#"{ "version": 3, @@ -4401,25 +4447,176 @@ mod tests { let param = WalletKeyParam { id: import_result.id.to_string(), - password: TEST_PASSWORD.to_string(), + key: Some(api::wallet_key_param::Key::Password( + TEST_PASSWORD.to_owned(), + )), }; let ret = call_api("backup", param).unwrap(); let export_result: BackupResult = BackupResult::decode(ret.as_slice()).unwrap(); assert!(export_result .original .contains("0x6031564e7b2F5cc33737807b2E58DaFF870B590b")); + + let param = WalletKeyParam { + id: import_result.id.to_string(), + key: Some(api::wallet_key_param::Key::Password( + TEST_PASSWORD.to_owned(), + )), + }; + + let ret = call_api("get_derived_key", param).unwrap(); + let derived_key_result: DerivedKeyResult = + DerivedKeyResult::decode(ret.as_slice()).unwrap(); + let param = WalletKeyParam { + id: import_result.id.to_string(), + key: Some(api::wallet_key_param::Key::DerivedKey( + derived_key_result.derived_key, + )), + }; + let ret = call_api("backup", param); + assert_eq!( + format!("{}", ret.err().unwrap()), + "backup_keystore_need_password" + ); }) } #[test] #[serial] - pub fn test_backup_mnemonic() { + pub fn test_backup_pjs_kystore() { run_test(|| { - let param: ImportMnemonicParam = ImportMnemonicParam { + let keystore_str: &str = r#"{ + "address": "JHBkzZJnLZ3S3HLvxjpFAjd6ywP7WAk5miL7MwVCn9a7jHS", + "encoded": "0xf7e7e89d3016c9b4d93bb1129adf69e5949ca1fb58c29da4591ddc72c52238a35835e3f2ae023f9867ff301bc4132463527ac03525eaac54664a7cb658eae68a0bbc99354222c194d6100b2bf3a492639229077a2e2818d8196e002f0b5556104be23b11633858259dbbd3f91ea1d34d6ce182b62d8381af1ef3c35e9ab1583267cfa41aa58bfd64435c2b5047baf9052f0953d9f7854d2d396dfcad13", + "encoding": { + "content": [ + "pkcs8", + "sr25519" + ], + "type": "xsalsa20-poly1305", + "version": "2" + }, + "meta": { + "genesisHash": "0xb0a8d493285c2df73290dfb7e61f870f17b41801197a149ca93654499ea3dafe", + "name": "i_can_save_name", + "tags": [], + "whenCreated": 1593591324334 + } + }"#; + let param: ImportJsonParam = ImportJsonParam { + password: TEST_PASSWORD.to_string(), + json: keystore_str.to_string(), + overwrite: true, + }; + let ret = call_api("import_json", param).unwrap(); + let import_result: ImportPrivateKeyResult = + ImportPrivateKeyResult::decode(ret.as_slice()).unwrap(); + assert_eq!( + vec!["KUSAMA".to_string(), "POLKADOT".to_string(),], + import_result.identified_chain_types + ); + + let param = WalletKeyParam { + id: import_result.id.to_string(), + key: Some(api::wallet_key_param::Key::Password( + TEST_PASSWORD.to_owned(), + )), + }; + let ret = call_api("backup", param).unwrap(); + let export_result: BackupResult = BackupResult::decode(ret.as_slice()).unwrap(); + assert!(export_result + .original + .contains("JHBkzZJnLZ3S3HLvxjpFAjd6ywP7WAk5miL7MwVCn9a7jHS")); + + let param = WalletKeyParam { + id: import_result.id.to_string(), + key: Some(api::wallet_key_param::Key::Password( + TEST_PASSWORD.to_owned(), + )), + }; + + let ret = call_api("get_derived_key", param).unwrap(); + let derived_key_result: DerivedKeyResult = + DerivedKeyResult::decode(ret.as_slice()).unwrap(); + let param = WalletKeyParam { + id: import_result.id.to_string(), + key: Some(api::wallet_key_param::Key::DerivedKey( + derived_key_result.derived_key, + )), + }; + let ret = call_api("backup", param); + assert_eq!( + format!("{}", ret.err().unwrap()), + "backup_keystore_need_password" + ); + }) + } + + #[test] + #[serial] + pub fn test_backup_private_key() { + run_test(|| { + let param: ImportPrivateKeyParam = ImportPrivateKeyParam { password: TEST_PASSWORD.to_string(), + private_key: TEST_WIF.to_string(), name: "".to_string(), password_hint: "".to_string(), + network: "TESTNET".to_string(), + overwrite: true, + }; + let ret = call_api("import_private_key", param).unwrap(); + let import_result: ImportPrivateKeyResult = + ImportPrivateKeyResult::decode(ret.as_slice()).unwrap(); + assert_eq!( + vec![ + "BITCOIN".to_string(), + "BITCOINCASH".to_string(), + "LITECOIN".to_string() + ], + import_result.identified_chain_types + ); + + let param = WalletKeyParam { + id: import_result.id.to_string(), + key: Some(api::wallet_key_param::Key::Password( + TEST_PASSWORD.to_owned(), + )), + }; + let ret = call_api("backup", param).unwrap(); + let export_result: BackupResult = BackupResult::decode(ret.as_slice()).unwrap(); + assert_eq!(export_result.original, TEST_WIF); + + let param = WalletKeyParam { + id: import_result.id.to_string(), + key: Some(api::wallet_key_param::Key::Password( + TEST_PASSWORD.to_owned(), + )), + }; + + let ret = call_api("get_derived_key", param).unwrap(); + let derived_key_result: DerivedKeyResult = + DerivedKeyResult::decode(ret.as_slice()).unwrap(); + let param = WalletKeyParam { + id: import_result.id.to_string(), + key: Some(api::wallet_key_param::Key::DerivedKey( + derived_key_result.derived_key, + )), + }; + let ret = call_api("backup", param).unwrap(); + let backup_result = BackupResult::decode(ret.as_slice()).unwrap(); + assert_eq!(backup_result.original, TEST_WIF); + }) + } + + #[test] + #[serial] + pub fn test_backup_mnemonic() { + run_test(|| { + let param: ImportMnemonicParam = ImportMnemonicParam { + password: TEST_PASSWORD.to_string(), mnemonic: TEST_MNEMONIC.to_string(), + password_hint: "".to_string(), + name: "".to_string(), network: "MAINNET".to_string(), overwrite: true, }; @@ -4428,7 +4625,29 @@ mod tests { let param = WalletKeyParam { id: import_result.id.to_string(), - password: TEST_PASSWORD.to_string(), + key: Some(api::wallet_key_param::Key::Password( + TEST_PASSWORD.to_owned(), + )), + }; + let ret = call_api("backup", param).unwrap(); + let export_result: BackupResult = BackupResult::decode(ret.as_slice()).unwrap(); + assert_eq!(export_result.original, TEST_MNEMONIC.to_string()); + + let param = WalletKeyParam { + id: import_result.id.to_string(), + key: Some(api::wallet_key_param::Key::Password( + TEST_PASSWORD.to_owned(), + )), + }; + + let ret = call_api("get_derived_key", param).unwrap(); + let derived_key_result: DerivedKeyResult = + DerivedKeyResult::decode(ret.as_slice()).unwrap(); + let param = WalletKeyParam { + id: import_result.id.to_string(), + key: Some(api::wallet_key_param::Key::DerivedKey( + derived_key_result.derived_key, + )), }; let ret = call_api("backup", param).unwrap(); let export_result: BackupResult = BackupResult::decode(ret.as_slice()).unwrap(); @@ -4479,7 +4698,9 @@ mod tests { access_time: 1514736000, identifier: wallet.identifier, device_token: "12345ABCDE".to_string(), - password: TEST_PASSWORD.to_string(), + key: Some(api::sign_authentication_message_param::Key::Password( + TEST_PASSWORD.to_owned(), + )), }; let ret = call_api("sign_authentication_message", param).unwrap(); let resp: SignAuthenticationMessageResult =