Skip to content

Commit 91c65ab

Browse files
committed
Feat: Add search(), get_domain(), and streaming bulk_export_stream()
1 parent fe51f15 commit 91c65ab

1 file changed

Lines changed: 47 additions & 1 deletion

File tree

leakix/client.py

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import json
2+
from collections.abc import Iterator
23
from enum import Enum
3-
from typing import Any
4+
from typing import Any, cast
45

56
import requests
67
from l9format import l9format
@@ -173,3 +174,48 @@ def bulk_service(
173174
return SuccessResponse(response=r, response_json=[])
174175
else:
175176
return ErrorResponse(response=r, response_json=r.json())
177+
178+
def get_domain(self, domain: str) -> AbstractResponse:
179+
"""
180+
Returns the list of services and associated leaks for a given domain.
181+
"""
182+
url = f"{self.base_url}/domain/{domain}"
183+
return self._parse_host_result(self.__get(url, params=None))
184+
185+
def search(
186+
self, query: str, scope: Scope = Scope.LEAK, page: int = 0
187+
) -> AbstractResponse:
188+
"""
189+
Simple search using a raw query string (same syntax as the website).
190+
191+
Example:
192+
>>> client.search("+plugin:GitConfigHttpPlugin", scope=Scope.LEAK)
193+
>>> client.search("+country:FR +port:22", scope=Scope.SERVICE)
194+
"""
195+
if page < 0:
196+
raise ValueError("Page argument must be a positive integer")
197+
url = f"{self.base_url}/search"
198+
r = self.__get(
199+
url=url,
200+
params={"scope": scope.value, "q": query, "page": page},
201+
)
202+
return self._parse_events(r)
203+
204+
def bulk_export_stream(
205+
self, queries: list[AbstractQuery] | None = None
206+
) -> Iterator[l9format.L9Aggregation]:
207+
"""
208+
Streaming version of bulk_export. Yields L9Aggregation objects one by one.
209+
More memory efficient for large result sets.
210+
"""
211+
url = f"{self.base_url}/bulk/search"
212+
params = {"q": serialize_queries(queries)}
213+
r = requests.get(url, params=params, headers=self.headers, stream=True)
214+
if r.status_code != 200:
215+
return
216+
for line in r.iter_lines():
217+
json_event = json.loads(line)
218+
yield cast(
219+
l9format.L9Aggregation,
220+
l9format.L9Aggregation.from_dict(json_event),
221+
)

0 commit comments

Comments
 (0)