66import re
77import ssl
88
9- from domaintools .constants import Endpoint , ENDPOINT_TO_SOURCE_MAP , RTTF_PRODUCTS_LIST , OutputFormat
9+ from domaintools .constants import (
10+ Endpoint ,
11+ OutputFormat ,
12+ ENDPOINT_TO_SOURCE_MAP ,
13+ RTTF_PRODUCTS_LIST ,
14+ RTTF_PRODUCTS_CMD_MAPPING ,
15+ )
1016from domaintools ._version import current as version
1117from domaintools .results import (
1218 GroupedIterable ,
@@ -92,7 +98,9 @@ def __init__(
9298 self ._build_api_url (api_url , api_port )
9399
94100 if not https :
95- raise Exception ("The DomainTools API endpoints no longer support http traffic. Please make sure https=True." )
101+ raise Exception (
102+ "The DomainTools API endpoints no longer support http traffic. Please make sure https=True."
103+ )
96104 if proxy_url and not isinstance (proxy_url , str ):
97105 raise Exception ("Proxy URL must be a string. For example: '127.0.0.1:8888'" )
98106
@@ -110,8 +118,12 @@ def _build_api_url(self, api_url=None, api_port=None):
110118
111119 self ._rest_api_url = rest_api_url
112120
113- def _rate_limit (self ):
121+ def _rate_limit (self , product ):
114122 """Pulls in and enforces the latest rate limits for the specified user"""
123+ if product in RTTF_PRODUCTS_LIST :
124+ self .limits_set = False
125+ return
126+
115127 self .limits_set = True
116128 for product in self .account_information ():
117129 limit_minutes = product ["per_minute_limit" ] or None
@@ -128,8 +140,9 @@ def _results(self, product, path, cls=Results, **kwargs):
128140 if product != "account-information" and self .rate_limit and not self .limits_set and not self .limits :
129141 always_sign_api_key_previous_value = self .always_sign_api_key
130142 header_authentication_previous_value = self .header_authentication
131- self ._rate_limit ()
132- # Reset always_sign_api_key and header_authentication to its original User-set values as these might be affected when self.account_information() was executed
143+ self ._rate_limit (product )
144+ # Reset always_sign_api_key and header_authentication to its original
145+ # User-set values as these might be affected when self.account_information() was executed
133146 self .always_sign_api_key = always_sign_api_key_previous_value
134147 self .header_authentication = header_authentication_previous_value
135148
@@ -139,7 +152,13 @@ def _results(self, product, path, cls=Results, **kwargs):
139152 is_rttf_product = product in RTTF_PRODUCTS_LIST
140153 self ._handle_api_key_parameters (is_rttf_product )
141154 self .handle_api_key (is_rttf_product , path , parameters )
142- parameters .update ({key : str (value ).lower () if value in (True , False ) else value for key , value in kwargs .items () if value is not None })
155+ parameters .update (
156+ {
157+ key : str (value ).lower () if value in (True , False ) else value
158+ for key , value in kwargs .items ()
159+ if value is not None
160+ }
161+ )
143162
144163 return cls (self , product , uri , ** parameters )
145164
@@ -189,8 +208,30 @@ def snakecase(string):
189208 string [1 :],
190209 )
191210
192- api_calls = tuple ((api_call for api_call in dir (API ) if not api_call .startswith ("_" ) and callable (getattr (API , api_call , None ))))
193- return sorted ([snakecase (p ["id" ]) for p in self .account_information ()["products" ] if snakecase (p ["id" ]) in api_calls ])
211+ api_calls = tuple (
212+ (
213+ api_call
214+ for api_call in dir (API )
215+ if not api_call .startswith ("_" ) and callable (getattr (API , api_call , None ))
216+ )
217+ )
218+
219+ account_information = self .account_information ()
220+
221+ available_calls = set ()
222+ for product in self .account_information ():
223+ product_id = product ["id" ]
224+ # for RTUF endpoints as we use different func name in our wrapper
225+ if product_id in RTTF_PRODUCTS_LIST :
226+ if rttf_api_command := RTTF_PRODUCTS_CMD_MAPPING .get (product_id ):
227+ available_calls .add (rttf_api_command )
228+
229+ # for IRIS endpoints
230+ snakecase_pid = snakecase (product_id )
231+ if snakecase_pid in api_calls :
232+ available_calls .add (snakecase_pid )
233+
234+ return sorted (available_calls )
194235
195236 def brand_monitor (self , query , exclude = None , domain_status = None , days_back = None , ** kwargs ):
196237 """Pass in one or more terms as a list or separated by the pipe character ( | )"""
@@ -445,7 +486,16 @@ def iris(
445486 """Performs a search for the provided search terms ANDed together,
446487 returning the pivot engine row data for the resulting domains.
447488 """
448- if not domain and not ip and not email and not nameserver and not registrar and not registrant and not registrant_org and not kwargs :
489+ if (
490+ not domain
491+ and not ip
492+ and not email
493+ and not nameserver
494+ and not registrar
495+ and not registrant
496+ and not registrant_org
497+ and not kwargs
498+ ):
449499 raise ValueError ("At least one search term must be specified" )
450500
451501 return self ._results (
@@ -1069,7 +1119,10 @@ def nod(self, **kwargs) -> FeedsResults:
10691119 validate_feeds_parameters (kwargs )
10701120 endpoint = kwargs .pop ("endpoint" , Endpoint .FEED .value )
10711121 source = ENDPOINT_TO_SOURCE_MAP .get (endpoint )
1072- if endpoint == Endpoint .DOWNLOAD .value or kwargs .get ("output_format" , OutputFormat .JSONL .value ) != OutputFormat .CSV .value :
1122+ if (
1123+ endpoint == Endpoint .DOWNLOAD .value
1124+ or kwargs .get ("output_format" , OutputFormat .JSONL .value ) != OutputFormat .CSV .value
1125+ ):
10731126 # headers param is allowed only in Feed API and CSV format
10741127 kwargs .pop ("headers" , None )
10751128
@@ -1101,7 +1154,10 @@ def nad(self, **kwargs) -> FeedsResults:
11011154 validate_feeds_parameters (kwargs )
11021155 endpoint = kwargs .pop ("endpoint" , Endpoint .FEED .value )
11031156 source = ENDPOINT_TO_SOURCE_MAP .get (endpoint ).value
1104- if endpoint == Endpoint .DOWNLOAD .value or kwargs .get ("output_format" , OutputFormat .JSONL .value ) != OutputFormat .CSV .value :
1157+ if (
1158+ endpoint == Endpoint .DOWNLOAD .value
1159+ or kwargs .get ("output_format" , OutputFormat .JSONL .value ) != OutputFormat .CSV .value
1160+ ):
11051161 # headers param is allowed only in Feed API and CSV format
11061162 kwargs .pop ("headers" , None )
11071163
@@ -1162,7 +1218,10 @@ def domaindiscovery(self, **kwargs) -> FeedsResults:
11621218 validate_feeds_parameters (kwargs )
11631219 endpoint = kwargs .pop ("endpoint" , Endpoint .FEED .value )
11641220 source = ENDPOINT_TO_SOURCE_MAP .get (endpoint ).value
1165- if endpoint == Endpoint .DOWNLOAD .value or kwargs .get ("output_format" , OutputFormat .JSONL .value ) != OutputFormat .CSV .value :
1221+ if (
1222+ endpoint == Endpoint .DOWNLOAD .value
1223+ or kwargs .get ("output_format" , OutputFormat .JSONL .value ) != OutputFormat .CSV .value
1224+ ):
11661225 # headers param is allowed only in Feed API and CSV format
11671226 kwargs .pop ("headers" , None )
11681227
@@ -1194,7 +1253,10 @@ def noh(self, **kwargs) -> FeedsResults:
11941253 validate_feeds_parameters (kwargs )
11951254 endpoint = kwargs .pop ("endpoint" , Endpoint .FEED .value )
11961255 source = ENDPOINT_TO_SOURCE_MAP .get (endpoint ).value
1197- if endpoint == Endpoint .DOWNLOAD .value or kwargs .get ("output_format" , OutputFormat .JSONL .value ) != OutputFormat .CSV .value :
1256+ if (
1257+ endpoint == Endpoint .DOWNLOAD .value
1258+ or kwargs .get ("output_format" , OutputFormat .JSONL .value ) != OutputFormat .CSV .value
1259+ ):
11981260 # headers param is allowed only in Feed API and CSV format
11991261 kwargs .pop ("headers" , None )
12001262
@@ -1225,12 +1287,15 @@ def realtime_domain_risk(self, **kwargs) -> FeedsResults:
12251287 validate_feeds_parameters (kwargs )
12261288 endpoint = kwargs .pop ("endpoint" , Endpoint .FEED .value )
12271289 source = ENDPOINT_TO_SOURCE_MAP .get (endpoint ).value
1228- if endpoint == Endpoint .DOWNLOAD .value or kwargs .get ("output_format" , OutputFormat .JSONL .value ) != OutputFormat .CSV .value :
1290+ if (
1291+ endpoint == Endpoint .DOWNLOAD .value
1292+ or kwargs .get ("output_format" , OutputFormat .JSONL .value ) != OutputFormat .CSV .value
1293+ ):
12291294 # headers param is allowed only in Feed API and CSV format
12301295 kwargs .pop ("headers" , None )
12311296
12321297 return self ._results (
1233- f"domain-risk-feed -({ source } )" ,
1298+ f"real-time- domain-risk-({ source } )" ,
12341299 f"v1/{ endpoint } /domainrisk/" ,
12351300 response_path = (),
12361301 cls = FeedsResults ,
@@ -1256,12 +1321,15 @@ def domainhotlist(self, **kwargs) -> FeedsResults:
12561321 validate_feeds_parameters (kwargs )
12571322 endpoint = kwargs .pop ("endpoint" , Endpoint .FEED .value )
12581323 source = ENDPOINT_TO_SOURCE_MAP .get (endpoint ).value
1259- if endpoint == Endpoint .DOWNLOAD .value or kwargs .get ("output_format" , OutputFormat .JSONL .value ) != OutputFormat .CSV .value :
1324+ if (
1325+ endpoint == Endpoint .DOWNLOAD .value
1326+ or kwargs .get ("output_format" , OutputFormat .JSONL .value ) != OutputFormat .CSV .value
1327+ ):
12601328 # headers param is allowed only in Feed API and CSV format
12611329 kwargs .pop ("headers" , None )
12621330
12631331 return self ._results (
1264- f"domain-hotlist-feed -({ source } )" ,
1332+ f"real-time- domain-hotlist-({ source } )" ,
12651333 f"v1/{ endpoint } /domainhotlist/" ,
12661334 response_path = (),
12671335 cls = FeedsResults ,
0 commit comments