From 3d496aa24f8c4b5348a73532a881c5dd86276d70 Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Fri, 25 Oct 2024 14:06:07 +0200 Subject: [PATCH] Adding request_intent trusted call (#3143) --- common/primitives/core/src/identity.rs | 4 + common/primitives/core/src/intent.rs | 13 ++ parachain/pallets/omni-account/src/lib.rs | 3 +- parachain/pallets/omni-account/src/tests.rs | 64 +++++--- tee-worker/Cargo.lock | 62 ++++---- tee-worker/Cargo.toml | 2 +- .../node-api/api-client-types/src/lib.rs | 1 + .../common/litentry/primitives/src/lib.rs | 1 + .../identity/app-libs/stf/src/trusted_call.rs | 12 +- .../identity/enclave-runtime/Cargo.lock | 72 +++++---- .../identity/enclave-runtime/Cargo.toml | 1 + .../enclave-runtime/src/rpc/common_api.rs | 79 ++++++++-- .../src/{web2 => }/helpers.rs | 0 .../core/identity-verification/src/lib.rs | 15 +- .../email => }/verification_code_store.rs | 11 +- .../src/web2/email/mod.rs | 9 +- .../identity-verification/src/web2/mod.rs | 6 +- .../src/web2/twitter/mod.rs | 3 +- .../core/native-task/receiver/Cargo.toml | 9 ++ .../core/native-task/receiver/src/lib.rs | 139 +++++++++++++++--- .../src/trusted_call_authenticated.rs | 124 ++++++++++++++++ .../core/native-task/receiver/src/types.rs | 27 +++- .../core/omni-account/src/in_memory_store.rs | 54 +++++-- .../core/omni-account/src/repository.rs | 22 +-- .../src/ocall_bridge/worker_on_chain_ocall.rs | 6 +- 25 files changed, 564 insertions(+), 175 deletions(-) rename tee-worker/identity/litentry/core/identity-verification/src/{web2 => }/helpers.rs (100%) rename tee-worker/identity/litentry/core/identity-verification/src/{web2/email => }/verification_code_store.rs (84%) create mode 100644 tee-worker/identity/litentry/core/native-task/receiver/src/trusted_call_authenticated.rs diff --git a/common/primitives/core/src/identity.rs b/common/primitives/core/src/identity.rs index 81384cc3aa..9fd36629d9 100644 --- a/common/primitives/core/src/identity.rs +++ b/common/primitives/core/src/identity.rs @@ -486,6 +486,10 @@ impl Identity { pub fn hash(&self) -> H256 { self.using_encoded(blake2_256).into() } + + pub fn from_email(email: &str) -> Self { + Identity::Email(IdentityString::new(email.as_bytes().to_vec())) + } } impl From for Identity { diff --git a/common/primitives/core/src/intent.rs b/common/primitives/core/src/intent.rs index 10e01a2344..50bdfb34fd 100644 --- a/common/primitives/core/src/intent.rs +++ b/common/primitives/core/src/intent.rs @@ -1,3 +1,4 @@ +use crate::{AccountId, Balance}; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_core::H160; @@ -5,12 +6,18 @@ use sp_runtime::{traits::ConstU32, BoundedVec}; pub const CALL_ETHEREUM_INPUT_LEN: u32 = 10 * 1024; +pub const MAX_REMARK_LEN: u32 = u32::max_value(); + #[derive(Encode, Decode, Debug, Clone, PartialEq, Eq, MaxEncodedLen, TypeInfo)] pub enum Intent { #[codec(index = 0)] TransferEthereum(TransferEthereum), #[codec(index = 1)] CallEthereum(CallEthereum), + #[codec(index = 2)] + SystemRemark(BoundedVec>), + #[codec(index = 3)] + TransferNative(TransferNative), } #[derive(Encode, Decode, Debug, Clone, PartialEq, Eq, MaxEncodedLen, TypeInfo)] @@ -26,3 +33,9 @@ pub struct CallEthereum { pub address: H160, pub input: BoundedVec, } + +#[derive(Encode, Decode, Debug, Clone, PartialEq, Eq, MaxEncodedLen, TypeInfo)] +pub struct TransferNative { + pub to: AccountId, + pub value: Balance, +} diff --git a/parachain/pallets/omni-account/src/lib.rs b/parachain/pallets/omni-account/src/lib.rs index 988c0b69a3..30d7a35fc3 100644 --- a/parachain/pallets/omni-account/src/lib.rs +++ b/parachain/pallets/omni-account/src/lib.rs @@ -22,7 +22,7 @@ mod mock; mod tests; pub use core_primitives::{Identity, Intent, MemberAccount, OmniAccountConverter}; -pub use frame_system::pallet_prelude::BlockNumberFor; +pub use frame_system::{self as system, pallet_prelude::BlockNumberFor}; pub use pallet::*; use frame_support::pallet_prelude::*; @@ -178,6 +178,7 @@ pub mod pallet { let omni_account = MemberAccountHash::::get(member_account_hash) .ok_or(Error::::AccountNotFound)?; let result = call.dispatch(RawOrigin::OmniAccount(omni_account.clone()).into()); + system::Pallet::::inc_account_nonce(&omni_account); Self::deposit_event(Event::DispatchedAsOmniAccount { who: omni_account, result: result.map(|_| ()).map_err(|e| e.error), diff --git a/parachain/pallets/omni-account/src/tests.rs b/parachain/pallets/omni-account/src/tests.rs index 7c42cc01bf..4cce2aa707 100644 --- a/parachain/pallets/omni-account/src/tests.rs +++ b/parachain/pallets/omni-account/src/tests.rs @@ -77,7 +77,7 @@ fn add_account_without_creating_store_fails() { OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), - call + call, ), Error::::AccountNotFound ); @@ -104,7 +104,7 @@ fn add_account_works() { assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), - call + call, )); System::assert_has_event( @@ -124,7 +124,7 @@ fn add_account_works() { assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), - call + call, )); System::assert_has_event( @@ -180,13 +180,13 @@ fn add_account_with_already_linked_account_fails() { assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), - call.clone() + call.clone(), )); assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), - call + call, )); System::assert_has_event( @@ -211,7 +211,7 @@ fn add_account_with_already_linked_account_fails() { assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), charlie().identity.hash(), - call + call, )); System::assert_has_event( @@ -256,7 +256,7 @@ fn add_account_store_len_limit_reached_works() { assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), - call + call, )); System::assert_has_event( @@ -288,7 +288,7 @@ fn remove_account_works() { assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), - call + call, )); // normal signed origin should give `BadOrigin`, no matter @@ -313,7 +313,7 @@ fn remove_account_works() { assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), - call + call, )); System::assert_has_event( @@ -345,7 +345,7 @@ fn remove_account_works() { assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), - call + call, )); assert!(!AccountStore::::contains_key(alice().omni_account)); @@ -367,7 +367,7 @@ fn remove_account_empty_account_check_works() { assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), - call + call, )); let call = remove_accounts_call(vec![]); @@ -375,7 +375,7 @@ fn remove_account_empty_account_check_works() { assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), - call + call, )); System::assert_has_event( Event::DispatchedAsOmniAccount { @@ -407,7 +407,7 @@ fn publicize_account_works() { assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), - call + call, )); let expected_member_accounts: MemberAccounts = @@ -421,7 +421,7 @@ fn publicize_account_works() { assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), - call + call, )); System::assert_has_event( @@ -460,7 +460,7 @@ fn publicize_account_identity_not_found_works() { OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), - call + call, ), Error::::AccountNotFound ); @@ -474,14 +474,14 @@ fn publicize_account_identity_not_found_works() { assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), - call + call, )); let call = publicize_account_call(charlie().identity); assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), - call + call, )); System::assert_has_event( Event::DispatchedAsOmniAccount { @@ -512,7 +512,7 @@ fn request_intent_works() { assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), - call + call, )); let intent = @@ -522,7 +522,7 @@ fn request_intent_works() { assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), - call + call, )); System::assert_has_event( @@ -559,7 +559,7 @@ fn dispatch_as_signed_works() { assert_ok!(OmniAccount::dispatch_as_omni_account( RuntimeOrigin::signed(tee_signer.clone()), alice().identity.hash(), - call + call, )); let call = make_balance_transfer_call(bob().native_account, 5); @@ -576,3 +576,27 @@ fn dispatch_as_signed_works() { assert_eq!(Balances::free_balance(bob().native_account), 5); }); } + +#[test] +fn dispatch_as_omni_account_increments_omni_account_nonce() { + new_test_ext().execute_with(|| { + let tee_signer = get_tee_signer(); + + let bob = private_member_account(bob()); + + assert_ok!(OmniAccount::create_account_store( + RuntimeOrigin::signed(tee_signer.clone()), + alice().identity, + )); + + assert_eq!(System::account_nonce(alice().omni_account), 0); + + let call = add_account_call(bob.clone()); + assert_ok!(OmniAccount::dispatch_as_omni_account( + RuntimeOrigin::signed(tee_signer.clone()), + alice().identity.hash(), + call, + )); + assert_eq!(System::account_nonce(alice().omni_account), 1); + }); +} diff --git a/tee-worker/Cargo.lock b/tee-worker/Cargo.lock index 99096e111c..fe5f008fd2 100644 --- a/tee-worker/Cargo.lock +++ b/tee-worker/Cargo.lock @@ -250,7 +250,7 @@ checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -1041,9 +1041,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "bitvec" @@ -2496,7 +2496,7 @@ dependencies = [ "proc-macro-warning", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -2508,7 +2508,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -2518,7 +2518,7 @@ source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -2688,7 +2688,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5197,6 +5197,7 @@ dependencies = [ "id-ita-stf", "id-itp-stf-executor", "id-itp-top-pool-author", + "itp-api-client-types", "itp-enclave-metrics", "itp-extrinsics-factory", "itp-node-api", @@ -5208,7 +5209,10 @@ dependencies = [ "itp-types", "lc-data-providers", "lc-dynamic-assertion", + "lc-identity-verification", "lc-native-task-sender", + "lc-omni-account", + "litentry-hex-utils", "litentry-macros", "litentry-primitives", "log 0.4.20", @@ -5613,7 +5617,7 @@ dependencies = [ "cargo_toml", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -6478,7 +6482,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -6887,7 +6891,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -6918,7 +6922,7 @@ checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -7074,7 +7078,7 @@ checksum = "0e99670bafb56b9a106419397343bdbc8b8742c3cc449fec6345f86173f47cd4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -7352,7 +7356,7 @@ checksum = "2dfaf0c85b766276c797f3791f5bc6d5bd116b41d53049af2789666b0c0bc9fa" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -7640,7 +7644,7 @@ version = "0.38.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys 0.4.3", @@ -8145,7 +8149,7 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -8587,7 +8591,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -8713,7 +8717,7 @@ dependencies = [ "proc-macro2", "quote", "sp-core-hashing", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -8723,7 +8727,7 @@ source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -8885,7 +8889,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -9014,7 +9018,7 @@ dependencies = [ "parity-scale-codec", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -9155,7 +9159,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -9239,9 +9243,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" dependencies = [ "proc-macro2", "quote", @@ -9351,7 +9355,7 @@ checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -9463,7 +9467,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -9620,7 +9624,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -10089,7 +10093,7 @@ dependencies = [ "once_cell 1.19.0", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", "wasm-bindgen-shared", ] @@ -10123,7 +10127,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -10704,5 +10708,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] diff --git a/tee-worker/Cargo.toml b/tee-worker/Cargo.toml index 19de9160a1..963d8c1e09 100644 --- a/tee-worker/Cargo.toml +++ b/tee-worker/Cargo.toml @@ -301,7 +301,7 @@ lc-stf-task-sender = { path = "identity/litentry/core/stf-task/sender", default- lc-stf-task-receiver = { path = "identity/litentry/core/stf-task/receiver", default-features = false } lc-vc-task-sender = { path = "identity/litentry/core/vc-task/sender", default-features = false } lc-vc-task-receiver = { path = "identity/litentry/core/vc-task/receiver", default-features = false } -lc-omni-account = { path = "identity/app-libs/omni-account", default-features = false } +lc-omni-account = { path = "identity/litentry/core/omni-account", default-features = false } lc-native-task-sender = { path = "identity/litentry/core/native-task/sender", default-features = false } lc-native-task-receiver = { path = "identity/litentry/core/native-task/receiver", default-features = false } diff --git a/tee-worker/common/core-primitives/node-api/api-client-types/src/lib.rs b/tee-worker/common/core-primitives/node-api/api-client-types/src/lib.rs index b82b0c376b..9a9c4cebc5 100644 --- a/tee-worker/common/core-primitives/node-api/api-client-types/src/lib.rs +++ b/tee-worker/common/core-primitives/node-api/api-client-types/src/lib.rs @@ -26,6 +26,7 @@ pub use itp_types::parentchain::{ AccountData, AccountId, AccountInfo, Address, Balance, Hash, Index, Signature as PairSignature, }; pub use substrate_api_client::{ + ac_compose_macros::{compose_call, compose_extrinsic_offline}, ac_node_api::{ metadata::{InvalidMetadataError, Metadata, MetadataError}, EventDetails, Events, StaticEvent, diff --git a/tee-worker/common/litentry/primitives/src/lib.rs b/tee-worker/common/litentry/primitives/src/lib.rs index 07ea4cf198..78b394d5ba 100644 --- a/tee-worker/common/litentry/primitives/src/lib.rs +++ b/tee-worker/common/litentry/primitives/src/lib.rs @@ -71,6 +71,7 @@ pub use parentchain_primitives::{ }, decl_rsa_request, identity::*, + intent::*, omni_account::*, teebag::*, AccountId as ParentchainAccountId, Balance as ParentchainBalance, diff --git a/tee-worker/identity/app-libs/stf/src/trusted_call.rs b/tee-worker/identity/app-libs/stf/src/trusted_call.rs index a912525176..3b4a1763b0 100644 --- a/tee-worker/identity/app-libs/stf/src/trusted_call.rs +++ b/tee-worker/identity/app-libs/stf/src/trusted_call.rs @@ -53,8 +53,8 @@ use itp_utils::stringify::account_id_to_string; use litentry_hex_utils::hex_encode; pub use litentry_primitives::{ aes_encrypt_default, all_evm_web3networks, all_substrate_web3networks, AesOutput, Assertion, - ErrorDetail, IMPError, Identity, LitentryMultiSignature, ParentchainBlockNumber, RequestAesKey, - VCMPError, ValidationData, Web3Network, + ErrorDetail, IMPError, Identity, Intent, LitentryMultiSignature, ParentchainBlockNumber, + RequestAesKey, VCMPError, ValidationData, Web3Network, }; use log::*; use sp_core::{ @@ -139,6 +139,8 @@ pub enum TrustedCall { #[cfg(feature = "development")] #[codec(index = 25)] clean_id_graphs(Identity), + #[codec(index = 26)] + request_intent(Identity, Intent), // original integritee trusted calls, starting from index 50 #[codec(index = 50)] @@ -229,6 +231,7 @@ impl TrustedCall { Self::request_batch_vc(sender_identity, ..) => sender_identity, #[cfg(feature = "development")] Self::clean_id_graphs(sender_identity) => sender_identity, + Self::request_intent(sender_identity, ..) => sender_identity, } } @@ -242,6 +245,7 @@ impl TrustedCall { Self::deactivate_identity(..) => "deactivate_identity", Self::activate_identity(..) => "activate_identity", Self::maybe_create_id_graph(..) => "maybe_create_id_graph", + Self::request_intent(..) => "request_intent", _ => "unsupported_trusted_call", } } @@ -896,6 +900,10 @@ where Ok(TrustedCallResult::Empty) }, + TrustedCall::request_intent(..) => { + error!("please use author_submitNativeRequest instead"); + Ok(TrustedCallResult::Empty) + }, } } diff --git a/tee-worker/identity/enclave-runtime/Cargo.lock b/tee-worker/identity/enclave-runtime/Cargo.lock index 960d4cb82a..0a028e44d7 100644 --- a/tee-worker/identity/enclave-runtime/Cargo.lock +++ b/tee-worker/identity/enclave-runtime/Cargo.lock @@ -192,7 +192,7 @@ checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote 1.0.36", - "syn 2.0.72", + "syn 2.0.82", ] [[package]] @@ -562,7 +562,7 @@ version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ - "num-traits 0.2.16", + "num-traits 0.2.19", "serde 1.0.204", ] @@ -953,6 +953,7 @@ dependencies = [ "lc-evm-dynamic-assertions", "lc-identity-verification", "lc-native-task-receiver", + "lc-omni-account", "lc-parachain-extrinsic-task-receiver", "lc-parachain-extrinsic-task-sender", "lc-stf-task-receiver", @@ -1235,7 +1236,7 @@ checksum = "36530797b9bf31cd4ff126dcfee8170f86b00cfdcea3269d73133cc0415945c3" dependencies = [ "either", "futures 0.3.28", - "num-traits 0.2.16", + "num-traits 0.2.19", "parity-scale-codec", "scale-info", ] @@ -1380,7 +1381,7 @@ dependencies = [ "proc-macro-warning", "proc-macro2", "quote 1.0.36", - "syn 2.0.72", + "syn 2.0.82", ] [[package]] @@ -1392,7 +1393,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote 1.0.36", - "syn 2.0.72", + "syn 2.0.82", ] [[package]] @@ -1402,7 +1403,7 @@ source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff dependencies = [ "proc-macro2", "quote 1.0.36", - "syn 2.0.72", + "syn 2.0.82", ] [[package]] @@ -2168,7 +2169,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "276ec31bcb4a9ee45f58bec6f9ec700ae4cf4f4f8f2fa7e06cb406bd5ffdd770" dependencies = [ - "num-traits 0.2.16", + "num-traits 0.2.19", ] [[package]] @@ -3121,6 +3122,7 @@ dependencies = [ "id-ita-stf", "id-itp-stf-executor", "id-itp-top-pool-author", + "itp-api-client-types", "itp-enclave-metrics", "itp-extrinsics-factory", "itp-node-api", @@ -3132,7 +3134,10 @@ dependencies = [ "itp-types", "lc-data-providers", "lc-dynamic-assertion", + "lc-identity-verification", "lc-native-task-sender", + "lc-omni-account", + "litentry-hex-utils", "litentry-macros", "litentry-primitives", "log", @@ -3151,6 +3156,21 @@ dependencies = [ "sgx_tstd", ] +[[package]] +name = "lc-omni-account" +version = "0.1.0" +dependencies = [ + "frame-support", + "itp-ocall-api", + "itp-storage", + "itp-types", + "lazy_static", + "litentry-primitives", + "log", + "sgx_tstd", + "sp-core", +] + [[package]] name = "lc-parachain-extrinsic-task-receiver" version = "0.1.0" @@ -3387,7 +3407,7 @@ dependencies = [ "cargo_toml", "proc-macro2", "quote 1.0.36", - "syn 2.0.72", + "syn 2.0.82", ] [[package]] @@ -3631,9 +3651,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg 1.1.0", ] @@ -3957,7 +3977,7 @@ checksum = "0e99670bafb56b9a106419397343bdbc8b8742c3cc449fec6345f86173f47cd4" dependencies = [ "proc-macro2", "quote 1.0.36", - "syn 2.0.72", + "syn 2.0.82", ] [[package]] @@ -4104,7 +4124,7 @@ checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" dependencies = [ "proc-macro2", "quote 1.0.36", - "syn 2.0.72", + "syn 2.0.82", ] [[package]] @@ -4264,7 +4284,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1790d1c4c0ca81211399e0e0af16333276f375209e71a37b67698a373db5b47a" dependencies = [ "arrayvec 0.7.4", - "num-traits 0.2.16", + "num-traits 0.2.19", ] [[package]] @@ -4577,7 +4597,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote 1.0.36", - "syn 2.0.72", + "syn 2.0.82", ] [[package]] @@ -4949,7 +4969,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote 1.0.36", - "syn 2.0.72", + "syn 2.0.82", ] [[package]] @@ -4970,7 +4990,7 @@ version = "6.0.0" source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "integer-sqrt", - "num-traits 0.2.16", + "num-traits 0.2.19", "parity-scale-codec", "scale-info", "sp-std", @@ -5057,7 +5077,7 @@ dependencies = [ "proc-macro2", "quote 1.0.36", "sp-core-hashing", - "syn 2.0.72", + "syn 2.0.82", ] [[package]] @@ -5067,7 +5087,7 @@ source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff dependencies = [ "proc-macro2", "quote 1.0.36", - "syn 2.0.72", + "syn 2.0.82", ] [[package]] @@ -5163,7 +5183,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote 1.0.36", - "syn 2.0.72", + "syn 2.0.82", ] [[package]] @@ -5252,7 +5272,7 @@ dependencies = [ "parity-scale-codec", "proc-macro2", "quote 1.0.36", - "syn 2.0.72", + "syn 2.0.82", ] [[package]] @@ -5346,7 +5366,7 @@ dependencies = [ "proc-macro2", "quote 1.0.36", "rustversion", - "syn 2.0.72", + "syn 2.0.82", ] [[package]] @@ -5401,9 +5421,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.72" +version = "2.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" dependencies = [ "proc-macro2", "quote 1.0.36", @@ -5851,7 +5871,7 @@ checksum = "941f7fd7c114e1e0c401bbbe8222e8adbb4bc8ebeb782f7812d8f1678a578934" dependencies = [ "log", "num-derive", - "num-traits 0.2.16", + "num-traits 0.2.19", "xous", "xous-ipc", ] @@ -5864,7 +5884,7 @@ checksum = "471502d9379d198738ec55dec7cd688ce21e1cfe7d93af6dad25e38c1c404d1c" dependencies = [ "log", "num-derive", - "num-traits 0.2.16", + "num-traits 0.2.19", "rkyv", "xous", "xous-api-log", @@ -5910,5 +5930,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote 1.0.36", - "syn 2.0.72", + "syn 2.0.82", ] diff --git a/tee-worker/identity/enclave-runtime/Cargo.toml b/tee-worker/identity/enclave-runtime/Cargo.toml index 94fb3534b4..e353980dd4 100644 --- a/tee-worker/identity/enclave-runtime/Cargo.toml +++ b/tee-worker/identity/enclave-runtime/Cargo.toml @@ -148,6 +148,7 @@ lc-data-providers = { path = "../litentry/core/data-providers", default-features lc-evm-dynamic-assertions = { path = "../litentry/core/evm-dynamic-assertions", default-features = false, features = ["sgx"] } lc-identity-verification = { path = "../litentry/core/identity-verification", default-features = false, features = ["sgx"] } lc-native-task-receiver = { path = "../litentry/core/native-task/receiver", default-features = false, features = ["sgx"] } +lc-omni-account = { path = "../litentry/core/omni-account", default-features = false, features = ["sgx"] } lc-parachain-extrinsic-task-receiver = { path = "../../common/litentry/core/parachain-extrinsic-task/receiver", default-features = false, features = ["sgx"] } lc-parachain-extrinsic-task-sender = { path = "../../common/litentry/core/parachain-extrinsic-task/sender", default-features = false, features = ["sgx"] } lc-stf-task-receiver = { path = "../litentry/core/stf-task/receiver", default-features = false, features = ["sgx"] } diff --git a/tee-worker/identity/enclave-runtime/src/rpc/common_api.rs b/tee-worker/identity/enclave-runtime/src/rpc/common_api.rs index 48c85a11dc..325e5d2505 100644 --- a/tee-worker/identity/enclave-runtime/src/rpc/common_api.rs +++ b/tee-worker/identity/enclave-runtime/src/rpc/common_api.rs @@ -24,12 +24,19 @@ use itp_sgx_externalities::SgxExternalitiesTrait; use itp_stf_executor::getter_executor::ExecuteGetter; use itp_stf_state_handler::handle_state::HandleState; use itp_top_pool_author::traits::AuthorApi; -use itp_types::{DirectRequestStatus, Index, RsaRequest, ShardIdentifier, H256}; +use itp_types::{ + parentchain::AccountId, DirectRequestStatus, Index, RsaRequest, ShardIdentifier, H256, +}; use itp_utils::{FromHexPrefixed, ToHexPrefixed}; use its_rpc_handler::direct_top_pool_api::add_top_pool_direct_rpc_methods; use jsonrpc_core::{serde_json::json, IoHandler, Params, Value}; use lc_data_providers::DataProviderConfig; -use lc_identity_verification::web2::{email, twitter}; +use lc_identity_verification::{ + generate_verification_code, + web2::{email, twitter}, + VerificationCodeStore, +}; +use lc_omni_account::InMemoryStore as OmniAccountStore; use litentry_macros::{if_development, if_development_or}; use litentry_primitives::{aes_decrypt, AesRequest, DecryptableRequest, Identity}; use log::debug; @@ -424,8 +431,8 @@ pub fn add_common_api() { - Ok((encoded_did, redirect_url)) => { - let account_id = match Identity::from_did(encoded_did.as_str()) { + Ok((did, redirect_url)) => { + let account_id = match Identity::from_did(did.as_str()) { Ok(identity) => if let Some(account_id) = identity.to_native_account() { account_id @@ -460,10 +467,12 @@ pub fn add_common_api() { - Ok((encoded_did, email)) => { - let account_id = match Identity::from_did(encoded_did.as_str()) { + Ok((did, email)) => { + let account_id = match Identity::from_did(did.as_str()) { Ok(identity) => if let Some(account_id) = identity.to_native_account() { account_id @@ -475,15 +484,65 @@ pub fn add_common_api { + if email::send_verification_email(&mut mailer, email, verification_code) + .is_err() + { + return Ok(json!(compute_hex_encoded_return_error( + "Could not send verification email" + ))) + } + let json_value = + RpcReturnValue::new(vec![], false, DirectRequestStatus::Ok); + Ok(json!(json_value.to_hex())) + }, + Err(_) => Ok(json!(compute_hex_encoded_return_error( + "Could not save verification code" + ))), + } + }, + Err(_) => Ok(json!(compute_hex_encoded_return_error("Could not parse params"))), + } + }); + + io_handler.add_sync_method("omni_requestEmailVerificationCode", move |params: Params| { + match params.parse::<(String, String)>() { + Ok((encoded_omni_account, email)) => { + let omni_account = match AccountId::from_hex(encoded_omni_account.as_str()) { + Ok(account_id) => account_id, + Err(_) => + return Ok(json!(compute_hex_encoded_return_error( + "Could not parse omni account" + ))), + }; + match OmniAccountStore::get_member_accounts(&omni_account) { + Ok(Some(_member_accounts)) => {}, + _ => + return Ok(json!(compute_hex_encoded_return_error("Omni account not found"))), + } let mut mailer = email::sendgrid_mailer::SendGridMailer::new( data_provider_config.sendgrid_api_key.clone(), data_provider_config.sendgrid_from_email.clone(), ); - let verification_code = email::generate_verification_code(); + let verification_code = generate_verification_code(); + let email_identity = Identity::from_email(&email); - match email::VerificationCodeStore::insert( - account_id, - email.clone(), + match VerificationCodeStore::insert( + omni_account, + email_identity.hash(), verification_code.clone(), ) { Ok(_) => { diff --git a/tee-worker/identity/litentry/core/identity-verification/src/web2/helpers.rs b/tee-worker/identity/litentry/core/identity-verification/src/helpers.rs similarity index 100% rename from tee-worker/identity/litentry/core/identity-verification/src/web2/helpers.rs rename to tee-worker/identity/litentry/core/identity-verification/src/helpers.rs diff --git a/tee-worker/identity/litentry/core/identity-verification/src/lib.rs b/tee-worker/identity/litentry/core/identity-verification/src/lib.rs index 763dd6b8aa..052c68b067 100644 --- a/tee-worker/identity/litentry/core/identity-verification/src/lib.rs +++ b/tee-worker/identity/litentry/core/identity-verification/src/lib.rs @@ -33,15 +33,22 @@ pub mod sgx_reexport_prelude { #[cfg(all(feature = "std", feature = "sgx"))] compile_error!("feature \"std\" and feature \"sgx\" cannot be enabled at the same time"); -use frame_support::pallet_prelude::*; -use litentry_primitives::Web2IdentityVerificationRequest; - +mod error; +mod helpers; +mod verification_code_store; pub mod web2; +pub use verification_code_store::VerificationCodeStore; -mod error; +use alloc::string::String; use error::{Error, Result}; +use frame_support::pallet_prelude::*; use lc_data_providers::DataProviderConfig; +use litentry_primitives::Web2IdentityVerificationRequest; pub fn verify(r: &Web2IdentityVerificationRequest, config: &DataProviderConfig) -> Result<()> { web2::verify(&r.who, &r.identity, &r.raw_msg, &r.validation_data, config) } + +pub fn generate_verification_code() -> String { + helpers::get_random_string(32) +} diff --git a/tee-worker/identity/litentry/core/identity-verification/src/web2/email/verification_code_store.rs b/tee-worker/identity/litentry/core/identity-verification/src/verification_code_store.rs similarity index 84% rename from tee-worker/identity/litentry/core/identity-verification/src/web2/email/verification_code_store.rs rename to tee-worker/identity/litentry/core/identity-verification/src/verification_code_store.rs index d20c865eb9..86222b6158 100644 --- a/tee-worker/identity/litentry/core/identity-verification/src/web2/email/verification_code_store.rs +++ b/tee-worker/identity/litentry/core/identity-verification/src/verification_code_store.rs @@ -6,6 +6,7 @@ use litentry_primitives::{ ErrorDetail, ErrorString, IntoErrorDetail, ParentchainAccountId as AccountId, }; use lru::LruCache; +use sp_core::H256; use std::num::NonZeroUsize; #[cfg(feature = "std")] use std::sync::RwLock; @@ -37,7 +38,7 @@ impl IntoErrorDetail for VerificationCodeStoreError { lazy_static! { static ref STORE: RwLock> = - RwLock::new(LruCache::new(NonZeroUsize::new(250).unwrap())); + RwLock::new(LruCache::new(NonZeroUsize::new(500).unwrap())); } pub struct VerificationCodeStore; @@ -45,24 +46,24 @@ pub struct VerificationCodeStore; impl VerificationCodeStore { pub fn insert( account_id: AccountId, - email: String, + identity_hash: H256, verification_code: String, ) -> Result<(), VerificationCodeStoreError> { STORE .write() .map_err(|_| VerificationCodeStoreError::LockPoisoning)? - .put(hex::encode((account_id, email).encode()), verification_code); + .put(hex::encode((account_id, identity_hash).encode()), verification_code); Ok(()) } pub fn get( account_id: &AccountId, - email: &str, + identity_hash: H256, ) -> Result, VerificationCodeStoreError> { let code = STORE .write() .map_err(|_| VerificationCodeStoreError::LockPoisoning)? - .pop(hex::encode((account_id, email).encode()).as_str()); + .pop(hex::encode((account_id, identity_hash).encode()).as_str()); Ok(code) } } diff --git a/tee-worker/identity/litentry/core/identity-verification/src/web2/email/mod.rs b/tee-worker/identity/litentry/core/identity-verification/src/web2/email/mod.rs index 51c58c1e5a..cb63aa851b 100644 --- a/tee-worker/identity/litentry/core/identity-verification/src/web2/email/mod.rs +++ b/tee-worker/identity/litentry/core/identity-verification/src/web2/email/mod.rs @@ -1,14 +1,7 @@ -mod verification_code_store; -pub use verification_code_store::*; - mod mailer; pub use mailer::*; -use crate::{alloc::string::String, web2::helpers}; - -pub fn generate_verification_code() -> String { - helpers::get_random_string(32) -} +use crate::alloc::string::String; pub fn send_verification_email( mailer: &mut impl Mailer, diff --git a/tee-worker/identity/litentry/core/identity-verification/src/web2/mod.rs b/tee-worker/identity/litentry/core/identity-verification/src/web2/mod.rs index 1bac3a62b5..77cd18ca38 100644 --- a/tee-worker/identity/litentry/core/identity-verification/src/web2/mod.rs +++ b/tee-worker/identity/litentry/core/identity-verification/src/web2/mod.rs @@ -22,10 +22,9 @@ compile_error!("feature \"std\" and feature \"sgx\" cannot be enabled at the sam mod discord; pub mod email; -mod helpers; pub mod twitter; -use crate::{ensure, Error, Result}; +use crate::{ensure, Error, Result, VerificationCodeStore}; use itp_sgx_crypto::ShieldingCryptoDecrypt; use itp_utils::stringify::account_id_to_string; use lc_data_providers::{ @@ -210,8 +209,9 @@ pub fn verify( let Some(account_id) = who.to_native_account() else { return Err(Error::LinkIdentityFailed(ErrorDetail::ParseError)); }; + let email_identity = Identity::from_email(&email); let stored_verification_code = - match email::VerificationCodeStore::get(&account_id, &email) { + match VerificationCodeStore::get(&account_id, email_identity.hash()) { Ok(data) => data.ok_or_else(|| { Error::LinkIdentityFailed(ErrorDetail::StfError( ErrorString::truncate_from( diff --git a/tee-worker/identity/litentry/core/identity-verification/src/web2/twitter/mod.rs b/tee-worker/identity/litentry/core/identity-verification/src/web2/twitter/mod.rs index df620133b3..508324ae53 100644 --- a/tee-worker/identity/litentry/core/identity-verification/src/web2/twitter/mod.rs +++ b/tee-worker/identity/litentry/core/identity-verification/src/web2/twitter/mod.rs @@ -3,8 +3,7 @@ pub use oauth_store::*; use crate::{ alloc::{format, string::String, vec::Vec}, - web2::helpers, - Error, Result, + helpers, Error, Result, }; use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine}; use lc_data_providers::twitter_official::Tweet; diff --git a/tee-worker/identity/litentry/core/native-task/receiver/Cargo.toml b/tee-worker/identity/litentry/core/native-task/receiver/Cargo.toml index 79d6a14414..2d8e34b41b 100644 --- a/tee-worker/identity/litentry/core/native-task/receiver/Cargo.toml +++ b/tee-worker/identity/litentry/core/native-task/receiver/Cargo.toml @@ -15,6 +15,7 @@ sp-core = { workspace = true, features = ["full_crypto"] } ita-sgx-runtime = { package = "id-ita-sgx-runtime", path = "../../../../app-libs/sgx-runtime", default-features = false } ita-stf = { package = "id-ita-stf", path = "../../../../app-libs/stf", default-features = false } +itp-api-client-types = { workspace = true } itp-enclave-metrics = { workspace = true } itp-extrinsics-factory = { workspace = true } itp-node-api = { workspace = true } @@ -30,7 +31,10 @@ itp-types = { workspace = true } frame-support = { workspace = true } lc-data-providers = { workspace = true } lc-dynamic-assertion = { workspace = true } +lc-identity-verification = { workspace = true } lc-native-task-sender = { workspace = true } +lc-omni-account = { workspace = true } +litentry-hex-utils = { workspace = true } litentry-macros = { workspace = true } litentry-primitives = { workspace = true } @@ -46,6 +50,8 @@ sgx = [ "itp-node-api/sgx", "itp-extrinsics-factory/sgx", "lc-native-task-sender/sgx", + "lc-identity-verification/sgx", + "lc-omni-account/sgx", ] std = [ "futures", @@ -61,6 +67,9 @@ std = [ "frame-support/std", "itp-node-api/std", "lc-native-task-sender/std", + "lc-identity-verification/std", + "lc-omni-account/std", + "itp-api-client-types/std", ] development = [ "litentry-macros/development", diff --git a/tee-worker/identity/litentry/core/native-task/receiver/src/lib.rs b/tee-worker/identity/litentry/core/native-task/receiver/src/lib.rs index b444a52187..14dd419862 100644 --- a/tee-worker/identity/litentry/core/native-task/receiver/src/lib.rs +++ b/tee-worker/identity/litentry/core/native-task/receiver/src/lib.rs @@ -22,6 +22,8 @@ compile_error!("feature \"std\" and feature \"sgx\" cannot be enabled at the sam #[cfg(all(not(feature = "std"), feature = "sgx"))] extern crate sgx_tstd as std; +extern crate alloc; + // re-export module to properly feature gate sgx and regular std environment #[cfg(all(not(feature = "std"), feature = "sgx"))] pub mod sgx_reexport_prelude { @@ -31,6 +33,9 @@ pub mod sgx_reexport_prelude { #[cfg(all(not(feature = "std"), feature = "sgx"))] pub use crate::sgx_reexport_prelude::*; +mod trusted_call_authenticated; +pub use trusted_call_authenticated::*; + mod types; pub use types::NativeTaskContext; use types::*; @@ -39,19 +44,23 @@ use codec::{Decode, Encode}; use futures::executor::ThreadPoolBuilder; use ita_sgx_runtime::Hash; use ita_stf::{Getter, TrustedCall, TrustedCallSigned}; +use itp_api_client_types::compose_call; use itp_extrinsics_factory::CreateExtrinsics; -use itp_node_api::metadata::{provider::AccessNodeMetadata, NodeMetadataTrait}; +use itp_node_api::metadata::{provider::AccessNodeMetadata, NodeMetadata}; use itp_ocall_api::{EnclaveAttestationOCallApi, EnclaveMetricsOCallApi, EnclaveOnChainOCallApi}; use itp_sgx_crypto::{key_repository::AccessKey, ShieldingCryptoDecrypt, ShieldingCryptoEncrypt}; use itp_stf_executor::traits::StfEnclaveSigning as StfEnclaveSigningTrait; -use itp_stf_primitives::{traits::TrustedCallVerification, types::TrustedOperation}; +use itp_stf_primitives::types::TrustedOperation; use itp_top_pool_author::traits::AuthorApi as AuthorApiTrait; +use itp_types::{parentchain::ParentchainId, OpaqueCall}; use lc_native_task_sender::init_native_task_sender; -use litentry_primitives::{AesRequest, DecryptableRequest}; +use litentry_primitives::{AesRequest, DecryptableRequest, Intent}; use sp_core::{blake2_256, H256}; use std::{ + borrow::ToOwned, boxed::Box, format, + string::ToString, sync::{ mpsc::{channel, Sender}, Arc, @@ -88,8 +97,7 @@ pub fn run_native_task_receiver< OCallApi: EnclaveOnChainOCallApi + EnclaveMetricsOCallApi + EnclaveAttestationOCallApi + 'static, ExtrinsicFactory: CreateExtrinsics + Send + Sync + 'static, - NodeMetadataRepo: AccessNodeMetadata + Send + Sync + 'static, - NodeMetadataRepo::MetadataType: NodeMetadataTrait, + NodeMetadataRepo: AccessNodeMetadata + Send + Sync + 'static, { let request_receiver = init_native_task_sender(); let thread_pool = ThreadPoolBuilder::new() @@ -117,15 +125,17 @@ pub fn run_native_task_receiver< thread_pool.spawn_ok(async move { let request = &mut req.request; let connection_hash = request.using_encoded(|x| H256::from(blake2_256(x))); - match get_trusted_call_from_request(request, context_pool.clone()) { - Ok(call) => process_trusted_call( + match handle_request(request, context_pool.clone()) { + Ok(trusted_call) => handle_trusted_call( context_pool.clone(), - call, + trusted_call, connection_hash, task_sender_pool, ), Err(e) => { log::error!("Failed to get trusted call from request: {:?}", e); + let res: Result<(), NativeTaskError> = Err(NativeTaskError::InvalidRequest); + context_pool.author_api.send_rpc_response(connection_hash, res.encode(), false); }, }; }); @@ -133,7 +143,7 @@ pub fn run_native_task_receiver< log::warn!("Native task receiver stopped"); } -fn process_trusted_call< +fn handle_trusted_call< ShieldingKeyRepository, AuthorApi, StfEnclaveSigning, @@ -162,22 +172,88 @@ fn process_trusted_call< OCallApi: EnclaveOnChainOCallApi + EnclaveMetricsOCallApi + EnclaveAttestationOCallApi + 'static, ExtrinsicFactory: CreateExtrinsics + Send + Sync + 'static, - NodeMetadataRepo: AccessNodeMetadata + Send + Sync + 'static, - NodeMetadataRepo::MetadataType: NodeMetadataTrait, + NodeMetadataRepo: AccessNodeMetadata + Send + Sync + 'static, { - match call { - // TODO: handle AccountStore related calls - TrustedCall::noop(_) => log::info!("Received noop call"), + let metadata = match context.node_metadata_repo.get_from_metadata(|m| m.get_metadata().cloned()) + { + Ok(Some(metadata)) => metadata, + _ => { + log::error!("Failed to get node metadata"); + let res: Result<(), NativeTaskError> = Err(NativeTaskError::MetadataRetrievalFailed( + "Failed to get node metadata".to_string(), + )); + context.author_api.send_rpc_response(connection_hash, res.encode(), false); + return + }, + }; + + let (who, intent_call) = match call { + TrustedCall::request_intent(who, intent) => match intent { + Intent::SystemRemark(remark) => + (who, OpaqueCall::from_tuple(&compose_call!(&metadata, "System", "remark", remark))), + Intent::TransferNative(transfer) => ( + who, + OpaqueCall::from_tuple(&compose_call!( + &metadata, + "Balances", + "transfer_allow_death", + transfer.to, + transfer.value + )), + ), + Intent::CallEthereum(_) | Intent::TransferEthereum(_) => ( + who, + OpaqueCall::from_tuple(&compose_call!( + &metadata, + "OmniAccount", + "request_intent", + intent + )), + ), + }, _ => { log::warn!("Received unsupported call: {:?}", call); let res: Result<(), NativeTaskError> = Err(NativeTaskError::UnexpectedCall(format!("Unexpected call: {:?}", call))); context.author_api.send_rpc_response(connection_hash, res.encode(), false); + return + }, + }; + + let omni_account_call = OpaqueCall::from_tuple(&compose_call!( + &metadata, + "OmniAccount", + "dispatch_as_omni_account", + who.hash(), + intent_call + )); + + let extrinsic = match context.extrinsic_factory.create_extrinsics(&[omni_account_call], None) { + Ok(extrinsic) => extrinsic, + Err(e) => { + log::error!("Failed to create extrinsic: {:?}", e); + let res: Result<(), NativeTaskError> = + Err(NativeTaskError::ExtrinsicConstructionFailed(e.to_string())); + context.author_api.send_rpc_response(connection_hash, res.encode(), false); + return + }, + }; + + match context.ocall_api.send_to_parentchain(extrinsic, &ParentchainId::Litentry, true) { + Ok(_) => { + let res: Result<(), NativeTaskError> = Ok(()); + context.author_api.send_rpc_response(connection_hash, res.encode(), true); + }, + Err(e) => { + log::error!("Failed to send extrinsic to parentchain: {:?}", e); + let res: Result<(), NativeTaskError> = + Err(NativeTaskError::ExtrinsicSendingFailed(e.to_string())); + context.author_api.send_rpc_response(connection_hash, res.encode(), false); }, } } -fn get_trusted_call_from_request< +fn handle_request< ShieldingKeyRepository, AuthorApi, StfEnclaveSigning, @@ -205,8 +281,7 @@ where OCallApi: EnclaveOnChainOCallApi + EnclaveMetricsOCallApi + EnclaveAttestationOCallApi + 'static, ExtrinsicFactory: CreateExtrinsics + Send + Sync + 'static, - NodeMetadataRepo: AccessNodeMetadata + Send + Sync + 'static, - NodeMetadataRepo::MetadataType: NodeMetadataTrait, + NodeMetadataRepo: AccessNodeMetadata + Send + Sync + 'static, { let connection_hash = request.using_encoded(|x| H256::from(blake2_256(x))); let enclave_shielding_key = match context.shielding_key.retrieve_key() { @@ -218,13 +293,15 @@ where return Err("Shielding key retrieval failed") }, }; - let tcs: TrustedCallSigned = match request + let tca: TrustedCallAuthenticated = match request .decrypt(Box::new(enclave_shielding_key)) .ok() - .and_then(|v| TrustedOperation::::decode(&mut v.as_slice()).ok()) + .and_then(|v| { + TrustedOperation::::decode(&mut v.as_slice()).ok() + }) .and_then(|top| top.to_call().cloned()) { - Some(tcs) => tcs, + Some(tca) => tca, None => { let res: Result<(), NativeTaskError> = Err(NativeTaskError::RequestPayloadDecodingFailed); @@ -240,11 +317,25 @@ where return Err("MrEnclave retrieval failed") }, }; - if !tcs.verify_signature(&mrenclave, &request.shard) { - let res: Result<(), NativeTaskError> = Err(NativeTaskError::SignatureVerificationFailed); + + let authentication_valid = match tca.authentication { + TCAuthentication::Web3(signature) => verify_tca_web3_authentication( + &signature, + &tca.call, + tca.nonce, + &mrenclave, + &request.shard, + ), + TCAuthentication::Email(verification_code) => + verify_tca_email_authentication(&tca.call, verification_code), + }; + + if !authentication_valid { + let res: Result<(), NativeTaskError> = + Err(NativeTaskError::AuthenticationVerificationFailed); context.author_api.send_rpc_response(connection_hash, res.encode(), false); - return Err("Signature verification failed") + return Err("Authentication verification failed") } - Ok(tcs.call) + Ok(tca.call) } diff --git a/tee-worker/identity/litentry/core/native-task/receiver/src/trusted_call_authenticated.rs b/tee-worker/identity/litentry/core/native-task/receiver/src/trusted_call_authenticated.rs new file mode 100644 index 0000000000..eda8bc3775 --- /dev/null +++ b/tee-worker/identity/litentry/core/native-task/receiver/src/trusted_call_authenticated.rs @@ -0,0 +1,124 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use alloc::string::String; +use codec::{Decode, Encode}; +use ita_stf::{LitentryMultiSignature, TrustedCall}; +use itp_stf_primitives::traits::TrustedCallVerification; +use itp_types::parentchain::Index as ParentchainIndex; +use lc_identity_verification::VerificationCodeStore; +use lc_omni_account::InMemoryStore as OmniAccountStore; +use litentry_hex_utils::hex_encode; +use litentry_primitives::{Identity, ShardIdentifier}; +use sp_core::{ + blake2_256, + crypto::{AccountId32, UncheckedFrom}, + ed25519, +}; + +type VerificationCode = String; + +#[derive(Encode, Decode, Clone, Debug, PartialEq, Eq)] +pub enum TCAuthentication { + Web3(LitentryMultiSignature), + Email(VerificationCode), +} + +#[derive(Encode, Decode, Clone, Debug, PartialEq, Eq)] +pub struct TrustedCallAuthenticated { + pub call: TrustedCall, + pub nonce: ParentchainIndex, + pub authentication: TCAuthentication, +} + +impl TrustedCallAuthenticated { + pub fn new( + call: TrustedCall, + nonce: ParentchainIndex, + authentication: TCAuthentication, + ) -> Self { + Self { call, nonce, authentication } + } +} + +impl Default for TrustedCallAuthenticated { + fn default() -> Self { + Self { + call: TrustedCall::noop(AccountId32::unchecked_from([0u8; 32].into()).into()), + nonce: 0, + authentication: TCAuthentication::Web3(LitentryMultiSignature::Ed25519( + ed25519::Signature::unchecked_from([0u8; 64]), + )), + } + } +} + +// TODO: we should refactor this as verify_signature should not be part of TrustedCallAuthenticated +impl TrustedCallVerification for TrustedCallAuthenticated { + fn sender_identity(&self) -> &Identity { + self.call.sender_identity() + } + + fn nonce(&self) -> ita_stf::Index { + self.nonce + } + + fn verify_signature(&self, _mrenclave: &[u8; 32], _shard: &ShardIdentifier) -> bool { + log::error!("verify_signature shold not be used for TrustedCallAuthenticated"); + false + } + + fn metric_name(&self) -> &'static str { + self.call.metric_name() + } +} + +pub fn verify_tca_web3_authentication( + signature: &LitentryMultiSignature, + call: &TrustedCall, + nonce: ParentchainIndex, + mrenclave: &[u8; 32], + shard: &ShardIdentifier, +) -> bool { + let mut payload = call.encode(); + payload.append(&mut nonce.encode()); + payload.append(&mut mrenclave.encode()); + payload.append(&mut shard.encode()); + + // The signature should be valid in either case: + // 1. blake2_256(payload) + // 2. Signature Prefix + blake2_256(payload) + + let hashed = blake2_256(&payload); + + let prettified_msg_hash = call.signature_message_prefix() + &hex_encode(&hashed); + let prettified_msg_hash = prettified_msg_hash.as_bytes(); + + // Most common signatures variants by clients are verified first (4 and 2). + signature.verify(prettified_msg_hash, call.sender_identity()) + || signature.verify(&hashed, call.sender_identity()) +} + +pub fn verify_tca_email_authentication(call: &TrustedCall, verification_code: String) -> bool { + let identity_hash = call.sender_identity().hash(); + match OmniAccountStore::get_omni_account(identity_hash) { + Ok(Some(account_id)) => match VerificationCodeStore::get(&account_id, identity_hash) { + Ok(Some(code)) => code == verification_code, + _ => false, + }, + _ => false, + } +} diff --git a/tee-worker/identity/litentry/core/native-task/receiver/src/types.rs b/tee-worker/identity/litentry/core/native-task/receiver/src/types.rs index a4377a6700..cc15a1f670 100644 --- a/tee-worker/identity/litentry/core/native-task/receiver/src/types.rs +++ b/tee-worker/identity/litentry/core/native-task/receiver/src/types.rs @@ -1,8 +1,24 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + use codec::{Decode, Encode}; use ita_sgx_runtime::Hash; use ita_stf::{Getter, TrustedCallSigned}; use itp_extrinsics_factory::CreateExtrinsics; -use itp_node_api::metadata::{provider::AccessNodeMetadata, NodeMetadataTrait}; +use itp_node_api::metadata::{provider::AccessNodeMetadata, NodeMetadata}; use itp_ocall_api::{EnclaveAttestationOCallApi, EnclaveMetricsOCallApi, EnclaveOnChainOCallApi}; use itp_sgx_crypto::{key_repository::AccessKey, ShieldingCryptoDecrypt, ShieldingCryptoEncrypt}; use itp_stf_executor::traits::StfEnclaveSigning as StfEnclaveSigningTrait; @@ -26,8 +42,7 @@ pub struct NativeTaskContext< OCallApi: EnclaveOnChainOCallApi + EnclaveMetricsOCallApi + EnclaveAttestationOCallApi + 'static, ExtrinsicFactory: CreateExtrinsics + Send + Sync + 'static, - NodeMetadataRepo: AccessNodeMetadata + Send + Sync + 'static, - NodeMetadataRepo::MetadataType: NodeMetadataTrait, + NodeMetadataRepo: AccessNodeMetadata + Send + Sync + 'static, { pub shielding_key: Arc, pub author_api: Arc, @@ -62,8 +77,7 @@ impl< OCallApi: EnclaveOnChainOCallApi + EnclaveMetricsOCallApi + EnclaveAttestationOCallApi + 'static, ExtrinsicFactory: CreateExtrinsics + Send + Sync + 'static, - NodeMetadataRepo: AccessNodeMetadata + Send + Sync + 'static, - NodeMetadataRepo::MetadataType: NodeMetadataTrait, + NodeMetadataRepo: AccessNodeMetadata + Send + Sync + 'static, { #[allow(clippy::too_many_arguments)] pub fn new( @@ -100,7 +114,7 @@ pub enum NativeTaskError { MissingAesKey, MrEnclaveRetrievalFailed, EnclaveSignerRetrievalFailed, - SignatureVerificationFailed, + AuthenticationVerificationFailed, ConnectionHashNotFound(String), MetadataRetrievalFailed(String), // Stringified itp_node_api_metadata_provider::Error InvalidMetadata(String), // Stringified itp_node_api_metadata::Error @@ -108,6 +122,7 @@ pub enum NativeTaskError { CallSendingFailed(String), ExtrinsicConstructionFailed(String), // Stringified itp_extrinsics_factory::Error ExtrinsicSendingFailed(String), // Stringified sgx_status_t + InvalidRequest, } pub enum NativeRequest { diff --git a/tee-worker/identity/litentry/core/omni-account/src/in_memory_store.rs b/tee-worker/identity/litentry/core/omni-account/src/in_memory_store.rs index 30da7a4234..a8ec1e4e1f 100644 --- a/tee-worker/identity/litentry/core/omni-account/src/in_memory_store.rs +++ b/tee-worker/identity/litentry/core/omni-account/src/in_memory_store.rs @@ -16,6 +16,7 @@ use crate::{AccountId, BTreeMap, Error, MemberAccount, OmniAccounts, Vec}; use lazy_static::lazy_static; +use sp_core::H256; #[cfg(feature = "std")] use std::sync::RwLock; @@ -23,27 +24,51 @@ use std::sync::RwLock; use std::sync::SgxRwLock as RwLock; lazy_static! { - static ref STORE: RwLock = RwLock::new(BTreeMap::new()); + static ref ACCCOUNT_STORE: RwLock = RwLock::new(BTreeMap::new()); + static ref MEMBER_ACCOUNT_HASH: RwLock> = + RwLock::new(BTreeMap::new()); } pub struct InMemoryStore; impl InMemoryStore { - pub fn get(&self, owner: AccountId) -> Result>, Error> { - let omni_account_members = STORE + pub fn get_member_accounts( + account_id: &AccountId, + ) -> Result>, Error> { + let omni_account_members = ACCCOUNT_STORE .read() .map_err(|_| { log::error!("[InMemoryStore] Lock poisoning"); Error::LockPoisoning })? - .get(&owner) + .get(account_id) .cloned(); Ok(omni_account_members) } - pub fn insert(&self, account_id: AccountId, members: Vec) -> Result<(), Error> { - STORE + pub fn get_omni_account(member_account_hash: H256) -> Result, Error> { + let account_id = MEMBER_ACCOUNT_HASH + .read() + .map_err(|_| { + log::error!("[InMemoryStore] Lock poisoning"); + Error::LockPoisoning + })? + .get(&member_account_hash) + .cloned(); + + Ok(account_id) + } + + pub fn insert(account_id: AccountId, members: Vec) -> Result<(), Error> { + let mut member_account_hash = MEMBER_ACCOUNT_HASH.write().map_err(|_| { + log::error!("[InMemoryStore] Lock poisoning"); + Error::LockPoisoning + })?; + for member in &members { + member_account_hash.insert(member.hash(), account_id.clone()); + } + ACCCOUNT_STORE .write() .map_err(|_| { log::error!("[InMemoryStore] Lock poisoning"); @@ -54,8 +79,8 @@ impl InMemoryStore { Ok(()) } - pub fn remove(&self, account_id: AccountId) -> Result<(), Error> { - STORE + pub fn remove(account_id: AccountId) -> Result<(), Error> { + ACCCOUNT_STORE .write() .map_err(|_| { log::error!("[InMemoryStore] Lock poisoning"); @@ -66,8 +91,17 @@ impl InMemoryStore { Ok(()) } - pub fn load(&self, accounts: OmniAccounts) -> Result<(), Error> { - *STORE.write().map_err(|_| { + pub fn load(accounts: OmniAccounts) -> Result<(), Error> { + for (account_id, members) in &accounts { + let mut member_account_hash = MEMBER_ACCOUNT_HASH.write().map_err(|_| { + log::error!("[InMemoryStore] Lock poisoning"); + Error::LockPoisoning + })?; + for member in members { + member_account_hash.insert(member.hash(), account_id.clone()); + } + } + *ACCCOUNT_STORE.write().map_err(|_| { log::error!("[InMemoryStore] Lock poisoning"); Error::LockPoisoning })? = accounts; diff --git a/tee-worker/identity/litentry/core/omni-account/src/repository.rs b/tee-worker/identity/litentry/core/omni-account/src/repository.rs index c12993d1eb..eba762c1e1 100644 --- a/tee-worker/identity/litentry/core/omni-account/src/repository.rs +++ b/tee-worker/identity/litentry/core/omni-account/src/repository.rs @@ -18,13 +18,9 @@ use crate::{AccountId, Error, Header, MemberAccount, OmniAccounts, ParentchainId use alloc::vec::Vec; use frame_support::storage::storage_prefix; use itp_ocall_api::EnclaveOnChainOCallApi; -use itp_storage::{ - decode_storage_key, extract_blake2_128concat_key, storage_map_key, StorageHasher, -}; +use itp_storage::{decode_storage_key, extract_blake2_128concat_key}; pub trait GetAccountStoresRepository { - fn get_by_account_id(&self, account_id: AccountId) - -> Result>, Error>; fn get_all(&self) -> Result; } @@ -46,22 +42,6 @@ impl OmniAccountRepository { impl GetAccountStoresRepository for OmniAccountRepository { - fn get_by_account_id(&self, owner: AccountId) -> Result>, Error> { - let storage_key = storage_map_key( - "OmniAccount", - "AccountStore", - &owner, - &StorageHasher::Blake2_128Concat, - ); - let storage_entry = self - .ocall_api - .get_storage_verified(storage_key, &self.header, &ParentchainId::Litentry) - .map_err(|_| Error::OCallApiError("Failed to get storage"))?; - let member_accounts = storage_entry.value().to_owned(); - - Ok(member_accounts) - } - fn get_all(&self) -> Result { let account_store_key_prefix = storage_prefix(b"OmniAccount", b"AccountStore"); let account_store_storage_keys_response = self diff --git a/tee-worker/identity/service/src/ocall_bridge/worker_on_chain_ocall.rs b/tee-worker/identity/service/src/ocall_bridge/worker_on_chain_ocall.rs index 3e1b181b78..1d309a3ea1 100644 --- a/tee-worker/identity/service/src/ocall_bridge/worker_on_chain_ocall.rs +++ b/tee-worker/identity/service/src/ocall_bridge/worker_on_chain_ocall.rs @@ -124,7 +124,7 @@ where &self, extrinsics_encoded: Vec, parentchain_id: Vec, - await_each_inlcusion: bool, + await_each_inclusion: bool, ) -> OCallBridgeResult<()> { // TODO: improve error handling, using a mut status is not good design? let mut status: OCallBridgeResult<()> = Ok(()); @@ -145,12 +145,12 @@ where debug!( "Enclave wants to send {} extrinsics to parentchain: {:?}. await each inclusion: {:?}", extrinsics.len(), - parentchain_id, await_each_inlcusion + parentchain_id, await_each_inclusion ); let api = self.create_api(parentchain_id)?; let mut send_extrinsic_failed = false; for call in extrinsics.into_iter() { - if await_each_inlcusion { + if await_each_inclusion { if let Err(e) = api.submit_and_watch_opaque_extrinsic_until( &call.encode().into(), XtStatus::InBlock,