1- use std:: fmt;
2- use std:: str:: FromStr ;
3-
41use async_trait:: async_trait;
5- use bcr_ebill_core:: { NodeId , ServiceTraitBounds } ;
2+ use bcr_ebill_core:: {
3+ ServiceTraitBounds ,
4+ identity_proof:: { IdentityProofStamp , IdentityProofStatus } ,
5+ } ;
66use log:: error;
7- use secp256k1:: { SecretKey , schnorr:: Signature } ;
87use thiserror:: Error ;
98use url:: Url ;
109
@@ -29,33 +28,20 @@ pub enum Error {
2928 #[ error( "External Identity Proof Crypto error: {0}" ) ]
3029 Crypto ( #[ from] util:: crypto:: Error ) ,
3130 /// 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 ) ,
3433}
3534
3635#[ cfg_attr( test, automock) ]
3736#[ cfg_attr( target_arch = "wasm32" , async_trait( ?Send ) ) ]
3837#[ cfg_attr( not( target_arch = "wasm32" ) , async_trait) ]
3938pub 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 > ;
5339 /// Checks if the given identity proof somewhere in the (successful) response of calling the given URL
5440 async fn check_url (
5541 & self ,
56- identity_proof : & IdentityProof ,
42+ identity_proof_stamp : & IdentityProofStamp ,
5743 url : & Url ,
58- ) -> CheckIdentityProofResult ;
44+ ) -> IdentityProofStatus ;
5945}
6046
6147#[ derive( Debug , Clone , Default ) ]
@@ -79,32 +65,11 @@ impl ServiceTraitBounds for MockIdentityProofApi {}
7965#[ cfg_attr( target_arch = "wasm32" , async_trait( ?Send ) ) ]
8066#[ cfg_attr( not( target_arch = "wasm32" ) , async_trait) ]
8167impl 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-
10368 async fn check_url (
10469 & self ,
105- identity_proof : & IdentityProof ,
70+ identity_proof : & IdentityProofStamp ,
10671 url : & Url ,
107- ) -> CheckIdentityProofResult {
72+ ) -> IdentityProofStatus {
10873 // Make an unauthenticated request to the given URL and retrieve its body
10974 match self . cl . get ( url. to_owned ( ) ) . send ( ) . await {
11075 Ok ( res) => {
@@ -114,111 +79,48 @@ impl IdentityProofApi for IdentityProofClient {
11479 Ok ( body) => {
11580 // Check if the identity proof is contained in the response
11681 if identity_proof. is_contained_in ( & body) {
117- CheckIdentityProofResult :: Success
82+ IdentityProofStatus :: Success
11883 } else {
119- CheckIdentityProofResult :: NotFound
84+ IdentityProofStatus :: NotFound
12085 }
12186 }
12287 Err ( body_err) => {
12388 error ! ( "Error checking url: {url} for identity proof: {body_err}" ) ;
124- CheckIdentityProofResult :: FailureClient
89+ IdentityProofStatus :: FailureClient
12590 }
12691 }
12792 }
12893 Err ( e) => {
12994 error ! ( "Error checking url: {url} for identity proof: {e}" ) ;
13095 if let Some ( status) = e. status ( ) {
13196 if status. is_client_error ( ) {
132- CheckIdentityProofResult :: FailureClient
97+ IdentityProofStatus :: FailureClient
13398 } else if status. is_server_error ( ) {
134- CheckIdentityProofResult :: FailureServer
99+ IdentityProofStatus :: FailureServer
135100 } else {
136- CheckIdentityProofResult :: FailureConnect
101+ IdentityProofStatus :: FailureConnect
137102 }
138103 } else {
139- CheckIdentityProofResult :: FailureConnect
104+ IdentityProofStatus :: FailureConnect
140105 }
141106 }
142107 }
143108 }
144109 Err ( req_err) => {
145110 error ! ( "Error checking url: {url} for identity proof: {req_err}" ) ;
146- CheckIdentityProofResult :: FailureConnect
111+ IdentityProofStatus :: FailureConnect
147112 }
148113 }
149114 }
150115}
151116
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-
200117#[ cfg( test) ]
201118pub 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 ;
210120
211- let identity_proof_client = IdentityProofClient :: new ( ) ;
121+ use crate :: tests :: tests :: node_id_test ;
212122
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 :: * ;
222124
223125 #[ tokio:: test]
224126 #[ ignore]
@@ -230,32 +132,25 @@ pub mod tests {
230132 let identity_proof_client = IdentityProofClient :: new ( ) ;
231133
232134 // 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) ) ;
239137
240138 let valid_url = Url :: parse ( "https://primal.net/e/nevent1qqs24kk3m0rc8e7a6f8k8daddqes0a2n74jszdszppu84e6y5q8ss3cy2rxs4" ) . unwrap ( ) ;
241139 let check_url_res = identity_proof_client
242140 . check_url ( & identity_proof, & valid_url)
243141 . await ;
244- assert ! ( matches!( check_url_res, CheckIdentityProofResult :: Success ) ) ;
142+ assert ! ( matches!( check_url_res, IdentityProofStatus :: Success ) ) ;
245143
246144 let not_found_url = Url :: parse ( "https://primal.net/e/nevent1qqsv64erdk323pkpuzqspyk3e842egaeuu8v6js970tvnyjlkjakzqc0whefs" ) . unwrap ( ) ;
247145 let check_url_res = identity_proof_client
248146 . check_url ( & identity_proof, & not_found_url)
249147 . await ;
250- assert ! ( matches!( check_url_res, CheckIdentityProofResult :: NotFound ) ) ;
148+ assert ! ( matches!( check_url_res, IdentityProofStatus :: NotFound ) ) ;
251149
252150 let invalid_url = Url :: parse ( "https://www.bit.cr/does-not-exist-ever" ) . unwrap ( ) ;
253151 let check_url_res = identity_proof_client
254152 . check_url ( & identity_proof, & invalid_url)
255153 . await ;
256- assert ! ( matches!(
257- check_url_res,
258- CheckIdentityProofResult :: FailureClient
259- ) ) ;
154+ assert ! ( matches!( check_url_res, IdentityProofStatus :: FailureClient ) ) ;
260155 }
261156}
0 commit comments