Skip to content

Commit f21ecf6

Browse files
committed
adapter - eth - identity ABI & has_privileges impl
- primitives - config - add Ganache config
1 parent 5d2ed8b commit f21ecf6

File tree

2 files changed

+90
-74
lines changed

2 files changed

+90
-74
lines changed

adapter/src/ethereum.rs

Lines changed: 85 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,9 @@ use primitives::{
1212
config::Config,
1313
Address, BigNum, Channel, ToETHChecksum, ValidatorId,
1414
};
15-
use reqwest::Client;
1615
use serde::{Deserialize, Serialize};
1716
use serde_json::Value;
1817
use std::{fs, str::FromStr};
19-
use thiserror::Error;
2018
use tiny_keccak::Keccak;
2119
use web3::{
2220
contract::{Contract, Options},
@@ -39,6 +37,9 @@ pub static ERC20_ABI: Lazy<&'static [u8]> = Lazy::new(|| {
3937
});
4038
pub static SWEEPER_ABI: Lazy<&'static [u8]> =
4139
Lazy::new(|| include_bytes!("../../lib/protocol-eth/abi/Sweeper.json"));
40+
pub static IDENTITY_ABI: Lazy<&'static [u8]> =
41+
Lazy::new(|| include_bytes!("../../lib/protocol-eth/abi/Identity5.2.json"));
42+
4243
/// Ready to use init code (i.e. decoded) for calculating the create2 address
4344
pub static DEPOSITOR_BYTECODE_DECODED: Lazy<Vec<u8>> = Lazy::new(|| {
4445
let bytecode = include_str!("../../lib/protocol-eth/resources/bytecode/Depositor.bin");
@@ -92,7 +93,6 @@ pub struct EthereumAdapter {
9293
config: Config,
9394
wallet: Option<SafeAccount>,
9495
web3: Web3<Http>,
95-
relayer: RelayerClient,
9696
}
9797

9898
impl EthereumAdapter {
@@ -113,7 +113,6 @@ impl EthereumAdapter {
113113
let transport =
114114
web3::transports::Http::new(&config.ethereum_network).map_err(Error::Web3)?;
115115
let web3 = web3::Web3::new(transport);
116-
let relayer = RelayerClient::new(&config.ethereum_adapter_relayer)?;
117116

118117
Ok(Self {
119118
address,
@@ -122,9 +121,45 @@ impl EthereumAdapter {
122121
wallet: None,
123122
config: config.to_owned(),
124123
web3,
125-
relayer,
126124
})
127125
}
126+
127+
/// Checks if the `from` address has privilages,
128+
/// by using the Identity contract with a create2 address created with the `from` address
129+
pub async fn has_privilages(
130+
&self,
131+
identity: Address,
132+
check_for: Address,
133+
hash: [u8; 32],
134+
signature: &[u8],
135+
) -> Result<bool, Error> {
136+
// see https://eips.ethereum.org/EIPS/eip-1271
137+
let magic_value: u32 = 0x1626ba7e;
138+
// 0x4e487b710000000000000000000000000000000000000000000000000000000000000021
139+
140+
let identity_contract =
141+
Contract::from_json(self.web3.eth(), H160(identity.to_bytes()), &IDENTITY_ABI)
142+
.map_err(Error::ContractInitialization)?;
143+
144+
let status: u32 = identity_contract
145+
.query(
146+
"isValidSignature",
147+
(
148+
// bytes32
149+
Token::FixedBytes(hash.to_vec()),
150+
// bytes
151+
Token::Bytes(signature.to_vec()),
152+
),
153+
Some(H160(check_for.to_bytes())),
154+
Options::default(),
155+
None,
156+
)
157+
.await
158+
.map_err(Error::ContractQuerying)?;
159+
160+
// if it is the magical value then the address has privileges.
161+
Ok(status == magic_value)
162+
}
128163
}
129164

130165
#[async_trait]
@@ -222,9 +257,19 @@ impl Adapter for EthereumAdapter {
222257

223258
let sess = match &verified.payload.identity {
224259
Some(identity) => {
260+
let decoded_signature =
261+
base64::decode_config(token_encoded, base64::URL_SAFE_NO_PAD).unwrap();
262+
263+
let hash =
264+
hash_message(format!("{}.{}", header_encoded, payload_encoded).as_bytes());
265+
225266
if self
226-
.relayer
227-
.has_privileges(&verified.from, identity)
267+
.has_privilages(
268+
identity.to_address(),
269+
self.whoami().to_address(),
270+
hash,
271+
&decoded_signature,
272+
)
228273
.await?
229274
{
230275
Session {
@@ -348,49 +393,6 @@ impl Adapter for EthereumAdapter {
348393
}
349394
}
350395

351-
#[derive(Debug, Clone)]
352-
struct RelayerClient {
353-
client: Client,
354-
relayer_url: String,
355-
}
356-
357-
#[derive(Debug, Error)]
358-
#[error(transparent)]
359-
pub struct RelayerError(#[from] pub reqwest::Error);
360-
361-
impl RelayerClient {
362-
pub fn new(relayer_url: &str) -> Result<Self, RelayerError> {
363-
let client = Client::builder().build()?;
364-
365-
Ok(Self {
366-
relayer_url: relayer_url.to_string(),
367-
client,
368-
})
369-
}
370-
371-
/// Checks whether there are any privileges (i.e. > 0)
372-
pub async fn has_privileges(
373-
&self,
374-
from: &ValidatorId,
375-
identity: &ValidatorId,
376-
) -> Result<bool, RelayerError> {
377-
use std::collections::HashMap;
378-
let relay_url = format!(
379-
"{}/identity/by-owner/{}",
380-
self.relayer_url,
381-
from.to_checksum()
382-
);
383-
384-
let identities_owned: HashMap<ValidatorId, u8> =
385-
self.client.get(&relay_url).send().await?.json().await?;
386-
387-
let has_privileges = identities_owned
388-
.get(identity)
389-
.map_or(false, |privileges| *privileges > 0);
390-
Ok(has_privileges)
391-
}
392-
}
393-
394396
fn hash_message(message: &[u8]) -> [u8; 32] {
395397
let eth = "\x19Ethereum Signed Message:\n";
396398
let message_length = message.len();
@@ -476,6 +478,10 @@ pub fn ewt_verify(
476478
let decoded_signature = base64::decode_config(&token, base64::URL_SAFE_NO_PAD)
477479
.map_err(EwtVerifyError::SignatureDecoding)?;
478480
let signature = Signature::from_electrum(&decoded_signature);
481+
// signature is empty, so it is invalid, see `Signature::from_electrum`
482+
if *signature == [0; 65] {
483+
return Err(EwtVerifyError::InvalidSignature);
484+
}
479485

480486
let address =
481487
public_to_address(&recover(&signature, &message).map_err(EwtVerifyError::AddressRecovery)?);
@@ -485,6 +491,7 @@ pub fn ewt_verify(
485491
.map_err(EwtVerifyError::PayloadDecoding)?,
486492
)
487493
.map_err(EwtVerifyError::PayloadUtf8)?;
494+
488495
let payload: Payload =
489496
serde_json::from_str(&payload_string).map_err(EwtVerifyError::PayloadDeserialization)?;
490497

@@ -502,14 +509,10 @@ mod test {
502509
use super::*;
503510
use chrono::Utc;
504511
use primitives::{
505-
config::DEVELOPMENT_CONFIG,
512+
config::{DEVELOPMENT_CONFIG, GANACHE_CONFIG},
506513
test_util::{CREATOR, IDS, LEADER},
507514
};
508515
use web3::{transports::Http, Web3};
509-
use wiremock::{
510-
matchers::{method, path},
511-
Mock, MockServer, ResponseTemplate,
512-
};
513516

514517
#[test]
515518
fn should_init_and_unlock_ethereum_adapter() {
@@ -590,6 +593,7 @@ mod test {
590593
};
591594

592595
let parts: Vec<&str> = expected.split('.').collect();
596+
593597
let verification =
594598
ewt_verify(parts[0], parts[1], parts[2]).expect("Failed to verify ewt token");
595599

@@ -602,37 +606,44 @@ mod test {
602606
#[tokio::test]
603607
async fn test_session_from_token() {
604608
use primitives::ToETHChecksum;
605-
use std::collections::HashMap;
606609

607-
let identity = ValidatorId::try_from("0x5B04DBc513F90CaAFAa09307Ad5e3C65EB4b26F0").unwrap();
608-
let server = MockServer::start().await;
609-
let mut identities_owned: HashMap<ValidatorId, u8> = HashMap::new();
610-
identities_owned.insert(identity, 2);
610+
// let identity = ValidatorId::try_from("0x5B04DBc513F90CaAFAa09307Ad5e3C65EB4b26F0").unwrap();
611611

612-
let mut eth_adapter = setup_eth_adapter(DEVELOPMENT_CONFIG.clone());
612+
// let mut eth_adapter = setup_eth_adapter(GANACHE_CONFIG.clone());
613+
let mut adapter = EthereumAdapter::init(KEYSTORES[&CREATOR].clone(), &GANACHE_CONFIG)
614+
.expect("should init ethereum adapter");
613615

614-
Mock::given(method("GET"))
615-
.and(path(format!("/identity/by-owner/{}", eth_adapter.whoami())))
616-
.respond_with(ResponseTemplate::new(200).set_body_json(&identities_owned))
617-
.mount(&server)
618-
.await;
616+
adapter.unlock().expect("should unlock eth adapter");
619617

620-
eth_adapter.unlock().expect("should unlock eth adapter");
621-
let wallet = eth_adapter.wallet.clone();
618+
let whoami = adapter.whoami().to_address();
619+
620+
// todo: Deploy Identity
621+
let (identity_address, _contract) =
622+
deploy_identity_contract(&adapter.web3, adapter.whoami().to_address(), &[whoami])
623+
.await
624+
.expect("Should deploy identity");
625+
let identity_id = ValidatorId::from(identity_address);
626+
627+
let wallet = adapter.wallet.clone().expect("Should have unlocked wallet");
622628

623629
let era = Utc::now().timestamp_millis() as f64 / 60000.0;
624630
let payload = Payload {
625-
id: eth_adapter.whoami().to_checksum(),
631+
id: adapter.whoami().to_checksum(),
626632
era: era.floor() as i64,
627-
identity: Some(identity),
628-
address: eth_adapter.whoami().to_checksum(),
633+
identity: Some(identity_id),
634+
address: adapter.whoami().to_checksum(),
629635
};
630636

631-
let token = ewt_sign(&wallet.unwrap(), &eth_adapter.keystore_pwd, &payload).unwrap();
637+
let token = ewt_sign(&wallet, &adapter.keystore_pwd, &payload)
638+
.expect("Sould successfully sign the Paypload");
639+
// let parts = token.split('.').collect::<Vec<_>>();
640+
641+
// double check that we have access for _Who Am I_
642+
// eth_adapter.has_privilages(identity_address, whoami, ).await.expect("Ok");
632643

633-
let session: Session = eth_adapter.session_from_token(&token).await.unwrap();
644+
let session: Session = adapter.session_from_token(&token).await.unwrap();
634645

635-
assert_eq!(session.uid, identity);
646+
assert_eq!(session.uid, identity_id);
636647
}
637648

638649
#[tokio::test]

primitives/src/config.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ pub static PRODUCTION_CONFIG: Lazy<Config> = Lazy::new(|| {
1717
.expect("Failed to parse prod.toml config file")
1818
});
1919

20+
pub static GANACHE_CONFIG: Lazy<Config> = Lazy::new(|| {
21+
Config::try_toml(include_str!("../../docs/config/ganache.toml"))
22+
.expect("Failed to parse ganache.toml config file")
23+
});
24+
2025
#[derive(Debug, Deserialize, PartialEq, Eq, Clone, Copy)]
2126
#[serde(rename_all = "camelCase")]
2227
/// The environment in which the application is running

0 commit comments

Comments
 (0)