From 904d2c65db69c7221dfde5088330a5359d226e45 Mon Sep 17 00:00:00 2001 From: Neal Xu Date: Thu, 12 Oct 2023 11:00:06 +0800 Subject: [PATCH] feat: implement the functions about identity --- Cargo.lock | 8 +- Cargo.toml | 1 - token-core/tcx-chain/Cargo.toml | 8 +- token-core/tcx-chain/src/identity.rs | 531 ++++++++++++++++++++++ token-core/tcx-chain/src/keystore/hd.rs | 2 +- token-core/tcx-chain/src/keystore/mod.rs | 7 +- token-core/tcx-chain/src/lib.rs | 23 + token-core/tcx-common/src/lib.rs | 2 +- token-core/tcx-identity/src/wallet_api.rs | 102 ----- token-core/tcx-migration/src/migration.rs | 2 +- token-core/tcx-proto/build.rs | 6 +- token-core/tcx-proto/src/params.proto | 70 ++- token-core/tcx-proto/src/wallet_api.proto | 61 --- token-core/tcx/Cargo.toml | 1 - token-core/tcx/src/api.rs | 96 +++- token-core/tcx/src/filemanager.rs | 8 + token-core/tcx/src/handler.rs | 166 ++++--- token-core/tcx/src/lib.rs | 49 +- 18 files changed, 881 insertions(+), 262 deletions(-) create mode 100644 token-core/tcx-chain/src/identity.rs diff --git a/Cargo.lock b/Cargo.lock index df4a6a5d..e37eed7e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6445,7 +6445,6 @@ dependencies = [ "tcx-eth", "tcx-eth2", "tcx-filecoin", - "tcx-identity", "tcx-migration", "tcx-primitive", "tcx-proto", @@ -6512,14 +6511,19 @@ dependencies = [ "cargo-husky", "failure", "hex 0.4.3", + "hmac-sha256", + "lazy_static", + "multihash 0.18.1", + "parking_lot", "prost 0.11.8", "regex 1.9.3", "secp256k1 0.24.3", "serde", "serde_json", + "sha2 0.10.6", + "tcx-common", "tcx-constants", "tcx-crypto", - "tcx-identity", "tcx-primitive", "tiny-bip39 0.7.3", "uuid 1.3.0", diff --git a/Cargo.toml b/Cargo.toml index e90410b6..ae0d43c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,6 @@ members=[ "token-core/tcx-tezos", "token-core/tcx-tester", "token-core/tcx-eth2", - "token-core/tcx-identity", "token-core/tcx-eth", "token-core/zksync-crypto", "token-core/tcx-common", diff --git a/token-core/tcx-chain/Cargo.toml b/token-core/tcx-chain/Cargo.toml index 914f4527..f009b7cb 100644 --- a/token-core/tcx-chain/Cargo.toml +++ b/token-core/tcx-chain/Cargo.toml @@ -8,7 +8,8 @@ edition = "2021" tcx-crypto = { path = "../tcx-crypto" } tcx-primitive = { path = "../tcx-primitive" } tcx-constants = { path = "../tcx-constants" } -tcx-identity = { path = "../tcx-identity" } +tcx-common = {path = "../tcx-common"} +# tcx-identity = { path = "../tcx-identity" } bitcoin = "0.29.2" byteorder = "1.4.3" @@ -22,6 +23,11 @@ failure = "0.1.8" regex = "1.7.0" hex = "0.4.3" +sha2 = "0.10.6" +hmac-sha256 = "1.1.6" +multihash = "0.18.1" +lazy_static = "1.4.0" +parking_lot = "0.12.1" prost = "0.11.2" bytes = "1.3.0" diff --git a/token-core/tcx-chain/src/identity.rs b/token-core/tcx-chain/src/identity.rs new file mode 100644 index 00000000..4ba07e26 --- /dev/null +++ b/token-core/tcx-chain/src/identity.rs @@ -0,0 +1,531 @@ +// use crate::constants::{CHAIN_TYPE_ETHEREUM, ETHEREUM_PATH}; +// use crate::imt_keystore::{IMTKeystore, WALLETS, WALLET_KEYSTORE_DIR}; +// use crate::model::{Metadata, FROM_NEW_IDENTITY, FROM_RECOVERED_IDENTITY}; +// use crate::wallet_api::{CreateIdentityParam, RecoverIdentityParam}; +use crate::Error; +use crate::Result; +use bip39::{Language, Mnemonic, Seed}; +use bitcoin::consensus::{Decodable, Encodable}; +use bitcoin::hashes::hex::{FromHex, ToHex}; +use bitcoin::network::constants::Network; +use bitcoin::util::base58; +use bitcoin::util::bip32::ExtendedPrivKey; +use bitcoin::util::key::PrivateKey; +use bitcoin::VarInt; +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; +use hmac_sha256::HMAC; +use lazy_static::lazy_static; +use multihash::{Code, MultihashDigest}; +use parking_lot::RwLock; +use secp256k1::ecdsa::{RecoverableSignature, RecoveryId}; +use secp256k1::{Message, PublicKey, Secp256k1, SecretKey}; +use serde::{Deserialize, Serialize}; +use std::fs; +use std::fs::File; +use std::io::{Cursor, Read, Write}; +use std::path::Path; +use std::time::{SystemTime, UNIX_EPOCH}; +use tcx_common::{keccak256, merkle_hash, random_u8_16, sha256, unix_timestamp}; +use tcx_crypto::aes::cbc::{decrypt_pkcs7, encrypt_pkcs7}; +use tcx_crypto::crypto::Unlocker; +use tcx_crypto::{Crypto, EncPair, Key}; +use tcx_primitive::{PrivateKey as TraitPrivateKey, Secp256k1PrivateKey}; +use uuid::Uuid; + +// lazy_static! { +// pub static ref IDENTITY_KEYSTORE: RwLock = +// RwLock::new(IdentityKeystore::default()); +// } + +pub const IDENTITY_KEYSTORE_FILE_NAME: &'static str = "identity.json"; +pub const VERSION: u32 = 1000; + +// #[derive(Debug, Deserialize, Serialize, Clone, Default)] +// #[serde(rename_all = "camelCase")] +// pub struct IdentityKeystore { +// pub crypto: Crypto, +// pub id: String, +// pub version: u32, +// pub enc_auth_key: EncPair, +// pub enc_key: String, +// pub enc_mnemonic: EncPair, +// pub identifier: String, +// pub ipfs_id: String, +// #[serde(rename = "walletIDs")] +// pub wallet_ids: Vec, +// pub im_token_meta: Metadata, +// } + +#[derive(Debug, Deserialize, Serialize, Clone, Default)] +#[serde(rename_all = "camelCase")] +pub struct Identity { + pub enc_auth_key: EncPair, + pub enc_key: String, + pub identifier: String, + pub ipfs_id: String, +} + +impl Identity { + pub fn new(mnemonic_phrase: &str, unlocker: &Unlocker) -> Result { + let network_type = Network::Bitcoin; + + let validate_result = Mnemonic::validate(mnemonic_phrase, Language::English); + if validate_result.is_err() { + return Err(Error::InvalidMnemonic.into()); + } + let mnemonic = Mnemonic::from_phrase(mnemonic_phrase, Language::English).unwrap(); + let seed = Seed::new(&mnemonic, ""); + let master_key = ExtendedPrivKey::new_master(network_type, seed.as_ref())?; + + let salt = "Automatic Backup Key Mainnet"; + + let backup_key = HMAC::mac(salt.as_bytes(), master_key.private_key.secret_bytes()); + + let authentication_key = HMAC::mac("Authentication Key".as_bytes(), backup_key); + + let auth_private_key = PrivateKey::from_slice(authentication_key.as_ref(), network_type)?; + let secp = Secp256k1::new(); + let auth_pubkey_hash = auth_private_key.public_key(&secp).pubkey_hash(); + + let network_header = 0; + + let version = 2; + let magic_hex = "0fdc0c"; + let full_identifier = format!( + "{}{:02x}{:02x}{:02x}", + magic_hex, network_header, version, auth_pubkey_hash + ); + let identifier = base58::check_encode_slice(hex::decode(full_identifier)?.as_slice()); + + //gen enckey + let enc_key_bytes = HMAC::mac("Encryption Key".as_bytes(), backup_key); + + let enc_private_key = PrivateKey::new_uncompressed( + secp256k1::SecretKey::from_slice(enc_key_bytes.as_ref())?, + network_type, + ); + let multihash = + Code::Sha2_256.digest(enc_private_key.public_key(&secp).to_bytes().as_slice()); + let ipfs_id = base58::encode_slice(&multihash.to_bytes()); + + let master_prikey_bytes = master_key.encode(); + // let master_prikey_bytes = base58::check_encode_slice(master_prikey_bytes.as_slice()); + + // let mut crypto: Crypto = Crypto::new(password, master_prikey_bytes.as_bytes()); + // let unlocker = crypto.use_key(&Key::Password(password.to_string()))?; + + let enc_auth_key = unlocker.encrypt_with_random_iv(authentication_key.as_slice())?; + // let enc_mnemonic = unlocker.encrypt_with_random_iv(mnemonic.phrase().as_bytes())?; + + // let identity_keystore = IdentityKeystore { + // crypto, + // id: Uuid::new_v4().as_hyphenated().to_string(), + // version: VERSION, + // enc_auth_key, + // enc_key: hex::encode(enc_key_bytes), + // enc_mnemonic, + // identifier, + // ipfs_id, + // wallet_ids: vec![], + // im_token_meta: metadata, + // }; + + Ok(Identity { + enc_auth_key, + enc_key: hex::encode(enc_key_bytes), + identifier, + ipfs_id, + }) + } + + pub fn calculate_ipfs_id(pub_key: &PublicKey) -> String { + let multihash = Code::Sha2_256.digest(&pub_key.serialize_uncompressed()); + base58::encode_slice(&multihash.to_bytes()) + } + + // pub fn to_json(&self) -> Result { + // Ok(serde_json::to_string(&self)?) + // } + + // pub fn cache(&self) { + // let mut identity_keystore_obj = IDENTITY_KEYSTORE.write(); + // *identity_keystore_obj = self.to_owned(); + // } + + // pub fn flush(&self) -> Result<()> { + // let json = self.to_json()?; + // let file_dir = WALLET_KEYSTORE_DIR.read(); + // let ks_path = format!("{}/{}", file_dir, IDENTITY_KEYSTORE_FILE_NAME); + // let path = Path::new(&ks_path); + // let mut file = fs::File::create(path)?; + // let _ = file.write_all(&json.as_bytes()); + // Ok(()) + // } + + // pub fn export_identity(&self, password: &str) -> Result { + // let decrypt_data = self + // .crypto + // .use_key(&Key::Password(password.to_string()))? + // .plaintext()?; + // Ok(String::from_utf8(decrypt_data)?) + // } + + // pub fn delete_identity(&self, password: &str) -> Result<()> { + // if !self.crypto.verify_password(password) { + // return Err(Error::WalletInvalidPassword.into()); + // } + + // let clean_wallet_keystore_result = IMTKeystore::clean_keystore_dir(); + // if clean_wallet_keystore_result.is_ok() { + // IMTKeystore::clear_keystore_map(); + // let mut identity_keystore = IDENTITY_KEYSTORE.write(); + // *identity_keystore = IdentityKeystore::default(); + // } + + // Ok(()) + // } + + pub fn encrypt_ipfs(&self, plaintext: &str) -> Result { + let iv: [u8; 16] = random_u8_16(); + self.encrypt_ipfs_wth_timestamp_iv(plaintext, unix_timestamp(), &iv) + } + fn encrypt_ipfs_wth_timestamp_iv( + &self, + plaintext: &str, + timestamp: u64, + iv: &[u8; 16], + ) -> Result { + let mut header = Vec::new(); + + header.write_u8(0x03)?; + header.write_all(×tamp.to_le_bytes()[..4]); + header.write_all(iv)?; + + let enc_key = Vec::from_hex(&self.enc_key)?; + + let ciphertext = encrypt_pkcs7(plaintext.as_bytes(), &enc_key[0..16], iv)?; + let hash = keccak256(&[header.clone(), merkle_hash(&ciphertext).to_vec()].concat()); + let mut signature = Secp256k1PrivateKey::from_slice(&enc_key)?.sign_recoverable(&hash)?; + //ETH-compatible ec_recover, in chain_id = 1 case, v = 27 + rec_id + signature[64] += 27; + + let var_len = VarInt(ciphertext.len() as u64); + + let mut payload = vec![]; + payload.write_all(&header)?; + var_len.consensus_encode(&mut payload)?; + payload.write_all(&ciphertext)?; + payload.write_all(&signature)?; + + Ok(payload.to_hex()) + } + + pub fn decrypt_ipfs(&self, ciphertext: &str) -> Result { + let ciphertext = Vec::::from_hex(ciphertext)?; + if ciphertext.len() <= 21 { + return Err(Error::InvalidEncryptionData.into()); + } + + let mut rdr = Cursor::new(&ciphertext); + let mut header = vec![]; + + let version = rdr.read_u8()?; + if version != 0x03 { + return Err(Error::UnsupportEncryptionDataVersion.into()); + } + header.write_u8(version)?; + header.write_u32::(rdr.read_u32::()?)?; + + let mut iv = [0u8; 16]; + rdr.read(&mut iv)?; + header.write(&iv)?; + + let var_len = VarInt::consensus_decode(&mut rdr)?; + if var_len.0 as usize != ciphertext.len() - 21 - 65 - var_len.len() { + return Err(Error::InvalidEncryptionData.into()); + } + + let mut enc_data = vec![0u8; var_len.0 as usize]; + rdr.read(&mut enc_data)?; + + let mut signature = [0u8; 64]; + rdr.read(&mut signature)?; + + let recover_id = RecoveryId::from_i32(rdr.read_u8()? as i32 - 27)?; + + let hash = keccak256( + [header, merkle_hash(&enc_data).to_vec()] + .concat() + .as_slice(), + ); + + let message = Message::from_slice(&hash)?; + let sig = RecoverableSignature::from_compact(&signature, recover_id)?; + let pub_key = Secp256k1::new().recover_ecdsa(&message, &sig)?; + let ipfs_id = Self::calculate_ipfs_id(&pub_key); + + if self.ipfs_id != ipfs_id { + return Err(Error::InvalidEncryptionDataSignature.into()); + } + + let enc_key = Vec::from_hex(&self.enc_key)?; + let plaintext = decrypt_pkcs7(&enc_data, &enc_key[..16], &iv)?; + + Ok(String::from_utf8(plaintext)?) + } + + pub fn sign_authentication_message( + &self, + access_time: u64, + device_token: &str, + unlocker: &Unlocker, + ) -> Result { + // let unlocker = self.crypto.use_key(&Key::Password(password.to_string()))?; + let enc_auth_key = unlocker.decrypt_enc_pair(&self.enc_auth_key)?; + let mut signature = Secp256k1PrivateKey::from_slice(&enc_auth_key)?.sign_recoverable( + &keccak256(format!("{}.{}.{}", access_time, self.identifier, device_token).as_bytes()), + )?; + signature[64] += 27; + Ok(format!("0x{}", signature.to_hex())) + } + + // pub fn get_wallets(&self) -> Result> { + // let ids = &self.wallet_ids; + // let dir = WALLET_KEYSTORE_DIR.read(); + + // let mut wallets = WALLETS.write(); + // let mut ret_wallets = Vec::new(); + // let mut keystore_context = String::new(); + // for id in ids { + // if wallets.get(id.as_str()).is_some() { + // ret_wallets.push(wallets.get(id.as_str()).unwrap().clone()); + // continue; + // } + + // let path_str = format!("{}/{}.json", dir.as_str(), id); + // let path = Path::new(path_str.as_str()); + // if !path.exists() { + // return Err(Error::KeystoreFileNotExist.into()); + // } + // let mut file = File::open(&path)?; + // file.read_to_string(&mut keystore_context)?; + // let imt_keystore: IMTKeystore = serde_json::from_str(keystore_context.as_str())?; + // ret_wallets.push(imt_keystore.to_owned()); + // wallets.insert(id.to_string(), imt_keystore); + // } + // Ok(ret_wallets) + // } +} + +// pub struct Identity(); + +// impl Identity { +// pub fn get_current_identity() -> Result { +// let mut identity_keystore_obj = IDENTITY_KEYSTORE.write(); +// if !identity_keystore_obj.id.is_empty() { +// return Ok(identity_keystore_obj.to_owned()); +// } +// let dir = WALLET_KEYSTORE_DIR.read(); +// let path_str = format!("{}/{}", dir.as_str(), IDENTITY_KEYSTORE_FILE_NAME); +// let path = Path::new(path_str.as_str()); +// if !path.exists() { +// return Err(Error::KeystoreFileNotExist.into()); +// } +// let mut file = File::open(&path)?; +// let mut keystore_context = String::new(); +// file.read_to_string(&mut keystore_context)?; +// let identity_keystore: IdentityKeystore = serde_json::from_str(keystore_context.as_str())?; +// *identity_keystore_obj = identity_keystore.to_owned(); + +// Ok(identity_keystore) +// } + +// pub fn create_identity(param: CreateIdentityParam) -> Result { +// let name = param.name.as_str(); +// let password = param.password.as_str(); +// let password_hint = param.password_hint; +// let network = param.network.as_str(); +// let seg_wit = param.seg_wit.as_deref(); +// let mnemonic_phrase = tcx_primitive::generate_mnemonic(); + +// let metadata = Metadata::new( +// name, +// password_hint.clone(), +// FROM_NEW_IDENTITY, +// network, +// None, +// seg_wit, +// )?; +// let mut identity_keystore = +// IdentityKeystore::new(metadata.clone(), password, mnemonic_phrase.as_str())?; + +// let eth_keystore = Self::derive_ethereum_wallet( +// password_hint, +// FROM_NEW_IDENTITY, +// mnemonic_phrase.as_str(), +// password, +// )?; + +// identity_keystore.wallet_ids.push(eth_keystore.id); +// identity_keystore.flush()?; +// identity_keystore.cache(); + +// Ok(identity_keystore) +// } + +// pub fn recover_identity(param: RecoverIdentityParam) -> Result { +// let name = param.name.as_str(); +// let password = param.password.as_str(); +// let password_hint = param.password_hint; +// let network = param.network.as_str(); +// let seg_wit = param.seg_wit.as_deref(); +// let mnemonic_phrase = param.mnemonic.as_str(); +// let metadata = Metadata::new( +// name, +// password_hint.clone(), +// FROM_RECOVERED_IDENTITY, +// network, +// None, +// seg_wit, +// )?; +// let mut identity_keystore = IdentityKeystore::new(metadata, password, mnemonic_phrase)?; +// let eth_keystore = Self::derive_ethereum_wallet( +// password_hint, +// FROM_RECOVERED_IDENTITY, +// mnemonic_phrase, +// password, +// )?; + +// identity_keystore.wallet_ids.push(eth_keystore.id); +// identity_keystore.flush()?; +// identity_keystore.cache(); + +// Ok(identity_keystore) +// } + +// fn derive_ethereum_wallet( +// password_hint: Option, +// source: &str, +// mnemonic_phrase: &str, +// password: &str, +// ) -> Result { +// let mut metadata = Metadata::default(); +// metadata.chain_type = Some(CHAIN_TYPE_ETHEREUM.to_string()); +// metadata.password_hint = password_hint; +// metadata.source = source.to_string(); +// metadata.name = "ETH".to_string(); +// let imt_keystore = IMTKeystore::create_v3_mnemonic_keystore( +// &mut metadata, +// password, +// mnemonic_phrase, +// ETHEREUM_PATH, +// )?; +// imt_keystore.create_wallet()?; +// Ok(imt_keystore) +// } +// } + +// #[cfg(test)] +// mod test { +// use crate::identity::Identity; +// use crate::model::FROM_NEW_IDENTITY; +// use crate::wallet_api::{CreateIdentityParam, RecoverIdentityParam}; +// use tcx_constants::sample_key::{MNEMONIC, NAME, PASSWORD, PASSWORD_HINT}; +// use tcx_constants::{sample_key, TEST_MNEMONIC}; +// #[test] +// fn test_ipfs() { +// let param = RecoverIdentityParam { +// name: NAME.to_string(), +// mnemonic: MNEMONIC.to_string(), +// password: PASSWORD.to_string(), +// password_hint: Some(PASSWORD_HINT.to_string()), +// network: "TESTNET".to_string(), +// seg_wit: None, +// }; +// let keystore = Identity::recover_identity(param).unwrap(); + +// // header: data, iv, encrypted data +// let test_cases = [ +// ("imToken", "11111111111111111111111111111111", "0340b2495a1111111111111111111111111111111110b6602c68084bdd08dae796657aa6854ad13312fedc88f5b6f16c56b3e755dde125a1c4775db536ac0442ac942f9634c777f3ae5ca39f6abcae4bd6c87e54ab29ae0062b04d917b32e8d7c88eeb6261301b"), +// ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "11111111111111111111111111111111", "0340b2495a11111111111111111111111111111111708b7e9486a339f6c482ec9d3786dd9f99222fa64753bc2e7d246b0fed9c2153b8a5dcc59ea3e320aa153ceefdd909e8484d215121a9b8416d395de38313ef65b9e27d2ba0cc17bf29c5b26fa5aa5be1a2500b017f06cdd001e8cd908c5a48f10962880a61b4704754fd6bbe3b5a1a8332376651c28205a02574ed95a70363e0d1031d133c8d2376808b74ffd78b831ec659b44e9f3d3734d26abd44dda88fac86d1a5f0128f77d0558fb1ef6d2cc8f9541c"), +// ("a", "11111111111111111111111111111111", "0340b2495a111111111111111111111111111111111084e741e2b83ec644e844985088fd58d8449cb690cd7389d74e3be1ccdca755b0235c90431b7635a441944d880bd52c860b109b7a05a960192719eb3f294ec1b72f5dfd1b8f4c6e992b9c3add7c7c1b871b"), +// ("A", "11111111111111111111111111111111", "0340b2495a1111111111111111111111111111111110de32f176b67269ddfe24b2162eae14968d2eafcb53ec5741a07a1d65dc10189e0f6b4c199e98b02fcb9ec744b134cecc4ae8bfbf79e7703781c259eab9ee2fa31f887b24d04b37b7c5aa49a3ff2a8d5e1b"), +// ("a", "11111111111111111111111111111111", "0340b2495a111111111111111111111111111111111084e741e2b83ec644e844985088fd58d8449cb690cd7389d74e3be1ccdca755b0235c90431b7635a441944d880bd52c860b109b7a05a960192719eb3f294ec1b72f5dfd1b8f4c6e992b9c3add7c7c1b871b"), +// ("a", "22222222222222222222222222222222", "0340b2495a22222222222222222222222222222222102906146aa78fadd4abac01d9aa34dbd66463220fa0a98b9212594e7624a34bb20ba50df75cb04362f8dcfe7a8c44b2b5740a2d66de015d867e609463482686959ebba6047600562fa82e94ee905f1d291c"), +// ]; + +// let unix_timestamp = 1514779200u64; +// for t in test_cases { +// let iv: [u8; 16] = hex::decode(t.1).unwrap().try_into().unwrap(); +// assert_eq!( +// keystore +// .encrypt_ipfs_wth_timestamp_iv(t.0, unix_timestamp, &iv) +// .unwrap(), +// t.2 +// ); +// assert_eq!(keystore.decrypt_ipfs(t.2).unwrap(), t.0); +// } +// } + +// #[test] +// fn test_authentication() { +// let test_cases = [ +// ("MAINNET", "0x120cc977f9023c90635144bd0f4c8b85ff8aa23c003edcced9449f0465d05e954bccf9c114484e472c1837b0394f1933ad78ec8050673099e8bf5e9329737fe01c"), +// ("TESTNET", "0x663ace6d60225f6d1a71d25735c66646f71977a9f25f709fca162db3c664a1e161881a51a8034c240dd8f0093285fd6245f65246708546e8eadd592f995daeb11c"), +// ]; + +// for item in test_cases { +// let param = RecoverIdentityParam { +// name: NAME.to_string(), +// mnemonic: MNEMONIC.to_string(), +// password: PASSWORD.to_string(), +// password_hint: Some(PASSWORD_HINT.to_string()), +// network: item.0.to_string(), +// seg_wit: None, +// }; +// let keystore = Identity::recover_identity(param).unwrap(); + +// let actual = keystore +// .sign_authentication_message(1514736000, "12345ABCDE", PASSWORD) +// .unwrap(); +// assert_eq!(actual, item.1); +// } +// } + +// #[test] +// fn test_create_identity() { +// let param = CreateIdentityParam { +// name: sample_key::NAME.to_string(), +// password: PASSWORD.to_string(), +// password_hint: Some(PASSWORD_HINT.to_string()), +// network: "TESTNET".to_string(), +// seg_wit: None, +// }; +// let identity_keystore = Identity::create_identity(param).unwrap(); +// let imt_keystore_id = identity_keystore.wallet_ids.get(0).unwrap(); +// let ret = Identity::get_current_identity(); +// assert_eq!(ret.is_ok(), true); +// assert_eq!(ret.unwrap().wallet_ids.get(0).unwrap(), imt_keystore_id); +// } + +// #[test] +// fn test_recover_identity() { +// let param = RecoverIdentityParam { +// name: NAME.to_string(), +// mnemonic: MNEMONIC.to_string(), +// password: PASSWORD.to_string(), +// password_hint: Some(PASSWORD_HINT.to_string()), +// network: "TESTNET".to_string(), +// seg_wit: None, +// }; +// let recover_result = Identity::recover_identity(param); +// assert_eq!(recover_result.is_ok(), true); +// let identity_keystore = Identity::get_current_identity().unwrap(); +// let wallets = identity_keystore.get_wallets().unwrap(); +// assert_eq!(wallets.len(), 1); +// assert_eq!( +// "6031564e7b2f5cc33737807b2e58daff870b590b", +// wallets.get(0).unwrap().address +// ); +// } +// } diff --git a/token-core/tcx-chain/src/keystore/hd.rs b/token-core/tcx-chain/src/keystore/hd.rs index e271438b..174e3545 100644 --- a/token-core/tcx-chain/src/keystore/hd.rs +++ b/token-core/tcx-chain/src/keystore/hd.rs @@ -1,6 +1,6 @@ use bip39::{Language, Mnemonic, Seed}; -use tcx_identity::identity::Identity; +use crate::identity::Identity; use uuid::Uuid; use super::Account; diff --git a/token-core/tcx-chain/src/keystore/mod.rs b/token-core/tcx-chain/src/keystore/mod.rs index a3d72c79..561209a5 100644 --- a/token-core/tcx-chain/src/keystore/mod.rs +++ b/token-core/tcx-chain/src/keystore/mod.rs @@ -10,15 +10,16 @@ mod private; use serde::{Deserialize, Serialize}; use tcx_constants::{CoinInfo, CurveType}; +use tcx_crypto::crypto::Unlocker; pub use self::{ guard::KeystoreGuard, hd::key_hash_from_mnemonic, hd::HdKeystore, private::key_hash_from_private_key, private::PrivateKeystore, }; +use crate::identity::Identity; use crate::signer::ChainSigner; use tcx_crypto::{Crypto, Key}; -use tcx_identity::identity::Identity; use tcx_primitive::{TypedDeterministicPublicKey, TypedPrivateKey, TypedPublicKey}; #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -282,6 +283,10 @@ impl Keystore { } } + pub fn use_key(&self, key: &Key) -> Result { + self.store().crypto.use_key(key) + } + #[cfg(feature = "cache_dk")] pub fn get_derived_key(&mut self, password: &str) -> Result { Ok(hex::encode( diff --git a/token-core/tcx-chain/src/lib.rs b/token-core/tcx-chain/src/lib.rs index 4296fc31..2a7bb7bf 100644 --- a/token-core/tcx-chain/src/lib.rs +++ b/token-core/tcx-chain/src/lib.rs @@ -19,6 +19,7 @@ use core::result; extern crate failure; extern crate regex; +pub mod identity; pub mod keystore; mod signer; @@ -31,6 +32,28 @@ pub use signer::{ChainSigner, HashSigner, MessageSigner, TransactionSigner}; pub type Result = result::Result; +#[derive(Fail, Debug, PartialOrd, PartialEq)] +pub enum Error { + #[fail(display = "network_params_invalid")] + NetworkParamsInvalid, + #[fail(display = "unsupported_chain")] + WalletInvalidType, + #[fail(display = "wallet_not_found")] + WalletNotFound, + #[fail(display = "keystore_file_not_exist")] + KeystoreFileNotExist, + #[fail(display = "password_incorrect")] + WalletInvalidPassword, + #[fail(display = "invalid_mnemonic")] + InvalidMnemonic, + #[fail(display = "unsupport_encryption_data_version")] + UnsupportEncryptionDataVersion, + #[fail(display = "invalid_encryption_data_signature")] + InvalidEncryptionDataSignature, + #[fail(display = "invalid_encryption_data")] + InvalidEncryptionData, +} + pub trait PublicKeyEncoder { fn encode(&self, public_key: &[u8]) -> Result; } diff --git a/token-core/tcx-common/src/lib.rs b/token-core/tcx-common/src/lib.rs index 2bf76d97..ac1d5bc9 100644 --- a/token-core/tcx-common/src/lib.rs +++ b/token-core/tcx-common/src/lib.rs @@ -1,6 +1,7 @@ mod hash; mod rand; +mod errors; mod time; pub use crate::errors::*; @@ -9,7 +10,6 @@ pub use crate::rand::*; pub use crate::time::*; pub use crate::util::*; -mod errors; pub mod util; use std::result; diff --git a/token-core/tcx-identity/src/wallet_api.rs b/token-core/tcx-identity/src/wallet_api.rs index c0ba066f..07653e1d 100644 --- a/token-core/tcx-identity/src/wallet_api.rs +++ b/token-core/tcx-identity/src/wallet_api.rs @@ -1,11 +1,5 @@ #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct GenerateMnemonicResult { - #[prost(string, tag = "1")] - pub mnemonic: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] pub struct CreateIdentityParam { #[prost(string, tag = "1")] pub name: ::prost::alloc::string::String, @@ -152,99 +146,3 @@ pub struct RecoverIdentityResult { #[prost(message, repeated, tag = "4")] pub wallets: ::prost::alloc::vec::Vec, } -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct RemoveIdentityParam { - #[prost(string, tag = "1")] - pub identifier: ::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 RemoveIdentityResult { - #[prost(string, tag = "1")] - pub identifier: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct V3KeystoreImportInput { - #[prost(string, tag = "1")] - pub keystore: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub password: ::prost::alloc::string::String, - #[prost(bool, tag = "3")] - pub overwrite: bool, - #[prost(string, tag = "4")] - pub name: ::prost::alloc::string::String, - #[prost(string, tag = "5")] - pub chain_type: ::prost::alloc::string::String, - #[prost(string, tag = "6")] - pub source: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct V3KeystoreExportInput { - #[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 V3KeystoreExportOutput { - #[prost(string, tag = "1")] - pub json: ::prost::alloc::string::String, -} -#[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, - #[prost(string, tag = "2")] - pub content: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct EncryptDataToIpfsResult { - #[prost(string, tag = "1")] - pub identifier: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub encrypted: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct DecryptDataFromIpfsParam { - #[prost(string, tag = "1")] - pub identifier: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub encrypted: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct DecryptDataFromIpfsResult { - #[prost(string, tag = "1")] - pub identifier: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub content: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SignAuthenticationMessageParam { - #[prost(uint64, tag = "1")] - pub access_time: u64, - #[prost(string, tag = "2")] - 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, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SignAuthenticationMessageResult { - #[prost(uint64, tag = "1")] - pub access_time: u64, - #[prost(string, tag = "2")] - pub signature: ::prost::alloc::string::String, -} diff --git a/token-core/tcx-migration/src/migration.rs b/token-core/tcx-migration/src/migration.rs index ff84e784..90aa97c4 100644 --- a/token-core/tcx-migration/src/migration.rs +++ b/token-core/tcx-migration/src/migration.rs @@ -13,10 +13,10 @@ use tcx_crypto::{Crypto, EncPair, KdfParams, Key}; use tcx_btc_kin::address::BtcKinAddress; use tcx_btc_kin::Error; +use tcx_chain::identity::Identity; use tcx_chain::keystore::{Keystore, Metadata, Store}; use tcx_eos::address::EosAddress; use tcx_eth::address::EthAddress; -use tcx_identity::identity::Identity; use tcx_primitive::{PrivateKey, Secp256k1PrivateKey}; #[derive(Debug, Serialize, Deserialize, Clone)] diff --git a/token-core/tcx-proto/build.rs b/token-core/tcx-proto/build.rs index b1b3b36f..2d00519b 100644 --- a/token-core/tcx-proto/build.rs +++ b/token-core/tcx-proto/build.rs @@ -59,9 +59,9 @@ fn main() { env::set_var("OUT_DIR", "../tcx-eth2/src"); prost_build::compile_protos(&["src/eth2.proto"], &["src/"]).unwrap(); - //tcx-identity - env::set_var("OUT_DIR", "../tcx-identity/src"); - prost_build::compile_protos(&["src/wallet_api.proto"], &["src/"]).unwrap(); + // //tcx-identity + // env::set_var("OUT_DIR", "../tcx-identity/src"); + // prost_build::compile_protos(&["src/wallet_api.proto"], &["src/"]).unwrap(); //tcx-eth env::set_var("OUT_DIR", "../tcx-eth/src"); diff --git a/token-core/tcx-proto/src/params.proto b/token-core/tcx-proto/src/params.proto index 75a0017b..2bd3505b 100644 --- a/token-core/tcx-proto/src/params.proto +++ b/token-core/tcx-proto/src/params.proto @@ -222,8 +222,74 @@ message PublicKeyResult { } -message KeystoreUpdateAccount { +// message KeystoreUpdateAccount { +// string id = 1; +// string password = 2; +// string accountName = 3; +// } + + + + +message RemoveWalletsParam { + string identifier = 1; + string password = 2; +} + +message RemoveWalletsResult { + string identifier = 1; +} + +message V3KeystoreImportInput { + string keystore = 1; + string password = 2; + bool overwrite = 3; + string name = 4; + string chainType = 5; + string source = 6; +} + +message V3KeystoreExportInput { string id = 1; string password = 2; - string accountName = 3; +} + +message V3KeystoreExportOutput { + string json = 1; +} + +message EncryptDataToIpfsParam { + string identifier = 1; + string content = 2; +} + +message EncryptDataToIpfsResult { + string identifier = 1; + string encrypted = 2; +} + +message DecryptDataFromIpfsParam { + string identifier = 1; + string encrypted = 2; +} + +message DecryptDataFromIpfsResult { + string identifier = 1; + string content = 2; +} + +message SignAuthenticationMessageParam { + uint64 accessTime = 1; + string identifier = 2 ; + string deviceToken = 3; + string password = 4; +} + +message SignAuthenticationMessageResult { + uint64 accessTime = 1; + string signature = 2; +} + +message GenerateMnemonicResult { + string mnemonic = 1; } \ No newline at end of file diff --git a/token-core/tcx-proto/src/wallet_api.proto b/token-core/tcx-proto/src/wallet_api.proto index 6f52ff25..97d6e892 100644 --- a/token-core/tcx-proto/src/wallet_api.proto +++ b/token-core/tcx-proto/src/wallet_api.proto @@ -1,9 +1,6 @@ syntax = "proto3"; package wallet_api; -message GenerateMnemonicResult { - string mnemonic = 1; -} message CreateIdentityParam { string name = 1; @@ -90,64 +87,6 @@ message RecoverIdentityResult { repeated Wallet wallets = 4; } -message RemoveIdentityParam { - string identifier = 1; - string password = 2; -} - -message RemoveIdentityResult { - string identifier = 1; -} - -message V3KeystoreImportInput { - string keystore = 1; - string password = 2; - bool overwrite = 3; - string name = 4; - string chainType = 5; - string source = 6; -} - -message V3KeystoreExportInput { - string id = 1; - string password = 2; -} - -message V3KeystoreExportOutput { - string json = 1; -} - -message EncryptDataToIpfsParam { - string identifier = 1; - string content = 2; -} - -message EncryptDataToIpfsResult { - string identifier = 1; - string encrypted = 2; -} - -message DecryptDataFromIpfsParam { - string identifier = 1; - string encrypted = 2; -} - -message DecryptDataFromIpfsResult { - string identifier = 1; - string content = 2; -} - -message SignAuthenticationMessageParam { - uint64 accessTime = 1; - string identifier = 2 ; - string deviceToken = 3; - string password = 4; -} - -message SignAuthenticationMessageResult { - uint64 accessTime = 1; - string signature = 2; -} diff --git a/token-core/tcx/Cargo.toml b/token-core/tcx/Cargo.toml index 22ace82f..4bfc8b3b 100644 --- a/token-core/tcx/Cargo.toml +++ b/token-core/tcx/Cargo.toml @@ -20,7 +20,6 @@ tcx-constants = { path = "../tcx-constants" } tcx-tezos = { path = "../tcx-tezos" } tcx-eth2 = { path = "../tcx-eth2" } zksync-crypto = { path = "../zksync-crypto" } -tcx-identity = { path = "../tcx-identity" } tcx-eth = { path = "../tcx-eth" } tcx-common = { path = "../tcx-common" } tcx-migration = { path = "../tcx-migration" } diff --git a/token-core/tcx/src/api.rs b/token-core/tcx/src/api.rs index e788add5..bd384ce9 100644 --- a/token-core/tcx/src/api.rs +++ b/token-core/tcx/src/api.rs @@ -367,13 +367,105 @@ pub struct PublicKeyResult { } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct KeystoreUpdateAccount { +pub struct RemoveWalletsParam { + #[prost(string, tag = "1")] + pub identifier: ::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 RemoveWalletsResult { + #[prost(string, tag = "1")] + pub identifier: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct V3KeystoreImportInput { + #[prost(string, tag = "1")] + pub keystore: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub password: ::prost::alloc::string::String, + #[prost(bool, tag = "3")] + pub overwrite: bool, + #[prost(string, tag = "4")] + pub name: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub chain_type: ::prost::alloc::string::String, + #[prost(string, tag = "6")] + pub source: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct V3KeystoreExportInput { #[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 V3KeystoreExportOutput { + #[prost(string, tag = "1")] + pub json: ::prost::alloc::string::String, +} +#[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, + #[prost(string, tag = "2")] + pub content: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EncryptDataToIpfsResult { + #[prost(string, tag = "1")] + pub identifier: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub encrypted: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DecryptDataFromIpfsParam { + #[prost(string, tag = "1")] + pub identifier: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub encrypted: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DecryptDataFromIpfsResult { + #[prost(string, tag = "1")] + pub identifier: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub content: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SignAuthenticationMessageParam { + #[prost(uint64, tag = "1")] + pub access_time: u64, + #[prost(string, tag = "2")] + pub identifier: ::prost::alloc::string::String, #[prost(string, tag = "3")] - pub account_name: ::prost::alloc::string::String, + pub device_token: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub password: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SignAuthenticationMessageResult { + #[prost(uint64, tag = "1")] + pub access_time: u64, + #[prost(string, tag = "2")] + pub signature: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenerateMnemonicResult { + #[prost(string, tag = "1")] + pub mnemonic: ::prost::alloc::string::String, } /// only support two types #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] diff --git a/token-core/tcx/src/filemanager.rs b/token-core/tcx/src/filemanager.rs index 796b6dd2..31ca3e97 100644 --- a/token-core/tcx/src/filemanager.rs +++ b/token-core/tcx/src/filemanager.rs @@ -86,6 +86,14 @@ pub fn delete_keystore_file(wid: &str) -> Result<()> { Ok(()) } +pub fn delete_keystore_files() -> Result<()> { + let file_dir = WALLET_FILE_DIR.read(); + let dir_str = file_dir.as_str(); + let path = Path::new(&dir_str); + fs::remove_dir(path)?; + Ok(()) +} + #[cfg(test)] mod tests { use std::{fs, path::Path}; diff --git a/token-core/tcx/src/handler.rs b/token-core/tcx/src/handler.rs index 917be7a9..b2b41696 100644 --- a/token-core/tcx/src/handler.rs +++ b/token-core/tcx/src/handler.rs @@ -22,11 +22,14 @@ use crate::api::keystore_common_derive_param::Derivation; use crate::api::sign_param::Key; use crate::api::{ AccountResponse, AccountsResponse, CalcExternalAddressParam, CalcExternalAddressResult, - DerivedKeyResult, ExportPrivateKeyParam, HdStoreCreateParam, HdStoreImportParam, - IdentityResult, KeyType, KeystoreCommonAccountsParam, KeystoreCommonDeriveParam, - KeystoreCommonExistsParam, KeystoreCommonExistsResult, KeystoreCommonExportResult, - KeystoreMigrationParam, KeystoreUpdateAccount, PrivateKeyStoreExportParam, - PrivateKeyStoreImportParam, PublicKeyParam, PublicKeyResult, Response, WalletKeyParam, + DecryptDataFromIpfsParam, DecryptDataFromIpfsResult, DerivedKeyResult, EncryptDataToIpfsParam, + EncryptDataToIpfsResult, ExportPrivateKeyParam, GenerateMnemonicResult, HdStoreCreateParam, + HdStoreImportParam, IdentityResult, KeyType, KeystoreCommonAccountsParam, + KeystoreCommonDeriveParam, KeystoreCommonExistsParam, KeystoreCommonExistsResult, + KeystoreCommonExportResult, KeystoreMigrationParam, PrivateKeyStoreExportParam, + PrivateKeyStoreImportParam, PublicKeyParam, PublicKeyResult, RemoveWalletsParam, + RemoveWalletsResult, Response, SignAuthenticationMessageParam, SignAuthenticationMessageResult, + V3KeystoreExportInput, V3KeystoreExportOutput, V3KeystoreImportInput, WalletKeyParam, WalletResult, ZksyncPrivateKeyFromSeedParam, ZksyncPrivateKeyFromSeedResult, ZksyncPrivateKeyToPubkeyHashParam, ZksyncPrivateKeyToPubkeyHashResult, ZksyncSignMusigParam, ZksyncSignMusigResult, @@ -34,7 +37,7 @@ use crate::api::{ use crate::api::{InitTokenCoreXParam, SignParam}; use crate::error_handling::Result; use crate::filemanager::{ - cache_keystore, clean_keystore, copy_to_v2_if_need, flush_keystore, KEYSTORE_BASE_DIR, + self, cache_keystore, clean_keystore, copy_to_v2_if_need, flush_keystore, KEYSTORE_BASE_DIR, WALLET_FILE_DIR, WALLET_V2_DIR, }; use crate::filemanager::{delete_keystore_file, KEYSTORE_MAP}; @@ -60,17 +63,17 @@ use tcx_substrate::{ SubstrateKeystore, SubstrateKeystoreParam, SubstrateRawTxIn, }; -use tcx_identity::identity::Identity; +use tcx_chain::identity::Identity; // use tcx_identity::imt_keystore::{IMTKeystore, WALLET_KEYSTORE_DIR}; // use tcx_identity::v3_keystore::import_wallet_from_keystore; -use tcx_identity::wallet_api::{ - CreateIdentityParam, CreateIdentityResult, DecryptDataFromIpfsParam, EncryptDataToIpfsParam, - EncryptDataToIpfsResult, ExportIdentityParam, ExportIdentityResult, GenerateMnemonicResult, - GetCurrentIdentityResult, ImtKeystore, Metadata as MetadataRes, RecoverIdentityParam, - RecoverIdentityResult, RemoveIdentityParam, RemoveIdentityResult, - SignAuthenticationMessageParam, SignAuthenticationMessageResult, V3KeystoreExportInput, - V3KeystoreExportOutput, V3KeystoreImportInput, Wallet, -}; +// use tcx_identity::wallet_api::{ +// CreateIdentityParam, CreateIdentityResult, DecryptDataFromIpfsParam, DecryptDataFromIpfsResult, +// EncryptDataToIpfsParam, EncryptDataToIpfsResult, ExportIdentityParam, ExportIdentityResult, +// GenerateMnemonicResult, GetCurrentIdentityResult, ImtKeystore, Metadata as MetadataRes, +// RecoverIdentityParam, RecoverIdentityResult, RemoveIdentityParam, RemoveIdentityResult, +// SignAuthenticationMessageParam, SignAuthenticationMessageResult, V3KeystoreExportInput, +// V3KeystoreExportOutput, V3KeystoreImportInput, Wallet, +// }; use tcx_migration::migration::LegacyKeystore; use tcx_tezos::transaction::TezosRawTxIn; use tcx_tezos::{build_tezos_base58_private_key, pars_tezos_private_key}; @@ -1091,18 +1094,24 @@ pub(crate) fn generate_mnemonic() -> Result> { // encode_message(result) // } -// pub(crate) fn remove_identity(data: &[u8]) -> Result> { -// let param: RemoveIdentityParam = RemoveIdentityParam::decode(data)?; -// let identity = Identity::get_current_identity()?; -// if identity.identifier != param.identifier { -// return Err(format_err!("invalid_identity")); -// } -// identity.delete_identity(param.password.as_str())?; -// let result = RemoveIdentityResult { -// identifier: param.identifier, -// }; -// encode_message(result) -// } +// TODO: may rename to remove wallets? +pub(crate) fn remove_wallets(data: &[u8]) -> Result> { + let param: RemoveWalletsParam = RemoveWalletsParam::decode(data)?; + let map = KEYSTORE_MAP.read(); + let Some(identity_ks) = map.values().find(|ks| ks.identity().is_some() && ks.identity().unwrap().identifier == param.identifier) else { + return Err(failure::format_err!("identity not found")); + }; + + if !identity_ks.verify_password(¶m.password) { + return Err(failure::format_err!("password_incorrect")); + } + filemanager::delete_keystore_files()?; + + let result = RemoveWalletsResult { + identifier: param.identifier, + }; + encode_message(result) +} pub(crate) fn eth_ec_sign(_data: &[u8]) -> Result> { todo!() @@ -1191,50 +1200,83 @@ pub(crate) fn eth_recover_address(data: &[u8]) -> Result> { // encode_message(output) // } -// pub(crate) fn encrypt_data_to_ipfs(data: &[u8]) -> Result> { -// let input = EncryptDataToIpfsParam::decode(data).expect("EncryptDataToIpfsParam"); -// let identity = Identity::get_current_identity()?; -// let ciphertext = identity.encrypt_ipfs(&input.content)?; +pub(crate) fn encrypt_data_to_ipfs(data: &[u8]) -> Result> { + let param = EncryptDataToIpfsParam::decode(data).expect("EncryptDataToIpfsParam"); + // let identity = Identity::get_current_identity()?; + // let ciphertext = identity.encrypt_ipfs(&input.content)?; + // Identity::encrypt_ipfs(&self, plaintext) -// let output = EncryptDataToIpfsResult { -// identifier: identity.identifier.to_string(), -// encrypted: ciphertext, -// }; + let map = KEYSTORE_MAP.read(); + let Some(identity_ks) = map.values().find(|ks| ks.identity().is_some() && ks.identity().unwrap().identifier == param.identifier) else { + return Err(failure::format_err!("identity not found")); + }; -// encode_message(output) -// } + let cipher_text = identity_ks + .identity() + .unwrap() + .encrypt_ipfs(¶m.content)?; -// pub(crate) fn decrypt_data_from_ipfs(data: &[u8]) -> Result> { -// let input = DecryptDataFromIpfsParam::decode(data).expect("EncryptDataToIpfsParam"); -// let identity = Identity::get_current_identity()?; -// let ciphertext = identity.decrypt_ipfs(&input.encrypted)?; + let output = EncryptDataToIpfsResult { + identifier: param.identifier.to_string(), + encrypted: cipher_text, + }; -// let output = EncryptDataToIpfsResult { -// identifier: identity.identifier.to_string(), -// encrypted: ciphertext, -// }; + encode_message(output) +} -// encode_message(output) -// } +pub(crate) fn decrypt_data_from_ipfs(data: &[u8]) -> Result> { + let param = DecryptDataFromIpfsParam::decode(data).expect("DecryptDataFromIpfsParam"); + // let identity = Identity::get_current_identity()?; + // let ciphertext = identity.decrypt_ipfs(&input.encrypted)?; + // let map = KEYSTORE_MAP.read(); + // let Some(identity_ks) = map.values().find(|ks| ks.identity().is_some() && ks.identity().unwrap().identifier == param.identifier) else { + // return Err(failure::format_err!("identity not found")); + // }; -// pub(crate) fn sign_authentication_message(data: &[u8]) -> Result> { -// let input = -// SignAuthenticationMessageParam::decode(data).expect("SignAuthenticationMessageParam"); -// let identity = Identity::get_current_identity()?; + let map = KEYSTORE_MAP.read(); + let Some(identity_ks) = map.values().find(|ks| ks.identity().is_some() && ks.identity().unwrap().identifier == param.identifier) else { + return Err(failure::format_err!("identity not found")); + }; -// let signature = identity.sign_authentication_message( -// input.access_time, -// &input.identifier, -// &input.device_token, -// )?; -// encode_message(SignAuthenticationMessageResult { -// signature, -// access_time: input.access_time, -// }) -// } + let content = identity_ks + .identity() + .unwrap() + .decrypt_ipfs(¶m.encrypted)?; + + let output = DecryptDataFromIpfsResult { + identifier: param.identifier.to_string(), + content, + }; + + encode_message(output) +} + +pub(crate) fn sign_authentication_message(data: &[u8]) -> Result> { + let param = + SignAuthenticationMessageParam::decode(data).expect("SignAuthenticationMessageParam"); + + let map = KEYSTORE_MAP.read(); + let Some(identity_ks) = map.values().find(|ks| ks.identity().is_some() && ks.identity().unwrap().identifier == param.identifier) else { + return Err(failure::format_err!("identity not found")); + }; + + let key = tcx_crypto::Key::Password(param.password); + let unlocker = identity_ks.use_key(&key)?; + + let signature = identity_ks + .identity() + .unwrap() + .sign_authentication_message(param.access_time, ¶m.device_token, &unlocker)?; + + encode_message(SignAuthenticationMessageResult { + signature, + access_time: param.access_time, + }) +} pub(crate) fn calc_external_address(data: &[u8]) -> Result> { - let param = CalcExternalAddressParam::decode(data).expect("CalcExternalAddressParam"); + let param: CalcExternalAddressParam = + CalcExternalAddressParam::decode(data).expect("CalcExternalAddressParam"); let mut map = KEYSTORE_MAP.write(); let keystore: &mut Keystore = match map.get_mut(¶m.id) { Some(keystore) => Ok(keystore), diff --git a/token-core/tcx/src/lib.rs b/token-core/tcx/src/lib.rs index 9a7c3415..be7ec002 100644 --- a/token-core/tcx/src/lib.rs +++ b/token-core/tcx/src/lib.rs @@ -2,7 +2,10 @@ use std::ffi::{CStr, CString}; use std::os::raw::c_char; -use handler::{calc_external_address, migrate_keystore, sign_message}; +use handler::{ + calc_external_address, decrypt_data_from_ipfs, encrypt_data_to_ipfs, migrate_keystore, + remove_wallets, sign_authentication_message, sign_message, +}; // use handler::{eth_v3keystore_export, eth_v3keystore_import}; use prost::Message; @@ -148,19 +151,19 @@ pub unsafe extern "C" fn call_tcx_api(hex_str: *const c_char) -> *const c_char { // "get_current_identity" => landingpad(|| get_current_identity()), // "recover_identity" => landingpad(|| recover_identity(&action.param.unwrap().value)), // "export_identity" => landingpad(|| export_identity(&action.param.unwrap().value)), - // "remove_identity" => landingpad(|| remove_identity(&action.param.unwrap().value)), + "remove_wallets" => landingpad(|| remove_wallets(&action.param.unwrap().value)), // "eth_ec_sign" => landingpad(|| eth_ec_sign(&action.param.unwrap().value)), // "eth_recover_address" => landingpad(|| eth_recover_address(&action.param.unwrap().value)), // "eos_update_account" => landingpad(|| eos_update_account(&action.param.unwrap().value)), // "eth_keystore_import" => landingpad(|| eth_v3keystore_import(&action.param.unwrap().value)), // "eth_keystore_export" => landingpad(|| eth_v3keystore_export(&action.param.unwrap().value)), - // "encrypt_data_to_ipfs" => landingpad(|| encrypt_data_to_ipfs(&action.param.unwrap().value)), - // "decrypt_data_from_ipfs" => { - // landingpad(|| decrypt_data_from_ipfs(&action.param.unwrap().value)) - // } - // "sign_authentication_message" => { - // landingpad(|| sign_authentication_message(&action.param.unwrap().value)) - // } + "encrypt_data_to_ipfs" => landingpad(|| encrypt_data_to_ipfs(&action.param.unwrap().value)), + "decrypt_data_from_ipfs" => { + landingpad(|| decrypt_data_from_ipfs(&action.param.unwrap().value)) + } + "sign_authentication_message" => { + landingpad(|| sign_authentication_message(&action.param.unwrap().value)) + } "migrate_keystore" => landingpad(|| migrate_keystore(&action.param.unwrap().value)), _ => landingpad(|| Err(format_err!("unsupported_method"))), }; @@ -215,23 +218,27 @@ mod tests { use crate::api::keystore_common_derive_param::Derivation; use crate::api::{ - sign_param, AccountsResponse, DerivedKeyResult, ExportPrivateKeyParam, HdStoreCreateParam, + sign_param, AccountResponse, AccountsResponse, CalcExternalAddressParam, + CalcExternalAddressResult, DecryptDataFromIpfsParam, DecryptDataFromIpfsResult, + DerivedKeyResult, EncryptDataToIpfsParam, EncryptDataToIpfsResult, ExportPrivateKeyParam, + GenerateMnemonicResult, HdStoreCreateParam, HdStoreImportParam, IdentityResult, InitTokenCoreXParam, KeyType, KeystoreCommonAccountsParam, KeystoreCommonDeriveParam, KeystoreCommonExistsParam, KeystoreCommonExistsResult, KeystoreCommonExportResult, - KeystoreUpdateAccount, PrivateKeyStoreExportParam, PrivateKeyStoreImportParam, - PublicKeyParam, PublicKeyResult, Response, SignParam, WalletKeyParam, - ZksyncPrivateKeyFromSeedParam, ZksyncPrivateKeyFromSeedResult, + KeystoreMigrationParam, PrivateKeyStoreExportParam, PrivateKeyStoreImportParam, + PublicKeyParam, PublicKeyResult, RemoveWalletsParam, RemoveWalletsResult, Response, + SignAuthenticationMessageParam, SignAuthenticationMessageResult, SignParam, + V3KeystoreExportInput, V3KeystoreExportOutput, V3KeystoreImportInput, WalletKeyParam, + WalletResult, ZksyncPrivateKeyFromSeedParam, ZksyncPrivateKeyFromSeedResult, ZksyncPrivateKeyToPubkeyHashParam, ZksyncPrivateKeyToPubkeyHashResult, ZksyncSignMusigParam, ZksyncSignMusigResult, }; - use crate::api::{HdStoreImportParam, WalletResult}; use crate::handler::hd_store_import; use crate::handler::{encode_message, private_key_store_import}; use prost::Message; use tcx_chain::{Keystore, Source}; use tcx_constants::sample_key; use tcx_constants::{TEST_MNEMONIC, TEST_PASSWORD}; - use tcx_identity::{constants, model}; + // use tcx_identity::{constants, model}; use std::fs; use tcx_btc_kin::transaction::BtcKinTxInput; @@ -249,12 +256,12 @@ mod tests { }; use tcx_eth2::transaction::{SignBlsToExecutionChangeParam, SignBlsToExecutionChangeResult}; use tcx_filecoin::{SignedMessage, UnsignedMessage}; - use tcx_identity::wallet_api::{ - CreateIdentityParam, CreateIdentityResult, ExportIdentityParam, ExportIdentityResult, - GenerateMnemonicResult, GetCurrentIdentityResult, RecoverIdentityParam, - RecoverIdentityResult, RemoveIdentityParam, RemoveIdentityResult, V3KeystoreExportInput, - V3KeystoreExportOutput, V3KeystoreImportInput, - }; + // use tcx_identity::wallet_api::{ + // CreateIdentityParam, CreateIdentityResult, ExportIdentityParam, ExportIdentityResult, + // GenerateMnemonicResult, GetCurrentIdentityResult, RecoverIdentityParam, + // RecoverIdentityResult, RemoveIdentityParam, RemoveIdentityResult, V3KeystoreExportInput, + // V3KeystoreExportOutput, V3KeystoreImportInput, + // }; use tcx_substrate::{ ExportSubstrateKeystoreResult, SubstrateKeystore, SubstrateKeystoreParam, SubstrateRawTxIn, SubstrateTxOut,