crowdsec-tracker-api 1.92.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Crowdsec
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,35 @@
1
+ Metadata-Version: 2.4
2
+ Name: crowdsec_tracker_api
3
+ Version: 1.92.0
4
+ Summary: This is the API to manage Crowdsec Live Exploit Tracker service
5
+ Author-email: crowdsec <info@crowdsec.net>
6
+ License: MIT
7
+ Requires-Python: >=3.11
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: httpx==0.27.0
11
+ Requires-Dist: botocore
12
+ Requires-Dist: pydantic[email,timezone]<3.0.0,>=2.5.0
13
+ Dynamic: license-file
14
+
15
+ # crowdsec_tracker_api
16
+
17
+ **crowdsec_tracker_api** is a Python SDK for the [CrowdSec Tracker API](https://docs.crowdsec.net/u/tracker_api/intro/).
18
+ This library enables you to manage CrowdSec Live Exploit Tracker resources such as CVEs data, IPs from a specific CVE and manage integrations.
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ pip install crowdsec_tracker_api
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ You can follow this [documentation](https://docs.crowdsec.net/u/tracker_api/intro/) to see the basic usage of the SDK.
29
+
30
+ ## Documentation
31
+ You can access the full usage documentation [here](https://github.com/crowdsecurity/crowdsec-tracker-api-sdk-python/tree/main/doc).
32
+
33
+ ## Contributing
34
+
35
+ This SDK is auto-generated from the API specification. You can open an issue on this repository if you find a bug or if you want to add a feature.
@@ -0,0 +1,21 @@
1
+ # crowdsec_tracker_api
2
+
3
+ **crowdsec_tracker_api** is a Python SDK for the [CrowdSec Tracker API](https://docs.crowdsec.net/u/tracker_api/intro/).
4
+ This library enables you to manage CrowdSec Live Exploit Tracker resources such as CVEs data, IPs from a specific CVE and manage integrations.
5
+
6
+ ## Installation
7
+
8
+ ```bash
9
+ pip install crowdsec_tracker_api
10
+ ```
11
+
12
+ ## Usage
13
+
14
+ You can follow this [documentation](https://docs.crowdsec.net/u/tracker_api/intro/) to see the basic usage of the SDK.
15
+
16
+ ## Documentation
17
+ You can access the full usage documentation [here](https://github.com/crowdsecurity/crowdsec-tracker-api-sdk-python/tree/main/doc).
18
+
19
+ ## Contributing
20
+
21
+ This SDK is auto-generated from the API specification. You can open an issue on this repository if you find a bug or if you want to add a feature.
@@ -0,0 +1,59 @@
1
+ from enum import Enum
2
+ from .models import *
3
+ from .base_model import Page
4
+ from .services.integrations import Integrations
5
+ from .services.cves import Cves
6
+ from .http_client import ApiKeyAuth
7
+
8
+ class Server(Enum):
9
+ production_server = 'https://admin.api.crowdsec.net/v1'
10
+
11
+ __all__ = [
12
+ 'Integrations',
13
+ 'Cves',
14
+ 'ApiKeyCredentials',
15
+ 'BasicAuthCredentials',
16
+ 'BlocklistSubscription',
17
+ 'CVESubscription',
18
+ 'HTTPValidationError',
19
+ 'IntegrationCreateRequest',
20
+ 'IntegrationCreateResponse',
21
+ 'IntegrationGetResponse',
22
+ 'IntegrationGetResponsePage',
23
+ 'IntegrationType',
24
+ 'IntegrationUpdateRequest',
25
+ 'IntegrationUpdateResponse',
26
+ 'Links',
27
+ 'OutputFormat',
28
+ 'Stats',
29
+ 'ValidationError',
30
+ 'AffectedComponent',
31
+ 'AllowlistSubscription',
32
+ 'AttackDetail',
33
+ 'Behavior',
34
+ 'CVEEvent',
35
+ 'CVEResponseBase',
36
+ 'CVEsubscription',
37
+ 'CWE',
38
+ 'Classification',
39
+ 'Classifications',
40
+ 'EntityType',
41
+ 'GetCVEIPsResponsePage',
42
+ 'GetCVEResponse',
43
+ 'GetCVESubscribedIntegrationsResponsePage',
44
+ 'GetCVEsResponsePage',
45
+ 'GetCVEsSortBy',
46
+ 'GetCVEsSortOrder',
47
+ 'History',
48
+ 'IPItem',
49
+ 'IntegrationResponse',
50
+ 'Location',
51
+ 'MitreTechnique',
52
+ 'Reference',
53
+ 'ScoreBreakdown',
54
+ 'Scores',
55
+ 'SubscribeCVEIntegrationRequest',
56
+ 'ApiKeyAuth',
57
+ 'Server',
58
+ 'Page'
59
+ ]
@@ -0,0 +1,58 @@
1
+ from urllib.parse import urlparse
2
+ from pydantic import BaseModel, ConfigDict, PrivateAttr, RootModel
3
+ from typing import Generic, Sequence, Optional, TypeVar, Any
4
+ from httpx import Auth
5
+ from .http_client import HttpClient
6
+
7
+
8
+ class BaseModelSdk(BaseModel):
9
+ model_config = ConfigDict(
10
+ extra="ignore",
11
+ )
12
+ _client: Optional["Service"] = PrivateAttr(default=None)
13
+
14
+ def __init__(self, /, _client: "Service" = None, **data):
15
+ super().__init__(**data)
16
+ self._client = _client
17
+
18
+ def next(self, client: "Service" = None) -> Optional["BaseModelSdk"]:
19
+ return (client if client is not None else self._client).next_page(self)
20
+
21
+
22
+ class RootModelSdk(RootModel):
23
+ def __getattr__(self, item: str) -> Any:
24
+ return getattr(self.root, item)
25
+
26
+
27
+ T = TypeVar("T")
28
+
29
+
30
+ class Page(BaseModelSdk, Generic[T]):
31
+ items: Sequence[T]
32
+ total: Optional[int]
33
+ page: Optional[int]
34
+ size: Optional[int]
35
+ pages: Optional[int] = None
36
+ links: Optional[dict] = None
37
+
38
+
39
+ class Service:
40
+ def __init__(self, base_url: str, auth: Auth) -> None:
41
+ self.http_client = HttpClient(base_url=base_url, auth=auth)
42
+
43
+ def next_page(self, page: BaseModelSdk) -> Optional[BaseModelSdk]:
44
+ if not hasattr(page, "links") or not page.links:
45
+ raise ValueError(
46
+ "No links found in the response, this is not a paginated response."
47
+ )
48
+ if page.links.next:
49
+ # links are relative to host not to full base url. We need to pass a full formatted url here
50
+ parsed_url = urlparse(self.http_client.base_url)
51
+ response = self.http_client.get(
52
+ f"{parsed_url.scheme}://{parsed_url.netloc}{page.links.next}",
53
+ path_params=None,
54
+ params=None,
55
+ headers=None,
56
+ )
57
+ return page.__class__(_client=self, **response.json())
58
+ return None
@@ -0,0 +1,153 @@
1
+ from urllib.parse import quote, urlparse
2
+
3
+ from botocore.auth import SigV4Auth
4
+ from botocore.awsrequest import AWSRequest
5
+ import botocore.session
6
+
7
+ import httpx
8
+
9
+
10
+ class AWSSignV4Auth(httpx.Auth):
11
+ def __init__(self, aws_region="eu-west-1") -> None:
12
+ self.aws_region = aws_region
13
+
14
+ def auth_flow(self, request):
15
+ request = self.sign_request(request)
16
+ yield request
17
+
18
+ def sign_request(self, request: httpx.Request) -> httpx.Request:
19
+ """Signs an httpx request with AWS Signature Version 4."""
20
+
21
+ session = botocore.session.get_session()
22
+ credentials = session.get_credentials()
23
+ aws_request = AWSRequest(
24
+ method=request.method.upper(), url=str(request.url), data=request.content
25
+ )
26
+ region = self.aws_region
27
+ service = "execute-api"
28
+
29
+ # Sign the request
30
+ SigV4Auth(credentials, service, region).add_auth(aws_request)
31
+
32
+ # Update the httpx request headers with the signed headers
33
+ request.headers.update(dict(aws_request.headers))
34
+
35
+ return request
36
+
37
+
38
+ class ApiKeyAuth(httpx.Auth):
39
+ def __init__(self, api_key: str) -> None:
40
+ self.api_key = api_key
41
+
42
+ def auth_flow(self, request):
43
+ request.headers["x-api-key"] = self.api_key
44
+ yield request
45
+
46
+
47
+ class HttpClient:
48
+ def __init__(self, base_url: str, auth: httpx.Auth, aws_region="eu-west-1") -> None:
49
+ self.aws_region = aws_region
50
+ self.base_url = base_url
51
+ self.auth = auth
52
+ self.client = httpx.Client(headers={"Accept-Encoding": "gzip"})
53
+ self.timeout = 30
54
+
55
+ def _replace_path_params(self, url: str, path_params: dict):
56
+ if path_params:
57
+ for param, value in path_params.items():
58
+ if not value:
59
+ raise ValueError(
60
+ f"Parameter {param} is required, cannot be empty or blank."
61
+ )
62
+ url = url.replace(f"{{{param}}}", quote(str(value)))
63
+ return url
64
+
65
+ def _normalize_url(self, url: str):
66
+ self.base_url = self.base_url.rstrip("/")
67
+ parsed_url = urlparse(url)
68
+ if not parsed_url.netloc:
69
+ return f"{self.base_url}{url}"
70
+ return url
71
+
72
+ def get(
73
+ self,
74
+ url: str,
75
+ path_params: dict = None,
76
+ params: dict = None,
77
+ headers: dict = None,
78
+ ):
79
+ url = self._replace_path_params(
80
+ url=self._normalize_url(url), path_params=path_params
81
+ )
82
+ response = self.client.get(
83
+ url=url,
84
+ params=params,
85
+ headers=headers,
86
+ auth=self.auth,
87
+ timeout=self.timeout,
88
+ )
89
+ response.raise_for_status()
90
+ return response
91
+
92
+ def post(
93
+ self, url: str, path_params: dict, params: dict, headers: dict, json: dict
94
+ ):
95
+ url = self._replace_path_params(
96
+ url=self._normalize_url(url), path_params=path_params
97
+ )
98
+ response = self.client.post(
99
+ url=url,
100
+ params=params,
101
+ headers=headers,
102
+ json=json,
103
+ auth=self.auth,
104
+ timeout=self.timeout,
105
+ )
106
+ response.raise_for_status()
107
+ return response
108
+
109
+ def put(self, url: str, path_params: dict, params: dict, headers: dict, json: dict):
110
+ url = self._replace_path_params(
111
+ url=self._normalize_url(url), path_params=path_params
112
+ )
113
+ response = self.client.put(
114
+ url=url,
115
+ params=params,
116
+ headers=headers,
117
+ json=json,
118
+ auth=self.auth,
119
+ timeout=self.timeout,
120
+ )
121
+ response.raise_for_status()
122
+ return response
123
+
124
+ def patch(
125
+ self, url: str, path_params: dict, params: dict, headers: dict, json: dict
126
+ ):
127
+ url = self._replace_path_params(
128
+ url=self._normalize_url(url), path_params=path_params
129
+ )
130
+ response = self.client.patch(
131
+ url=url,
132
+ params=params,
133
+ headers=headers,
134
+ json=json,
135
+ auth=self.auth,
136
+ timeout=self.timeout,
137
+ )
138
+ response.raise_for_status()
139
+ return response
140
+
141
+ def delete(self, url: str, path_params: dict, params: dict, headers: dict):
142
+ url = self._replace_path_params(
143
+ url=self._normalize_url(url), path_params=path_params
144
+ )
145
+ response = self.client.delete(
146
+ url=url,
147
+ params=params,
148
+ headers=headers,
149
+ auth=self.auth,
150
+ timeout=self.timeout,
151
+ )
152
+ response.raise_for_status()
153
+ return response