@@ -38,9 +38,10 @@ class APIClientArgs:
38
38
39
39
# port is set to None by default, but it gets replaced with 443 if not specified
40
40
# context possible values - web_api (default) or gaia_api
41
+ # single_conn is set to True by default, when work on parallel set to False
41
42
def __init__ (self , port = None , fingerprint = None , sid = None , server = "127.0.0.1" , http_debug_level = 0 ,
42
43
api_calls = None , debug_file = "" , proxy_host = None , proxy_port = 8080 ,
43
- api_version = None , unsafe = False , unsafe_auto_accept = False , context = "web_api" ):
44
+ api_version = None , unsafe = False , unsafe_auto_accept = False , context = "web_api" , single_conn = True ):
44
45
self .port = port
45
46
# management server fingerprint
46
47
self .fingerprint = fingerprint
@@ -66,6 +67,8 @@ def __init__(self, port=None, fingerprint=None, sid=None, server="127.0.0.1", ht
66
67
self .unsafe_auto_accept = unsafe_auto_accept
67
68
# The context of using the client - defaults to web_api
68
69
self .context = context
70
+ # Indicates that the client should use single HTTPS connection
71
+ self .single_conn = single_conn
69
72
70
73
71
74
class APIClient :
@@ -108,6 +111,10 @@ def __init__(self, api_client_args=None):
108
111
self .unsafe_auto_accept = api_client_args .unsafe_auto_accept
109
112
# The context of using the client - defaults to web_api
110
113
self .context = api_client_args .context
114
+ # HTTPS connection
115
+ self .conn = None
116
+ # Indicates that the client should use single HTTPS connection
117
+ self .single_conn = api_client_args .single_conn
111
118
112
119
def __enter__ (self ):
113
120
return self
@@ -117,6 +124,7 @@ def __exit__(self, exc_type, exc_value, traceback):
117
124
# if sid is not empty (the login api was called), then call logout
118
125
if self .sid :
119
126
self .api_call ("logout" )
127
+ self .close_connection ()
120
128
# save debug data with api calls to disk
121
129
self .save_debug_data ()
122
130
@@ -265,8 +273,8 @@ def api_call(self, command, payload=None, sid=None, wait_for_task=True, timeout=
265
273
:side-effects: updates the class's uid and server variables
266
274
"""
267
275
timeout_start = time .time ()
268
-
269
- self . check_fingerprint ( )
276
+ if self . check_fingerprint () is False :
277
+ return APIResponse ( "" , False , err_message = "Invalid fingerprint" )
270
278
if payload is None :
271
279
payload = {}
272
280
# Convert the json payload to a string if needed
@@ -292,23 +300,8 @@ def api_call(self, command, payload=None, sid=None, wait_for_task=True, timeout=
292
300
if sid is not None :
293
301
_headers ["X-chkp-sid" ] = sid
294
302
295
- # Create ssl context with no ssl verification, we do it by ourselves
296
- context = ssl .create_default_context ()
297
- context .check_hostname = False
298
- context .verify_mode = ssl .CERT_NONE
299
-
300
- # create https connection
301
- if self .proxy_host and self .proxy_port :
302
- conn = HTTPSConnection (self .proxy_host , self .proxy_port , context = context )
303
- conn .set_tunnel (self .server , self .get_port ())
304
- else :
305
- conn = HTTPSConnection (self .server , self .get_port (), context = context )
306
-
307
- # Set fingerprint
308
- conn .fingerprint = self .fingerprint
309
-
310
- # Set debug level
311
- conn .set_debuglevel (self .http_debug_level )
303
+ # init https connection. if single connection is True, use last connection
304
+ conn = self .get_https_connection ()
312
305
url = "/" + self .context + "/" + (("v" + str (self .api_version ) + "/" ) if self .api_version else "" ) + command
313
306
response = None
314
307
try :
@@ -328,7 +321,8 @@ def api_call(self, command, payload=None, sid=None, wait_for_task=True, timeout=
328
321
except Exception as err :
329
322
res = APIResponse ("" , False , err_message = err )
330
323
finally :
331
- conn .close ()
324
+ if not self .single_conn :
325
+ conn .close ()
332
326
333
327
if response :
334
328
res .status_code = response .status
@@ -464,21 +458,13 @@ def gen_api_query(self, command, details_level="standard", container_keys=None,
464
458
465
459
def get_server_fingerprint (self ):
466
460
"""
467
- Initiates an HTTPS connection to the server and extracts the SHA1 fingerprint from the server's certificate.
461
+ Initiates an HTTPS connection to the server if need and extracts the SHA1 fingerprint from the server's certificate.
468
462
:return: string with SHA1 fingerprint (all uppercase letters)
469
463
"""
470
- context = ssl .create_default_context ()
471
- context .check_hostname = False
472
- context .verify_mode = ssl .CERT_NONE
473
-
474
- if self .proxy_host and self .proxy_port :
475
- conn = HTTPSConnection (self .proxy_host , self .proxy_port , context = context )
476
- conn .set_tunnel (self .server , self .get_port ())
477
- else :
478
- conn = HTTPSConnection (self .server , self .get_port (), context = context )
479
-
464
+ conn = self .get_https_connection (set_fingerprint = False , set_debug_level = False )
480
465
fingerprint_hash = conn .get_fingerprint_hash ()
481
- conn .close ()
466
+ if not self .single_conn :
467
+ conn .close ()
482
468
return fingerprint_hash
483
469
484
470
def __wait_for_task (self , task_id , timeout = - 1 ):
@@ -723,22 +709,50 @@ def read_fingerprint_from_file(server, filename="fingerprints.txt"):
723
709
return json_dict [server ]
724
710
return ""
725
711
712
+ def create_https_connection (self , set_fingerprint , set_debug_level ):
713
+ context = ssl .create_default_context ()
714
+ context .check_hostname = False
715
+ context .verify_mode = ssl .CERT_NONE
716
+ # create https connection
717
+ if self .proxy_host and self .proxy_port :
718
+ conn = HTTPSConnection (self .proxy_host , self .proxy_port , context = context )
719
+ conn .set_tunnel (self .server , self .get_port ())
720
+ else :
721
+ conn = HTTPSConnection (self .server , self .get_port (), context = context )
722
+
723
+ # Set fingerprint
724
+ if set_fingerprint :
725
+ conn .fingerprint = self .fingerprint
726
+
727
+ # Set debug level
728
+ if set_debug_level :
729
+ conn .set_debuglevel (self .http_debug_level )
730
+ conn .connect ()
731
+ return conn
732
+
733
+ def get_https_connection (self , set_fingerprint = True , set_debug_level = True ):
734
+ if self .single_conn :
735
+ if self .conn is None :
736
+ self .conn = self .create_https_connection (set_fingerprint , set_debug_level )
737
+ return self .conn
738
+ return self .create_https_connection (set_fingerprint , set_debug_level )
739
+
740
+ def close_connection (self ):
741
+ if self .conn :
742
+ self .conn .close ()
743
+
726
744
727
745
class HTTPSConnection (http_client .HTTPSConnection ):
728
746
"""
729
747
A class for making HTTPS connections that overrides the default HTTPS checks (e.g. not accepting
730
748
self-signed-certificates) and replaces them with a server fingerprint check.
731
749
"""
732
-
733
750
def connect (self ):
734
751
http_client .HTTPConnection .connect (self )
735
752
self .sock = ssl .wrap_socket (self .sock , self .key_file , self .cert_file , cert_reqs = ssl .CERT_NONE )
736
753
737
754
def get_fingerprint_hash (self ):
738
- try :
739
- http_client .HTTPConnection .connect (self )
740
- self .sock = ssl .wrap_socket (self .sock , self .key_file , self .cert_file , cert_reqs = ssl .CERT_NONE )
741
- except Exception :
742
- return ""
755
+ if self .sock is None :
756
+ self .connect ()
743
757
fingerprint = hashlib .new ("SHA1" , self .sock .getpeercert (True )).hexdigest ()
744
758
return fingerprint .upper ()
0 commit comments