domaintools-api 2.7.2__tar.gz → 2.7.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {domaintools_api-2.7.2/domaintools_api.egg-info → domaintools_api-2.7.4}/PKG-INFO +1 -1
- domaintools_api-2.7.4/VERSION +1 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools/_version.py +1 -1
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools/api.py +10 -31
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools/decorators.py +4 -4
- {domaintools_api-2.7.2 → domaintools_api-2.7.4/domaintools_api.egg-info}/PKG-INFO +1 -1
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/tests/test_api.py +3 -12
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/tests/test_decorators.py +32 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/tests/test_filters.py +5 -12
- domaintools_api-2.7.2/VERSION +0 -1
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/LICENSE +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/README.md +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools/__init__.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools/base_results.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools/cli/__init__.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools/cli/api.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools/cli/commands/__init__.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools/cli/commands/accounts.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools/cli/commands/detects.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools/cli/commands/domains.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools/cli/commands/feeds.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools/cli/commands/ips.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools/cli/commands/iris.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools/cli/constants.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools/cli/main.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools/cli/utils.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools/constants.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools/docstring_patcher.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools/exceptions.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools/filters.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools/request_validator.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools/results.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools/specs/iris-openapi.yaml +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools/utils.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools_api.egg-info/SOURCES.txt +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools_api.egg-info/dependency_links.txt +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools_api.egg-info/entry_points.txt +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools_api.egg-info/requires.txt +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools_api.egg-info/top_level.txt +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools_async/__init__.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/pyproject.toml +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/setup.cfg +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/setup.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/tests/test_async.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/tests/test_cli.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/tests/test_docstring_patcher.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/tests/test_request_validator.py +0 -0
- {domaintools_api-2.7.2 → domaintools_api-2.7.4}/tests/test_utils.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2.7.4
|
|
@@ -128,11 +128,7 @@ class API(object):
|
|
|
128
128
|
print(f"Error loading {specs_file_path}: {e}")
|
|
129
129
|
|
|
130
130
|
def _get_ssl_default_context(self, verify_ssl: Union[str, bool]):
|
|
131
|
-
return (
|
|
132
|
-
ssl.create_default_context(cafile=verify_ssl)
|
|
133
|
-
if isinstance(verify_ssl, str)
|
|
134
|
-
else verify_ssl
|
|
135
|
-
)
|
|
131
|
+
return ssl.create_default_context(cafile=verify_ssl) if isinstance(verify_ssl, str) else verify_ssl
|
|
136
132
|
|
|
137
133
|
def _build_api_url(self, api_url=None, api_port=None):
|
|
138
134
|
"""Build the API url based on the given url and port. Defaults to `https://api.domaintools.com`"""
|
|
@@ -160,18 +156,11 @@ class API(object):
|
|
|
160
156
|
hours = limit_hours and 3600 / float(limit_hours)
|
|
161
157
|
minutes = limit_minutes and 60 / float(limit_minutes)
|
|
162
158
|
|
|
163
|
-
self.limits[product["id"]] = {
|
|
164
|
-
"interval": timedelta(seconds=minutes or hours or default)
|
|
165
|
-
}
|
|
159
|
+
self.limits[product["id"]] = {"interval": timedelta(seconds=minutes or hours or default)}
|
|
166
160
|
|
|
167
161
|
def _results(self, product, path, cls=Results, **kwargs):
|
|
168
162
|
"""Returns _results for the specified API path with the specified **kwargs parameters"""
|
|
169
|
-
if
|
|
170
|
-
product != "account-information"
|
|
171
|
-
and self.rate_limit
|
|
172
|
-
and not self.limits_set
|
|
173
|
-
and not self.limits
|
|
174
|
-
):
|
|
163
|
+
if product != "account-information" and self.rate_limit and not self.limits_set and not self.limits:
|
|
175
164
|
always_sign_api_key_previous_value = self.always_sign_api_key
|
|
176
165
|
header_authentication_previous_value = self.header_authentication
|
|
177
166
|
self._rate_limit(product)
|
|
@@ -215,9 +204,7 @@ class API(object):
|
|
|
215
204
|
else:
|
|
216
205
|
raise ValueError(
|
|
217
206
|
"Invalid value '{0}' for 'key_sign_hash'. "
|
|
218
|
-
"Values available are {1}".format(
|
|
219
|
-
self.key_sign_hash, ",".join(AVAILABLE_KEY_SIGN_HASHES)
|
|
220
|
-
)
|
|
207
|
+
"Values available are {1}".format(self.key_sign_hash, ",".join(AVAILABLE_KEY_SIGN_HASHES))
|
|
221
208
|
)
|
|
222
209
|
|
|
223
210
|
parameters["timestamp"] = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
@@ -229,9 +216,7 @@ class API(object):
|
|
|
229
216
|
|
|
230
217
|
def account_information(self, **kwargs):
|
|
231
218
|
"""Provides a snapshot of your accounts current API usage"""
|
|
232
|
-
return self._results(
|
|
233
|
-
"account-information", "/v1/account", items_path=("products",), **kwargs
|
|
234
|
-
)
|
|
219
|
+
return self._results("account-information", "/v1/account", items_path=("products",), **kwargs)
|
|
235
220
|
|
|
236
221
|
def available_api_calls(self):
|
|
237
222
|
"""Provides a list of api calls that you can use based on your account information."""
|
|
@@ -434,9 +419,7 @@ class API(object):
|
|
|
434
419
|
|
|
435
420
|
def reverse_ip(self, domain=None, limit=None, **kwargs):
|
|
436
421
|
"""Pass in a domain name."""
|
|
437
|
-
return self._results(
|
|
438
|
-
"reverse-ip", "/v1/{0}/reverse-ip".format(domain), limit=limit, **kwargs
|
|
439
|
-
)
|
|
422
|
+
return self._results("reverse-ip", "/v1/{0}/reverse-ip".format(domain), limit=limit, **kwargs)
|
|
440
423
|
|
|
441
424
|
def host_domains(self, ip=None, limit=None, **kwargs):
|
|
442
425
|
"""Pass in an IP address."""
|
|
@@ -610,12 +593,8 @@ class API(object):
|
|
|
610
593
|
younger_than_date = kwargs.pop("younger_than_date", {}) or None
|
|
611
594
|
older_than_date = kwargs.pop("older_than_date", {}) or None
|
|
612
595
|
updated_after = kwargs.pop("updated_after", {}) or None
|
|
613
|
-
include_domains_with_missing_field = (
|
|
614
|
-
|
|
615
|
-
)
|
|
616
|
-
exclude_domains_with_missing_field = (
|
|
617
|
-
kwargs.pop("exclude_domains_with_missing_field", {}) or None
|
|
618
|
-
)
|
|
596
|
+
include_domains_with_missing_field = kwargs.pop("include_domains_with_missing_field", {}) or None
|
|
597
|
+
exclude_domains_with_missing_field = kwargs.pop("exclude_domains_with_missing_field", {}) or None
|
|
619
598
|
|
|
620
599
|
filtered_results = DTResultFilter(result_set=results).by(
|
|
621
600
|
[
|
|
@@ -677,7 +656,7 @@ class API(object):
|
|
|
677
656
|
create_date=None,
|
|
678
657
|
active=None,
|
|
679
658
|
search_hash=None,
|
|
680
|
-
|
|
659
|
+
risk_score_threshold=None,
|
|
681
660
|
younger_than_date=None,
|
|
682
661
|
older_than_date=None,
|
|
683
662
|
updated_after=None,
|
|
@@ -732,7 +711,7 @@ class API(object):
|
|
|
732
711
|
|
|
733
712
|
filtered_results = DTResultFilter(result_set=results).by(
|
|
734
713
|
[
|
|
735
|
-
filter_by_riskscore(threshold=
|
|
714
|
+
filter_by_riskscore(threshold=risk_score_threshold),
|
|
736
715
|
filter_by_expire_date(date=younger_than_date, lookup_type="before"),
|
|
737
716
|
filter_by_expire_date(date=older_than_date, lookup_type="after"),
|
|
738
717
|
filter_by_date_updated_after(date=updated_after),
|
|
@@ -51,9 +51,7 @@ def api_endpoint(spec_name: str, path: str, methods: Union[str, List[str]]):
|
|
|
51
51
|
|
|
52
52
|
if "domains" in arguments.keys():
|
|
53
53
|
domains = arguments.pop("domains")
|
|
54
|
-
arguments["domain"] = (
|
|
55
|
-
",".join(domains) if isinstance(domains, (list, tuple)) else domains
|
|
56
|
-
)
|
|
54
|
+
arguments["domain"] = ",".join(domains) if isinstance(domains, (list, tuple)) else domains
|
|
57
55
|
|
|
58
56
|
if spec:
|
|
59
57
|
# Determine which HTTP method is currently being executed.
|
|
@@ -61,6 +59,8 @@ def api_endpoint(spec_name: str, path: str, methods: Union[str, List[str]]):
|
|
|
61
59
|
# Otherwise, default to the first method defined in the decorator.
|
|
62
60
|
current_method = kwargs.get("method", normalized_methods[0])
|
|
63
61
|
|
|
62
|
+
filtered_arguments = {k: v for k, v in arguments.items() if v is not None}
|
|
63
|
+
|
|
64
64
|
# Run Validation
|
|
65
65
|
# This will raise a ValueError and stop execution if validation fails.
|
|
66
66
|
try:
|
|
@@ -68,7 +68,7 @@ def api_endpoint(spec_name: str, path: str, methods: Union[str, List[str]]):
|
|
|
68
68
|
spec=spec,
|
|
69
69
|
path=path,
|
|
70
70
|
method=current_method,
|
|
71
|
-
parameters=
|
|
71
|
+
parameters=filtered_arguments,
|
|
72
72
|
)
|
|
73
73
|
except ValueError as e:
|
|
74
74
|
print(f"[Validation Error] {e}")
|
|
@@ -143,7 +143,6 @@ def test_name_server_monitor():
|
|
|
143
143
|
def test_parsed_whois():
|
|
144
144
|
api_call = api.parsed_whois("google.com")
|
|
145
145
|
with api_call as result:
|
|
146
|
-
assert "registrant" in result
|
|
147
146
|
assert "registration" in result
|
|
148
147
|
assert "name_servers" in result
|
|
149
148
|
assert "whois" in result
|
|
@@ -291,8 +290,6 @@ def test_whois():
|
|
|
291
290
|
assert "whois" in whois
|
|
292
291
|
assert "record_source" in whois
|
|
293
292
|
|
|
294
|
-
assert "abusecomplaints@markmonitor.com" in api_call.emails()
|
|
295
|
-
|
|
296
293
|
|
|
297
294
|
@vcr.use_cassette
|
|
298
295
|
def test_whois_history():
|
|
@@ -345,9 +342,7 @@ def test_exception_handling():
|
|
|
345
342
|
ValueError,
|
|
346
343
|
match=r"Invalid value 'notahash' for 'key_sign_hash'. Values available are sha1,sha256",
|
|
347
344
|
):
|
|
348
|
-
API(
|
|
349
|
-
"notauser", "notakey", always_sign_api_key=True, key_sign_hash="notahash"
|
|
350
|
-
).domain_search("amazon")
|
|
345
|
+
API("notauser", "notakey", always_sign_api_key=True, key_sign_hash="notahash").domain_search("amazon")
|
|
351
346
|
|
|
352
347
|
|
|
353
348
|
@vcr.use_cassette
|
|
@@ -356,9 +351,7 @@ def test_md5_is_not_supported():
|
|
|
356
351
|
ValueError,
|
|
357
352
|
match=r"Invalid value 'md5' for 'key_sign_hash'. Values available are sha1,sha256",
|
|
358
353
|
):
|
|
359
|
-
API("notauser", "notakey", always_sign_api_key=True, key_sign_hash="md5").domain_search(
|
|
360
|
-
"amazon"
|
|
361
|
-
)
|
|
354
|
+
API("notauser", "notakey", always_sign_api_key=True, key_sign_hash="md5").domain_search("amazon")
|
|
362
355
|
|
|
363
356
|
|
|
364
357
|
# @vcr.use_cassette
|
|
@@ -468,9 +461,7 @@ def test_iris_detect_monitors():
|
|
|
468
461
|
|
|
469
462
|
@vcr.use_cassette
|
|
470
463
|
def test_iris_detect_new_domains():
|
|
471
|
-
detect_results = api.iris_detect_new_domains(
|
|
472
|
-
monitor_id="nAwmQg2pqg", sort=["risk_score"], order="desc"
|
|
473
|
-
)
|
|
464
|
+
detect_results = api.iris_detect_new_domains(monitor_id="nAwmQg2pqg", sort=["risk_score"], order="desc")
|
|
474
465
|
assert detect_results["watchlist_domains"][0]["risk_score"] == 100
|
|
475
466
|
|
|
476
467
|
|
|
@@ -217,3 +217,35 @@ class TestApiEndpointDecorator:
|
|
|
217
217
|
call_kwargs = mock_validate.call_args[1]
|
|
218
218
|
|
|
219
219
|
assert call_kwargs.get("parameters") == {"name": "test-name"}
|
|
220
|
+
|
|
221
|
+
def test_none_arguments_are_filtered_before_validation(self, mock_client):
|
|
222
|
+
"""
|
|
223
|
+
Test that parameters with None values are excluded from the arguments
|
|
224
|
+
passed to the validator.
|
|
225
|
+
"""
|
|
226
|
+
|
|
227
|
+
@api_endpoint(spec_name="v1", path="/users", methods="POST")
|
|
228
|
+
def create_user(name=None, status=None):
|
|
229
|
+
return "Success"
|
|
230
|
+
|
|
231
|
+
with patch("domaintools.request_validator.RequestValidator.validate") as mock_validate:
|
|
232
|
+
create_user(mock_client, name="Alice", status=None)
|
|
233
|
+
|
|
234
|
+
call_kwargs = mock_validate.call_args[1]
|
|
235
|
+
assert call_kwargs.get("parameters") == {"name": "Alice"}
|
|
236
|
+
assert "status" not in call_kwargs.get("parameters", {})
|
|
237
|
+
|
|
238
|
+
def test_all_none_arguments_passes_empty_parameters(self, mock_client):
|
|
239
|
+
"""
|
|
240
|
+
Test that when all arguments are None, an empty dict is passed to the validator.
|
|
241
|
+
"""
|
|
242
|
+
|
|
243
|
+
@api_endpoint(spec_name="v1", path="/users", methods="POST")
|
|
244
|
+
def create_user(name=None, body=None):
|
|
245
|
+
return "Success"
|
|
246
|
+
|
|
247
|
+
with patch("domaintools.request_validator.RequestValidator.validate") as mock_validate:
|
|
248
|
+
create_user(mock_client, name=None, body=None)
|
|
249
|
+
|
|
250
|
+
call_kwargs = mock_validate.call_args[1]
|
|
251
|
+
assert call_kwargs.get("parameters") == {}
|
|
@@ -16,20 +16,17 @@ class DTFiltersTest(unittest.TestCase):
|
|
|
16
16
|
domaintools_iris_result = iris_investigate_data.domaintools()
|
|
17
17
|
int_chase_iris_result = iris_investigate_data.int_chase()
|
|
18
18
|
|
|
19
|
-
test_results = {
|
|
20
|
-
"results": domaintools_iris_result["results"]
|
|
21
|
-
+ int_chase_iris_result["results"]
|
|
22
|
-
}
|
|
19
|
+
test_results = {"results": domaintools_iris_result["results"] + int_chase_iris_result["results"]}
|
|
23
20
|
|
|
24
21
|
self.dt_res_filter = DTResultFilter(result_set=test_results)
|
|
25
22
|
|
|
26
23
|
def test_filter_by_riskscore(self):
|
|
27
24
|
"""Test domaintools filter by riskcore"""
|
|
28
|
-
|
|
25
|
+
risk_score_threshold = 69
|
|
29
26
|
|
|
30
27
|
result = self.dt_res_filter.by(
|
|
31
28
|
[
|
|
32
|
-
filter_by_riskscore(threshold=
|
|
29
|
+
filter_by_riskscore(threshold=risk_score_threshold),
|
|
33
30
|
]
|
|
34
31
|
)
|
|
35
32
|
|
|
@@ -77,9 +74,7 @@ class DTFiltersTest(unittest.TestCase):
|
|
|
77
74
|
|
|
78
75
|
results = self.dt_res_filter.by(
|
|
79
76
|
[
|
|
80
|
-
filter_by_field(
|
|
81
|
-
field=include_domains_with_missing_field, filter_type="include"
|
|
82
|
-
),
|
|
77
|
+
filter_by_field(field=include_domains_with_missing_field, filter_type="include"),
|
|
83
78
|
]
|
|
84
79
|
)
|
|
85
80
|
|
|
@@ -90,9 +85,7 @@ class DTFiltersTest(unittest.TestCase):
|
|
|
90
85
|
|
|
91
86
|
results = self.dt_res_filter.by(
|
|
92
87
|
[
|
|
93
|
-
filter_by_field(
|
|
94
|
-
field=exclude_domains_with_missing_field, filter_type="exclude"
|
|
95
|
-
),
|
|
88
|
+
filter_by_field(field=exclude_domains_with_missing_field, filter_type="exclude"),
|
|
96
89
|
]
|
|
97
90
|
)
|
|
98
91
|
|
domaintools_api-2.7.2/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
2.7.2
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{domaintools_api-2.7.2 → domaintools_api-2.7.4}/domaintools_api.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|