From b1c5fd0ec1b0eab2d69a314396b1fb9ab4035b02 Mon Sep 17 00:00:00 2001 From: XuNeal Date: Tue, 26 Mar 2024 19:44:10 +0800 Subject: [PATCH 1/2] feat: mark identity wallet ids --- token-core/tcx-migration/src/migration.rs | 2 +- token-core/tcx-proto/src/params.proto | 5 + token-core/tcx/src/api.rs | 8 + token-core/tcx/src/handler.rs | 16 +- token-core/tcx/src/lib.rs | 4 + token-core/tcx/src/migration.rs | 245 ++++++++++++------ token-core/tcx/tests/migration_test.rs | 91 ++++--- token-core/test-data/.gitignore | 5 +- .../wallets/.DS_Store | Bin 0 -> 6148 bytes .../00fc0804-7cea-46d8-9e95-ed1efac65358 | 39 +++ .../0a2756cd-ff70-437b-9bdb-ad46b8bb0819.json | 106 ++++++++ .../6c3eae60-ad03-48db-a5e5-61a6f72aef8d | 67 +++++ .../wallets/identity.json | 54 ++++ 13 files changed, 513 insertions(+), 129 deletions(-) create mode 100644 token-core/test-data/identity-keystore-delete/wallets/.DS_Store create mode 100644 token-core/test-data/identity-keystore-delete/wallets/00fc0804-7cea-46d8-9e95-ed1efac65358 create mode 100644 token-core/test-data/identity-keystore-delete/wallets/0a2756cd-ff70-437b-9bdb-ad46b8bb0819.json create mode 100644 token-core/test-data/identity-keystore-delete/wallets/6c3eae60-ad03-48db-a5e5-61a6f72aef8d create mode 100644 token-core/test-data/identity-keystore-delete/wallets/identity.json 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..cb473d15 100644 --- a/token-core/tcx-proto/src/params.proto +++ b/token-core/tcx-proto/src/params.proto @@ -277,4 +277,9 @@ message MigrateKeystoreParam { message BackupResult { string original = 1; + } + + message MarkIdentityWalletsParam { + repeated string ids = 1; + string source = 2; } \ No newline at end of file diff --git a/token-core/tcx/src/api.rs b/token-core/tcx/src/api.rs index 40f09dae..28038e25 100644 --- a/token-core/tcx/src/api.rs +++ b/token-core/tcx/src/api.rs @@ -704,6 +704,14 @@ 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 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..d14ce352 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; use prost::Message; pub mod api; @@ -122,6 +123,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..de3974f1 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, + ScanLegacyKeystoresResult, }; 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,66 @@ 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 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 +308,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)?; @@ -425,34 +466,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 +568,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 +623,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 +714,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..e51d5289 100644 --- a/token-core/tcx/tests/migration_test.rs +++ b/token-core/tcx/tests/migration_test.rs @@ -11,8 +11,8 @@ 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, SignParam, WalletKeyParam, }; use tcx::handler::encode_message; @@ -994,57 +994,64 @@ 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 + ); } 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 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 Date: Tue, 26 Mar 2024 20:00:30 +0800 Subject: [PATCH 2/2] feat: add read_keystore_menmonic_path api --- token-core/tcx-proto/src/params.proto | 4 ++++ token-core/tcx/src/api.rs | 6 +++++ token-core/tcx/src/lib.rs | 5 +++- token-core/tcx/src/migration.rs | 33 ++++++++++++++++++++++++-- token-core/tcx/tests/migration_test.rs | 28 +++++++++++++++++++++- 5 files changed, 72 insertions(+), 4 deletions(-) diff --git a/token-core/tcx-proto/src/params.proto b/token-core/tcx-proto/src/params.proto index cb473d15..0724827d 100644 --- a/token-core/tcx-proto/src/params.proto +++ b/token-core/tcx-proto/src/params.proto @@ -282,4 +282,8 @@ message MigrateKeystoreParam { 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 28038e25..61488d93 100644 --- a/token-core/tcx/src/api.rs +++ b/token-core/tcx/src/api.rs @@ -712,6 +712,12 @@ pub struct MarkIdentityWalletsParam { } #[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/lib.rs b/token-core/tcx/src/lib.rs index d14ce352..6c442948 100644 --- a/token-core/tcx/src/lib.rs +++ b/token-core/tcx/src/lib.rs @@ -7,7 +7,7 @@ use std::os::raw::c_char; use anyhow::anyhow; use handler::{backup, sign_bls_to_execution_change}; -use migration::mark_identity_wallets; +use migration::{mark_identity_wallets, read_legacy_keystore_mnemonic_path}; use prost::Message; pub mod api; @@ -79,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)), diff --git a/token-core/tcx/src/migration.rs b/token-core/tcx/src/migration.rs index de3974f1..3318f29e 100644 --- a/token-core/tcx/src/migration.rs +++ b/token-core/tcx/src/migration.rs @@ -1,7 +1,7 @@ use crate::api::{ migrate_keystore_param, AccountResponse, GeneralResult, KeystoreResult, LegacyKeystoreResult, MarkIdentityWalletsParam, MigrateKeystoreParam, MigrateKeystoreResult, - ScanLegacyKeystoresResult, + ReadKeystoreMnemonicPathResult, ScanLegacyKeystoresResult, WalletId, }; use crate::error_handling::Result; use crate::filemanager::{cache_keystore, KEYSTORE_MAP, WALLET_FILE_DIR}; @@ -224,6 +224,35 @@ pub(crate) fn mark_identity_wallets(data: &[u8]) -> Result> { 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!( "{}/{}", @@ -391,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, diff --git a/token-core/tcx/tests/migration_test.rs b/token-core/tcx/tests/migration_test.rs index e51d5289..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; @@ -12,7 +13,8 @@ use prost::Message; use tcx::api::{ export_mnemonic_param, migrate_keystore_param, wallet_key_param, BackupResult, ExportMnemonicParam, ExportMnemonicResult, GeneralResult, MarkIdentityWalletsParam, - MigrateKeystoreParam, MigrateKeystoreResult, SignParam, WalletKeyParam, + MigrateKeystoreParam, MigrateKeystoreResult, ReadKeystoreMnemonicPathResult, SignParam, + WalletId, WalletKeyParam, }; use tcx::handler::encode_message; @@ -1055,3 +1057,27 @@ fn test_delete_all_identity_wallets() { 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); + } +}