Skip to content

Commit 54c9ea7

Browse files
authored
Merge pull request #208 from DomainTools/release-v2.10.0
DT Python Wrapper Release v2.10.0
2 parents a323b3f + 2362de3 commit 54c9ea7

58 files changed

Lines changed: 12650 additions & 237 deletions

Some content is hidden

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

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
### 2.10.0
4+
- [NEW] Support HMAC signature authentication for feed endpoints and CLI (`--no-sign-api-key`).
5+
- [UPDATE] Officially support all available feed parameters and CLI options across real-time threat feed endpoints (including `--frombeginning`, risk filters, and IP-specific filters).
6+
- [FIX] Prevent authentication credentials from being passed as plain-text query parameters when header or HMAC authentication is enabled.
7+
- [FIX] Remove incorrect requirement for `sessionID`, `after`, or `before` parameters when using the feed download endpoint.
8+
39
### 2.9.0
410
- [NEW] Add support for querying real-time IP feeds (`iphotlist` and `iprisk`).
511
- [FIX] Type hint used for `top` parameter in Feeds API from str to int.

PYTHON_SUPPORT.md

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,20 @@
22

33
## Policy
44

5-
The DomainTools API library will support all versions of Python that are actively maintained by the Python
5+
The DomainTools API library will support all versions of Python that are actively maintained by the Python
66
Software Foundation. When a version of Python enters End of Life (EOL), the API library will also end support
7-
for that version of Python.
7+
for that version of Python.
88

9-
When a version's End of Life date is reached, DomainTools will ensure that a release of the API library that
9+
When a version's End of Life date is reached, DomainTools will ensure that a release of the API library that
1010
contains all changes up to that point in time is available. If a release already exists that has all
11-
changes at the point of a version's EOL date, no new one will be made. Any changes (features, bugfixes, etc)
11+
changes at the point of a version's EOL date, no new one will be made. Any changes (features, bugfixes, etc)
1212
released after an EOL date will not be tested on the now-unsupported version.
1313

14-
Versions of Python from other organizations (e.g. cython, pypy, jython) will not be actively supported. DomainTools
15-
will not develop specifically for those versions of Python, but we welcome community assistance (such as pull
14+
Versions of Python from other organizations (e.g. cython, pypy, jython) will not be actively supported. DomainTools
15+
will not develop specifically for those versions of Python, but we welcome community assistance (such as pull
1616
requests) to support them.
1717

18-
### Python 2
1918

20-
DomainTools API library support for Python 2.7 (and all Python 2) will end on November 30, 2020.
19+
### Python >=3.9
2120

22-
### Python 3.5
23-
24-
DomainTools will continue to support Python 3.5 until November 30, 2020.
25-
26-
## Upcoming Timeline:
27-
28-
- Support for Python 2.7 will end on Nov 30, 2020
29-
- Support for Python 3.5 will end on Nov 30, 2020
21+
DomainTools currently supports Python 3.9 and above.

README.md

Lines changed: 89 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,19 @@ Please see the [supported versions](https://github.com/DomainTools/python_api/ra
253253
for the DomainTools Python support policy.
254254

255255

256+
Authentication
257+
===================
258+
259+
The wrapper supports two authentication modes, selected automatically based on the product:
260+
261+
| Product | Default method | Params sent |
262+
|---|---|---|
263+
| Standard API (Iris, Whois, etc.) | HMAC-SHA256 signed | `api_username`, `timestamp`, `signature` as query params |
264+
| Real-Time Threat Feeds (RTTF) | Header authentication | `X-Api-Key` header |
265+
266+
RTTF feeds also support HMAC signing as an opt-in via `always_sign_api_key=True` — see the RTTF section below.
267+
268+
256269
Real-Time Threat Feeds
257270
===================
258271

@@ -264,18 +277,24 @@ Custom parameters aside from the common `GET` Request parameters:
264277
api = API(USERNAME, KEY)
265278
api.nod(endpoint="feed", **kwargs)
266279
```
267-
- `header_authentication`: by default, we're using API Header Authentication. Set this False if you want to use API Key and Secret Authentication. Apparently, you can't use API Header Authentication for `download` endpoints so this will be defaulted to `False` even without explicitly setting it.
280+
- `header_authentication`: by default, all RTTF endpoints (both `feed` and `download`) use API Header Authentication, sending the API key via the `X-Api-Key` header. Set this to `False` to pass the API key as a query parameter instead.
268281
```python
269282
api = API(USERNAME, KEY, header_authentication=False)
270283
api.nod(**kwargs)
271284
```
285+
- `always_sign_api_key`: set to `True` to use HMAC-SHA256 signed authentication instead of header auth. When set, `header_authentication` automatically defaults to `False` — both methods do not fire simultaneously. The signing algorithm is identical to the standard API: `HMAC-SHA256(key, username + timestamp + path)`, with `timestamp` and `signature` sent as query parameters.
286+
```python
287+
api = API(USERNAME, KEY, always_sign_api_key=True)
288+
api.nod(after="-60")
289+
# sends: api_username, timestamp, signature — no X-Api-Key header
290+
```
272291
- `output_format`: (choose either `csv` or `jsonl` - default is `jsonl`). Cannot be used in `domainrdap` feeds. Additionally, `csv` is not available for `download` endpoints.
273292
```python
274293
api = API(USERNAME, KEY)
275294
api.nod(output_format="csv", **kwargs)
276295
```
277296

278-
The Feed API standard access pattern is to periodically request the most recent feed data, as often as every 60 seconds. Specify the range of data you receive in one of two ways:
297+
The `feed` endpoint streams live NDJSON data. The standard access pattern is to poll as often as every 60 seconds. Specify the range of data you receive in one of two ways:
279298

280299
1. With `sessionID`: Make a call and provide a new `sessionID` parameter of your choosing. The API will return the last hour of data by default.
281300
- Each subsequent call to the API using your `sessionID` will return all data since the last.
@@ -284,9 +303,75 @@ The Feed API standard access pattern is to periodically request the most recent
284303
- Either an `after=-60` query parameter, where (in this example) -60 indicates the previous 60 seconds.
285304
- Or `after` and `before` query parameters for a time range, with each parameter accepting an ISO-8601 UTC formatted timestamp (a UTC date and time of the format YYYY-MM-DDThh:mm:ssZ)
286305

287-
## Handling iterative response from RTUF endpoints:
306+
The `download` endpoint returns a standard JSON response (not a stream) listing available S3 batch files. Time parameters (`sessionID`, `after`, `before`) are **not** required for download calls.
307+
308+
```python
309+
api = API(USERNAME, KEY)
310+
result = api.nod(endpoint="download", limit=5)
311+
print(result["download_name"])
312+
for f in result["files"]:
313+
print(f["name"], f["url"])
314+
```
315+
316+
### Feed parameters
317+
318+
The feed methods accept the following parameters, grouped by purpose. Availability depends on the feed (see the notes below the table).
319+
320+
#### Session Management Parameters
321+
322+
- `sessionID`: A custom string used to distinguish between different sessions. Required when using `fromBeginning`.
323+
- `after`: Start of the query window. Either an integer offset relative to now in seconds (e.g. `-60`), or an absolute ISO 8601 UTC datetime (`YYYY-MM-DDTHH:MM:SSZ`).
324+
- `before`: End of the query window (inclusive). Either an integer from `-1` to `-432000` (seconds before now), or an absolute ISO 8601 UTC datetime. The query window covers at most the most recent 5 days; a value older than 5 days returns no records.
325+
- `fromBeginning`: Boolean (`true`/`false`/`1`/`0`, default `false`). Requires a valid `sessionID`. When `true` on the first request of a new session, returns the first hour of data in the time window instead of the last. Using it with an existing `sessionID` returns an HTTP 406; using it without a `sessionID` or with a non-boolean value returns an HTTP 422.
326+
327+
```python
328+
api = API(USERNAME, KEY)
329+
api.nod(sessionID="my-new-session-id", after=-3600, fromBeginning=True)
330+
```
331+
332+
#### Filter Parameters
333+
334+
- `domain`: Filter for an exact domain or a substring contained within a domain by prefixing or suffixing your substring with `*`.
335+
- `overall_min`, `malware_min`, `phishing_min`, `spam_min`, `proximity_min`: Integer risk score thresholds (range `1` to `99`, optional). Available on the `realtime_domain_risk` and `domainhotlist` feeds only. When multiple are supplied they act as a logical AND — a domain must meet ALL specified thresholds to be returned.
336+
337+
```python
338+
api = API(USERNAME, KEY)
339+
api.domainhotlist(after=-3600, overall_min=70, phishing_min=50)
340+
```
341+
342+
- IP feed filters (available on the `iprisk` and `iphotlist` feeds only). All are optional integers/strings and combine as a logical AND:
343+
- Domain activity & volume: `pdns_resolutions_min`, `bad_pdns_resolutions_min` (positive integers, distinct/bad domains resolving to the IP in the last 24 hours) and `total_domains_max` (positive integer; caps total hosted domains to filter out superhosters like CDNs).
344+
- Threat intelligence & combined risk percentages: `third_party_threats_min` (positive integer), plus `all_threats_combined_percent_min`, `combined_phishing_percent_min`, `combined_malware_percent_min`, `combined_spam_percent_min` (percentages `0` to `100` of hosted domains confirmed or predicted malicious).
345+
- Confirmed threat percentages: `all_threats_percent_min`, `percent_phishing_min`, `percent_malware_min`, `percent_spam_min` (percentages `0` to `100` of hosted domains actively confirmed).
346+
- Infrastructure & geolocation: `asn` (integer, digits only — no `AS` prefix or wildcards), `organization` (exact name, no wildcards) and `country_code` (case-sensitive two-letter code, e.g. `CN`, `US`, `NL`).
347+
348+
```python
349+
api = API(USERNAME, KEY)
350+
api.iprisk(after=-3600, bad_pdns_resolutions_min=5, total_domains_max=1000, country_code="US")
351+
```
352+
353+
#### Result formatting parameters
354+
355+
- `output_format`: `csv` or `jsonl` (default `jsonl`). Not available on the `domainrdap` feed. `csv` is not available for `download` endpoints.
356+
- `headers`: When `csv` output is used, adds a header row to the first line of the response.
357+
- `top`: Positive integer from `1` to `1,000,000,000` limiting the number of results in the response payload. Ignored for the `download` endpoint.
358+
359+
#### Download-only parameters
360+
361+
These parameters are only accepted when `endpoint="download"`. They are ignored for the `feed` endpoint.
362+
363+
- `limit`: Maximum number of files to return in the response.
364+
- `page`: Zero-indexed page of results to return. Available on `realtime_domain_risk`, `domainhotlist`, `iphotlist`, and `iprisk`.
365+
- `prefix`: Filter files by date prefix (e.g. `"2026-08-"`). Available on `realtime_domain_risk`, `domainhotlist`, `iphotlist`, and `iprisk`.
366+
367+
```python
368+
api = API(USERNAME, KEY)
369+
api.iphotlist(endpoint="download", limit=10, page=0, prefix="2026-08-")
370+
```
371+
372+
## Handling iterative response from RTTF endpoints:
288373

289-
Since we may dealing with large feeds datasets, the python wrapper uses `generator` for efficient memory handling. Therefore, we need to iterate through the `generator` if we're accessing the partial results of the feeds data.
374+
Since we may be dealing with large feeds datasets, the python wrapper uses `generator` for efficient memory handling. Therefore, we need to iterate through the `generator` if we're accessing the partial results of the feeds data.
290375

291376
### Single request because the requested data is within the maximum result:
292377
```python

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.9.0
1+
2.10.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.9.0"
23+
current = "2.10.0"

0 commit comments

Comments
 (0)