Skip to content

Commit 147875d

Browse files
authored
Merge pull request #30 from feedly/older-than-iocs-downloader
IoCDownloader: older_than param
2 parents 4faea80 + 25a9ccb commit 147875d

File tree

2 files changed

+57
-14
lines changed

2 files changed

+57
-14
lines changed

feedly/api_client/enterprise/indicators_of_compromise.py

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
from datetime import datetime
55
from enum import Enum
66
from itertools import chain
7+
from requests import Response
78
from typing import ClassVar, Dict, Generic, Iterable, List, Optional, TypeVar
89
from urllib.parse import parse_qs
9-
from requests import Response
1010

1111
from feedly.api_client.data import Streamable
1212
from feedly.api_client.session import FeedlySession
@@ -24,38 +24,61 @@ class IoCDownloaderABC(ABC, Generic[T]):
2424
RELATIVE_URL = "/v3/enterprise/ioc"
2525
FORMAT: ClassVar[str]
2626

27-
def __init__(self, session: FeedlySession, newer_than: Optional[datetime], stream_id: str):
27+
def __init__(
28+
self,
29+
session: FeedlySession,
30+
newer_than: Optional[datetime],
31+
older_than: Optional[datetime],
32+
stream_id: str,
33+
max_batches: Optional[int] = None,
34+
):
2835
"""
2936
Use this class to export the contextualized IoCs from a stream.
3037
Enterprise/personals feeds/boards are supported (see dedicated methods below).
3138
The IoCs will be returned along with their context and relationships in a dictionary representing a valid
3239
STIX v2.1 Bundle object. https://docs.oasis-open.org/cti/stix/v2.1/os/stix-v2.1-os.html#_gms872kuzdmg
3340
Use the newer_than parameter to filter articles that are newer than your last call.
41+
Use the older_than parameter to filter articles that are older than your last call.
42+
Use the max_batches parameter to limit the number of batches/pages to retrieve.
3443
3544
:param session: The authenticated session to use to make the api calls
3645
:param newer_than: Only articles newer than this parameter will be used. If None only one call will be make,
3746
and the continuation will be ignored
47+
:param older_than: Only articles older than this parameter will be used. If None only one call will be make,
48+
and the continuation will be ignored
49+
:param max_batches: Maximum number of batches to retrieve. If None, will continue until no more data is available
3850
"""
3951
self.newer_than = newer_than
52+
self.older_than = older_than
4053
self.session = session
4154
self.stream_id = stream_id
55+
self.max_batches = max_batches
4256

4357
def download_all(self) -> List[T]:
4458
return self._merge(self.stream_bundles())
4559

4660
def stream_bundles(self) -> Iterable[T]:
4761
continuation = None
62+
batch_count = 0
4863
while True:
49-
resp = self.session.make_api_request(
50-
f"{self.RELATIVE_URL}",
51-
params={
52-
"newerThan": int(self.newer_than.timestamp()) if self.newer_than else None,
53-
"continuation": continuation,
54-
"streamId": self.stream_id,
55-
"format": self.FORMAT,
56-
},
57-
)
64+
params = {
65+
"continuation": continuation,
66+
"streamId": self.stream_id,
67+
"format": self.FORMAT,
68+
}
69+
if self.newer_than:
70+
params["newerThan"] = int(self.newer_than.timestamp())
71+
if self.older_than:
72+
params["olderThan"] = int(self.older_than.timestamp())
73+
74+
resp = self.session.make_api_request(f"{self.RELATIVE_URL}", params=params)
5875
yield self._parse_response(resp)
76+
batch_count += 1
77+
78+
# Check if we've reached max_batches limit
79+
if self.max_batches and batch_count >= self.max_batches:
80+
return
81+
5982
if not self.newer_than or "link" not in resp.headers:
6083
return
6184
next_url = resp.headers["link"][1:].split(">")[0]
@@ -70,21 +93,35 @@ def _merge(self, resp_jsons: Iterable[T]) -> T:
7093

7194

7295
class IoCDownloaderBuilder:
73-
def __init__(self, session: FeedlySession, format: IoCFormat, newer_than: Optional[datetime] = None):
96+
def __init__(
97+
self,
98+
session: FeedlySession,
99+
format: IoCFormat,
100+
newer_than: Optional[datetime] = None,
101+
older_than: Optional[datetime] = None,
102+
max_batches: Optional[int] = None,
103+
):
74104
"""
75105
Use this class to export the contextualized IoCs from a stream.
76106
Enterprise/personals feeds/boards are supported (see dedicated methods below).
77107
The IoCs will be returned along with their context and relationships in a dictionary representing a valid
78108
STIX v2.1 Bundle object. https://docs.oasis-open.org/cti/stix/v2.1/os/stix-v2.1-os.html#_gms872kuzdmg
79109
Use the newer_than parameter to filter articles that are newer than your last call.
110+
Use the older_than parameter to filter articles that are older than your last call.
111+
Use the max_batches parameter to limit the number of batches/pages to retrieve.
80112
81113
:param session: The authenticated session to use to make the api calls
82114
:param newer_than: Only articles newer than this parameter will be used. If None only one call will be make,
83115
and the continuation will be ignored
116+
:param older_than: Only articles older than this parameter will be used. If None only one call will be make,
117+
and the continuation will be ignored
118+
:param max_batches: Maximum number of batches to retrieve. If None, will continue until no more data is available
84119
"""
85120
self.session = session
86121
self.format = format
87122
self.newer_than = newer_than
123+
self.older_than = older_than
124+
self.max_batches = max_batches
88125

89126
self.session.api_host = "https://cloud.feedly.com"
90127
self.user = self.session.user
@@ -113,7 +150,13 @@ def from_stream_id(self, stream_id: str) -> IoCDownloaderABC:
113150
IoCFormat.STIX: StixIoCDownloader,
114151
IoCFormat.CSV: CsvIoCDownloader,
115152
}
116-
return format2class[self.format](session=self.session, newer_than=self.newer_than, stream_id=stream_id)
153+
return format2class[self.format](
154+
session=self.session,
155+
newer_than=self.newer_than,
156+
older_than=self.older_than,
157+
stream_id=stream_id,
158+
max_batches=self.max_batches,
159+
)
117160

118161

119162
class StixIoCDownloader(IoCDownloaderABC[Dict]):

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
1919
AUTHOR = "Feedly"
2020
REQUIRES_PYTHON = ">=3.6.0"
21-
VERSION = "0.26"
21+
VERSION = "0.27"
2222

2323
# What packages are required for this module to be executed?
2424
with open("requirements.txt") as f:

0 commit comments

Comments
 (0)