4
4
use crate :: EthereumChannel ;
5
5
use base64;
6
6
use chrono:: Utc ;
7
- use ethkey:: { recover, sign, verify_address, Address , KeyPair , Message , Public , Signature } ;
7
+ use eth_checksum;
8
+ use ethkey:: {
9
+ public_to_address, recover, sign, verify_address, Address , KeyPair , Message , Public , Signature ,
10
+ } ;
8
11
use ethsign:: { keyfile:: KeyFile , Protected } ;
12
+ use hex:: ToHex ;
9
13
use primitives:: {
10
14
adapter:: { Adapter , AdapterError , AdapterOptions , AdapterResult , Session } ,
11
15
channel_validator:: ChannelValidator ,
@@ -15,17 +19,16 @@ use primitives::{
15
19
use serde:: { Deserialize , Serialize } ;
16
20
use std:: collections:: HashMap ;
17
21
use std:: convert:: TryFrom ;
22
+ use std:: error:: Error ;
18
23
use std:: fs:: File ;
19
24
use std:: path:: { Path , PathBuf } ;
20
25
use std:: str:: FromStr ;
26
+ use tiny_keccak:: Keccak ;
21
27
use web3:: {
22
28
contract:: { Contract , Options } ,
23
29
futures:: Future ,
24
30
types:: U256 ,
25
31
} ;
26
- use tiny_keccak:: Keccak ;
27
-
28
- use std:: error:: Error ;
29
32
30
33
pub type Password = Protected ;
31
34
@@ -81,7 +84,7 @@ impl Adapter for EthereumAdapter {
81
84
82
85
let json_file = match File :: open ( & path) {
83
86
Ok ( data) => data,
84
- Err ( e ) => {
87
+ Err ( _ ) => {
85
88
return Err ( AdapterError :: Configuration (
86
89
"Invalid keystore location provided" . to_string ( ) ,
87
90
) )
@@ -90,16 +93,12 @@ impl Adapter for EthereumAdapter {
90
93
println ! ( "{:?}" , json_file) ;
91
94
let key_file: KeyFile = match serde_json:: from_reader ( json_file) {
92
95
Ok ( data) => data,
93
- Err ( e) => {
94
- return Err ( AdapterError :: Configuration (
95
- format ! ( "{}" , e)
96
- ) )
97
- }
96
+ Err ( e) => return Err ( AdapterError :: Configuration ( format ! ( "{}" , e) ) ) ,
98
97
} ;
99
98
100
99
let plain_secret = match key_file. crypto . decrypt ( & password) {
101
100
Ok ( data) => data,
102
- Err ( e ) => {
101
+ Err ( _ ) => {
103
102
return Err ( AdapterError :: Configuration (
104
103
"Invalid keystore password provided" . to_string ( ) ,
105
104
) )
@@ -117,20 +116,24 @@ impl Adapter for EthereumAdapter {
117
116
118
117
fn whoami ( & self ) -> AdapterResult < String > {
119
118
match & self . wallet {
120
- Some ( wallet) => Ok ( format ! ( "{:?}" , wallet. address( ) ) ) ,
119
+ Some ( wallet) => {
120
+ let address = format ! ( "{:?}" , wallet. address( ) ) ;
121
+ let checksum_address = eth_checksum:: checksum ( & address) ;
122
+ Ok ( checksum_address)
123
+ }
121
124
None => Err ( AdapterError :: Configuration (
122
125
"Unlock wallet before use" . to_string ( ) ,
123
126
) ) ,
124
127
}
125
128
}
126
129
127
- fn sign ( & self , state_root : & str ) -> AdapterResult < String > {
130
+ fn sign ( & self , state_root : & str ) -> AdapterResult < String > {
128
131
let message = Message :: from_slice ( & hash_message ( state_root) ) ;
129
132
match & self . wallet {
130
133
Some ( wallet) => {
131
- let signature = sign ( wallet. secret ( ) , & message) . expect ( "sign message" ) ;
132
- println ! ( "{:?}" , signature) ;
133
- Ok ( format ! ( "{}" , signature) )
134
+ let wallet_sign = sign ( wallet. secret ( ) , & message) . expect ( "sign message" ) ;
135
+ let signature: Signature = wallet_sign . into_electrum ( ) . into ( ) ;
136
+ Ok ( format ! ( "0x {}" , signature) )
134
137
}
135
138
None => Err ( AdapterError :: Configuration (
136
139
"Unlock the wallet before signing" . to_string ( ) ,
@@ -139,21 +142,25 @@ impl Adapter for EthereumAdapter {
139
142
}
140
143
141
144
fn verify ( & self , signer : & str , state_root : & str , sig : & str ) -> AdapterResult < bool > {
142
- let address = Address :: from_slice ( signer. as_bytes ( ) ) ;
143
- let signature = match Signature :: from_str ( sig) {
144
- Ok ( sig) => sig,
145
- Err ( e) => {
145
+ let ( decoded_adress, decoded_signature) = match ( hex:: decode ( signer) , hex:: decode ( sig) ) {
146
+ ( Ok ( address) , Ok ( sig) ) => ( address, sig) ,
147
+ ( _, _) => {
146
148
return Err ( AdapterError :: Signature (
147
- "verify: Failed to parse signature " . to_string ( ) ,
149
+ "invalid signature or address " . to_string ( ) ,
148
150
) )
149
151
}
150
152
} ;
151
153
152
- let message = Message :: from_slice ( state_root. as_bytes ( ) ) ;
154
+ let address = Address :: from_slice ( & decoded_adress) ;
155
+ let signature = Signature :: from_electrum ( & decoded_signature) ;
156
+ let message = Message :: from_slice ( & hash_message ( state_root) ) ;
153
157
154
158
match verify_address ( & address, & signature, & message) {
155
159
Ok ( result) => Ok ( result) ,
156
- Err ( e) => Ok ( false ) ,
160
+ Err ( e) => {
161
+ println ! ( "{}" , e) ;
162
+ Ok ( false )
163
+ }
157
164
}
158
165
}
159
166
@@ -217,16 +224,7 @@ impl Adapter for EthereumAdapter {
217
224
Err ( e) => return Err ( AdapterError :: EwtVerifyFailed ( format ! ( "{}" , e) ) ) ,
218
225
} ;
219
226
220
- let wallet = match & self . wallet {
221
- Some ( w) => w,
222
- None => {
223
- return Err ( AdapterError :: Configuration (
224
- "Failed to unlock wallet" . to_string ( ) ,
225
- ) )
226
- }
227
- } ;
228
-
229
- let whoami = wallet. public ( ) . to_owned ( ) ;
227
+ let whoami = self . whoami ( ) ?;
230
228
if whoami != verified. from {
231
229
return Err ( AdapterError :: Configuration (
232
230
"token payload.id !== whoami(): token was not intended for us" . to_string ( ) ,
@@ -249,13 +247,8 @@ impl Adapter for EthereumAdapter {
249
247
)
250
248
. unwrap ( ) ;
251
249
252
- let contract_query = contract. query (
253
- "privileges" ,
254
- format ! ( "{}" , verified. from) ,
255
- None ,
256
- Options :: default ( ) ,
257
- None ,
258
- ) ;
250
+ let contract_query =
251
+ contract. query ( "privileges" , verified. from , None , Options :: default ( ) , None ) ;
259
252
let priviledge_level: U256 = contract_query. wait ( ) . unwrap ( ) ;
260
253
261
254
if priviledge_level == 0 . into ( ) {
@@ -270,7 +263,7 @@ impl Adapter for EthereumAdapter {
270
263
}
271
264
None => Session {
272
265
era : verified. payload . era ,
273
- uid : format ! ( "{}" , verified. from) ,
266
+ uid : verified. from ,
274
267
} ,
275
268
} ;
276
269
@@ -328,58 +321,72 @@ pub struct Payload {
328
321
329
322
#[ derive( Clone , Debug ) ]
330
323
pub struct VerifyPayload {
331
- pub from : Public ,
324
+ pub from : String ,
332
325
pub payload : Payload ,
333
326
}
334
327
328
+ #[ derive( Serialize , Deserialize ) ]
329
+ struct Header {
330
+ #[ serde( rename = "type" ) ]
331
+ header_type : String ,
332
+ alg : String ,
333
+ }
334
+
335
335
pub fn ewt_sign ( signer : & KeyPair , payload : & Payload ) -> Result < String , Box < dyn Error > > {
336
- let header_json = r#"
337
- {
338
- "type": "JWT",
339
- "alg": "ETH"
340
- }
341
- "# ;
342
- let header = base64:: encode ( header_json) ;
336
+ let header_json = Header {
337
+ header_type : "JWT" . to_string ( ) ,
338
+ alg : "ETH" . to_string ( ) ,
339
+ } ;
340
+ let header_1 = serde_json:: to_string ( & header_json) ?;
341
+ println ! ( "header json {}" , header_1) ;
342
+
343
+ let header = base64:: encode_config ( & header_1. as_bytes ( ) , base64:: URL_SAFE_NO_PAD ) ;
344
+ println ! ( "header hex {}" , header) ;
343
345
let payload_json = serde_json:: to_string ( & payload) ?;
344
- let payload_encoded = base64:: encode ( & payload_json) ;
346
+ println ! ( "payload json hex {}" , payload_json) ;
347
+ let payload_encoded = base64:: encode_config ( & payload_json, base64:: URL_SAFE_NO_PAD ) ;
345
348
let payload_string = format ! ( "{}.{}" , header, payload_encoded) ;
346
349
347
- let message = Message :: from_slice ( payload_string. as_bytes ( ) ) ;
348
- let signature = sign ( signer. secret ( ) , & message) ?;
350
+ println ! ( "payload string {}" , payload_string) ;
349
351
350
- Ok ( format ! ( "{}.{}.{}" , header, payload_encoded, signature) )
352
+ let message = Message :: from_slice ( & hash_message ( & payload_string) ) ;
353
+ let wallet_sign = sign ( signer. secret ( ) , & message) ?;
354
+ let signature: Signature = wallet_sign. into_electrum ( ) . into ( ) ;
355
+ println ! ( "\n available signature {} \n " , signature) ;
356
+ let sig_hex = hex:: decode ( format ! ( "{}" , signature) ) ?;
357
+ let tail = base64:: encode_config ( & sig_hex, base64:: URL_SAFE_NO_PAD ) ;
358
+ Ok ( format ! ( "{}.{}.{}" , header, payload_encoded, tail) )
351
359
}
352
360
353
361
pub fn ewt_verify ( token : & str ) -> Result < VerifyPayload , Box < dyn Error > > {
354
362
let parts: Vec < String > = token. split ( '.' ) . map ( ToString :: to_string) . collect ( ) ;
355
363
356
364
let msg = format ! ( "{}.{}" , parts[ 0 ] , parts[ 1 ] ) ;
357
- let message = Message :: from_slice ( msg . as_bytes ( ) ) ;
365
+ let message = Message :: from_slice ( & hash_message ( & msg ) ) ;
358
366
359
- let sig = base64:: decode ( & parts[ 2 ] ) ?;
360
- let signature = Signature :: from_str ( & hex :: encode ( & sig. as_slice ( ) ) ) . unwrap ( ) ;
367
+ let sig = base64:: decode_config ( & parts[ 2 ] , base64 :: URL_SAFE_NO_PAD ) ?;
368
+ let signature = Signature :: from_electrum ( & sig) ;
361
369
362
370
let public_key = recover ( & signature, & message) ?;
371
+ let address = public_to_address ( & public_key) ;
363
372
364
- let decode_part1 = base64:: decode ( & parts[ 1 ] ) ?;
373
+ let decode_part1 = base64:: decode_config ( & parts[ 1 ] , base64 :: URL_SAFE_NO_PAD ) ?;
365
374
let payload_string = String :: from_utf8 ( decode_part1) ?;
366
375
367
376
let payload: Payload = serde_json:: from_str ( & payload_string) ?;
368
377
369
378
let verified_payload = VerifyPayload {
370
- from : public_key ,
379
+ from : eth_checksum :: checksum ( & format ! ( "{:?}" , address ) ) ,
371
380
payload,
372
381
} ;
373
382
374
383
Ok ( verified_payload)
375
384
}
376
385
377
-
378
386
#[ cfg( test) ]
379
387
mod test {
380
- use primitives:: config:: configuration;
381
388
use super :: * ;
382
-
389
+ use primitives :: config :: configuration ;
383
390
384
391
fn setup_eth_adapter ( ) -> EthereumAdapter {
385
392
let config = configuration ( "development" , None ) . expect ( "failed parse config" ) ;
@@ -389,12 +396,11 @@ mod test {
389
396
dummy_identity : None ,
390
397
dummy_auth : None ,
391
398
dummy_auth_tokens : None ,
392
-
393
399
} ;
394
400
395
- EthereumAdapter :: init ( adapter_options, & config)
396
- . expect ( "should init ethereum adapter" )
401
+ EthereumAdapter :: init ( adapter_options, & config) . expect ( "should init ethereum adapter" )
397
402
}
403
+
398
404
#[ test]
399
405
fn should_init_and_unlock_ethereum_adapter ( ) {
400
406
let mut eth_adapter = setup_eth_adapter ( ) ;
@@ -405,17 +411,62 @@ mod test {
405
411
406
412
#[ test]
407
413
fn should_get_whoami_sign_and_verify_messages ( ) {
414
+ // whoami
408
415
let mut eth_adapter = setup_eth_adapter ( ) ;
409
416
eth_adapter. unlock ( ) . expect ( "should unlock eth adapter" ) ;
410
417
411
418
let whoami = eth_adapter. whoami ( ) . expect ( "failed to get whoami" ) ;
412
419
println ! ( "whami {}" , whoami) ;
413
- // assert_eq!(whoami, "0x2bdeafae53940669daa6f519373f686c1f3d3393", "failed to get correct whoami");
414
-
420
+ assert_eq ! (
421
+ whoami, "0x2bDeAFAE53940669DaA6F519373f686c1f3d3393" ,
422
+ "failed to get correct whoami"
423
+ ) ;
424
+ // Sign
415
425
let message = "2bdeafae53940669daa6f519373f686c" ;
416
- let expected_response =
417
- "b9f9b4b811539f77f48616b551bbc2a085d55e777ca5dab7e0f7b624ec3bd703393805904eb7bc6cbcf89ac84248b33a5498fab238dea57a0715e0a8bb69c63200 " ;
426
+ let expected_response =
427
+ "0xce654de0b3d14d63e1cb3181eee7a7a37ef4a06c9fabc204faf96f26357441b625b1be460fbe8f5278cc02aa88a5d0ac2f238e9e3b8e4893760d33bccf77e47f1b " ;
418
428
let response = eth_adapter. sign ( message) . expect ( "failed to sign message" ) ;
419
429
println ! ( "{}" , response) ;
430
+ // assert_eq!(expected_response, response, "invalid signature");
431
+ // Verify
432
+ let signature =
433
+ "ce654de0b3d14d63e1cb3181eee7a7a37ef4a06c9fabc204faf96f26357441b625b1be460fbe8f5278cc02aa88a5d0ac2f238e9e3b8e4893760d33bccf77e47f1b" ;
434
+ let verify = eth_adapter
435
+ . verify (
436
+ "2bDeAFAE53940669DaA6F519373f686c1f3d3393" ,
437
+ "2bdeafae53940669daa6f519373f686c" ,
438
+ & signature,
439
+ )
440
+ . expect ( "Failed to verify signatures" ) ;
441
+ println ! ( "{}" , verify) ;
420
442
}
421
- }
443
+
444
+ #[ test]
445
+ fn should_generate_correct_ewt_sign_and_verify ( ) {
446
+ let mut eth_adapter = setup_eth_adapter ( ) ;
447
+ eth_adapter. unlock ( ) . expect ( "should unlock eth adapter" ) ;
448
+
449
+ let payload = Payload {
450
+ id : "awesomeValidator" . to_string ( ) ,
451
+ era : 10_0000 ,
452
+ address : Some ( eth_adapter. whoami ( ) . expect ( "should get whoami ewt sign" ) ) ,
453
+ identity : None ,
454
+ } ;
455
+
456
+ let response = ewt_sign ( & eth_adapter. wallet . unwrap ( ) , & payload)
457
+ . expect ( "failed to generate ewt signature" ) ;
458
+ let expected =
459
+ "eyJ0eXBlIjoiSldUIiwiYWxnIjoiRVRIIn0.eyJpZCI6ImF3ZXNvbWVWYWxpZGF0b3IiLCJlcmEiOjEwMDAwMCwiYWRkcmVzcyI6IjB4MmJEZUFGQUU1Mzk0MDY2OURhQTZGNTE5MzczZjY4NmMxZjNkMzM5MyJ9.gGw_sfnxirENdcX5KJQWaEt4FVRvfEjSLD4f3OiPrJIltRadeYP2zWy9T2GYcK5xxD96vnqAw4GebAW7rMlz4xw" ;
460
+ assert_eq ! ( response, expected, "generated wrong ewt signature" ) ;
461
+
462
+ let expected_verification_response =
463
+ r#"VerifyPayload { from: "0x2bDeAFAE53940669DaA6F519373f686c1f3d3393", payload: Payload { id: "awesomeValidator", era: 100000, address: Some("0x2bDeAFAE53940669DaA6F519373f686c1f3d3393"), identity: None } }"# ;
464
+ let verification = ewt_verify ( & expected) . expect ( "Failed to verify ewt token" ) ;
465
+
466
+ assert_eq ! (
467
+ expected_verification_response,
468
+ format!( "{:?}" , verification) ,
469
+ "generated wrong verification payload"
470
+ ) ;
471
+ }
472
+ }
0 commit comments