Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: open tcx scan_keystores api[R2D2-13481] #141

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/build-release-ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ jobs:

- name: Install Rust
run: |
rustup toolchain install nightly-2022-10-31
rustup default nightly-2022-10-31-x86_64-apple-darwin
rustup toolchain install nightly-2023-06-15
rustup default nightly-2023-06-15-x86_64-apple-darwin
rustup target add aarch64-apple-ios x86_64-apple-ios
rustup show
cargo install cargo-lipo
cargo install cbindgen
cargo install cbindgen --version 0.26.0
brew install protobuf

- name: Read VERSION file
Expand Down
18 changes: 16 additions & 2 deletions token-core/tcx-proto/src/params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,22 @@ message MigrateKeystoreResult {
}

message ScanKeystoresResult {
repeated KeystoreResult hdKeystores = 1;
repeated ImportPrivateKeyResult privateKeyKeystores = 2;
repeated ScannedKeystore keystores = 1;
}

message ScannedKeystore {
string id = 1;
string name = 2;
string identifier = 3;
string ipfsId = 4;
string source = 5;
int64 createdAt = 6;
repeated AccountResponse accounts = 7;
string migration_status = 8;// This field can have one of three values: "migrated", "unmigrated", or "new".
repeated string identifiedChainTypes = 9;
string identifiedNetwork = 10;
string identifiedCurve = 11;
string sourceFingerprint = 12;
}

message LegacyKeystoreResult {
Expand Down
33 changes: 30 additions & 3 deletions token-core/tcx/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -666,9 +666,36 @@ pub struct MigrateKeystoreResult {
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ScanKeystoresResult {
#[prost(message, repeated, tag = "1")]
pub hd_keystores: ::prost::alloc::vec::Vec<KeystoreResult>,
#[prost(message, repeated, tag = "2")]
pub private_key_keystores: ::prost::alloc::vec::Vec<ImportPrivateKeyResult>,
pub keystores: ::prost::alloc::vec::Vec<ScannedKeystore>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ScannedKeystore {
#[prost(string, tag = "1")]
pub id: ::prost::alloc::string::String,
#[prost(string, tag = "2")]
pub name: ::prost::alloc::string::String,
#[prost(string, tag = "3")]
pub identifier: ::prost::alloc::string::String,
#[prost(string, tag = "4")]
pub ipfs_id: ::prost::alloc::string::String,
#[prost(string, tag = "5")]
pub source: ::prost::alloc::string::String,
#[prost(int64, tag = "6")]
pub created_at: i64,
#[prost(message, repeated, tag = "7")]
pub accounts: ::prost::alloc::vec::Vec<AccountResponse>,
/// This field can have one of three values: "migrated", "unmigrated", or "new".
#[prost(string, tag = "8")]
pub migration_status: ::prost::alloc::string::String,
#[prost(string, repeated, tag = "9")]
pub identified_chain_types: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
#[prost(string, tag = "10")]
pub identified_network: ::prost::alloc::string::String,
#[prost(string, tag = "11")]
pub identified_curve: ::prost::alloc::string::String,
#[prost(string, tag = "12")]
pub source_fingerprint: ::prost::alloc::string::String,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
Expand Down
127 changes: 105 additions & 22 deletions token-core/tcx/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ use crate::api::{
GetExtendedPublicKeysParam, GetExtendedPublicKeysResult, GetPublicKeysParam,
GetPublicKeysResult, ImportJsonParam, ImportMnemonicParam, ImportPrivateKeyParam,
ImportPrivateKeyResult, KeystoreResult, MnemonicToPublicKeyParam, MnemonicToPublicKeyResult,
ScanKeystoresResult, SignAuthenticationMessageParam, SignAuthenticationMessageResult,
SignHashesParam, SignHashesResult, WalletKeyParam,
ScanKeystoresResult, ScannedKeystore, SignAuthenticationMessageParam,
SignAuthenticationMessageResult, SignHashesParam, SignHashesResult, WalletKeyParam,
};
use crate::api::{EthBatchPersonalSignParam, EthBatchPersonalSignResult};
use crate::api::{InitTokenCoreXParam, SignParam};
Expand Down Expand Up @@ -72,7 +72,8 @@ use tcx_tezos::{encode_tezos_private_key, parse_tezos_private_key};

use crate::macros::{impl_to_key, use_chains};
use crate::migration::{
read_all_identity_wallet_ids, remove_all_identity_wallets, remove_old_keystore_by_id,
is_migrated, read_all_identity_wallet_ids, remove_all_identity_wallets,
remove_old_keystore_by_id, scan_legacy_keystores,
};
use crate::reset_password::assert_seed_equals;

Expand Down Expand Up @@ -414,6 +415,27 @@ pub fn init_token_core_x(data: &[u8]) -> Result<()> {

pub fn scan_keystores() -> Result<ScanKeystoresResult> {
clean_keystore();

let mut ret_keystores = vec![];
let legacy_keystores = scan_legacy_keystores()?;
for keystore in legacy_keystores.keystores.iter() {
let mut scanned_keystore = ScannedKeystore {
id: keystore.id.clone(),
name: keystore.name.clone(),
identifier: legacy_keystores.identifier.clone(),
ipfs_id: legacy_keystores.ipfs_id.clone(),
source: legacy_keystores.source.clone(),
created_at: f64::from_str(&keystore.created_at).expect("f64 from timestamp") as i64,
accounts: keystore.accounts.clone(),
migration_status: "unmigrated".to_string(),
..Default::default()
};
if is_migrated(&keystore.id) {
scanned_keystore.migration_status = "migrated".to_string();
}
ret_keystores.push(scanned_keystore);
}

let file_dir = WALLET_FILE_DIR.read();
let p = Path::new(file_dir.as_str());
let walk_dir = std::fs::read_dir(p).expect("read dir");
Expand Down Expand Up @@ -444,7 +466,6 @@ pub fn scan_keystores() -> Result<ScanKeystoresResult> {

if version == HdKeystore::VERSION || version == PrivateKeystore::VERSION {
let keystore = Keystore::from_json(&contents)?;

if version == HdKeystore::VERSION {
let keystore_result = KeystoreResult {
id: keystore.id(),
Expand All @@ -456,12 +477,37 @@ pub fn scan_keystores() -> Result<ScanKeystoresResult> {
source_fingerprint: keystore.fingerprint().to_string(),
..Default::default()
};
if is_migrated(&keystore.id()) {
let mut found = false;
for legacy_keystore in &mut ret_keystores {
if legacy_keystore.id == keystore.id() {
legacy_keystore.migration_status = "migrated".to_string();
legacy_keystore.source_fingerprint =
keystore_result.source_fingerprint.clone();
found = true;
break;
}
}
if !found {
let scanned_keystore = ScannedKeystore {
id: keystore_result.id.clone(),
name: keystore_result.name.clone(),
identifier: keystore_result.identifier.clone(),
ipfs_id: keystore_result.ipfs_id.clone(),
source: keystore_result.source.clone(),
created_at: keystore_result.created_at.clone(),
migration_status: "new".to_string(),
..Default::default()
};
ret_keystores.push(scanned_keystore);
}
}
hd_keystores.push(keystore_result);
} else {
let curve = keystore
.get_curve()
.expect("pk keystore must contains curve");
let kestore_result = ImportPrivateKeyResult {
let keystore_result = ImportPrivateKeyResult {
id: keystore.id(),
name: keystore.meta().name.to_string(),
identifier: keystore.identity().identifier.to_string(),
Expand All @@ -474,15 +520,52 @@ pub fn scan_keystores() -> Result<ScanKeystoresResult> {
identified_curve: curve.as_str().to_string(),
..Default::default()
};
private_key_keystores.push(kestore_result);
if is_migrated(&keystore_result.id) {
let mut found = false;
for legacy_keystore in &mut ret_keystores {
if legacy_keystore.id == keystore_result.id {
legacy_keystore.migration_status = "migrated".to_string();
legacy_keystore.source_fingerprint =
keystore_result.source_fingerprint.clone();
legacy_keystore.identified_chain_types =
keystore_result.identified_chain_types.clone();
legacy_keystore.identified_network =
keystore_result.identified_network.clone();
legacy_keystore.identified_curve =
keystore_result.identified_curve.clone();
legacy_keystore.source_fingerprint =
keystore_result.source_fingerprint.clone();
found = true;
break;
}
}
if !found {
let scanned_keystore = ScannedKeystore {
id: keystore_result.id.clone(),
name: keystore_result.name.clone(),
identifier: keystore_result.identifier.clone(),
ipfs_id: keystore_result.ipfs_id.clone(),
source: keystore_result.source.clone(),
created_at: keystore_result.created_at.clone(),
migration_status: "new".to_string(),
identified_chain_types: keystore_result.identified_chain_types.clone(),
identified_network: keystore_result.identified_network.clone(),
identified_curve: keystore_result.identified_curve.clone(),
source_fingerprint: keystore_result.source_fingerprint.clone(),
..Default::default()
};
ret_keystores.push(scanned_keystore);
}
}
private_key_keystores.push(keystore_result);
}

cache_keystore(keystore);
}
}

Ok(ScanKeystoresResult {
hd_keystores,
private_key_keystores,
keystores: ret_keystores,
})
}

Expand Down Expand Up @@ -1487,7 +1570,7 @@ mod tests {
use tcx_constants::CurveType;
use tcx_keystore::Source;

use crate::{api::ImportPrivateKeyResult, filemanager::WALLET_FILE_DIR};
use crate::{api::{ImportPrivateKeyResult, ScannedKeystore}, filemanager::WALLET_FILE_DIR};

use super::{decode_private_key, scan_keystores};
use serial_test::serial;
Expand Down Expand Up @@ -1578,8 +1661,8 @@ mod tests {
fn test_scan_keystores() {
*WALLET_FILE_DIR.write() = "../test-data/scan-keystores-fixtures/".to_string();
let result = scan_keystores().unwrap();
assert_eq!(result.hd_keystores.len(), 1);
let hd = result.hd_keystores.first().unwrap();
assert_eq!(result.keystores.len(), 1);
let hd = result.keystores.first().unwrap();
assert_eq!(hd.id, "1055741c-2904-4973-b7ee-4b69bfd8bcc6");
assert_eq!(hd.identifier, "im14x5UYkoqtYbJFTLam7c9Ft4BQiFvJbieKWfK");
assert_eq!(hd.ipfs_id, "Qme1RuM33X8SmVjisWS3sP4irqNZv6vuqL3L3T6poZ6c2b");
Expand All @@ -1590,10 +1673,10 @@ mod tests {
assert_eq!(hd.created_at, 1705040852);
assert_eq!(hd.source, "MNEMONIC");
assert_eq!(hd.name, "test-wallet");
assert_eq!(result.private_key_keystores.len(), 4);
assert_eq!(result.keystores.len(), 4);

let founded_pk_stores: Vec<&ImportPrivateKeyResult> = result
.private_key_keystores
let founded_pk_stores: Vec<&ScannedKeystore> = result
.keystores
.iter()
.filter(|x| x.id == "7e1c2c55-5b7f-4a5a-8061-c42b594ceb2f")
.collect();
Expand All @@ -1609,8 +1692,8 @@ mod tests {
assert_eq!(pk.name, "test_filecoin_import_private_key");
assert_eq!(pk.identified_curve, "bls12-381");

let founded_pk_stores: Vec<&ImportPrivateKeyResult> = result
.private_key_keystores
let founded_pk_stores: Vec<&ScannedKeystore> = result
.keystores
.iter()
.filter(|x| x.id == "1233134b-8377-4fb0-b06f-56062e858708")
.collect();
Expand All @@ -1626,8 +1709,8 @@ mod tests {
assert_eq!(pk.name, "test account");
assert_eq!(pk.identified_curve, "sr25519");

let founded_pk_stores: Vec<&ImportPrivateKeyResult> = result
.private_key_keystores
let founded_pk_stores: Vec<&ScannedKeystore> = result
.keystores
.iter()
.filter(|x| x.id == "beb68589-0f0f-41e2-94d9-d78f10a72dec")
.collect();
Expand All @@ -1643,8 +1726,8 @@ mod tests {
assert_eq!(pk.name, "test_filecoin_import_private_key");
assert_eq!(pk.identified_curve, "secp256k1");

let founded_pk_stores: Vec<&ImportPrivateKeyResult> = result
.private_key_keystores
let founded_pk_stores: Vec<&ScannedKeystore> = result
.keystores
.iter()
.filter(|x| x.id == "beb68589-0f0f-41e2-94d9-d78f10a72dec")
.collect();
Expand All @@ -1660,8 +1743,8 @@ mod tests {
assert_eq!(pk.name, "test_filecoin_import_private_key");
assert_eq!(pk.identified_curve, "secp256k1");

let founded_pk_stores: Vec<&ImportPrivateKeyResult> = result
.private_key_keystores
let founded_pk_stores: Vec<&ScannedKeystore> = result
.keystores
.iter()
.filter(|x| x.id == "efcfffb2-9b63-418b-a9d0-ec3600012284")
.collect();
Expand Down
8 changes: 6 additions & 2 deletions token-core/tcx/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ use crate::handler::{
encode_message, encrypt_data_to_ipfs, eth_batch_personal_sign, exists_json, exists_mnemonic,
exists_private_key, export_json, export_mnemonic, export_private_key, get_derived_key,
get_extended_public_keys, get_public_keys, import_json, import_mnemonic, import_private_key,
mnemonic_to_public, sign_authentication_message, sign_hashes, sign_message, sign_psbt,
sign_psbts, sign_tx, unlock_then_crash, verify_password,
mnemonic_to_public, scan_keystores, sign_authentication_message, sign_hashes, sign_message,
sign_psbt, sign_psbts, sign_tx, unlock_then_crash, verify_password,
};
use crate::migration::{migrate_keystore, scan_legacy_keystores};

Expand Down Expand Up @@ -80,6 +80,10 @@ pub unsafe extern "C" fn call_tcx_api(hex_str: *const c_char) -> *const c_char {
let ret = scan_legacy_keystores()?;
encode_message(ret)
}),
"scan_keystores" => landingpad(|| {
let ret = scan_keystores()?;
encode_message(ret)
}),
"read_keystore_mnemonic_path" => {
landingpad(|| read_legacy_keystore_mnemonic_path(&action.param.unwrap().value))
}
Expand Down
9 changes: 8 additions & 1 deletion token-core/tcx/src/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::api::{
ReadKeystoreMnemonicPathResult, ScanLegacyKeystoresResult, WalletId,
};
use crate::error_handling::Result;
use crate::filemanager::{cache_keystore, KEYSTORE_MAP, WALLET_FILE_DIR};
use crate::filemanager::{cache_keystore, KEYSTORE_MAP, WALLET_FILE_DIR, WALLET_V1_DIR};
use crate::filemanager::{flush_keystore, LEGACY_WALLET_FILE_DIR};
use crate::handler::{encode_message, encrypt_xpub};
use anyhow::anyhow;
Expand Down Expand Up @@ -523,6 +523,13 @@ fn merge_migrate_source(id: &str, ori_source: &str) -> String {
}
}

pub fn is_migrated(id: &str) -> bool {
let migrated_id_map = read_migrated_map().1;
migrated_id_map
.values()
.any(|ids| ids.contains(&id.to_string()))
}

#[cfg(test)]
mod tests {
use std::fs;
Expand Down
4 changes: 2 additions & 2 deletions token-core/tcx/tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ pub fn import_default_pk_store() -> ImportPrivateKeyResult {
ImportPrivateKeyResult::decode(ret.as_slice()).unwrap()
}

pub fn import_filecoin_pk_store() -> KeystoreResult {
pub fn import_filecoin_pk_store() -> ImportPrivateKeyResult {
let param: ImportPrivateKeyParam = ImportPrivateKeyParam {
private_key: "f15716d3b003b304b8055d9cc62e6b9c869d56cc930c3858d4d7c31f5f53f14a".to_string(),
password: TEST_PASSWORD.to_string(),
Expand All @@ -98,7 +98,7 @@ pub fn import_filecoin_pk_store() -> KeystoreResult {
};

let ret = import_private_key(&encode_message(param).unwrap()).unwrap();
KeystoreResult::decode(ret.as_slice()).unwrap()
ImportPrivateKeyResult::decode(ret.as_slice()).unwrap()
}

pub fn import_and_derive(derivation: Derivation) -> (KeystoreResult, DeriveAccountsResult) {
Expand Down
3 changes: 2 additions & 1 deletion token-core/tcx/tests/export_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ pub fn test_tezos_import_private_key_export() {
};

let ret = import_private_key(&encode_message(param).unwrap()).unwrap();
let import_result: KeystoreResult = KeystoreResult::decode(ret.as_slice()).unwrap();
let import_result: ImportPrivateKeyResult =
ImportPrivateKeyResult::decode(ret.as_slice()).unwrap();

let derivations = vec![Derivation {
chain_type: "TEZOS".to_string(),
Expand Down
Loading
Loading