Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,26 @@ and this project adheres to

## [Unreleased]

## [0.2.0] - 2026-02-XX

### Added

- Async client (`AsyncClient`) with full async/await support using
httpx ([8895e58], [#28])
- Simple `search()` method accepting raw query strings on both
clients ([8895e58], [#28])
- `get_domain()` method for domain lookups ([8895e58], [#28])
- `get_api_status()` and `is_pro()` methods for account status
detection ([8895e58], [#28])
- `bulk_export_stream()` streaming generator for memory-efficient
bulk exports ([8895e58], [#28])

### Changed

- Bumped l9format from 1.3.2 to 1.4.0 ([b47ade8], [#28])
- Lowered minimum Python requirement from 3.13 to 3.11 ([8895e58],
[#28])

## [0.1.10] - 2024-12-XX

### Changed
Expand Down Expand Up @@ -38,15 +58,21 @@ and this project adheres to
- Query building with MustQuery, MustNotQuery, ShouldQuery
- Field filters: TimeField, PluginField, IPField, PortField, CountryField

[unreleased]: https://github.com/LeakIX/LeakIXClient-Python/compare/v0.1.10...HEAD
[unreleased]: https://github.com/LeakIX/LeakIXClient-Python/compare/v0.2.0...HEAD
[0.2.0]: https://github.com/LeakIX/LeakIXClient-Python/compare/v0.1.10...v0.2.0
[0.1.10]: https://github.com/LeakIX/LeakIXClient-Python/compare/v0.1.9...v0.1.10
[0.1.9]: https://github.com/LeakIX/LeakIXClient-Python/releases/tag/v0.1.9

<!-- Commit links -->
[8895e58]: https://github.com/LeakIX/LeakIXClient-Python/commit/8895e58
[b47ade8]: https://github.com/LeakIX/LeakIXClient-Python/commit/b47ade8
[65c5121]: https://github.com/LeakIX/LeakIXClient-Python/commit/65c5121
[0975c1c]: https://github.com/LeakIX/LeakIXClient-Python/commit/0975c1c
[7cb5dae]: https://github.com/LeakIX/LeakIXClient-Python/commit/7cb5dae
[b1bc0da]: https://github.com/LeakIX/LeakIXClient-Python/commit/b1bc0da
[6777ad9]: https://github.com/LeakIX/LeakIXClient-Python/commit/6777ad9
[62550bc]: https://github.com/LeakIX/LeakIXClient-Python/commit/62550bc
[4dd4948]: https://github.com/LeakIX/LeakIXClient-Python/commit/4dd4948

<!-- PR links -->
[#28]: https://github.com/LeakIX/LeakIXClient-Python/pull/28
86 changes: 86 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,48 @@ pip install leakix

To run tests, use `poetry run pytest`.

## Quick Start

```python
from leakix import Client

client = Client(api_key="your-api-key")

# Simple search - same syntax as the website
results = client.search("+plugin:GitConfigHttpPlugin", scope="leak")
for event in results.json():
print(event.ip, event.host)

# Search services
results = client.search("+country:FR +port:22", scope="service")
```

## Async Client

For async applications, use `AsyncClient`:

```python
import asyncio
from leakix import AsyncClient

async def main():
async with AsyncClient(api_key="your-api-key") as client:
# Simple search
results = await client.search("+plugin:GitConfigHttpPlugin", scope="leak")
for event in results:
print(event.ip, event.host)

# Host lookup
host = await client.get_host("8.8.8.8")
print(host["services"])

# Streaming bulk export
async for aggregation in client.bulk_export_stream(queries):
print(aggregation.events[0].ip)

asyncio.run(main())
```

## Documentation

Docstrings are used to document the library.
Expand Down Expand Up @@ -156,6 +198,46 @@ def example_get_plugins():
print(p.description)


def example_search_simple():
"""
Simple search using query string syntax (same as the website).
No need to build Query objects manually.
"""
response = CLIENT.search("+plugin:GitConfigHttpPlugin", scope="leak")
for event in response.json():
print(event.ip)


def example_search_service():
"""
Search for services with multiple filters.
"""
response = CLIENT.search("+country:FR +port:22", scope="service")
for event in response.json():
print(event.ip, event.port)


def example_get_domain():
"""
Get services and leaks for a domain.
"""
response = CLIENT.get_domain("example.com")
if response.is_success():
print("Services:", response.json()["services"])
print("Leaks:", response.json()["leaks"])


def example_bulk_stream():
"""
Streaming bulk export - memory efficient for large datasets.
Results are yielded one by one instead of loading all into memory.
"""
query = MustQuery(field=PluginField(Plugin.GitConfigHttpPlugin))
for aggregation in CLIENT.bulk_export_stream(queries=[query]):
for event in aggregation.events:
print(event.ip)


if __name__ == "__main__":
example_get_host_filter_plugin()
example_get_service_filter_plugin()
Expand All @@ -165,4 +247,8 @@ if __name__ == "__main__":
example_get_leak_plugins_with_time()
example_get_leak_raw_query()
example_get_plugins()
example_search_simple()
example_search_service()
example_get_domain()
example_bulk_stream()
```
2 changes: 2 additions & 0 deletions leakix/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from importlib.metadata import version

from leakix.async_client import AsyncClient as AsyncClient
from leakix.client import Client as Client
from leakix.client import HostResult as HostResult
from leakix.client import Scope as Scope
Expand Down Expand Up @@ -71,6 +72,7 @@

__all__ = [
"__version__",
"AsyncClient",
"Client",
"HostResult",
"L9Subdomain",
Expand Down
Loading