Skip to content

Commit fd2b259

Browse files
committed
fix: rename tokens_verified, tokens_for_auth
1 parent a28fa02 commit fd2b259

File tree

2 files changed

+111
-86
lines changed

2 files changed

+111
-86
lines changed

adapter/src/dummy.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ use std::collections::HashMap;
88
pub struct DummyAdapter {
99
identity: String,
1010
config: Config,
11-
tokens_verified: HashMap<String, String>,
12-
tokens_for_auth: HashMap<String, String>,
11+
// Auth tokens that we have verified (tokenId => session)
12+
session_tokens: HashMap<String, String>,
13+
// Auth tokens that we've generated to authenticate with someone (address => token)
14+
authorization_tokens: HashMap<String, String>,
1315
}
1416

1517
// Enables DummyAdapter to be able to
@@ -20,10 +22,10 @@ impl Adapter for DummyAdapter {
2022
type Output = DummyAdapter;
2123

2224
fn init(opts: AdapterOptions, config: &Config) -> AdapterResult<DummyAdapter> {
23-
let (identity, tokens_for_auth, tokens_verified) =
25+
let (identity, authorization_tokens, session_tokens) =
2426
match (opts.dummy_identity, opts.dummy_auth, opts.dummy_auth_tokens) {
25-
(Some(identity), Some(tokens_for_auth), Some(tokens_verified)) => {
26-
(identity, tokens_for_auth, tokens_verified)
27+
(Some(identity), Some(authorization_tokens), Some(session_tokens)) => {
28+
(identity, authorization_tokens, session_tokens)
2729
}
2830
(_, _, _) => {
2931
return Err(AdapterError::Configuration(
@@ -35,8 +37,8 @@ impl Adapter for DummyAdapter {
3537
Ok(Self {
3638
identity,
3739
config: config.to_owned(),
38-
tokens_verified,
39-
tokens_for_auth,
40+
session_tokens,
41+
authorization_tokens,
4042
})
4143
}
4244

@@ -77,7 +79,7 @@ impl Adapter for DummyAdapter {
7779

7880
fn session_from_token(&self, token: &str) -> AdapterResult<Session> {
7981
let identity = self
80-
.tokens_for_auth
82+
.authorization_tokens
8183
.clone()
8284
.into_iter()
8385
.find(|(_, id)| *id == token);
@@ -93,14 +95,14 @@ impl Adapter for DummyAdapter {
9395

9496
fn get_auth(&self, _validator: &ValidatorDesc) -> AdapterResult<String> {
9597
let who = self
96-
.tokens_verified
98+
.session_tokens
9799
.clone()
98100
.into_iter()
99101
.find(|(_, id)| *id == self.identity);
100102

101103
match who {
102104
Some((id, _)) => {
103-
let auth = self.tokens_for_auth.get(&id).expect("id should exist");
105+
let auth = self.authorization_tokens.get(&id).expect("id should exist");
104106
Ok(auth.to_owned())
105107
}
106108
None => Err(AdapterError::Authentication(format!(

adapter/src/ethereum.rs

Lines changed: 99 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use std::error::Error;
1616
use std::fs::File;
1717
use std::path::Path;
1818
use tiny_keccak::Keccak;
19+
use web3::transports::Http;
1920
use web3::{
2021
contract::{Contract, Options},
2122
futures::Future,
@@ -34,8 +35,10 @@ pub struct EthereumAdapter {
3435
keystore_json: String,
3536
keystore_pwd: Password,
3637
config: Config,
37-
tokens_verified: RefCell<HashMap<String, Session>>,
38-
tokens_for_auth: RefCell<HashMap<String, String>>,
38+
// Auth tokens that we have verified (tokenId => session)
39+
session_tokens: RefCell<HashMap<String, Session>>,
40+
// Auth tokens that we've generated to authenticate with someone (address => token)
41+
authorization_tokens: RefCell<HashMap<String, String>>,
3942
wallet: RefCell<Option<SafeAccount>>,
4043
}
4144

@@ -59,8 +62,8 @@ impl Adapter for EthereumAdapter {
5962
Ok(Self {
6063
keystore_json,
6164
keystore_pwd: keystore_pwd.into(),
62-
tokens_verified: RefCell::new(HashMap::new()),
63-
tokens_for_auth: RefCell::new(HashMap::new()),
65+
session_tokens: RefCell::new(HashMap::new()),
66+
authorization_tokens: RefCell::new(HashMap::new()),
6467
wallet: RefCell::new(None),
6568
config: config.to_owned(),
6669
})
@@ -87,12 +90,11 @@ impl Adapter for EthereumAdapter {
8790
fn whoami(&self) -> AdapterResult<String> {
8891
match self.wallet.borrow().clone() {
8992
Some(wallet) => {
90-
let public = &wallet
93+
let public = wallet
9194
.public(&self.keystore_pwd)
9295
.map_err(|_| map_error("Failed to get public key"))?;
93-
let address = format!("{:?}", public_to_address(public));
94-
let checksum_address = eth_checksum::checksum(&address);
95-
Ok(checksum_address)
96+
let address = format!("{:?}", public_to_address(&public));
97+
Ok(eth_checksum::checksum(&address))
9698
}
9799
None => Err(AdapterError::Configuration(
98100
"Unlock wallet before use".to_string(),
@@ -137,16 +139,7 @@ impl Adapter for EthereumAdapter {
137139
}
138140

139141
fn validate_channel(&self, channel: &Channel) -> AdapterResult<bool> {
140-
let (_eloop, transport) = web3::transports::Http::new(&self.config.ethereum_network)
141-
.map_err(|_| map_error("Failed to initialise web3 transport"))?;
142-
let web3 = web3::Web3::new(transport);
143-
let contract_address = Address::from_slice(self.config.ethereum_core_address.as_bytes());
144-
145-
let contract = Contract::from_json(web3.eth(), contract_address, &ADEXCORE_ABI)
146-
.map_err(|_| map_error("Failed to initialise web3 transport"))?;
147-
148142
let eth_channel: EthereumChannel = channel.into();
149-
150143
let channel_id = eth_channel
151144
.hash_hex(&self.config.ethereum_core_address)
152145
.map_err(|_| map_error("Failed to hash the channel id"))?;
@@ -157,14 +150,7 @@ impl Adapter for EthereumAdapter {
157150
));
158151
}
159152

160-
let validators: Vec<&str> = channel
161-
.spec
162-
.validators
163-
.into_iter()
164-
.map(|v| &v.id[..])
165-
.collect();
166-
let invalid_address_checkum = check_address_checksum(&validators);
167-
if invalid_address_checkum {
153+
if check_validator_id_checksum(channel) {
168154
return Err(AdapterError::Configuration(
169155
"channel.validators: all addresses are checksummed".to_string(),
170156
));
@@ -173,13 +159,19 @@ impl Adapter for EthereumAdapter {
173159
let is_channel_valid = EthereumAdapter::is_channel_valid(&self.config, channel);
174160
if is_channel_valid.is_err() {
175161
return Err(AdapterError::InvalidChannel(
176-
is_channel_valid.err().unwrap().to_string(),
162+
is_channel_valid
163+
.err()
164+
.expect("failed to get channel error")
165+
.to_string(),
177166
));
178167
}
179-
180168
// query the blockchain for the channel status
181-
let contract_query = contract.query("states", channel_id, None, Options::default(), None);
182-
let channel_status: U256 = contract_query
169+
let contract_address = Address::from_slice(self.config.ethereum_core_address.as_bytes());
170+
let contract = get_contract(&self.config, contract_address, &ADEXCORE_ABI)
171+
.map_err(|_| map_error("failed to init core contract"))?;
172+
173+
let channel_status: U256 = contract
174+
.query("states", channel_id, None, Options::default(), None)
183175
.wait()
184176
.map_err(|_| map_error("contract channel status query failed"))?;
185177

@@ -193,40 +185,49 @@ impl Adapter for EthereumAdapter {
193185
}
194186

195187
fn session_from_token(&self, token: &str) -> AdapterResult<Session> {
196-
let token_id = token.to_owned()[..16].to_string();
197-
let result = self.tokens_verified.borrow_mut();
198-
if result.get(&token_id).is_some() {
199-
return Ok(result.get(&token_id).unwrap().to_owned());
188+
let token_id = token.to_owned()[token.len() - 16..].to_string();
189+
190+
let mut session_tokens = self.session_tokens.borrow_mut();
191+
if session_tokens.get(&token_id).is_some() {
192+
return Ok(session_tokens
193+
.get(&token_id)
194+
.expect("failed to get session")
195+
.to_owned());
200196
}
201197

202-
let verified = match ewt_verify(&token) {
198+
let parts: Vec<&str> = token.split('.').collect();
199+
let (header_encoded, payload_encoded, token_encoded) =
200+
match (parts.get(0), parts.get(1), parts.get(2)) {
201+
(Some(header_encoded), Some(payload_encoded), Some(token_encoded)) => {
202+
(header_encoded, payload_encoded, token_encoded)
203+
}
204+
(_, _, _) => {
205+
return Err(AdapterError::Failed(format!(
206+
"{} token string is incorrect",
207+
token
208+
)))
209+
}
210+
};
211+
212+
let verified = match ewt_verify(header_encoded, payload_encoded, token_encoded) {
203213
Ok(v) => v,
204214
Err(e) => return Err(AdapterError::EwtVerifyFailed(e.to_string())),
205215
};
206216

207-
let whoami = self.whoami()?;
208-
if whoami != verified.from {
217+
if self.whoami()? != verified.payload.id {
209218
return Err(AdapterError::Configuration(
210219
"token payload.id !== whoami(): token was not intended for us".to_string(),
211220
));
212221
}
213222

214223
let sess = match &verified.payload.identity {
215224
Some(identity) => {
216-
let (_eloop, transport) =
217-
web3::transports::Http::new(&self.config.ethereum_network)
218-
.map_err(|_| map_error("Failed to initialise web3 transport"))?;
219-
let web3 = web3::Web3::new(transport);
220-
221-
let contract_address =
222-
Address::from_slice(self.config.ethereum_core_address.as_bytes());
223-
224-
let contract = Contract::from_json(web3.eth(), contract_address, &IDENTITY_ABI)
225+
let contract_address = Address::from_slice(identity.as_bytes());
226+
let contract = get_contract(&self.config, contract_address, &IDENTITY_ABI)
225227
.map_err(|_| map_error("failed to init identity contract"))?;
226228

227-
let contract_query =
228-
contract.query("privileges", verified.from, None, Options::default(), None);
229-
let priviledge_level: U256 = contract_query
229+
let priviledge_level: U256 = contract
230+
.query("privileges", verified.from, None, Options::default(), None)
230231
.wait()
231232
.map_err(|_| map_error("failed query priviledge level on contract"))?;
232233

@@ -246,32 +247,29 @@ impl Adapter for EthereumAdapter {
246247
},
247248
};
248249

249-
self.tokens_verified
250-
.borrow_mut()
251-
.insert(token_id, sess.clone());
250+
session_tokens.insert(token_id, sess.clone());
252251
Ok(sess)
253252
}
254253

255254
fn get_auth(&self, validator: &ValidatorDesc) -> AdapterResult<String> {
256-
let tokens_for_auth = self.tokens_for_auth.borrow();
255+
let mut authorization_tokens = self.authorization_tokens.borrow_mut();
257256
match (
258257
self.wallet.borrow().clone(),
259-
tokens_for_auth.get(&validator.id),
258+
authorization_tokens.get(&validator.id),
260259
) {
261260
(Some(_), Some(token)) => Ok(token.to_owned()),
262261
(Some(wallet), None) => {
262+
let era = Utc::now().timestamp() as f64 / 60000.0;
263263
let payload = Payload {
264264
id: validator.id.clone(),
265-
era: Utc::now().timestamp(),
265+
era: era.floor() as i64,
266266
identity: None,
267267
address: None,
268268
};
269269
let token = ewt_sign(&wallet, &self.keystore_pwd, &payload)
270270
.map_err(|_| map_error("Failed to sign token"))?;
271271

272-
self.tokens_for_auth
273-
.borrow_mut()
274-
.insert(validator.id.clone(), token.clone());
272+
authorization_tokens.insert(validator.id.clone(), token.clone());
275273

276274
Ok(token)
277275
}
@@ -282,11 +280,12 @@ impl Adapter for EthereumAdapter {
282280
}
283281
}
284282

285-
fn check_address_checksum(addresses: &[&str]) -> bool {
286-
let invalid_address_checkum: Vec<&str> = addresses
287-
.iter()
288-
.cloned()
289-
.filter(|address| *address != eth_checksum::checksum(address))
283+
fn check_validator_id_checksum(channel: &Channel) -> bool {
284+
let invalid_address_checkum: Vec<&ValidatorDesc> = channel
285+
.spec
286+
.validators
287+
.into_iter()
288+
.filter(|v| v.id != eth_checksum::checksum(&v.id))
290289
.collect();
291290

292291
invalid_address_checkum.is_empty()
@@ -307,6 +306,22 @@ fn hash_message(message: &str) -> [u8; 32] {
307306
res
308307
}
309308

309+
fn map_error(err: &str) -> AdapterError {
310+
AdapterError::Failed(err.to_string())
311+
}
312+
313+
fn get_contract(
314+
config: &Config,
315+
contract_address: Address,
316+
abi: &[u8],
317+
) -> Result<Contract<Http>, Box<dyn Error>> {
318+
let (_eloop, transport) = web3::transports::Http::new(&config.ethereum_network)?;
319+
let web3 = web3::Web3::new(transport);
320+
let contract = Contract::from_json(web3.eth(), contract_address, abi)?;
321+
322+
Ok(contract)
323+
}
324+
310325
// Ethereum Web Tokens
311326
#[derive(Clone, Debug, Serialize, Deserialize)]
312327
pub struct Payload {
@@ -346,8 +361,10 @@ pub fn ewt_sign(
346361
base64::URL_SAFE_NO_PAD,
347362
);
348363

349-
let payload_encoded =
350-
base64::encode_config(&serde_json::to_string(payload)?, base64::URL_SAFE_NO_PAD);
364+
let payload_encoded = base64::encode_config(
365+
&serde_json::to_string(payload)?.as_bytes(),
366+
base64::URL_SAFE_NO_PAD,
367+
);
351368

352369
let message = Message::from_slice(&hash_message(&format!(
353370
"{}.{}",
@@ -367,18 +384,25 @@ pub fn ewt_sign(
367384
Ok(format!("{}.{}.{}", header_encoded, payload_encoded, token))
368385
}
369386

370-
pub fn ewt_verify(token: &str) -> Result<VerifyPayload, Box<dyn Error>> {
371-
let parts: Vec<String> = token.split('.').map(ToString::to_string).collect();
372-
373-
let message = Message::from_slice(&hash_message(&format!("{}.{}", parts[0], parts[1])));
387+
pub fn ewt_verify(
388+
header_encoded: &str,
389+
payload_encoded: &str,
390+
token: &str,
391+
) -> Result<VerifyPayload, Box<dyn Error>> {
392+
let message = Message::from_slice(&hash_message(&format!(
393+
"{}.{}",
394+
header_encoded, payload_encoded
395+
)));
374396

375-
let decoded_signature = base64::decode_config(&parts[2], base64::URL_SAFE_NO_PAD)?;
397+
let decoded_signature = base64::decode_config(&token, base64::URL_SAFE_NO_PAD)?;
376398
let signature = Signature::from_electrum(&decoded_signature);
377399

378400
let address = public_to_address(&recover(&signature, &message)?);
379401

380-
let payload_string =
381-
String::from_utf8(base64::decode_config(&parts[1], base64::URL_SAFE_NO_PAD)?)?;
402+
let payload_string = String::from_utf8(base64::decode_config(
403+
&payload_encoded,
404+
base64::URL_SAFE_NO_PAD,
405+
)?)?;
382406
let payload: Payload = serde_json::from_str(&payload_string)?;
383407

384408
let verified_payload = VerifyPayload {
@@ -389,10 +413,6 @@ pub fn ewt_verify(token: &str) -> Result<VerifyPayload, Box<dyn Error>> {
389413
Ok(verified_payload)
390414
}
391415

392-
fn map_error(err: &str) -> AdapterError {
393-
AdapterError::Failed(err.to_string())
394-
}
395-
396416
#[cfg(test)]
397417
mod test {
398418
use super::*;
@@ -471,7 +491,10 @@ mod test {
471491

472492
let expected_verification_response =
473493
r#"VerifyPayload { from: "0x2bDeAFAE53940669DaA6F519373f686c1f3d3393", payload: Payload { id: "awesomeValidator", era: 100000, address: Some("0x2bDeAFAE53940669DaA6F519373f686c1f3d3393"), identity: None } }"#;
474-
let verification = ewt_verify(&expected).expect("Failed to verify ewt token");
494+
495+
let parts: Vec<&str> = expected.split('.').collect();
496+
let verification =
497+
ewt_verify(parts[0], parts[1], parts[2]).expect("Failed to verify ewt token");
475498

476499
assert_eq!(
477500
expected_verification_response,

0 commit comments

Comments
 (0)