diff options
| author | Louis Burda <dev@sinitax.com> | 2026-01-27 03:31:54 +0100 |
|---|---|---|
| committer | Louis Burda <dev@sinitax.com> | 2026-01-27 03:31:54 +0100 |
| commit | c6625238403d8ea2957bc91ea3e0f04090cbd5aa (patch) | |
| tree | ae85a763ac1b2bdaa3897f4ecf3252489839dd72 /src/vulners/api.py | |
| download | vulners-py-main.tar.gz vulners-py-main.zip | |
Diffstat (limited to 'src/vulners/api.py')
| -rw-r--r-- | src/vulners/api.py | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/src/vulners/api.py b/src/vulners/api.py new file mode 100644 index 0000000..2c0fdbd --- /dev/null +++ b/src/vulners/api.py @@ -0,0 +1,74 @@ +import os +from dataclasses import dataclass +from typing import Any + +import httpx + +BASE_URL = "https://vulners.com/api/v3" + + +@dataclass +class VulnersClient: + api_key: str | None = None + timeout: float = 30.0 + + def __post_init__(self): + if not self.api_key: + self.api_key = os.environ.get("VULNERS_API_KEY") + + def _request(self, endpoint: str, payload: dict[str, Any]) -> dict[str, Any]: + headers = {"Content-Type": "application/json"} + if self.api_key: + headers["X-Api-Key"] = self.api_key + + with httpx.Client(timeout=self.timeout) as client: + resp = client.post(f"{BASE_URL}{endpoint}", headers=headers, json=payload) + resp.raise_for_status() + return resp.json() + + def search( + self, + query: str, + size: int = 10, + skip: int = 0, + fields: list[str] | None = None, + ) -> dict[str, Any]: + payload = {"query": query, "size": size, "skip": skip} + if fields: + payload["fields"] = fields + return self._request("/search/lucene/", payload) + + def get_cve(self, cve_id: str) -> dict[str, Any]: + return self.search(f"id:{cve_id}", size=1) + + def search_cpe( + self, + vendor: str | None = None, + product: str | None = None, + version: str | None = None, + size: int = 10, + ) -> dict[str, Any]: + parts = [] + if vendor: + parts.append(f"cpe.vendor:{vendor}") + if product: + parts.append(f"cpe.product:{product}") + if version: + parts.append(f"cpe.version:{version}") + query = " AND ".join(parts) if parts else "*" + return self.search(query, size=size) + + def software_vulns( + self, + software: str, + version: str | None = None, + max_vulns: int = 20, + ) -> dict[str, Any]: + payload = { + "software": software, + "type": "software", + "maxVulnerabilities": max_vulns, + } + if version: + payload["version"] = version + return self._request("/burp/softwareapi/", payload) |
