1
1
from CommonServerPython import *
2
2
3
3
''' IMPORTS '''
4
- from typing import Dict , Tuple , Union
5
4
import urllib3
6
5
7
6
# Disable insecure warnings
26
25
27
26
class Client (BaseClient ):
28
27
def __init__ (self , base_url , headers , verify , proxy , default_threshold , max_indicator_relationships ,
29
- reliability , create_relationships = True ):
28
+ reliability , create_relationships = True , should_error = True ):
30
29
31
30
BaseClient .__init__ (self , base_url = base_url , headers = headers , verify = verify , proxy = proxy , )
32
31
33
32
self .reliability = reliability
34
33
self .create_relationships = create_relationships
35
34
self .default_threshold = default_threshold
36
35
self .max_indicator_relationships = 0 if not max_indicator_relationships else max_indicator_relationships
36
+ self .should_error = should_error
37
37
38
- def test_module (self ) -> Dict :
38
+ def test_module (self ) -> dict :
39
39
"""Performs basic GET request to check if the API is reachable and authentication is successful.
40
40
41
41
Returns:
42
42
Response json
43
43
"""
44
44
return self .query (section = 'IPv4' , argument = '8.8.8.8' )
45
45
46
- def query (self , section : str , argument : str = None , sub_section : str = 'general' , params : dict = None ) -> Dict :
46
+ def query (self , section : str , argument : str = None , sub_section : str = 'general' , params : dict = None ) -> dict :
47
47
"""Query the specified kwargs.
48
48
49
49
Args:
@@ -89,7 +89,7 @@ def query(self, section: str, argument: str = None, sub_section: str = 'general'
89
89
''' HELPER FUNCTIONS '''
90
90
91
91
92
- def calculate_dbot_score (client : Client , raw_response : Union [ dict , None ] ) -> float :
92
+ def calculate_dbot_score (client : Client , raw_response : dict | None ) -> float :
93
93
"""
94
94
calculate DBot score for query
95
95
@@ -267,7 +267,7 @@ def create_relationships(client: Client, relevant_field: list, entity_a: str,
267
267
return relationships
268
268
269
269
270
- def delete_duplicated_entities (entities_list : List [Dict ], field_name : str ):
270
+ def delete_duplicated_entities (entities_list : List [dict ], field_name : str ):
271
271
"""delete duplicated results from a response
272
272
273
273
Args:
@@ -277,14 +277,14 @@ def delete_duplicated_entities(entities_list: List[Dict], field_name: str):
277
277
Returns:
278
278
a list without duplicated entities.
279
279
"""
280
- unique_dict : Dict = {}
280
+ unique_dict : dict = {}
281
281
for entity_dict in entities_list :
282
- if isinstance (entity_dict , dict ) and (ind_value := entity_dict .get (field_name )) not in unique_dict . keys () :
282
+ if isinstance (entity_dict , dict ) and (ind_value := entity_dict .get (field_name )) not in unique_dict :
283
283
unique_dict [ind_value ] = entity_dict
284
284
return list (unique_dict .values ())
285
285
286
286
287
- def validate_string_is_not_url (entities_list : List [Dict ], field_name : str ):
287
+ def validate_string_is_not_url (entities_list : List [dict ], field_name : str ):
288
288
"""delete url type entities from a given list.
289
289
290
290
Args:
@@ -294,18 +294,44 @@ def validate_string_is_not_url(entities_list: List[Dict], field_name: str):
294
294
Returns:
295
295
a list without url type entities.
296
296
"""
297
- return [dict for dict in entities_list if not auto_detect_indicator_type (dict .get (field_name )) == " URL" ]
297
+ return [dict for dict in entities_list if auto_detect_indicator_type (dict .get (field_name )) != ' URL' ]
298
298
299
299
300
300
def lowercase_protocol_callback (pattern : re .Match ) -> str :
301
301
return pattern .group (0 ).lower ()
302
302
303
303
304
+ def reputation_with_handling_error (client , section , argument , sub_section = None ):
305
+ """Query data while handling ReadTimeout errors.
306
+
307
+ Args:
308
+ client: The client object used to perform the query.
309
+ section: The section to query (e.g., 'domain', 'file', 'url', etc.).
310
+ argument: The argument for the query (e.g., domain name, file hash, URL, or IP).
311
+ sub_section: (Optional) A sub-section for more specific queries (e.g., 'analysis' for file reputation).
312
+
313
+ Returns:
314
+ The raw response from the query if successful, or an empty dictionary if a ReadTimeout occurs.
315
+ """
316
+ try :
317
+ if sub_section :
318
+ return client .query (section = section , argument = argument , sub_section = sub_section )
319
+ return client .query (section = section , argument = argument )
320
+ except requests .exceptions .ReadTimeout as e :
321
+ if client .should_error :
322
+ raise e
323
+ demisto .info (f"An error was raised { e = } " )
324
+ return_warning (f"{ e } " )
325
+ if section == 'url' :
326
+ return 404
327
+ return {}
328
+
329
+
304
330
''' COMMANDS '''
305
331
306
332
307
333
@logger
308
- def test_module_command (client : Client , * _ ) -> Tuple [None , None , str ]:
334
+ def test_module_command (client : Client , * _ ) -> tuple [None , None , str ]:
309
335
"""Performs a basic GET request to check if the API is reachable and authentication is successful.
310
336
311
337
Args:
@@ -342,8 +368,8 @@ def ip_command(client: Client, ip_address: str, ip_version: str) -> List[Command
342
368
command_results : List [CommandResults ] = []
343
369
344
370
for ip_ in ips_list :
345
- raw_response = client . query ( section = ip_version ,
346
- argument = ip_ )
371
+ raw_response = reputation_with_handling_error ( client = client , section = ip_version , argument = ip_ )
372
+
347
373
if raw_response and raw_response != 404 :
348
374
ip_version = FeedIndicatorType .IP if ip_version == 'IPv4' else FeedIndicatorType .IPv6
349
375
relationships = relationships_manager (client , entity_a = ip_ , entity_a_type = ip_version ,
@@ -411,7 +437,8 @@ def domain_command(client: Client, domain: str) -> List[CommandResults]:
411
437
command_results : List [CommandResults ] = []
412
438
413
439
for domain in domains_list :
414
- raw_response = client .query (section = 'domain' , argument = domain )
440
+ raw_response = reputation_with_handling_error (client = client , section = 'domain' , argument = domain )
441
+
415
442
if raw_response and raw_response != 404 :
416
443
relationships = relationships_manager (client , entity_a = domain , indicator_type = 'domain' ,
417
444
entity_a_type = FeedIndicatorType .Domain , indicator = domain ,
@@ -469,11 +496,14 @@ def file_command(client: Client, file: str) -> List[CommandResults]:
469
496
command_results : List [CommandResults ] = []
470
497
471
498
for hash_ in hashes_list :
472
- raw_response_analysis = client .query (section = 'file' ,
473
- argument = hash_ ,
474
- sub_section = 'analysis' )
475
- raw_response_general = client .query (section = 'file' ,
476
- argument = hash_ )
499
+ raw_response_analysis = reputation_with_handling_error (client = client ,
500
+ section = 'file' ,
501
+ argument = hash_ ,
502
+ sub_section = 'analysis' )
503
+ raw_response_general = reputation_with_handling_error (client = client ,
504
+ section = 'file' ,
505
+ argument = hash_ )
506
+
477
507
if raw_response_analysis and raw_response_general and (
478
508
shortcut := dict_safe_get (raw_response_analysis , ['analysis' , 'info' , 'results' ],
479
509
{})) and raw_response_general != 404 and raw_response_analysis != 404 :
@@ -544,7 +574,8 @@ def url_command(client: Client, url: str) -> List[CommandResults]:
544
574
545
575
for url in urls_list :
546
576
url = re .sub (r'(\w+)://' , lowercase_protocol_callback , url )
547
- raw_response = client .query (section = 'url' , argument = url )
577
+ raw_response = reputation_with_handling_error (client = client , section = 'url' , argument = url )
578
+
548
579
if raw_response :
549
580
if raw_response == 404 :
550
581
command_results .append (create_indicator_result_with_dbotscore_unknown (indicator = url ,
@@ -597,7 +628,7 @@ def url_command(client: Client, url: str) -> List[CommandResults]:
597
628
598
629
599
630
@logger
600
- def alienvault_search_hostname_command (client : Client , hostname : str ) -> Tuple [str , Dict , Dict ]:
631
+ def alienvault_search_hostname_command (client : Client , hostname : str ) -> tuple [str , dict , dict ]:
601
632
"""Search for hostname details
602
633
603
634
Args:
@@ -639,7 +670,7 @@ def alienvault_search_hostname_command(client: Client, hostname: str) -> Tuple[s
639
670
640
671
641
672
@logger
642
- def alienvault_search_cve_command (client : Client , cve_id : str ) -> Tuple [str , Dict , Dict ]:
673
+ def alienvault_search_cve_command (client : Client , cve_id : str ) -> tuple [str , dict , dict ]:
643
674
"""Get Common Vulnerabilities and Exposures by id
644
675
645
676
Args:
@@ -680,7 +711,7 @@ def alienvault_search_cve_command(client: Client, cve_id: str) -> Tuple[str, Dic
680
711
@logger
681
712
def alienvault_get_related_urls_by_indicator_command (client : Client , indicator_type : str , indicator : str ,
682
713
limit : str = '' ) \
683
- -> Tuple [str , Dict , Dict ]:
714
+ -> tuple [str , dict , dict ]:
684
715
"""Get related urls by indicator (IPv4,IPv6,domain,hostname,url)
685
716
686
717
Args:
@@ -717,7 +748,7 @@ def alienvault_get_related_urls_by_indicator_command(client: Client, indicator_t
717
748
@logger
718
749
def alienvault_get_related_hashes_by_indicator_command (client : Client , indicator_type : str , indicator : str ,
719
750
limit : str = '' ) \
720
- -> Tuple [str , Dict , Dict ]:
751
+ -> tuple [str , dict , dict ]:
721
752
"""Get related file hashes by indicator (IPv4,IPv6,domain,hostname)
722
753
723
754
Args:
@@ -755,7 +786,7 @@ def alienvault_get_related_hashes_by_indicator_command(client: Client, indicator
755
786
756
787
@logger
757
788
def alienvault_get_passive_dns_data_by_indicator_command (client : Client , indicator_type : str , indicator : str ,
758
- limit : str = '' ) -> Tuple [str , Dict , Dict ]:
789
+ limit : str = '' ) -> tuple [str , dict , dict ]:
759
790
"""Get related file hashes by indicator (IPv4,IPv6,domain,hostname)
760
791
761
792
Args:
@@ -794,7 +825,7 @@ def alienvault_get_passive_dns_data_by_indicator_command(client: Client, indicat
794
825
795
826
796
827
@logger
797
- def alienvault_search_pulses_command (client : Client , page : str ) -> Tuple [str , Dict , Dict ]:
828
+ def alienvault_search_pulses_command (client : Client , page : str ) -> tuple [str , dict , dict ]:
798
829
"""Get pulse page by number of the page
799
830
800
831
Args:
@@ -825,7 +856,7 @@ def alienvault_search_pulses_command(client: Client, page: str) -> Tuple[str, Di
825
856
826
857
827
858
@logger
828
- def alienvault_get_pulse_details_command (client : Client , pulse_id : str ) -> Tuple [str , Dict , Dict ]:
859
+ def alienvault_get_pulse_details_command (client : Client , pulse_id : str ) -> tuple [str , dict , dict ]:
829
860
"""Get pulse by ID
830
861
831
862
Args:
@@ -879,6 +910,7 @@ def main():
879
910
reliability = DBotScoreReliability .get_dbot_score_reliability_from_str (reliability )
880
911
else :
881
912
Exception ("Please provide a valid value for the Source Reliability parameter." )
913
+ should_error = argToBoolean (params .get ('should_error' , True ))
882
914
883
915
client = Client (
884
916
base_url = base_url ,
@@ -888,7 +920,8 @@ def main():
888
920
default_threshold = default_threshold ,
889
921
reliability = reliability ,
890
922
create_relationships = argToBoolean (params .get ('create_relationships' )),
891
- max_indicator_relationships = max_indicator_relationships
923
+ max_indicator_relationships = max_indicator_relationships ,
924
+ should_error = should_error
892
925
)
893
926
894
927
command = demisto .command ()
0 commit comments