Skip to content

Commit 58eb831

Browse files
authored
Merge pull request #197 from DomainTools/IDEV-2478-add-domain-history
IDEV-2478: Add domain history
2 parents b0341cd + 406fb4f commit 58eb831

6 files changed

Lines changed: 251 additions & 0 deletions

File tree

domaintools/api.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,57 @@ def domain_profile(self, query, **kwargs):
275275
"""Returns a profile for the specified domain name"""
276276
return self._results("domain-profile", "/v1/{0}".format(query))
277277

278+
def domain_history(
279+
self,
280+
query,
281+
include_fields=None,
282+
exclude_fields=None,
283+
page_size=None,
284+
offset=None,
285+
next=None,
286+
parsed_whois=None,
287+
parsed_domain_rdap=None,
288+
**kwargs,
289+
):
290+
"""Returns the history of changes for a given domain name.
291+
292+
Results are returned in reverse chronological order. Each change event includes
293+
a timestamp, the field that changed, and the complete before/after domain state.
294+
295+
Args:
296+
query: The apex domain name to retrieve history for (e.g. "domaintools.com").
297+
include_fields: Comma-separated list of exact field names. Only change events
298+
matching these fields appear in results. Cannot be combined with
299+
exclude_fields. Supports aggregate prefixes (e.g. "all_ssl", "all_ip").
300+
Example: "ip,registrar,all_ssl"
301+
exclude_fields: Comma-separated list of exact field names. Change events
302+
matching these fields are omitted. Cannot be combined with include_fields.
303+
Example: "all_web_trackers,all_ssl"
304+
page_size: Number of change events per page. Maximum and default is 100.
305+
offset: 0-indexed starting point for pagination. Increment by page_size for
306+
each subsequent page.
307+
next: When True, includes a next URL in the response for cursor-based
308+
pagination. Auth parameters must still be included when following it.
309+
parsed_whois: When True, includes the full parsed WHOIS record in the
310+
before/after objects of each change event.
311+
parsed_domain_rdap: When True, includes the full parsed Domain RDAP record
312+
in the before/after objects of each change event.
313+
"""
314+
return self._results(
315+
"domain-history",
316+
"/v1/domain-history",
317+
domain=query,
318+
include_fields=include_fields,
319+
exclude_fields=exclude_fields,
320+
page_size=page_size,
321+
offset=offset,
322+
next=next,
323+
parsed_whois=parsed_whois,
324+
parsed_domain_rdap=parsed_domain_rdap,
325+
items_path=("changes",),
326+
**kwargs,
327+
)
328+
278329
def domain_search(
279330
self,
280331
query,

domaintools/cli/commands/domains.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,51 @@ def domain_profile(
8787
DTCLICommand.run(name=c.DOMAIN_PROFILE, params=ctx.params)
8888

8989

90+
@dt_cli.command(
91+
name=c.DOMAIN_HISTORY,
92+
help=get_cli_helptext_by_name(command_name=c.DOMAIN_HISTORY),
93+
)
94+
def domain_history(
95+
ctx: typer.Context,
96+
query: str = typer.Option(..., "-q", "--query", help="The apex domain name to retrieve history for (e.g. domaintools.com)."),
97+
include_fields: str = typer.Option(None, "--include-fields", help="Comma-separated list of exact field names. Only change events matching these fields appear in results. Cannot be combined with --exclude-fields. Example: ip,registrar,all_ssl"),
98+
exclude_fields: str = typer.Option(None, "--exclude-fields", help="Comma-separated list of exact field names. Change events matching these fields are omitted. Cannot be combined with --include-fields. Example: all_web_trackers,all_ssl"),
99+
page_size: int = typer.Option(None, "--page-size", help="Number of change events per page. Maximum is 100 (default: 100)."),
100+
offset: int = typer.Option(None, "--offset", help="0-indexed starting point for pagination. Increment by page-size for each subsequent page."),
101+
next: bool = typer.Option(None, "--next", help="When true, includes a next URL in the response for cursor-based pagination."),
102+
parsed_whois: bool = typer.Option(None, "--parsed-whois", help="When true, includes the full parsed WHOIS record in the before/after objects of each change event."),
103+
parsed_domain_rdap: bool = typer.Option(None, "--parsed-domain-rdap", help="When true, includes the full parsed Domain RDAP record in the before/after objects of each change event."),
104+
user: str = typer.Option(None, "-u", "--user", help="Domaintools API Username."),
105+
key: str = typer.Option(None, "-k", "--key", help="DomainTools API key"),
106+
creds_file: str = typer.Option(
107+
"~/.dtapi",
108+
"-c",
109+
"--credfile",
110+
help="Optional file with API username and API key, one per line.",
111+
),
112+
rate_limit: bool = typer.Option(
113+
False,
114+
"-l",
115+
"--rate-limit",
116+
help="Rate limit API calls against the API based on per minute limits.",
117+
),
118+
format: str = typer.Option(
119+
"json",
120+
"-f",
121+
"--format",
122+
help="Output format in {'list', 'json', 'xml', 'html'}",
123+
callback=DTCLICommand.validate_format_input,
124+
),
125+
out_file: typer.FileTextWrite = typer.Option(sys.stdout, "-o", "--out-file", help="Output file (defaults to stdout)"),
126+
no_verify_ssl: bool = typer.Option(
127+
False,
128+
"--no-verify-ssl",
129+
help="Skip verification of SSL certificate when making HTTPs API calls",
130+
),
131+
):
132+
DTCLICommand.run(name=c.DOMAIN_HISTORY, params=ctx.params)
133+
134+
90135
@dt_cli.command(
91136
name=c.DOMAIN_SEARCH,
92137
help=get_cli_helptext_by_name(command_name=c.DOMAIN_SEARCH),
@@ -666,6 +711,7 @@ def risk_evidence(
666711

667712
__all__ = [
668713
"brand_monitor",
714+
"domain_history",
669715
"domain_profile",
670716
"domain_search",
671717
"name_server_monitor",

domaintools/cli/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
# domains
66
BRAND_MONITOR = "brand_monitor"
7+
DOMAIN_HISTORY = "domain_history"
78
DOMAIN_PROFILE = "domain_profile"
89
DOMAIN_SEARCH = "domain_search"
910
HOSTING_HISTORY = "hosting_history"

domaintools/cli/utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ def _iris_investigate_helptext():
3535
c.IRIS_INVESTIGATE: _iris_investigate_helptext(),
3636
c.IRIS_ENRICH: "Returns back enriched data related to the specified domains using our Iris Enrich service.",
3737
c.BRAND_MONITOR: "Pass in one or more terms as a list or separated by the pipe character ( | )",
38+
c.DOMAIN_HISTORY: "Returns the history of changes for a given domain name.",
3839
c.DOMAIN_PROFILE: "Returns a profile for the specified domain name",
3940
c.DOMAIN_SEARCH: """Each term in the query string must be at least three characters long. Pass in a list or use spaces to separate multiple terms.""",
4041
c.HOSTING_HISTORY: "Returns the hosting history from the given domain name.",

0 commit comments

Comments
 (0)