1
- use std:: fmt;
2
- use std:: str:: FromStr ;
3
-
4
1
use async_trait:: async_trait;
5
- use bcr_ebill_core:: { NodeId , ServiceTraitBounds } ;
2
+ use bcr_ebill_core:: {
3
+ ServiceTraitBounds ,
4
+ identity_proof:: { IdentityProofStamp , IdentityProofStatus } ,
5
+ } ;
6
6
use log:: error;
7
- use secp256k1:: { SecretKey , schnorr:: Signature } ;
8
7
use thiserror:: Error ;
9
8
use url:: Url ;
10
9
@@ -29,33 +28,20 @@ pub enum Error {
29
28
#[ error( "External Identity Proof Crypto error: {0}" ) ]
30
29
Crypto ( #[ from] util:: crypto:: Error ) ,
31
30
/// all errors originating from interacting with base58
32
- #[ error( "External Identity Proof Base58 error: {0}" ) ]
33
- Base58 ( #[ from] util:: Error ) ,
31
+ #[ error( "External Identity Proof Validation error: {0}" ) ]
32
+ Validation ( #[ from] util:: ValidationError ) ,
34
33
}
35
34
36
35
#[ cfg_attr( test, automock) ]
37
36
#[ cfg_attr( target_arch = "wasm32" , async_trait( ?Send ) ) ]
38
37
#[ cfg_attr( not( target_arch = "wasm32" ) , async_trait) ]
39
38
pub trait IdentityProofApi : ServiceTraitBounds {
40
- /// Sign the base58 sha256 hash of the given node_id using the given keys and returns the resulting signature
41
- /// This is the string users are supposed to post on their social media
42
- fn create_identity_proof (
43
- & self ,
44
- node_id : & NodeId ,
45
- private_key : & SecretKey ,
46
- ) -> Result < IdentityProof > ;
47
- /// Verifies that the given node_id corresponds to the given identity proof
48
- fn verify_identity_proof (
49
- & self ,
50
- node_id : & NodeId ,
51
- identity_proof : & IdentityProof ,
52
- ) -> Result < bool > ;
53
39
/// Checks if the given identity proof somewhere in the (successful) response of calling the given URL
54
40
async fn check_url (
55
41
& self ,
56
- identity_proof : & IdentityProof ,
42
+ identity_proof_stamp : & IdentityProofStamp ,
57
43
url : & Url ,
58
- ) -> CheckIdentityProofResult ;
44
+ ) -> IdentityProofStatus ;
59
45
}
60
46
61
47
#[ derive( Debug , Clone , Default ) ]
@@ -79,32 +65,11 @@ impl ServiceTraitBounds for MockIdentityProofApi {}
79
65
#[ cfg_attr( target_arch = "wasm32" , async_trait( ?Send ) ) ]
80
66
#[ cfg_attr( not( target_arch = "wasm32" ) , async_trait) ]
81
67
impl IdentityProofApi for IdentityProofClient {
82
- fn create_identity_proof (
83
- & self ,
84
- node_id : & NodeId ,
85
- private_key : & SecretKey ,
86
- ) -> Result < IdentityProof > {
87
- let hash = util:: sha256_hash ( node_id. to_string ( ) . as_bytes ( ) ) ;
88
- let signature = util:: crypto:: signature ( & hash, private_key) . map_err ( Error :: Crypto ) ?;
89
- Ok ( IdentityProof :: from_str ( & signature) ?)
90
- }
91
-
92
- fn verify_identity_proof (
93
- & self ,
94
- node_id : & NodeId ,
95
- identity_proof : & IdentityProof ,
96
- ) -> Result < bool > {
97
- let hash = util:: sha256_hash ( node_id. to_string ( ) . as_bytes ( ) ) ;
98
- let verified = util:: crypto:: verify ( & hash, & identity_proof. to_string ( ) , & node_id. pub_key ( ) )
99
- . map_err ( Error :: Crypto ) ?;
100
- Ok ( verified)
101
- }
102
-
103
68
async fn check_url (
104
69
& self ,
105
- identity_proof : & IdentityProof ,
70
+ identity_proof : & IdentityProofStamp ,
106
71
url : & Url ,
107
- ) -> CheckIdentityProofResult {
72
+ ) -> IdentityProofStatus {
108
73
// Make an unauthenticated request to the given URL and retrieve its body
109
74
match self . cl . get ( url. to_owned ( ) ) . send ( ) . await {
110
75
Ok ( res) => {
@@ -114,111 +79,48 @@ impl IdentityProofApi for IdentityProofClient {
114
79
Ok ( body) => {
115
80
// Check if the identity proof is contained in the response
116
81
if identity_proof. is_contained_in ( & body) {
117
- CheckIdentityProofResult :: Success
82
+ IdentityProofStatus :: Success
118
83
} else {
119
- CheckIdentityProofResult :: NotFound
84
+ IdentityProofStatus :: NotFound
120
85
}
121
86
}
122
87
Err ( body_err) => {
123
88
error ! ( "Error checking url: {url} for identity proof: {body_err}" ) ;
124
- CheckIdentityProofResult :: FailureClient
89
+ IdentityProofStatus :: FailureClient
125
90
}
126
91
}
127
92
}
128
93
Err ( e) => {
129
94
error ! ( "Error checking url: {url} for identity proof: {e}" ) ;
130
95
if let Some ( status) = e. status ( ) {
131
96
if status. is_client_error ( ) {
132
- CheckIdentityProofResult :: FailureClient
97
+ IdentityProofStatus :: FailureClient
133
98
} else if status. is_server_error ( ) {
134
- CheckIdentityProofResult :: FailureServer
99
+ IdentityProofStatus :: FailureServer
135
100
} else {
136
- CheckIdentityProofResult :: FailureConnect
101
+ IdentityProofStatus :: FailureConnect
137
102
}
138
103
} else {
139
- CheckIdentityProofResult :: FailureConnect
104
+ IdentityProofStatus :: FailureConnect
140
105
}
141
106
}
142
107
}
143
108
}
144
109
Err ( req_err) => {
145
110
error ! ( "Error checking url: {url} for identity proof: {req_err}" ) ;
146
- CheckIdentityProofResult :: FailureConnect
111
+ IdentityProofStatus :: FailureConnect
147
112
}
148
113
}
149
114
}
150
115
}
151
116
152
- #[ derive( Debug , Clone ) ]
153
- pub struct IdentityProof {
154
- inner : Signature ,
155
- }
156
-
157
- impl IdentityProof {
158
- /// Checks if the identity proof signature string is within the given body of text
159
- pub fn is_contained_in ( & self , body : & str ) -> bool {
160
- let self_str = self . to_string ( ) ;
161
- body. contains ( & self_str)
162
- }
163
- }
164
-
165
- impl fmt:: Display for IdentityProof {
166
- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
167
- write ! ( f, "{}" , util:: base58_encode( & self . inner. serialize( ) ) )
168
- }
169
- }
170
-
171
- impl From < Signature > for IdentityProof {
172
- fn from ( value : Signature ) -> Self {
173
- Self { inner : value }
174
- }
175
- }
176
-
177
- impl FromStr for IdentityProof {
178
- type Err = Error ;
179
- fn from_str ( s : & str ) -> std:: result:: Result < Self , Self :: Err > {
180
- Ok ( Self {
181
- inner : Signature :: from_slice ( & util:: base58_decode ( s) ?) ?,
182
- } )
183
- }
184
- }
185
-
186
- #[ derive( Debug , Clone ) ]
187
- pub enum CheckIdentityProofResult {
188
- /// The request succeeded and we found the signature we were looking for in the response
189
- Success ,
190
- /// The request succeeded, but we didn't find the signature we were looking for in the response
191
- NotFound ,
192
- /// The request failed with a connection error
193
- FailureConnect ,
194
- /// The request failed with a client error (4xx)
195
- FailureClient ,
196
- /// The request failed with a server error (5xx)
197
- FailureServer ,
198
- }
199
-
200
117
#[ cfg( test) ]
201
118
pub mod tests {
202
- use crate :: tests:: tests:: { node_id_test, private_key_test} ;
203
-
204
- use super :: * ;
205
-
206
- #[ test]
207
- fn test_create_and_verify ( ) {
208
- let node_id = node_id_test ( ) ;
209
- let private_key = private_key_test ( ) ;
119
+ use std:: str:: FromStr ;
210
120
211
- let identity_proof_client = IdentityProofClient :: new ( ) ;
121
+ use crate :: tests :: tests :: node_id_test ;
212
122
213
- let identity_proof = identity_proof_client
214
- . create_identity_proof ( & node_id, & private_key)
215
- . expect ( "can create identity proof" ) ;
216
- assert ! (
217
- identity_proof_client
218
- . verify_identity_proof( & node_id, & identity_proof)
219
- . expect( "can verify identity proof" )
220
- ) ;
221
- }
123
+ use super :: * ;
222
124
223
125
#[ tokio:: test]
224
126
#[ ignore]
@@ -230,32 +132,25 @@ pub mod tests {
230
132
let identity_proof_client = IdentityProofClient :: new ( ) ;
231
133
232
134
// is a valid identity proof
233
- let identity_proof = IdentityProof :: from_str ( "2DmtcWtNk2hvXaBCUAng63Gn1VDBZEojMwoZWr2VqDL5LZNgszj26YT4Pj4MUSf5o4HSmdiAEENyuNQ5UEK7zG1p" ) . expect ( "is valid" ) ;
234
- assert ! (
235
- identity_proof_client
236
- . verify_identity_proof( & node_id, & identity_proof)
237
- . expect( "can verify identity proof" )
238
- ) ;
135
+ let identity_proof = IdentityProofStamp :: from_str ( "2DmtcWtNk2hvXaBCUAng63Gn1VDBZEojMwoZWr2VqDL5LZNgszj26YT4Pj4MUSf5o4HSmdiAEENyuNQ5UEK7zG1p" ) . expect ( "is valid" ) ;
136
+ assert ! ( identity_proof. verify_against_node_id( & node_id) ) ;
239
137
240
138
let valid_url = Url :: parse ( "https://primal.net/e/nevent1qqs24kk3m0rc8e7a6f8k8daddqes0a2n74jszdszppu84e6y5q8ss3cy2rxs4" ) . unwrap ( ) ;
241
139
let check_url_res = identity_proof_client
242
140
. check_url ( & identity_proof, & valid_url)
243
141
. await ;
244
- assert ! ( matches!( check_url_res, CheckIdentityProofResult :: Success ) ) ;
142
+ assert ! ( matches!( check_url_res, IdentityProofStatus :: Success ) ) ;
245
143
246
144
let not_found_url = Url :: parse ( "https://primal.net/e/nevent1qqsv64erdk323pkpuzqspyk3e842egaeuu8v6js970tvnyjlkjakzqc0whefs" ) . unwrap ( ) ;
247
145
let check_url_res = identity_proof_client
248
146
. check_url ( & identity_proof, & not_found_url)
249
147
. await ;
250
- assert ! ( matches!( check_url_res, CheckIdentityProofResult :: NotFound ) ) ;
148
+ assert ! ( matches!( check_url_res, IdentityProofStatus :: NotFound ) ) ;
251
149
252
150
let invalid_url = Url :: parse ( "https://www.bit.cr/does-not-exist-ever" ) . unwrap ( ) ;
253
151
let check_url_res = identity_proof_client
254
152
. check_url ( & identity_proof, & invalid_url)
255
153
. await ;
256
- assert ! ( matches!(
257
- check_url_res,
258
- CheckIdentityProofResult :: FailureClient
259
- ) ) ;
154
+ assert ! ( matches!( check_url_res, IdentityProofStatus :: FailureClient ) ) ;
260
155
}
261
156
}
0 commit comments