1
1
use super :: types:: * ;
2
2
use crate :: Error ;
3
+ use lighthouse_version;
3
4
use reqwest:: {
4
5
IntoUrl ,
5
6
header:: { HeaderMap , HeaderValue } ,
@@ -45,8 +46,13 @@ impl Display for AuthorizationHeader {
45
46
impl ValidatorClientHttpClient {
46
47
/// Create a new client pre-initialised with an API token.
47
48
pub fn new ( server : SensitiveUrl , secret : String ) -> Result < Self , Error > {
49
+ let client = reqwest:: ClientBuilder :: new ( )
50
+ . user_agent ( lighthouse_version:: user_agent ( ) )
51
+ . build ( )
52
+ . unwrap_or_else ( |_| reqwest:: Client :: new ( ) ) ;
53
+
48
54
Ok ( Self {
49
- client : reqwest :: Client :: new ( ) ,
55
+ client,
50
56
server,
51
57
api_token : Some ( secret. into ( ) ) ,
52
58
authorization_header : AuthorizationHeader :: Bearer ,
@@ -57,8 +63,13 @@ impl ValidatorClientHttpClient {
57
63
///
58
64
/// A token can be fetched by using `self.get_auth`, and then reading the token from disk.
59
65
pub fn new_unauthenticated ( server : SensitiveUrl ) -> Result < Self , Error > {
66
+ let client = reqwest:: ClientBuilder :: new ( )
67
+ . user_agent ( lighthouse_version:: user_agent ( ) )
68
+ . build ( )
69
+ . unwrap_or_else ( |_| reqwest:: Client :: new ( ) ) ;
70
+
60
71
Ok ( Self {
61
- client : reqwest :: Client :: new ( ) ,
72
+ client,
62
73
server,
63
74
api_token : None ,
64
75
authorization_header : AuthorizationHeader :: Omit ,
@@ -698,3 +709,87 @@ async fn ok_or_error(response: Response) -> Result<Response, Error> {
698
709
Err ( Error :: StatusCode ( status) )
699
710
}
700
711
}
712
+
713
+ #[ cfg( test) ]
714
+ mod tests {
715
+ use super :: * ;
716
+ use mockito:: { Matcher , Server } ;
717
+ use std:: str:: FromStr ;
718
+
719
+ #[ test]
720
+ fn test_validator_client_creation_with_user_agent ( ) {
721
+ let server = SensitiveUrl :: parse ( "http://localhost:5062" ) . unwrap ( ) ;
722
+ let secret = "test-secret" . to_string ( ) ;
723
+
724
+ // Test authenticated client
725
+ let client = ValidatorClientHttpClient :: new ( server. clone ( ) , secret. clone ( ) ) . unwrap ( ) ;
726
+ assert ! ( client. api_token( ) . is_some( ) ) ;
727
+ assert_eq ! ( client. authorization_header, AuthorizationHeader :: Bearer ) ;
728
+
729
+ // Test unauthenticated client
730
+ let unauth_client = ValidatorClientHttpClient :: new_unauthenticated ( server) . unwrap ( ) ;
731
+ assert ! ( unauth_client. api_token( ) . is_none( ) ) ;
732
+ assert_eq ! ( unauth_client. authorization_header, AuthorizationHeader :: Omit ) ;
733
+ }
734
+
735
+ #[ tokio:: test]
736
+ async fn test_validator_client_user_agent_in_requests ( ) {
737
+ // Create mock server
738
+ let mut server = Server :: new_async ( ) . await ;
739
+ let expected_user_agent = lighthouse_version:: user_agent ( ) ;
740
+
741
+ // Mock the auth endpoint with user agent verification
742
+ let auth_mock = server
743
+ . mock ( "GET" , "/lighthouse/auth" )
744
+ . match_header ( "user-agent" , expected_user_agent. as_str ( ) )
745
+ . with_status ( 200 )
746
+ . with_body ( r#"{"token_path":"/tmp/test","api_token":"test-token"}"# )
747
+ . create_async ( )
748
+ . await ;
749
+
750
+ // Create client
751
+ let server_url = SensitiveUrl :: parse ( & server. url ( ) ) . unwrap ( ) ;
752
+ let client = ValidatorClientHttpClient :: new_unauthenticated ( server_url) . unwrap ( ) ;
753
+
754
+ // Make request - this should include the user agent header
755
+ let _result = client. get_auth ( ) . await ;
756
+
757
+ // Verify the mock was called with correct user agent
758
+ auth_mock. assert_async ( ) . await ;
759
+ }
760
+
761
+ #[ tokio:: test]
762
+ async fn test_validator_client_user_agent_with_auth_token ( ) {
763
+ // Create mock server
764
+ let mut server = Server :: new_async ( ) . await ;
765
+ let expected_user_agent = lighthouse_version:: user_agent ( ) ;
766
+ let auth_token = "test-bearer-token" ;
767
+
768
+ // Mock the keystores endpoint with both user agent and authorization verification
769
+ let keystores_mock = server
770
+ . mock ( "GET" , "/eth/v1/keystores" )
771
+ . match_header ( "user-agent" , expected_user_agent. as_str ( ) )
772
+ . match_header ( "authorization" , format ! ( "Bearer {}" , auth_token) . as_str ( ) )
773
+ . with_status ( 200 )
774
+ . with_body ( r#"{"data":[]}"# )
775
+ . create_async ( )
776
+ . await ;
777
+
778
+ // Create authenticated client
779
+ let server_url = SensitiveUrl :: parse ( & server. url ( ) ) . unwrap ( ) ;
780
+ let client = ValidatorClientHttpClient :: new ( server_url, auth_token. to_string ( ) ) . unwrap ( ) ;
781
+
782
+ // Make request - this should include both user agent and authorization headers
783
+ let _result = client. get_keystores ( ) . await ;
784
+
785
+ // Verify the mock was called with correct headers
786
+ keystores_mock. assert_async ( ) . await ;
787
+ }
788
+
789
+ #[ test]
790
+ fn test_authorization_header_display ( ) {
791
+ assert_eq ! ( AuthorizationHeader :: Omit . to_string( ) , "Omit" ) ;
792
+ assert_eq ! ( AuthorizationHeader :: Basic . to_string( ) , "Basic" ) ;
793
+ assert_eq ! ( AuthorizationHeader :: Bearer . to_string( ) , "Bearer" ) ;
794
+ }
795
+ }
0 commit comments