Skip to content

Commit 9876f8b

Browse files
authored
Merge pull request #162 from DomainTools/2.4
Merge 2.4 changes
2 parents 32f1beb + 8a616f7 commit 9876f8b

File tree

56 files changed

+864098
-1292
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+864098
-1292
lines changed

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.3.0
1+
2.4.0

domaintools/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@
2020
2121
"""
2222

23-
current = "2.3.0"
23+
current = "2.4.0"

domaintools/api.py

Lines changed: 95 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -411,38 +411,6 @@ def whois_history(self, query, mode=None, sort=None, offset=None, limit=None, **
411411
**kwargs,
412412
)
413413

414-
def phisheye(self, query, days_back=None, **kwargs):
415-
"""Returns domain results for the specified term for today or the specified number of days_back.
416-
Terms must be setup for monitoring via the web interface: https://research.domaintools.com/phisheye.
417-
418-
NOTE: Properties of a domain are only provided if we have been able to obtain them.
419-
Many domains will have incomplete data because that information isn't available in their Whois records,
420-
or they don't have DNS results for a name server or IP address.
421-
"""
422-
return self._results(
423-
"phisheye",
424-
"/v1/phisheye",
425-
query=query,
426-
days_back=days_back,
427-
items_path=("domains",),
428-
**kwargs,
429-
)
430-
431-
def phisheye_term_list(self, include_inactive=False, **kwargs):
432-
"""Provides a list of terms that are set up for this account.
433-
This call is not charged against your API usage limit.
434-
435-
NOTE: The terms must be configured in the PhishEye web interface: https://research.domaintools.com/phisheye.
436-
There is no API call to set up the terms.
437-
"""
438-
return self._results(
439-
"phisheye_term_list",
440-
"/v1/phisheye/term-list",
441-
include_inactive=include_inactive,
442-
items_path=("terms",),
443-
**kwargs,
444-
)
445-
446414
def iris(
447415
self,
448416
domain=None,
@@ -1065,7 +1033,21 @@ def iris_detect_ignored_domains(
10651033
)
10661034

10671035
def nod(self, **kwargs) -> FeedsResults:
1068-
"""Returns back list of the newly observed domains feed"""
1036+
"""Returns back list of the newly observed domains feed.
1037+
Apex-level domains (e.g. example.com but not www.example.com) that we observe for the first time, and have not observed previously with our global DNS sensor network.
1038+
1039+
domain: str: Filter for an exact domain or a substring contained within a domain by prefixing or suffixing your substring with "*". Check the documentation for examples
1040+
1041+
before: str: Filter for records before the given time value inclusive or time offset relative to now
1042+
1043+
after: str: Filter for records after the given time value inclusive or time offset relative to now
1044+
1045+
headers: bool: Use in combination with Accept: text/csv headers to control if headers are sent or not
1046+
1047+
sessionID: str: A custom string to distinguish between different sessions
1048+
1049+
top: int: Limit the number of results to the top N, where N is the value of this parameter.
1050+
"""
10691051
validate_feeds_parameters(kwargs)
10701052
endpoint = kwargs.pop("endpoint", Endpoint.FEED.value)
10711053
source = ENDPOINT_TO_SOURCE_MAP.get(endpoint)
@@ -1082,7 +1064,22 @@ def nod(self, **kwargs) -> FeedsResults:
10821064
)
10831065

10841066
def nad(self, **kwargs) -> FeedsResults:
1085-
"""Returns back list of the newly active domains feed"""
1067+
"""Returns back list of the newly active domains feed. Contains domains that have been observed after having not been seen for at least 10 days in passive DNS.
1068+
Apex-level domains (e.g. example.com but not www.example.com) that we observe based on the latest lifecycle of the domain. A domain may be seen either for the first time ever, or again after at least 10 days of inactivity (no observed resolutions in DNS).
1069+
Populated with our global passive DNS (pDNS) sensor network.
1070+
1071+
domain: str: Filter for an exact domain or a substring contained within a domain by prefixing or suffixing your substring with "*". Check the documentation for examples
1072+
1073+
before: str: Filter for records before the given time value inclusive or time offset relative to now
1074+
1075+
after: str: Filter for records after the given time value inclusive or time offset relative to now
1076+
1077+
headers: bool: Use in combination with Accept: text/csv headers to control if headers are sent or not
1078+
1079+
sessionID: str: A custom string to distinguish between different sessions
1080+
1081+
top: int: Limit the number of results to the top N, where N is the value of this parameter.
1082+
"""
10861083
validate_feeds_parameters(kwargs)
10871084
endpoint = kwargs.pop("endpoint", Endpoint.FEED.value)
10881085
source = ENDPOINT_TO_SOURCE_MAP.get(endpoint).value
@@ -1099,7 +1096,22 @@ def nad(self, **kwargs) -> FeedsResults:
10991096
)
11001097

11011098
def domainrdap(self, **kwargs) -> FeedsResults:
1102-
"""Returns changes to global domain registration information, populated by the Registration Data Access Protocol (RDAP)"""
1099+
"""Returns changes to global domain registration information, populated by the Registration Data Access Protocol (RDAP).
1100+
Compliments the 5-Minute WHOIS Feed as registries and registrars switch from Whois to RDAP.
1101+
Contains parsed and raw RDAP-format domain registration data, emitted as soon as they are collected and parsed into a normalized structure.
1102+
1103+
domain: str: Filter for an exact domain or a substring contained within a domain by prefixing or suffixing your substring with "*". Check the documentation for examples
1104+
1105+
before: str: Filter for records before the given time value inclusive or time offset relative to now
1106+
1107+
after: str: Filter for records after the given time value inclusive or time offset relative to now
1108+
1109+
headers: bool: Use in combination with Accept: text/csv headers to control if headers are sent or not
1110+
1111+
sessionID: str: A custom string to distinguish between different sessions
1112+
1113+
top: int: Limit the number of results to the top N, where N is the value of this parameter.
1114+
"""
11031115
validate_feeds_parameters(kwargs)
11041116
endpoint = kwargs.pop("endpoint", Endpoint.FEED.value)
11051117
source = ENDPOINT_TO_SOURCE_MAP.get(endpoint).value
@@ -1113,7 +1125,22 @@ def domainrdap(self, **kwargs) -> FeedsResults:
11131125
)
11141126

11151127
def domaindiscovery(self, **kwargs) -> FeedsResults:
1116-
"""Returns new domains as they are either discovered in domain registration information, observed by our global sensor network, or reported by trusted third parties"""
1128+
"""Returns new domains as they are either discovered in domain registration information, observed by our global sensor network, or reported by trusted third parties".
1129+
Contains domains that are newly-discovered by Domain Tools in both passive and active DNS sources, emitted as soon as they are first observed.
1130+
New domains as they are either discovered in domain registration information, observed by our global sensor network, or reported by trusted third parties.
1131+
1132+
domain: str: Filter for an exact domain or a substring contained within a domain by prefixing or suffixing your substring with "*". Check the documentation for examples
1133+
1134+
before: str: Filter for records before the given time value inclusive or time offset relative to now
1135+
1136+
after: str: Filter for records after the given time value inclusive or time offset relative to now
1137+
1138+
headers: bool: Use in combination with Accept: text/csv headers to control if headers are sent or not
1139+
1140+
sessionID: str: A custom string to distinguish between different sessions
1141+
1142+
top: int: Limit the number of results to the top N, where N is the value of this parameter.
1143+
"""
11171144
validate_feeds_parameters(kwargs)
11181145
endpoint = kwargs.pop("endpoint", Endpoint.FEED.value)
11191146
source = ENDPOINT_TO_SOURCE_MAP.get(endpoint).value
@@ -1128,3 +1155,35 @@ def domaindiscovery(self, **kwargs) -> FeedsResults:
11281155
cls=FeedsResults,
11291156
**kwargs,
11301157
)
1158+
1159+
def noh(self, **kwargs) -> FeedsResults:
1160+
"""Returns back list of the newly observed hostnames feed.
1161+
Contains fully qualified domain names (i.e. host names) that have never been seen before in passive DNS, emitted as soon as they are first observed.
1162+
Hostname resolutions that we observe for the first time with our global DNS sensor network.
1163+
1164+
domain: str: Filter for an exact domain or a substring contained within a domain by prefixing or suffixing your substring with "*". Check the documentation for examples
1165+
1166+
before: str: Filter for records before the given time value inclusive or time offset relative to now
1167+
1168+
after: str: Filter for records after the given time value inclusive or time offset relative to now
1169+
1170+
headers: bool: Use in combination with Accept: text/csv headers to control if headers are sent or not
1171+
1172+
sessionID: str: A custom string to distinguish between different sessions
1173+
1174+
top: int: Limit the number of results to the top N, where N is the value of this parameter.
1175+
"""
1176+
validate_feeds_parameters(kwargs)
1177+
endpoint = kwargs.pop("endpoint", Endpoint.FEED.value)
1178+
source = ENDPOINT_TO_SOURCE_MAP.get(endpoint).value
1179+
if endpoint == Endpoint.DOWNLOAD.value or kwargs.get("output_format", OutputFormat.JSONL.value) != OutputFormat.CSV.value:
1180+
# headers param is allowed only in Feed API and CSV format
1181+
kwargs.pop("headers", None)
1182+
1183+
return self._results(
1184+
f"newly-observed-hosts-feed-({source})",
1185+
f"v1/{endpoint}/noh/",
1186+
response_path=(),
1187+
cls=FeedsResults,
1188+
**kwargs,
1189+
)

domaintools/cli/commands/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,5 @@
22
from .iris import *
33
from .domains import *
44
from .ips import *
5-
from .phisheye import *
65
from .detects import *
76
from .feeds import *

domaintools/cli/commands/feeds.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,3 +314,83 @@ def feeds_domaindiscovery(
314314
),
315315
):
316316
DTCLICommand.run(name=c.FEEDS_DOMAINDISCOVERY, params=ctx.params)
317+
318+
319+
@dt_cli.command(
320+
name=c.FEEDS_NOH,
321+
help=get_cli_helptext_by_name(command_name=c.FEEDS_NOH),
322+
)
323+
def feeds_noh(
324+
ctx: typer.Context,
325+
user: str = typer.Option(None, "-u", "--user", help="Domaintools API Username."),
326+
key: str = typer.Option(None, "-k", "--key", help="DomainTools API key"),
327+
creds_file: str = typer.Option(
328+
"~/.dtapi",
329+
"-c",
330+
"--credfile",
331+
help="Optional file with API username and API key, one per line.",
332+
),
333+
no_verify_ssl: bool = typer.Option(
334+
False,
335+
"--no-verify-ssl",
336+
help="Skip verification of SSL certificate when making HTTPs API calls",
337+
),
338+
no_sign_api_key: bool = typer.Option(
339+
False,
340+
"--no-sign-api-key",
341+
help="Skip signing of api key",
342+
),
343+
header_authentication: bool = typer.Option(
344+
True,
345+
"--no-header-auth",
346+
help="Don't use header authentication",
347+
),
348+
output_format: str = typer.Option(
349+
"jsonl",
350+
"-f",
351+
"--format",
352+
help=f"Output format in [{OutputFormat.JSONL.value}, {OutputFormat.CSV.value}]",
353+
callback=DTCLICommand.validate_feeds_format_input,
354+
),
355+
endpoint: str = typer.Option(
356+
Endpoint.FEED.value,
357+
"-e",
358+
"--endpoint",
359+
help=f"Valid endpoints: [{Endpoint.FEED.value}, {Endpoint.DOWNLOAD.value}]",
360+
callback=DTCLICommand.validate_endpoint_input,
361+
),
362+
sessionID: str = typer.Option(
363+
None,
364+
"--session-id",
365+
help="Unique identifier for the session",
366+
),
367+
after: str = typer.Option(
368+
None,
369+
"--after",
370+
help="Start of the time window, relative to the current time in seconds, for which data will be provided",
371+
callback=DTCLICommand.validate_after_or_before_input,
372+
),
373+
before: str = typer.Option(
374+
None,
375+
"--before",
376+
help="The end of the query window in seconds, relative to the current time, inclusive",
377+
callback=DTCLICommand.validate_after_or_before_input,
378+
),
379+
domain: str = typer.Option(
380+
None,
381+
"-d",
382+
"--domain",
383+
help="A string value used to filter feed results",
384+
),
385+
headers: bool = typer.Option(
386+
False,
387+
"--headers",
388+
help="Adds a header to the first line of response when text/csv is set in header parameters",
389+
),
390+
top: str = typer.Option(
391+
None,
392+
"--top",
393+
help="Number of results to return in the response payload. This is ignored in download endpoint",
394+
),
395+
):
396+
DTCLICommand.run(name=c.FEEDS_NOH, params=ctx.params)

domaintools/cli/commands/phisheye.py

Lines changed: 0 additions & 100 deletions
This file was deleted.

domaintools/cli/constants.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,9 @@
3939
IRIS_DETECT_ESCALATE_DOMAINS = "iris_detect_escalate_domains"
4040
IRIS_DETECT_IGNORED_DOMAINS = "iris_detect_ignored_domains"
4141

42-
# phisheye
43-
PHISHEYE = "phisheye"
44-
PHISHEYE_TERM_LIST = "phisheye_term_list"
45-
4642
# feeds
4743
FEEDS_NAD = "nad"
4844
FEEDS_NOD = "nod"
45+
FEEDS_NOH = "noh"
4946
FEEDS_DOMAINRDAP = "domainrdap"
5047
FEEDS_DOMAINDISCOVERY = "domaindiscovery"

0 commit comments

Comments
 (0)