@@ -38,9 +38,10 @@ class APIClientArgs:
3838
3939 # port is set to None by default, but it gets replaced with 443 if not specified
4040 # 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
4142 def __init__ (self , port = None , fingerprint = None , sid = None , server = "127.0.0.1" , http_debug_level = 0 ,
4243 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 ):
4445 self .port = port
4546 # management server fingerprint
4647 self .fingerprint = fingerprint
@@ -66,6 +67,8 @@ def __init__(self, port=None, fingerprint=None, sid=None, server="127.0.0.1", ht
6667 self .unsafe_auto_accept = unsafe_auto_accept
6768 # The context of using the client - defaults to web_api
6869 self .context = context
70+ # Indicates that the client should use single HTTPS connection
71+ self .single_conn = single_conn
6972
7073
7174class APIClient :
@@ -108,6 +111,10 @@ def __init__(self, api_client_args=None):
108111 self .unsafe_auto_accept = api_client_args .unsafe_auto_accept
109112 # The context of using the client - defaults to web_api
110113 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
111118
112119 def __enter__ (self ):
113120 return self
@@ -117,6 +124,7 @@ def __exit__(self, exc_type, exc_value, traceback):
117124 # if sid is not empty (the login api was called), then call logout
118125 if self .sid :
119126 self .api_call ("logout" )
127+ self .close_connection ()
120128 # save debug data with api calls to disk
121129 self .save_debug_data ()
122130
@@ -265,8 +273,8 @@ def api_call(self, command, payload=None, sid=None, wait_for_task=True, timeout=
265273 :side-effects: updates the class's uid and server variables
266274 """
267275 timeout_start = time .time ()
268-
269- self . check_fingerprint ( )
276+ if self . check_fingerprint () is False :
277+ return APIResponse ( "" , False , err_message = "Invalid fingerprint" )
270278 if payload is None :
271279 payload = {}
272280 # 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=
292300 if sid is not None :
293301 _headers ["X-chkp-sid" ] = sid
294302
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 ()
312305 url = "/" + self .context + "/" + (("v" + str (self .api_version ) + "/" ) if self .api_version else "" ) + command
313306 response = None
314307 try :
@@ -328,7 +321,8 @@ def api_call(self, command, payload=None, sid=None, wait_for_task=True, timeout=
328321 except Exception as err :
329322 res = APIResponse ("" , False , err_message = err )
330323 finally :
331- conn .close ()
324+ if not self .single_conn :
325+ conn .close ()
332326
333327 if response :
334328 res .status_code = response .status
@@ -464,21 +458,13 @@ def gen_api_query(self, command, details_level="standard", container_keys=None,
464458
465459 def get_server_fingerprint (self ):
466460 """
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.
468462 :return: string with SHA1 fingerprint (all uppercase letters)
469463 """
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 )
480465 fingerprint_hash = conn .get_fingerprint_hash ()
481- conn .close ()
466+ if not self .single_conn :
467+ conn .close ()
482468 return fingerprint_hash
483469
484470 def __wait_for_task (self , task_id , timeout = - 1 ):
@@ -723,22 +709,50 @@ def read_fingerprint_from_file(server, filename="fingerprints.txt"):
723709 return json_dict [server ]
724710 return ""
725711
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+
726744
727745class HTTPSConnection (http_client .HTTPSConnection ):
728746 """
729747 A class for making HTTPS connections that overrides the default HTTPS checks (e.g. not accepting
730748 self-signed-certificates) and replaces them with a server fingerprint check.
731749 """
732-
733750 def connect (self ):
734751 http_client .HTTPConnection .connect (self )
735752 self .sock = ssl .wrap_socket (self .sock , self .key_file , self .cert_file , cert_reqs = ssl .CERT_NONE )
736753
737754 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 ()
743757 fingerprint = hashlib .new ("SHA1" , self .sock .getpeercert (True )).hexdigest ()
744758 return fingerprint .upper ()
0 commit comments