diff --git a/token-core/tcx-migration/src/migration.rs b/token-core/tcx-migration/src/migration.rs index 4a392a36..159220bd 100644 --- a/token-core/tcx-migration/src/migration.rs +++ b/token-core/tcx-migration/src/migration.rs @@ -59,7 +59,7 @@ impl OldMetadata { self.source .clone() .map_or((Source::Mnemonic, None), |source| match source.as_str() { - "RECOVER_IDENTITY" => (Source::Mnemonic, None), + "RECOVERED_IDENTITY" => (Source::Mnemonic, None), "NEW_IDENTITY" => (Source::NewMnemonic, None), "KEYSTORE" => (Source::KeystoreV3, Some(vec!["ETHEREUM".to_string()])), "PRIVATE" => (Source::Private, Some(vec!["ETHEREUM".to_string()])), diff --git a/token-core/tcx-proto/src/params.proto b/token-core/tcx-proto/src/params.proto index b64d0e95..0724827d 100644 --- a/token-core/tcx-proto/src/params.proto +++ b/token-core/tcx-proto/src/params.proto @@ -277,4 +277,13 @@ message MigrateKeystoreParam { message BackupResult { string original = 1; + } + + message MarkIdentityWalletsParam { + repeated string ids = 1; + string source = 2; + } + +message ReadKeystoreMnemonicPathResult { + string path = 1; } \ No newline at end of file diff --git a/token-core/tcx/src/api.rs b/token-core/tcx/src/api.rs index 40f09dae..61488d93 100644 --- a/token-core/tcx/src/api.rs +++ b/token-core/tcx/src/api.rs @@ -704,6 +704,20 @@ pub struct BackupResult { } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] +pub struct MarkIdentityWalletsParam { + #[prost(string, repeated, tag = "1")] + pub ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + #[prost(string, tag = "2")] + pub source: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ReadKeystoreMnemonicPathResult { + #[prost(string, tag = "1")] + pub path: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] pub struct VerifyDerivedKeyParam { #[prost(string, tag = "1")] pub id: ::prost::alloc::string::String, diff --git a/token-core/tcx/src/handler.rs b/token-core/tcx/src/handler.rs index 37dfd592..d3c54d9d 100644 --- a/token-core/tcx/src/handler.rs +++ b/token-core/tcx/src/handler.rs @@ -70,7 +70,9 @@ use tcx_primitive::TypedDeterministicPublicKey; use tcx_tezos::{encode_tezos_private_key, parse_tezos_private_key}; use crate::macros::{impl_to_key, use_chains}; -use crate::migration::remove_old_keystore_by_id; +use crate::migration::{ + read_all_identity_wallet_ids, remove_all_identity_wallets, remove_old_keystore_by_id, +}; use_chains!( tcx_btc_kin::bitcoin, @@ -727,12 +729,24 @@ pub(crate) fn delete_keystore(data: &[u8]) -> Result> { delete_keystore_file(¶m.id)?; map.remove(¶m.id); + // Used to delete all duplicated mnemonic keystore if let Some(file_ids) = remove_old_keystore_by_id(¶m.id.clone()) { for file_id in file_ids { map.remove(&file_id); } } + // Used to delete all identity keystore if is deleting identity wallet + if let Some(all_identity_wallets) = read_all_identity_wallet_ids() { + if all_identity_wallets.wallet_ids.contains(¶m.id) { + if let Some(file_ids) = remove_all_identity_wallets() { + for file_id in file_ids { + map.remove(&file_id); + } + } + } + } + let rsp = GeneralResult { is_success: true, error: "".to_owned(), diff --git a/token-core/tcx/src/lib.rs b/token-core/tcx/src/lib.rs index 540558a4..6c442948 100644 --- a/token-core/tcx/src/lib.rs +++ b/token-core/tcx/src/lib.rs @@ -7,6 +7,7 @@ use std::os::raw::c_char; use anyhow::anyhow; use handler::{backup, sign_bls_to_execution_change}; +use migration::{mark_identity_wallets, read_legacy_keystore_mnemonic_path}; use prost::Message; pub mod api; @@ -78,6 +79,9 @@ pub unsafe extern "C" fn call_tcx_api(hex_str: *const c_char) -> *const c_char { let ret = scan_legacy_keystores()?; encode_message(ret) }), + "read_keystore_mnemonic_path" => { + landingpad(|| read_legacy_keystore_mnemonic_path(&action.param.unwrap().value)) + } "create_keystore" => landingpad(|| create_keystore(&action.param.unwrap().value)), "import_mnemonic" => landingpad(|| import_mnemonic(&action.param.unwrap().value)), "export_mnemonic" => landingpad(|| export_mnemonic(&action.param.unwrap().value)), @@ -122,6 +126,9 @@ pub unsafe extern "C" fn call_tcx_api(hex_str: *const c_char) -> *const c_char { "eth_batch_personal_sign" => { landingpad(|| eth_batch_personal_sign(&action.param.unwrap().value)) } + "mark_identity_wallets" => { + landingpad(|| mark_identity_wallets(&action.param.unwrap().value)) + } _ => landingpad(|| Err(anyhow!("unsupported_method"))), }; match reply { diff --git a/token-core/tcx/src/migration.rs b/token-core/tcx/src/migration.rs index fbc0eb36..3318f29e 100644 --- a/token-core/tcx/src/migration.rs +++ b/token-core/tcx/src/migration.rs @@ -1,6 +1,7 @@ use crate::api::{ - migrate_keystore_param, AccountResponse, KeystoreResult, LegacyKeystoreResult, - MigrateKeystoreParam, MigrateKeystoreResult, ScanLegacyKeystoresResult, + migrate_keystore_param, AccountResponse, GeneralResult, KeystoreResult, LegacyKeystoreResult, + MarkIdentityWalletsParam, MigrateKeystoreParam, MigrateKeystoreResult, + ReadKeystoreMnemonicPathResult, ScanLegacyKeystoresResult, WalletId, }; use crate::error_handling::Result; use crate::filemanager::{cache_keystore, KEYSTORE_MAP, WALLET_FILE_DIR}; @@ -9,7 +10,7 @@ use crate::handler::{encode_message, encrypt_xpub}; use anyhow::anyhow; use prost::Message; use serde::{Deserialize, Serialize}; -use serde_json::Value; +use serde_json::{json, Value}; use std::collections::{HashMap, HashSet}; use std::fs; use std::io::Read; @@ -18,12 +19,21 @@ use std::str::FromStr; use tcx_common::{FromHex, ToHex}; use tcx_constants::coin_info::get_xpub_prefix; use tcx_keystore::keystore::IdentityNetwork; -use tcx_keystore::Keystore; use tcx_keystore::Metadata; +use tcx_keystore::{Keystore, Source}; use tcx_migration::keystore_upgrade::{mapping_curve_name, KeystoreUpgrade}; use tcx_migration::migration::{LegacyKeystore, NumberOrNumberStr}; use tcx_primitive::{Bip32DeterministicPublicKey, Ss58Codec}; +const IDENTITY_WALLET_IDS_FILE: &str = "identity-wallet-ids.json"; + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct AllIdentityWallets { + pub wallet_ids: Vec, + pub source: String, +} + fn read_migrated_map() -> (String, HashMap>) { let legacy_file_dir = { let dir = LEGACY_WALLET_FILE_DIR.read(); @@ -40,66 +50,31 @@ fn read_migrated_map() -> (String, HashMap>) { (migrated_file, map) } -pub fn remove_old_keystore_by_id(id: &str) -> Option> { +fn remove_old_keystore_file(id: &str) { let legacy_file_dir = { let dir = LEGACY_WALLET_FILE_DIR.read(); dir.to_string() }; + let mut file_path = format!("{}/{}.json", legacy_file_dir, id); + if !Path::new(&file_path).exists() { + file_path = format!("{}/{}", legacy_file_dir, id); + } + + if Path::new(&file_path).exists() { + fs::remove_file(&file_path); + } +} + +pub fn remove_old_keystore_by_id(id: &str) -> Option> { let result = read_migrated_map(); let migrated_file = result.0; let mut map = result.1; - let mut is_identity_keystore = false; let marked_files = map.get(id).and_then(|x| Some(x.to_vec())).clone(); if let Some(files) = map.get(id) { for file_id in files.iter() { - let mut file_path = format!("{}/{}.json", legacy_file_dir, file_id); - if !Path::new(&file_path).exists() { - file_path = format!("{}/{}", legacy_file_dir, file_id); - } - - if !is_identity_keystore { - let json = serde_json::from_str::(&fs::read_to_string(&file_path).unwrap()) - .unwrap(); - let source = json["imTokenMeta"]["source"] - .as_str() - .unwrap_or("") - .to_string(); - if source.ends_with("_IDENTITY") { - is_identity_keystore = true; - } - } - - if Path::new(&file_path).exists() { - fs::remove_file(&file_path); - } - } - if is_identity_keystore { - let p = Path::new(legacy_file_dir.as_str()); - let walk_dir = std::fs::read_dir(p).expect("read dir"); - for entry in walk_dir { - let entry = entry.expect("DirEntry"); - let fp = entry.path(); - let mut f = fs::File::open(&fp).expect("open file"); - let mut contents = String::new(); - let read_ret = f.read_to_string(&mut contents); - if read_ret.is_err() { - continue; - } - - let v_result = serde_json::from_str::(&contents); - let Ok(v) = v_result else { - continue; - }; - let source = v["imTokenMeta"]["source"] - .as_str() - .unwrap_or("") - .to_string(); - if source.ends_with("_IDENTITY") { - fs::remove_file(fp); - } - } + remove_old_keystore_file(&file_id); } } @@ -166,6 +141,7 @@ pub(crate) fn migrate_keystore(data: &[u8]) -> Result> { keystore = legacy_keystore.migrate(&key, &network)?; } } + let id = param.id.clone(); let mut is_existed = false; let mut existed_id = "".to_string(); @@ -226,6 +202,95 @@ pub(crate) fn migrate_keystore(data: &[u8]) -> Result> { } } +pub(crate) fn mark_identity_wallets(data: &[u8]) -> Result> { + let param: MarkIdentityWalletsParam = + MarkIdentityWalletsParam::decode(data).expect("param: MarkIdentityWalletsParam"); + let json = AllIdentityWallets { + wallet_ids: param.ids, + source: param.source, + }; + + let legacy_file_dir = { + let dir = LEGACY_WALLET_FILE_DIR.read(); + dir.to_string() + }; + + let file_path = format!("{}/{}", legacy_file_dir, IDENTITY_WALLET_IDS_FILE); + fs::write(file_path, serde_json::to_string(&json)?)?; + let ret = GeneralResult { + is_success: true, + error: "".to_string(), + }; + return encode_message(ret); +} + +pub(crate) fn read_legacy_keystore_mnemonic_path(data: &[u8]) -> Result> { + let param: WalletId = WalletId::decode(data).expect("param: WalletId"); + + let legacy_file_dir = { + let dir = LEGACY_WALLET_FILE_DIR.read(); + dir.to_string() + }; + + let mut file_path = format!("{}/{}", legacy_file_dir, param.id); + if !Path::new(&file_path).exists() { + file_path = format!("{}/{}.json", legacy_file_dir, param.id); + } + let path = Path::new(&file_path); + if path.exists() { + let json_str = fs::read_to_string(path)?; + let json: Value = serde_json::from_str(&json_str)?; + + if let Some(path) = json["mnemonicPath"].as_str() { + return encode_message(ReadKeystoreMnemonicPathResult { + path: path.to_string(), + }); + } + } + + return encode_message(ReadKeystoreMnemonicPathResult { + path: "".to_string(), + }); +} + +pub fn read_all_identity_wallet_ids() -> Option { + let file_path_str = format!( + "{}/{}", + LEGACY_WALLET_FILE_DIR.read(), + IDENTITY_WALLET_IDS_FILE + ); + let file_path = Path::new(&file_path_str); + if Path::exists(&file_path) { + let json_str = fs::read_to_string(file_path).expect("read identity-wallet-ids"); + let all_identity_wallets = + serde_json::from_str::(&json_str).expect("AllIdentityWallets"); + return Some(all_identity_wallets); + } else { + None + } +} + +pub fn remove_all_identity_wallets() -> Option> { + if let Some(all_identity_wallets) = read_all_identity_wallet_ids() { + for id in &all_identity_wallets.wallet_ids { + remove_old_keystore_file(&id); + } + let legacy_file_dir = { + let dir = LEGACY_WALLET_FILE_DIR.read(); + dir.to_string() + }; + + let file_path = format!("{}/identity.json", legacy_file_dir); + let _ = fs::remove_file(file_path); + let file_path = format!("{}/{}", legacy_file_dir, IDENTITY_WALLET_IDS_FILE); + let _ = fs::remove_file(file_path); + + Some(all_identity_wallets.wallet_ids) + } else { + None + } +} + pub fn existed_keystore_file(id: &str) -> bool { let file_path = format!("{}/{}.json", WALLET_FILE_DIR.read(), id); let path = Path::new(&file_path); @@ -272,11 +337,16 @@ pub(crate) fn scan_legacy_keystores() -> Result { continue; }; - let version = v["version"].as_i64().expect("version"); + let Some(version) = v["version"].as_i64() else { + continue; + }; if version == 11000 || version == 11001 { // let keystore = Keystore::from_json(&contents)?; - let keystore_result = parse_tcx_keystore(&v)?; + let mut keystore_result = parse_tcx_keystore(&v)?; + dbg!(&keystore_result); + keystore_result.source = + merge_migrate_source(&keystore_result.id, &keystore_result.source); keystores.push(keystore_result); } else if version == 44 || version == 3 || version == 10001 { let keystore_result = parse_legacy_kesytore(contents)?; @@ -350,7 +420,7 @@ fn parse_legacy_kesytore(contents: String) -> Result { }; let account = AccountResponse { chain_type, - address: legacy_keystore.address.expect("legacy address"), + address: legacy_keystore.address.unwrap_or("".to_string()), path, curve: "secp256k1".to_string(), public_key, @@ -425,34 +495,81 @@ fn parse_tcx_keystore(v: &Value) -> Result { Ok(keystore_result) } -fn read_identity_network() -> Result { - let dir = LEGACY_WALLET_FILE_DIR.read(); - let identify_path = format!("{}/identity.json", dir); - let mut identify_file = fs::File::open(&identify_path)?; - - let mut json_str = String::new(); - identify_file.read_to_string(&mut json_str)?; - let json: Value = serde_json::from_str(&json_str)?; - let network = json["imTokenMeta"]["network"] - .as_str() - .expect("network") - .to_string(); - IdentityNetwork::from_str(&network) +fn merge_migrate_source(id: &str, ori_source: &str) -> String { + // Note: tcx keystore treat _identity source as mnemonic, below code fix that + if let Some(all_identity_wallets) = read_all_identity_wallet_ids() { + if all_identity_wallets.wallet_ids.contains(&id.to_string()) { + all_identity_wallets.source.to_string() + } else { + ori_source.to_string() + } + } else { + ori_source.to_string() + } } - #[cfg(test)] mod tests { - use crate::{filemanager::LEGACY_WALLET_FILE_DIR, migration::scan_legacy_keystores}; + use std::fs; + + use crate::{ + api::MarkIdentityWalletsParam, + filemanager::LEGACY_WALLET_FILE_DIR, + handler::encode_message, + migration::{mark_identity_wallets, scan_legacy_keystores}, + }; use serial_test::serial; use tcx_keystore::keystore::IdentityNetwork; - use super::read_identity_network; + #[test] + #[serial] + + fn test_scan_tcx_legacy_keystores_return_right_source() { + *LEGACY_WALLET_FILE_DIR.write() = "../test-data/wallets-ios-2_14_1/".to_string(); + let param = MarkIdentityWalletsParam { + ids: vec!["0a2756cd-ff70-437b-9bdb-ad46b8bb0819".to_string()], + source: "RECOVERED_IDENTITY".to_string(), + }; + mark_identity_wallets(&encode_message(param).unwrap()); + + let result = scan_legacy_keystores().unwrap(); + + let keystore = result + .keystores + .iter() + .find(|x| x.id.eq("0a2756cd-ff70-437b-9bdb-ad46b8bb0819")) + .clone() + .unwrap(); + assert_eq!(keystore.source, "RECOVERED_IDENTITY"); + + let param = MarkIdentityWalletsParam { + ids: vec!["0a2756cd-ff70-437b-9bdb-ad46b8bb0819".to_string()], + source: "NEW_IDENTITY".to_string(), + }; + mark_identity_wallets(&encode_message(param).unwrap()); + + let result = scan_legacy_keystores().unwrap(); + + let keystore = result + .keystores + .iter() + .find(|x| x.id.eq("0a2756cd-ff70-437b-9bdb-ad46b8bb0819")) + .clone() + .unwrap(); + assert_eq!(keystore.source, "NEW_IDENTITY"); + fs::remove_file("../test-data/wallets-ios-2_14_1/identity-wallet-ids.json").unwrap(); + } #[test] #[serial] fn test_scan_tcx_legacy_keystores() { *LEGACY_WALLET_FILE_DIR.write() = "../test-data/wallets-ios-2_14_1/".to_string(); + let param = MarkIdentityWalletsParam { + ids: vec!["0a2756cd-ff70-437b-9bdb-ad46b8bb0819".to_string()], + source: "RECOVERED_IDENTITY".to_string(), + }; + let _ = mark_identity_wallets(&encode_message(param).unwrap()); + let result = scan_legacy_keystores().unwrap(); assert_eq!(result.identifier, "im18MDKM8hcTykvMmhLnov9m2BaFqsdjoA7cwNg"); @@ -480,6 +597,7 @@ mod tests { ); assert_eq!(account.extended_public_key, "tpubDCxD6k9PreNhSacpfSZ3iErESZnncY1n7qU7e3stZXLPh84xVVt5ERMAqKeefUU8jswx2GpCkQpeYow4xH3PGx2iim6ftPa32GNvTKAtknz"); assert_eq!(account.encrypted_extended_public_key, "b78BOM632Fph4a2xIzWH7Y2fUbHbkYVr2OgJ4WuNxubppAue5npoXgG1kjB7ATxYxpjxYqu/0TgRM1Dz8QO3cT1GPVASzzt4U+f2qeiQcUSj3pnYneGRDcTnY9JsXZmshVbmX7s1He9a0j8x7UeUCS61JM3S9nATdx6YVU/+ViD2tDdRHk6v8IwGnh1uoKb2a/CCsYQbPs5taZoLfwS3BA=="); + assert_eq!(keystore.source, "RECOVERED_IDENTITY"); let account = keystore .accounts @@ -534,6 +652,8 @@ mod tests { assert_eq!(account.path, ""); assert_eq!(account.extended_public_key, ""); assert_eq!(account.encrypted_extended_public_key, ""); + + fs::remove_file("../test-data/wallets-ios-2_14_1/identity-wallet-ids.json").unwrap(); } #[test] @@ -623,18 +743,4 @@ mod tests { assert_eq!(account.path, "m/44'/60'/0'/0/1"); assert_eq!(keystore.source, "MNEMONIC"); } - - #[test] - #[serial] - fn test_read_mainnet_identity() { - *LEGACY_WALLET_FILE_DIR.write() = "../test-data/mainnet-identity/".to_string(); - assert_eq!(read_identity_network().unwrap(), IdentityNetwork::Mainnet); - } - - #[test] - #[serial] - fn test_read_testnet_identity() { - *LEGACY_WALLET_FILE_DIR.write() = "../test-data/testnet-identity/".to_string(); - assert_eq!(read_identity_network().unwrap(), IdentityNetwork::Testnet); - } } diff --git a/token-core/tcx/tests/migration_test.rs b/token-core/tcx/tests/migration_test.rs index 414e3830..98307461 100644 --- a/token-core/tcx/tests/migration_test.rs +++ b/token-core/tcx/tests/migration_test.rs @@ -1,3 +1,4 @@ +use libc::id_t; use serial_test::serial; mod common; @@ -11,8 +12,9 @@ use tcx_atom::transaction::{AtomTxInput, AtomTxOutput}; use prost::Message; use tcx::api::{ export_mnemonic_param, migrate_keystore_param, wallet_key_param, BackupResult, - ExportMnemonicParam, ExportMnemonicResult, GeneralResult, MigrateKeystoreParam, - MigrateKeystoreResult, SignParam, WalletKeyParam, + ExportMnemonicParam, ExportMnemonicResult, GeneralResult, MarkIdentityWalletsParam, + MigrateKeystoreParam, MigrateKeystoreResult, ReadKeystoreMnemonicPathResult, SignParam, + WalletId, WalletKeyParam, }; use tcx::handler::encode_message; @@ -994,57 +996,88 @@ fn test_migrate_ios_old_eos_private_keystore() { #[test] #[serial] -pub fn test_migrate_identity_keystore_then_delete() { - let base_dir = "../test-data/identity-keystore-delete"; - let wallets_dir = "../test-data/identity-keystore-delete/wallets"; - let _ = fs::remove_dir_all(base_dir); - let _ = fs::create_dir_all(wallets_dir); - - let copy_keystore_list = [ - "identity.json", - "00fc0804-7cea-46d8-9e95-ed1efac65358", - "0597526e-105f-425b-bb44-086fc9dc9568", - "1bfddca9-84dc-4561-bbe9-844a9ff2b281", - "6c3eae60-ad03-48db-a5e5-61a6f72aef8d", - "ac59ccc1-285b-47a7-92f5-a6c432cee21a", - ]; - for file in ©_keystore_list { - let mut source_file = fs::File::open(format!("../test-data/wallets/{}", file)).unwrap(); - let mut destination_file = fs::File::create(format!("{}/{}", wallets_dir, file)).unwrap(); - io::copy(&mut source_file, &mut destination_file).unwrap(); - } - - init_token_core_x(base_dir); - - let param: MigrateKeystoreParam = MigrateKeystoreParam { - id: "0597526e-105f-425b-bb44-086fc9dc9568".to_string(), - network: "TESTNET".to_string(), - key: Some(migrate_keystore_param::Key::Password( - TEST_PASSWORD.to_string(), - )), +fn test_delete_all_identity_wallets() { + setup_test("../test-data/identity-keystore-delete"); + let param = MarkIdentityWalletsParam { + ids: vec![ + "0a2756cd-ff70-437b-9bdb-ad46b8bb0819".to_string(), + "00fc0804-7cea-46d8-9e95-ed1efac65358".to_string(), + "6c3eae60-ad03-48db-a5e5-61a6f72aef8d".to_string(), + ], + source: "RECOVERED_IDENTITY".to_string(), }; - let ret = call_api("migrate_keystore", param).unwrap(); - let result: MigrateKeystoreResult = MigrateKeystoreResult::decode(ret.as_slice()).unwrap(); - assert!(!result.is_existed); + assert_eq!( + Path::new("/tmp/token-core-x/wallets/0a2756cd-ff70-437b-9bdb-ad46b8bb0819.json").exists(), + true + ); + assert_eq!( + Path::new("/tmp/token-core-x/wallets/00fc0804-7cea-46d8-9e95-ed1efac65358").exists(), + true + ); + assert_eq!( + Path::new("/tmp/token-core-x/wallets/6c3eae60-ad03-48db-a5e5-61a6f72aef8d").exists(), + true + ); + assert_eq!( + Path::new("/tmp/token-core-x/wallets/identity.json").exists(), + true + ); + call_api("mark_identity_wallets", param).unwrap(); - let param: MigrateKeystoreParam = MigrateKeystoreParam { - id: "00fc0804-7cea-46d8-9e95-ed1efac65358".to_string(), + let param = MigrateKeystoreParam { + id: "0a2756cd-ff70-437b-9bdb-ad46b8bb0819".to_string(), network: "TESTNET".to_string(), key: Some(migrate_keystore_param::Key::Password( TEST_PASSWORD.to_string(), )), }; let ret = call_api("migrate_keystore", param).unwrap(); - let result: MigrateKeystoreResult = MigrateKeystoreResult::decode(ret.as_slice()).unwrap(); - assert!(result.is_existed); + let migrated_ks = MigrateKeystoreResult::decode(ret.as_slice()).unwrap(); let param = WalletKeyParam { - id: "0597526e-105f-425b-bb44-086fc9dc9568".to_string(), + id: "0a2756cd-ff70-437b-9bdb-ad46b8bb0819".to_string(), key: Some(wallet_key_param::Key::Password(TEST_PASSWORD.to_string())), }; let ret = call_api("delete_keystore", param).unwrap(); - let result: GeneralResult = GeneralResult::decode(ret.as_slice()).unwrap(); - assert!(result.is_success); - let file_count = fs::read_dir(wallets_dir).unwrap().count(); - assert_eq!(file_count, 0); + + assert_eq!( + Path::new("/tmp/token-core-x/wallets/0a2756cd-ff70-437b-9bdb-ad46b8bb0819.json").exists(), + false + ); + assert_eq!( + Path::new("/tmp/token-core-x/wallets/00fc0804-7cea-46d8-9e95-ed1efac65358").exists(), + false + ); + assert_eq!( + Path::new("/tmp/token-core-x/wallets/6c3eae60-ad03-48db-a5e5-61a6f72aef8d").exists(), + false + ); + assert_eq!( + Path::new("/tmp/token-core-x/wallets/identity.json").exists(), + false + ); +} + +#[test] +#[serial] +fn test_read_keystore_mnemonic_path() { + setup_test("../test-data/identity-keystore-delete"); + + let wallet_ids = vec![ + ("0a2756cd-ff70-437b-9bdb-ad46b8bb0819".to_string(), ""), + ( + "00fc0804-7cea-46d8-9e95-ed1efac65358".to_string(), + "m/49'/1'/0'", + ), + ( + "6c3eae60-ad03-48db-a5e5-61a6f72aef8d".to_string(), + "m/44'/194'/0'/0/0", + ), + ]; + for (id, path) in wallet_ids { + let param = WalletId { id }; + let ret = call_api("read_keystore_mnemonic_path", param).unwrap(); + let mnemonic_path = ReadKeystoreMnemonicPathResult::decode(ret.as_slice()).unwrap(); + assert_eq!(mnemonic_path.path, path); + } } diff --git a/token-core/test-data/.gitignore b/token-core/test-data/.gitignore index 4a9c1f52..15c8f302 100644 --- a/token-core/test-data/.gitignore +++ b/token-core/test-data/.gitignore @@ -8,6 +8,7 @@ !wallets/imkey/* !wallets-ios-2_14_1 !wallets-ios-2_14_1/* +wallets-ios-2_14_1/identity-wallet-ids.json !scan-keystores-fixtures !scan-keystores-fixtures/* !mainnet-identity @@ -16,4 +17,6 @@ !testnet-identity/* !migrate-duplication-fixtures !migrate-duplication-fixtures/wallets/** -wallets/_migrated.json \ No newline at end of file +wallets/_migrated.json +!identity-keystore-delete +!identity-keystore-delete/wallets/* \ No newline at end of file diff --git a/token-core/test-data/identity-keystore-delete/wallets/.DS_Store b/token-core/test-data/identity-keystore-delete/wallets/.DS_Store new file mode 100644 index 00000000..5008ddfc Binary files /dev/null and b/token-core/test-data/identity-keystore-delete/wallets/.DS_Store differ diff --git a/token-core/test-data/identity-keystore-delete/wallets/00fc0804-7cea-46d8-9e95-ed1efac65358 b/token-core/test-data/identity-keystore-delete/wallets/00fc0804-7cea-46d8-9e95-ed1efac65358 new file mode 100644 index 00000000..cab57d2b --- /dev/null +++ b/token-core/test-data/identity-keystore-delete/wallets/00fc0804-7cea-46d8-9e95-ed1efac65358 @@ -0,0 +1,39 @@ +{ + "address": "2MwN441dq8qudMvtM5eLVwC3u4zfKuGSQAB", + "imTokenMeta": { + "source": "RECOVERED_IDENTITY", + "timestamp": "1703213076.948025", + "backup": [], + "mode": "normal", + "name": "BTC", + "version": "iOS-2.14.1.1742", + "passwordHint": "", + "chain": "BITCOIN", + "network": "TESTNET", + "segWit": "P2WPKH" + }, + "id": "00fc0804-7cea-46d8-9e95-ed1efac65358", + "encMnemonic": { + "nonce": "406c972f073ebf5b9102d262e6713408", + "encStr": "76b940d06641023f995cffde6ee9c4bc7c063a780897b5debd619aafc769b37db684eafb10dd48c3c3cbcb810952bb4455984fde5aa34a1dfb4d5ad93293c0d3f3a78124639a4530b4c2" + }, + "xpub": "tpubDCwNET9ErXmBracx3ZBfi6rXQZRjYkpitFe23FAW9M3RcCw4aveNC4SAV5yYrFDjtP3b46eFfv4VtiYP3EXoTZsbnJia2yNznExS8EEcACv", + "crypto": { + "kdfparams": { + "dklen": 32, + "r": 8, + "salt": "8fac63b4cc6d75817269a380bc8107572ecba3a8fe1ab87e46e30ab696ce2320", + "p": 1, + "n": 262144 + }, + "mac": "6daa39ee727416a135b02d6183c71624de0b7cf74fb3a3d1562488e66f308c76", + "cipher": "aes-128-ctr", + "ciphertext": "cdde8cafd9eff3f9715ef40577913e2ded3b8a9f009781d3367e4a1b02e95894c45ab6ef2658e7ef99b8437cba0f05f5c12caca60e97745b71581075f086a57afac8f626f3d2f7c94813edb6eb26b5cf8147fd32419a3abc762d71dc2be77d555cb75e983a74fa45f7b08e59ce7945", + "cipherparams": { + "iv": "a575c61a89577eea45af32df6aa4005a" + }, + "kdf": "scrypt" + }, + "version": 44, + "mnemonicPath": "m/49'/1'/0'" +} diff --git a/token-core/test-data/identity-keystore-delete/wallets/0a2756cd-ff70-437b-9bdb-ad46b8bb0819.json b/token-core/test-data/identity-keystore-delete/wallets/0a2756cd-ff70-437b-9bdb-ad46b8bb0819.json new file mode 100644 index 00000000..b0e2ffdc --- /dev/null +++ b/token-core/test-data/identity-keystore-delete/wallets/0a2756cd-ff70-437b-9bdb-ad46b8bb0819.json @@ -0,0 +1,106 @@ +{ + "id": "0a2756cd-ff70-437b-9bdb-ad46b8bb0819", + "version": 11000, + "keyHash": "512115eca3ae86646aeb06861d551e403b543509", + "crypto": { + "cipher": "aes-128-ctr", + "cipherparams": { "iv": "acc1209c400cfff80668e9a36ef8a2e5" }, + "ciphertext": "033964aa3253c904f50b3798a14299802765ddd84ffa7b699e24ee531076ab6256682a45c8f4c9a4c98f202e5791f5061833d3936fc9f12728d1658ea6bb49fac38e577861981a5e5d43", + "kdf": "pbkdf2", + "kdfparams": { + "c": 1024, + "prf": "hmac-sha256", + "dklen": 32, + "salt": "4fba99988c8eec256f138e1f5e098b03d91461b8969544878f315343f42d1e5f" + }, + "mac": "d94cca35619e88fccdc6778b8c0c5691fe163378b02cf32ec3e6afbe0ce5ff05" + }, + "activeAccounts": [ + { + "address": "TY2uroBeZ5trA9QT96aEWj32XLkAAhQ9R2", + "derivationPath": "m/44'/195'/0'/0/0", + "curve": "SECP256k1", + "coin": "TRON", + "network": "", + "segWit": "", + "extPubKey": "037e39800880000000988ebb67dc6f173948ccaed62dd3c4b60fea66a4280da93eed971b55d4e6e9c203349ff19e96c1aa7f568e493f85fa506320410245b4e69146bb0d3d8b5df3b901", + "publicKey": "037b5253c24ce2a293566f9e066051366cda5073e4a43b25f07c990d7c9ac0aab5" + }, + { + "address": "ckt1qyqtr684u76tu7r8efkd24hw8922xfvhnazskzdzy6", + "derivationPath": "m/44'/309'/0'/0/0", + "curve": "SECP256k1", + "coin": "NERVOS", + "network": "TESTNET", + "segWit": "", + "extPubKey": "03b4fb97788000000048c75f39fe91ddfe4a0e6ef2fa53795a006e0e78f06b1af7d2b107ea3cefe22903ad9d0e2d9181e23c7075a56ed4f10e249aaf38a2bb7aa0cb604f8b768ea84b86", + "publicKey": "03554851980004ff256888612bf0d64d9b1002bf82331450fd5a7405d1b23cc5bd" + }, + { + "address": "qqurlwqukz3lcujttcyvlzaagppnd4c37chrtrylmc", + "derivationPath": "m/44'/1'/0'/0/0", + "curve": "SECP256k1", + "coin": "BITCOINCASH", + "network": "TESTNET", + "segWit": "NONE", + "extPubKey": "036c2b38ad8000000023332f38a77023d3c1a450499c8aeb3db2e666aa2cc6fff7db6797c5d2aef8fc036663443d71127b332c68cd6bffb6c2b5eb4dc6861404ed055dc36a25b8c18020", + "publicKey": "033d710ab45bb54ac99618ad23b3c1da661631aa25f23bfe9d22b41876f1d46e4e" + }, + { + "address": "myxdgXjCRgAskD2g1b6WJttJbuv67hq6sQ", + "derivationPath": "m/44'/2'/0'/0/0", + "curve": "SECP256k1", + "coin": "LITECOIN", + "network": "TESTNET", + "segWit": "NONE", + "extPubKey": "03bd0b1c14800000003bd4b941a0eebb0bfa4c3324bb77f0a1643aa80d112e2a6d48187c1b333a3d2d02c7709248e6205fefa7366efb0269021f1f2f1e04fdc334fe7c7fd2628d7451e8", + "publicKey": "0289ca41680edbc5594ee6378ebd937e42cd6b4b969e40dd82c20ef2a8aa5bad7b" + }, + { + "address": "JHBkzZJnLZ3S3HLvxjpFAjd6ywP7WAk5miL7MwVCn9a7jHS", + "derivationPath": "", + "curve": "SubSr25519", + "coin": "KUSAMA", + "network": "", + "segWit": "", + "extPubKey": "", + "publicKey": "fc581c897af481b10cf846d88754f1d115e486e5b7bcc39c0588c01b0a9b7a11" + }, + { + "address": "16hsF1UW1kob7vUR7tymVNCmp1eo18uhhtc4szetH4xbYpbd", + "derivationPath": "", + "curve": "SubSr25519", + "coin": "POLKADOT", + "network": "", + "segWit": "", + "extPubKey": "", + "publicKey": "fc581c897af481b10cf846d88754f1d115e486e5b7bcc39c0588c01b0a9b7a11" + }, + { + "address": "t12i3bop43tprlnymx2c75u6uvlq7iur2rcd7qsey", + "derivationPath": "m/44'/461'/0'/0/0", + "curve": "SECP256k1", + "coin": "FILECOIN", + "network": "TESTNET", + "segWit": "", + "extPubKey": "03d2bab08e80000000b2045e43ef88287b28ca49251d4fdc5e2810b1340e7e1be6fe3f8e968c33e4fd02611325073f61ae5feb6c8dce96857d007cdb765937e53e43e6f91374dac62edb", + "publicKey": "03bd460186d29fd9ac68ee88b110c3acc4a4443648a1ec7607af9ce306ad76f785" + }, + { + "address": "tz1d2TfcvWBwtPqo7f21DVv7HSSCoNAVp8gz", + "derivationPath": "m/44'/1729'/0'/0'", + "curve": "ED25519", + "coin": "TEZOS", + "network": "MAINNET", + "segWit": "", + "extPubKey": "", + "publicKey": "bdb7b056d28a8610de329fb4c367886256cc15a5e438a42fff485cd4fc73e574" + } + ], + "imTokenMeta": { + "name": "tcx-wallet", + "passwordHint": "", + "timestamp": 1703213098, + "source": "MNEMONIC" + } +} diff --git a/token-core/test-data/identity-keystore-delete/wallets/6c3eae60-ad03-48db-a5e5-61a6f72aef8d b/token-core/test-data/identity-keystore-delete/wallets/6c3eae60-ad03-48db-a5e5-61a6f72aef8d new file mode 100644 index 00000000..3f086a2f --- /dev/null +++ b/token-core/test-data/identity-keystore-delete/wallets/6c3eae60-ad03-48db-a5e5-61a6f72aef8d @@ -0,0 +1,67 @@ +{ + "encMnemonic": { + "encStr": "476ee81e62675ffb5e727f8e3f15f0222ff084bd4b064089d7a8397efe10bde265d965b214171f9e946128c7855cf53866b753021f6df8bd49b92bdb2caed5b8f618667177eaa5594933", + "nonce": "b553ebb7521eb1a9aa7d8738811ab102" + }, + "keyPathPrivates": [ + { + "derivedMode": "HD_SHA256", + "path": "", + "publicKey": "EOS7tpXQ1thFJ69ZXDqqEan7GMmuWdcptKmwgbs7n1cnx3hWPw3jw", + "privateKey": { + "encStr": "e44fc17b5bedd1f3409c07c84067f4d8af051b6edf72bfda4a4306f00f87cbde", + "nonce": "5485ffc4230fa0d389dde221ec22a0e2" + } + }, + { + "privateKey": { + "encStr": "4267397725dda86d8a45079d7246fac0784c75494308cd8f5c5f157d74ce3a65", + "nonce": "d2f0a53208b5ddbda3e3c1808e92c64c" + }, + "derivedMode": "HD_SHA256", + "publicKey": "EOS5SxZMjhKiXsmjxac8HBx56wWdZV1sCLZESh3ys1rzbMn4FUumU", + "path": "" + }, + { + "privateKey": { + "nonce": "dae366211338af8bcc01610b0358b78e", + "encStr": "622c4a67b70c3e1fb33653dc56dc961cd8b4185252f31dceebab15a98e77f361" + }, + "publicKey": "EOS88XhiiP7Cu5TmAUJqHbyuhyYgd6sei68AU266PyetDDAtjmYWF", + "path": "m/44'/194'/0'/0/0", + "derivedMode": "PATH_DIRECTLY" + } + ], + "mnemonicPath": "m/44'/194'/0'/0/0", + "id": "6c3eae60-ad03-48db-a5e5-61a6f72aef8d", + "version": 10001, + "crypto": { + "kdf": "scrypt", + "kdfparams": { + "salt": "43800be9d3459b3ce9b61826555165d5706a2e8ecfceb9e4b1fa341d743f5e60", + "r": 8, + "dklen": 32, + "n": 262144, + "p": 1 + }, + "mac": "50a4fdbb20dc1a860ac93134e9edf15267f9f1a2443c4a329841bc17553758a9", + "cipherparams": { + "iv": "ac19624cfcb3cd32bd092ddf73aa6157" + }, + "ciphertext": "7cd696ce21680fb9b02c326ec0563b05", + "cipher": "aes-128-ctr" + }, + "imTokenMeta": { + "network": "MAINNET", + "segWit": "NONE", + "mode": "normal", + "backup": [], + "timestamp": "1703213102.143412", + "source": "RECOVERED_IDENTITY", + "name": "EOS", + "version": "iOS-2.14.1.1742", + "passwordHint": "", + "chain": "EOS" + }, + "address": "" +} diff --git a/token-core/test-data/identity-keystore-delete/wallets/identity.json b/token-core/test-data/identity-keystore-delete/wallets/identity.json new file mode 100644 index 00000000..ecab78d3 --- /dev/null +++ b/token-core/test-data/identity-keystore-delete/wallets/identity.json @@ -0,0 +1,54 @@ +{ + "imTokenMeta": { + "network": "TESTNET", + "name": "identity_name", + "version": "iOS-2.14.1.1742", + "source": "RECOVERED_IDENTITY", + "passwordHint": "", + "timestamp": "1703213073.8432422", + "backup": [], + "segWit": "P2WPKH", + "mode": "normal" + }, + "version": 10000, + "walletIds": [ + "0597526e-105f-425b-bb44-086fc9dc9568", + "00fc0804-7cea-46d8-9e95-ed1efac65358", + "ac59ccc1-285b-47a7-92f5-a6c432cee21a", + "6c3eae60-ad03-48db-a5e5-61a6f72aef8d", + "f3615a56-cb03-4aa4-a893-89944e49920d", + "60573d8d-8e83-45c3-85a5-34fbb2aad5e1", + "9e3e1a17-ccad-4d93-98ab-cfe1e3f82ed3", + "9b696367-69c1-4cfe-8325-e5530399fc3f", + "6c20aab6-1596-456d-9749-212e6139c5ed", + "792a0051-16d7-44a7-921a-9b4a0c893b8f", + "9f4acb4a-7431-4c7d-bd25-a19656a86ea0", + "d9e3bb9c-87fd-4836-b146-10a3e249eb75" + ], + "crypto": { + "cipherparams": { "iv": "b947b2ece06b648a75187dcddee67cc1" }, + "ciphertext": "5f1cbaef883def74b4b27a64586188da00f020f9611d1efc84dffba5ae31a173962e2196589aa66a065e5e0f929b26eac27ca04c8eecc0727f5f91e0038cf6aaba9d827c76c6f225ceaa9d937c3a3f1a958e5fe74585565175d301ead8a67f401250abcd0e832f76a4ed37628170b6", + "kdf": "scrypt", + "cipher": "aes-128-ctr", + "mac": "deeabc0d49e9b2ec0eb97d55cff25e2c14ff74e257c96145fb8e47bc31d8df26", + "kdfparams": { + "n": 262144, + "r": 8, + "dklen": 32, + "p": 1, + "salt": "b0fdfcb67bdfc6461d907f6b55c364ce98e21057b74df586953e2bc6e293c248" + } + }, + "encMnemonic": { + "encStr": "74c4b82c2af67c35b8ff31c3547a705d94f9a66397f1aa4118eb6450ec140f055117ec2a87a4402069a3837db7d1b20d16e4e1b9b93c6b615c739b833bd9cb20148c6c37efd777fb6b30", + "nonce": "a293778a4eec6fdd6f7c7ac0edcd869f" + }, + "encAuthKey": { + "encStr": "628e9f0926f12abed0c201bc605af2a378a72cbc397c182c270888ca7dad4d1f", + "nonce": "93e5aff1a87c6f3be9b5bef506478dae" + }, + "id": "d5017486-f9b2-4aeb-8f7b-c57da9b77668", + "identifier": "im18MDKM8hcTykvMmhLnov9m2BaFqsdjoA7cwNg", + "ipfsId": "QmSTTidyfa4np9ak9BZP38atuzkCHy4K59oif23f4dNAGU", + "encKey": "9513617c9b398edebfb46080a8f0cf6cab6763866bb06daa63503722bea78907" +}