binalyze-air-sdk 1.0.1__py3-none-any.whl
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.
- binalyze_air/__init__.py +77 -0
- binalyze_air/apis/__init__.py +27 -0
- binalyze_air/apis/authentication.py +27 -0
- binalyze_air/apis/auto_asset_tags.py +75 -0
- binalyze_air/apis/endpoints.py +22 -0
- binalyze_air/apis/event_subscription.py +97 -0
- binalyze_air/apis/evidence.py +53 -0
- binalyze_air/apis/evidences.py +216 -0
- binalyze_air/apis/interact.py +36 -0
- binalyze_air/apis/params.py +40 -0
- binalyze_air/apis/settings.py +27 -0
- binalyze_air/apis/user_management.py +74 -0
- binalyze_air/apis/users.py +68 -0
- binalyze_air/apis/webhooks.py +231 -0
- binalyze_air/base.py +133 -0
- binalyze_air/client.py +1338 -0
- binalyze_air/commands/__init__.py +146 -0
- binalyze_air/commands/acquisitions.py +387 -0
- binalyze_air/commands/assets.py +363 -0
- binalyze_air/commands/authentication.py +37 -0
- binalyze_air/commands/auto_asset_tags.py +231 -0
- binalyze_air/commands/baseline.py +396 -0
- binalyze_air/commands/cases.py +603 -0
- binalyze_air/commands/event_subscription.py +102 -0
- binalyze_air/commands/evidences.py +988 -0
- binalyze_air/commands/interact.py +58 -0
- binalyze_air/commands/organizations.py +221 -0
- binalyze_air/commands/policies.py +203 -0
- binalyze_air/commands/settings.py +29 -0
- binalyze_air/commands/tasks.py +56 -0
- binalyze_air/commands/triage.py +360 -0
- binalyze_air/commands/user_management.py +126 -0
- binalyze_air/commands/users.py +101 -0
- binalyze_air/config.py +245 -0
- binalyze_air/exceptions.py +50 -0
- binalyze_air/http_client.py +306 -0
- binalyze_air/models/__init__.py +285 -0
- binalyze_air/models/acquisitions.py +251 -0
- binalyze_air/models/assets.py +439 -0
- binalyze_air/models/audit.py +273 -0
- binalyze_air/models/authentication.py +70 -0
- binalyze_air/models/auto_asset_tags.py +117 -0
- binalyze_air/models/baseline.py +232 -0
- binalyze_air/models/cases.py +276 -0
- binalyze_air/models/endpoints.py +76 -0
- binalyze_air/models/event_subscription.py +172 -0
- binalyze_air/models/evidence.py +66 -0
- binalyze_air/models/evidences.py +349 -0
- binalyze_air/models/interact.py +136 -0
- binalyze_air/models/organizations.py +294 -0
- binalyze_air/models/params.py +128 -0
- binalyze_air/models/policies.py +250 -0
- binalyze_air/models/settings.py +84 -0
- binalyze_air/models/tasks.py +149 -0
- binalyze_air/models/triage.py +143 -0
- binalyze_air/models/user_management.py +97 -0
- binalyze_air/models/users.py +82 -0
- binalyze_air/queries/__init__.py +134 -0
- binalyze_air/queries/acquisitions.py +156 -0
- binalyze_air/queries/assets.py +105 -0
- binalyze_air/queries/audit.py +417 -0
- binalyze_air/queries/authentication.py +56 -0
- binalyze_air/queries/auto_asset_tags.py +60 -0
- binalyze_air/queries/baseline.py +185 -0
- binalyze_air/queries/cases.py +293 -0
- binalyze_air/queries/endpoints.py +25 -0
- binalyze_air/queries/event_subscription.py +55 -0
- binalyze_air/queries/evidence.py +140 -0
- binalyze_air/queries/evidences.py +280 -0
- binalyze_air/queries/interact.py +28 -0
- binalyze_air/queries/organizations.py +223 -0
- binalyze_air/queries/params.py +115 -0
- binalyze_air/queries/policies.py +150 -0
- binalyze_air/queries/settings.py +20 -0
- binalyze_air/queries/tasks.py +82 -0
- binalyze_air/queries/triage.py +231 -0
- binalyze_air/queries/user_management.py +83 -0
- binalyze_air/queries/users.py +69 -0
- binalyze_air_sdk-1.0.1.dist-info/METADATA +635 -0
- binalyze_air_sdk-1.0.1.dist-info/RECORD +82 -0
- binalyze_air_sdk-1.0.1.dist-info/WHEEL +5 -0
- binalyze_air_sdk-1.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,276 @@
|
|
1
|
+
"""
|
2
|
+
Case-related data models for the Binalyze AIR SDK.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from typing import List, Optional, Dict, Any, Literal, Union
|
6
|
+
from datetime import datetime
|
7
|
+
from enum import Enum
|
8
|
+
from pydantic import Field, field_validator
|
9
|
+
|
10
|
+
from ..base import AIRBaseModel, Filter
|
11
|
+
|
12
|
+
|
13
|
+
class CaseStatus(str, Enum):
|
14
|
+
"""Case status."""
|
15
|
+
OPEN = "open"
|
16
|
+
CLOSED = "closed"
|
17
|
+
ARCHIVED = "archived"
|
18
|
+
|
19
|
+
|
20
|
+
class CaseNote(AIRBaseModel):
|
21
|
+
"""Case note model."""
|
22
|
+
|
23
|
+
id: str = Field(alias="_id")
|
24
|
+
case_id: str = Field(alias="caseId")
|
25
|
+
value: str
|
26
|
+
written_at: Optional[datetime] = Field(default=None, alias="writtenAt")
|
27
|
+
written_by: Optional[str] = Field(default=None, alias="writtenBy")
|
28
|
+
created_at: Optional[datetime] = Field(default=None, alias="createdAt")
|
29
|
+
updated_at: Optional[datetime] = Field(default=None, alias="updatedAt")
|
30
|
+
|
31
|
+
|
32
|
+
class Case(AIRBaseModel):
|
33
|
+
"""Case model."""
|
34
|
+
|
35
|
+
id: str = Field(alias="_id")
|
36
|
+
name: str
|
37
|
+
status: CaseStatus = CaseStatus.OPEN
|
38
|
+
owner_user_id: str = Field(alias="ownerUserId")
|
39
|
+
owner_user: Optional[Any] = Field(default=None, alias="ownerUser")
|
40
|
+
assigned_user_ids: List[str] = Field(default=[], alias="assignedUserIds")
|
41
|
+
assigned_users: List[Any] = Field(default=[], alias="assignedUsers")
|
42
|
+
visibility: str
|
43
|
+
organization_id: int = Field(default=0, alias="organizationId")
|
44
|
+
notes: List[Any] = []
|
45
|
+
endpoint_count: int = Field(default=0, alias="endpointCount")
|
46
|
+
task_count: int = Field(default=0, alias="taskCount")
|
47
|
+
acquisition_task_count: int = Field(default=0, alias="acquisitionTaskCount")
|
48
|
+
created_at: Optional[datetime] = Field(default=None, alias="createdAt")
|
49
|
+
updated_at: Optional[datetime] = Field(default=None, alias="updatedAt")
|
50
|
+
closed_at: Optional[datetime] = Field(default=None, alias="closedAt")
|
51
|
+
archived_at: Optional[datetime] = Field(default=None, alias="archivedAt")
|
52
|
+
# Optional fields that may not be in all responses
|
53
|
+
source: Optional[str] = None
|
54
|
+
started_on: Optional[datetime] = Field(default=None, alias="startedOn")
|
55
|
+
total_days: int = Field(default=0, alias="totalDays")
|
56
|
+
total_endpoints: int = Field(default=0, alias="totalEndpoints")
|
57
|
+
closed_on: Optional[datetime] = Field(default=None, alias="closedOn")
|
58
|
+
|
59
|
+
|
60
|
+
class CaseActivity(AIRBaseModel):
|
61
|
+
"""Case activity model."""
|
62
|
+
|
63
|
+
id: Optional[str] = Field(default=None, alias="_id")
|
64
|
+
case_id: Optional[str] = Field(default=None, alias="caseId")
|
65
|
+
user_id: Optional[str] = Field(default=None, alias="userId")
|
66
|
+
user: Optional[Any] = None
|
67
|
+
activity_type: Optional[str] = Field(default=None, alias="activityType")
|
68
|
+
description: Optional[str] = None
|
69
|
+
details: Dict[str, Any] = {}
|
70
|
+
created_at: Optional[datetime] = Field(default=None, alias="createdAt")
|
71
|
+
# Legacy fields that may still exist
|
72
|
+
updated_at: Optional[datetime] = Field(default=None, alias="updatedAt")
|
73
|
+
type: Optional[str] = None
|
74
|
+
performed_by: Optional[str] = Field(default=None, alias="performedBy")
|
75
|
+
data: Optional[Any] = None
|
76
|
+
organization_ids: List[int] = Field(default=[], alias="organizationIds")
|
77
|
+
|
78
|
+
|
79
|
+
class CaseEndpoint(AIRBaseModel):
|
80
|
+
"""Case endpoint model."""
|
81
|
+
|
82
|
+
platform: str
|
83
|
+
tags: List[str] = []
|
84
|
+
isolation_status: str = Field(alias="isolationStatus")
|
85
|
+
id: str = Field(alias="_id")
|
86
|
+
created_at: Optional[datetime] = Field(default=None, alias="createdAt")
|
87
|
+
updated_at: Optional[datetime] = Field(default=None, alias="updatedAt")
|
88
|
+
organization_id: int = Field(default=0, alias="organizationId")
|
89
|
+
ip_address: Optional[str] = Field(default=None, alias="ipAddress")
|
90
|
+
name: str
|
91
|
+
group_id: Optional[str] = Field(default=None, alias="groupId")
|
92
|
+
group_full_path: Optional[str] = Field(default=None, alias="groupFullPath")
|
93
|
+
os: str
|
94
|
+
is_server: bool = Field(default=False, alias="isServer")
|
95
|
+
is_managed: bool = Field(default=True, alias="isManaged")
|
96
|
+
last_seen: Optional[datetime] = Field(default=None, alias="lastSeen")
|
97
|
+
version: Optional[str] = None
|
98
|
+
version_no: Optional[int] = Field(default=None, alias="versionNo")
|
99
|
+
registered_at: Optional[datetime] = Field(default=None, alias="registeredAt")
|
100
|
+
security_token: Optional[str] = Field(default=None, alias="securityToken")
|
101
|
+
online_status: str = Field(alias="onlineStatus")
|
102
|
+
issues: List[str] = []
|
103
|
+
label: Optional[str] = None
|
104
|
+
waiting_for_version_update_fix: bool = Field(default=False, alias="waitingForVersionUpdateFix")
|
105
|
+
|
106
|
+
|
107
|
+
class CaseTask(AIRBaseModel):
|
108
|
+
"""Case task model."""
|
109
|
+
|
110
|
+
id: str = Field(alias="_id")
|
111
|
+
task_id: str = Field(alias="taskId")
|
112
|
+
name: str
|
113
|
+
type: str
|
114
|
+
endpoint_id: str = Field(alias="endpointId")
|
115
|
+
endpoint_name: str = Field(alias="endpointName")
|
116
|
+
organization_id: int = Field(default=0, alias="organizationId")
|
117
|
+
status: str
|
118
|
+
recurrence: Optional[str] = None
|
119
|
+
progress: int = 0
|
120
|
+
duration: Optional[int] = None
|
121
|
+
case_ids: List[str] = Field(default=[], alias="caseIds")
|
122
|
+
is_comparable: bool = Field(default=False, alias="isComparable")
|
123
|
+
created_at: Optional[datetime] = Field(default=None, alias="createdAt")
|
124
|
+
updated_at: Optional[datetime] = Field(default=None, alias="updatedAt")
|
125
|
+
response: Optional[Any] = None
|
126
|
+
|
127
|
+
|
128
|
+
class UserProfile(AIRBaseModel):
|
129
|
+
"""User profile model."""
|
130
|
+
|
131
|
+
name: str
|
132
|
+
surname: str
|
133
|
+
department: str
|
134
|
+
|
135
|
+
|
136
|
+
class Role(AIRBaseModel):
|
137
|
+
"""User role model."""
|
138
|
+
|
139
|
+
id: str = Field(alias="_id")
|
140
|
+
name: str
|
141
|
+
created_by: str = Field(alias="createdBy")
|
142
|
+
tag: str
|
143
|
+
privilege_types: List[str] = Field(default=[], alias="privilegeTypes")
|
144
|
+
created_at: Optional[datetime] = Field(default=None, alias="createdAt")
|
145
|
+
updated_at: Optional[datetime] = Field(default=None, alias="updatedAt")
|
146
|
+
|
147
|
+
|
148
|
+
class User(AIRBaseModel):
|
149
|
+
"""User model."""
|
150
|
+
|
151
|
+
id: str = Field(alias="_id")
|
152
|
+
email: str
|
153
|
+
username: str
|
154
|
+
organization_ids: Union[List[int], str] = Field(default=[], alias="organizationIds")
|
155
|
+
strategy: str
|
156
|
+
profile: UserProfile
|
157
|
+
created_at: Optional[datetime] = Field(default=None, alias="createdAt")
|
158
|
+
updated_at: Optional[datetime] = Field(default=None, alias="updatedAt")
|
159
|
+
roles: List[Role] = []
|
160
|
+
|
161
|
+
@field_validator('organization_ids', mode='before')
|
162
|
+
@classmethod
|
163
|
+
def parse_organization_ids(cls, v):
|
164
|
+
"""Handle organizationIds which can be a list of ints or the string 'ALL'."""
|
165
|
+
if isinstance(v, str):
|
166
|
+
# Handle the "ALL" case - return as is for now
|
167
|
+
return v
|
168
|
+
elif isinstance(v, list):
|
169
|
+
# Ensure all items are integers
|
170
|
+
return [int(item) if not isinstance(item, int) else item for item in v]
|
171
|
+
else:
|
172
|
+
# Default to empty list for other cases
|
173
|
+
return []
|
174
|
+
|
175
|
+
|
176
|
+
class CaseFilter(Filter):
|
177
|
+
"""Filter for case queries."""
|
178
|
+
|
179
|
+
name: Optional[str] = None
|
180
|
+
status: Optional[List[CaseStatus]] = None
|
181
|
+
owner_user_id: Optional[str] = None
|
182
|
+
assigned_user_ids: Optional[List[str]] = None
|
183
|
+
visibility: Optional[str] = None
|
184
|
+
source: Optional[str] = None
|
185
|
+
|
186
|
+
|
187
|
+
class CaseActivityFilter(Filter):
|
188
|
+
"""Filter for case activity queries."""
|
189
|
+
|
190
|
+
performed_by: Optional[List[str]] = None # User IDs who performed the activities
|
191
|
+
types: Optional[List[str]] = None # Activity types to filter
|
192
|
+
search_term: Optional[str] = None # Search term for activity descriptions
|
193
|
+
occurred_at: Optional[str] = None # Date range filter
|
194
|
+
page_number: Optional[int] = Field(default=1, ge=1) # Page number (min: 1)
|
195
|
+
page_size: Optional[int] = Field(default=10, ge=1) # Page size (min: 1)
|
196
|
+
sort_by: Optional[str] = Field(default="createdAt") # Sort field
|
197
|
+
sort_type: Optional[Literal["ASC", "DESC"]] = Field(default="ASC") # Sort direction
|
198
|
+
|
199
|
+
|
200
|
+
class CaseEndpointFilter(Filter):
|
201
|
+
"""Filter for case endpoint queries."""
|
202
|
+
|
203
|
+
organization_ids: Optional[List[int]] = None # Required organization IDs
|
204
|
+
search_term: Optional[str] = None # Search term for endpoint names
|
205
|
+
name: Optional[str] = None # Endpoint name filter
|
206
|
+
ip_address: Optional[str] = None # IP address filter
|
207
|
+
group_id: Optional[str] = None # Group ID filter
|
208
|
+
group_full_path: Optional[str] = None # Group full path filter
|
209
|
+
label: Optional[str] = None # Label filter
|
210
|
+
last_seen: Optional[str] = None # Last seen date range (e.g., "2023-03-06T21:00:00.000Z,2023-03-24T21:00:00.000Z")
|
211
|
+
managed_status: Optional[List[str]] = None # Managed status filter (unmanaged, managed, off-network)
|
212
|
+
isolation_status: Optional[List[str]] = None # Isolation status filter (isolating, isolated, unisolating, unisolated)
|
213
|
+
platform: Optional[List[str]] = None # Platform filter (windows, linux, darwin)
|
214
|
+
issue: Optional[List[str]] = None # Issue filter (unreachable, old-version, update-required)
|
215
|
+
online_status: Optional[List[str]] = None # Online status filter (online, offline)
|
216
|
+
tags: Optional[List[str]] = None # Tags filter
|
217
|
+
version: Optional[str] = None # Version filter
|
218
|
+
policy: Optional[str] = None # Policy filter
|
219
|
+
included_endpoint_ids: Optional[List[str]] = None # Included endpoint IDs
|
220
|
+
excluded_endpoint_ids: Optional[List[str]] = None # Excluded endpoint IDs
|
221
|
+
aws_regions: Optional[List[str]] = None # AWS regions filter
|
222
|
+
azure_regions: Optional[List[str]] = None # Azure regions filter
|
223
|
+
page_number: Optional[int] = Field(default=1, ge=1) # Page number (min: 1)
|
224
|
+
page_size: Optional[int] = Field(default=10, ge=1) # Page size (min: 1)
|
225
|
+
sort_by: Optional[str] = Field(default="createdAt") # Sort field
|
226
|
+
sort_type: Optional[Literal["ASC", "DESC"]] = Field(default="ASC") # Sort direction
|
227
|
+
|
228
|
+
|
229
|
+
class CaseTaskFilter(Filter):
|
230
|
+
"""Filter for case task queries."""
|
231
|
+
|
232
|
+
organization_ids: Optional[List[int]] = None # Required organization IDs
|
233
|
+
search_term: Optional[str] = None # Search term for task names
|
234
|
+
name: Optional[str] = None # Task name filter
|
235
|
+
endpoint_ids: Optional[List[str]] = None # Endpoint IDs filter
|
236
|
+
execution_type: Optional[str] = None # Execution type filter (instant, scheduled)
|
237
|
+
status: Optional[str] = None # Status filter (scheduled, assigned, processing, completed, failed, expired, cancelled, compressing, uploading, analyzing, partially-completed)
|
238
|
+
type: Optional[str] = None # Task type filter (acquisition, offline-acquisition, triage, offline-triage, investigation, interact-shell, baseline-comparison, baseline-acquisition, acquire-image)
|
239
|
+
asset_names: Optional[str] = None # Comma separated asset names
|
240
|
+
started_by: Optional[str] = None # Started by user filter
|
241
|
+
page_number: Optional[int] = Field(default=1, ge=1) # Page number (min: 1)
|
242
|
+
page_size: Optional[int] = Field(default=10, ge=1) # Page size (min: 1)
|
243
|
+
sort_by: Optional[str] = Field(default="createdAt") # Sort field
|
244
|
+
sort_type: Optional[Literal["ASC", "DESC"]] = Field(default="ASC") # Sort direction
|
245
|
+
|
246
|
+
|
247
|
+
class CaseUserFilter(Filter):
|
248
|
+
"""Filter for case user queries."""
|
249
|
+
|
250
|
+
organization_ids: Optional[List[int]] = None # Required organization IDs
|
251
|
+
search_term: Optional[str] = None # Search term for user filtering
|
252
|
+
page_number: Optional[int] = Field(default=1, ge=1) # Page number (min: 1)
|
253
|
+
page_size: Optional[int] = Field(default=10, ge=1) # Page size (min: 1)
|
254
|
+
sort_by: Optional[str] = Field(default="createdAt") # Sort field
|
255
|
+
sort_type: Optional[Literal["ASC", "DESC"]] = Field(default="ASC") # Sort direction
|
256
|
+
|
257
|
+
|
258
|
+
class CreateCaseRequest(AIRBaseModel):
|
259
|
+
"""Request model for creating a case."""
|
260
|
+
|
261
|
+
organization_id: int = 0
|
262
|
+
name: str
|
263
|
+
owner_user_id: str
|
264
|
+
visibility: str
|
265
|
+
assigned_user_ids: List[str] = []
|
266
|
+
|
267
|
+
|
268
|
+
class UpdateCaseRequest(AIRBaseModel):
|
269
|
+
"""Request model for updating a case."""
|
270
|
+
|
271
|
+
name: Optional[str] = None
|
272
|
+
owner_user_id: Optional[str] = None
|
273
|
+
visibility: Optional[str] = None
|
274
|
+
assigned_user_ids: Optional[List[str]] = None
|
275
|
+
status: Optional[CaseStatus] = None
|
276
|
+
notes: Optional[List[Any]] = None
|
@@ -0,0 +1,76 @@
|
|
1
|
+
"""
|
2
|
+
Endpoints API models for the Binalyze AIR SDK.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from typing import List, Optional, Dict, Any
|
6
|
+
from datetime import datetime
|
7
|
+
from enum import Enum
|
8
|
+
|
9
|
+
from ..base import AIRBaseModel, Filter
|
10
|
+
|
11
|
+
|
12
|
+
class TagType(str, Enum):
|
13
|
+
"""Endpoint tag types."""
|
14
|
+
SYSTEM = "system"
|
15
|
+
USER = "user"
|
16
|
+
CUSTOM = "custom"
|
17
|
+
AUTO = "auto"
|
18
|
+
|
19
|
+
|
20
|
+
class TagScope(str, Enum):
|
21
|
+
"""Tag scope."""
|
22
|
+
GLOBAL = "global"
|
23
|
+
ORGANIZATION = "organization"
|
24
|
+
GROUP = "group"
|
25
|
+
|
26
|
+
|
27
|
+
class EndpointTag(AIRBaseModel):
|
28
|
+
"""Endpoint tag model."""
|
29
|
+
|
30
|
+
id: str
|
31
|
+
name: str
|
32
|
+
description: Optional[str] = None
|
33
|
+
color: Optional[str] = None
|
34
|
+
tag_type: TagType = TagType.USER
|
35
|
+
scope: TagScope = TagScope.ORGANIZATION
|
36
|
+
organization_id: Optional[int] = None
|
37
|
+
created_by: Optional[str] = None
|
38
|
+
created_at: Optional[datetime] = None
|
39
|
+
updated_at: Optional[datetime] = None
|
40
|
+
usage_count: int = 0
|
41
|
+
is_system: bool = False
|
42
|
+
is_deletable: bool = True
|
43
|
+
metadata: Optional[Dict[str, Any]] = None
|
44
|
+
rules: Optional[Dict[str, Any]] = None # Auto-tagging rules
|
45
|
+
|
46
|
+
|
47
|
+
class CreateEndpointTagRequest(AIRBaseModel):
|
48
|
+
"""Request model for creating endpoint tags."""
|
49
|
+
|
50
|
+
name: str
|
51
|
+
description: Optional[str] = None
|
52
|
+
color: Optional[str] = None
|
53
|
+
tag_type: TagType = TagType.USER
|
54
|
+
scope: TagScope = TagScope.ORGANIZATION
|
55
|
+
organization_id: Optional[int] = None
|
56
|
+
metadata: Optional[Dict[str, Any]] = None
|
57
|
+
rules: Optional[Dict[str, Any]] = None
|
58
|
+
|
59
|
+
|
60
|
+
class UpdateEndpointTagRequest(AIRBaseModel):
|
61
|
+
"""Request model for updating endpoint tags."""
|
62
|
+
|
63
|
+
name: Optional[str] = None
|
64
|
+
description: Optional[str] = None
|
65
|
+
color: Optional[str] = None
|
66
|
+
metadata: Optional[Dict[str, Any]] = None
|
67
|
+
rules: Optional[Dict[str, Any]] = None
|
68
|
+
|
69
|
+
|
70
|
+
class EndpointTagFilter(Filter):
|
71
|
+
"""Filter for endpoint tag queries."""
|
72
|
+
|
73
|
+
name: Optional[str] = None
|
74
|
+
tag_type: Optional[TagType] = None
|
75
|
+
scope: Optional[TagScope] = None
|
76
|
+
created_by: Optional[str] = None
|
@@ -0,0 +1,172 @@
|
|
1
|
+
"""
|
2
|
+
Event Subscription API models for the Binalyze AIR SDK.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from typing import List, Optional, Dict, Any
|
6
|
+
from datetime import datetime
|
7
|
+
from enum import Enum
|
8
|
+
from pydantic import Field, field_validator
|
9
|
+
|
10
|
+
from ..base import AIRBaseModel, Filter
|
11
|
+
|
12
|
+
|
13
|
+
class SubscriptionStatus(str, Enum):
|
14
|
+
"""Event subscription status."""
|
15
|
+
ACTIVE = "active"
|
16
|
+
INACTIVE = "inactive"
|
17
|
+
PENDING = "pending"
|
18
|
+
FAILED = "failed"
|
19
|
+
|
20
|
+
|
21
|
+
class EventType(str, Enum):
|
22
|
+
"""Event types for subscriptions."""
|
23
|
+
# Real API event names from JSON specification
|
24
|
+
DEPLOYMENT_TOKEN_REGENERATED = "DeploymentTokenRegeneratedEvent"
|
25
|
+
TASK_PROCESSING_FAILED = "TaskProcessingFailedEvent"
|
26
|
+
TASK_PROCESSING_COMPLETED = "TaskProcessingCompletedEvent"
|
27
|
+
CASE_FILE_SAVED = "CaseFileSavedEvent"
|
28
|
+
|
29
|
+
# Additional common event types (these may exist in the system)
|
30
|
+
ASSET_CREATED = "AssetCreatedEvent"
|
31
|
+
ASSET_UPDATED = "AssetUpdatedEvent"
|
32
|
+
ASSET_DELETED = "AssetDeletedEvent"
|
33
|
+
CASE_CREATED = "CaseCreatedEvent"
|
34
|
+
CASE_UPDATED = "CaseUpdatedEvent"
|
35
|
+
CASE_CLOSED = "CaseClosedEvent"
|
36
|
+
TASK_STARTED = "TaskStartedEvent"
|
37
|
+
POLICY_EXECUTED = "PolicyExecutedEvent"
|
38
|
+
ALERT_TRIGGERED = "AlertTriggeredEvent"
|
39
|
+
|
40
|
+
|
41
|
+
class DeliveryMethod(str, Enum):
|
42
|
+
"""Event delivery methods."""
|
43
|
+
WEBHOOK = "webhook"
|
44
|
+
EMAIL = "email"
|
45
|
+
SYSLOG = "syslog"
|
46
|
+
|
47
|
+
|
48
|
+
class EventSubscription(AIRBaseModel):
|
49
|
+
"""Event subscription model."""
|
50
|
+
|
51
|
+
id: str = Field(alias="id") # API returns int, but we'll convert to string
|
52
|
+
name: str
|
53
|
+
description: Optional[str] = None
|
54
|
+
event_types: Optional[List[EventType]] = Field(default=[], alias="events") # API: events -> SDK: event_types
|
55
|
+
delivery_method: Optional[DeliveryMethod] = Field(default=None, alias="deliveryMethod")
|
56
|
+
endpoint_url: Optional[str] = Field(default=None, alias="url") # API: url -> SDK: endpoint_url
|
57
|
+
email_addresses: Optional[List[str]] = Field(default=None, alias="emailAddresses")
|
58
|
+
syslog_server: Optional[str] = Field(default=None, alias="syslogServer")
|
59
|
+
status: Optional[SubscriptionStatus] = None
|
60
|
+
active: Optional[bool] = None # API uses active boolean instead of status enum
|
61
|
+
organization_id: Optional[int] = Field(default=None, alias="organizationId")
|
62
|
+
created_by: Optional[str] = Field(default=None, alias="createdBy")
|
63
|
+
created_at: Optional[datetime] = Field(default=None, alias="createdAt")
|
64
|
+
updated_at: Optional[datetime] = Field(default=None, alias="updatedAt")
|
65
|
+
last_triggered: Optional[datetime] = Field(default=None, alias="lastTriggered")
|
66
|
+
trigger_count: int = Field(default=0, alias="triggerCount")
|
67
|
+
retry_count: int = Field(default=3, alias="retryCount")
|
68
|
+
retry_interval: int = Field(default=300, alias="retryInterval") # seconds
|
69
|
+
headers: Optional[Dict[str, str]] = None # For webhook headers
|
70
|
+
authentication: Optional[Dict[str, Any]] = None
|
71
|
+
filters: Optional[Dict[str, Any]] = None # Event filtering criteria
|
72
|
+
url: Optional[str] = None # Keep original API field name for backward compatibility
|
73
|
+
auth_token: Optional[str] = Field(default=None, alias="authToken")
|
74
|
+
|
75
|
+
@field_validator('id', mode='before')
|
76
|
+
@classmethod
|
77
|
+
def convert_id_to_string(cls, v):
|
78
|
+
"""Convert ID from int to string as API returns numbers."""
|
79
|
+
return str(v) if v is not None else v
|
80
|
+
|
81
|
+
|
82
|
+
class CreateEventSubscriptionRequest(AIRBaseModel):
|
83
|
+
"""Request model for creating event subscriptions."""
|
84
|
+
|
85
|
+
name: str
|
86
|
+
description: Optional[str] = None
|
87
|
+
event_types: List[EventType]
|
88
|
+
delivery_method: DeliveryMethod
|
89
|
+
endpoint_url: Optional[str] = None
|
90
|
+
email_addresses: Optional[List[str]] = None
|
91
|
+
syslog_server: Optional[str] = None
|
92
|
+
organization_id: int
|
93
|
+
retry_count: Optional[int] = 3
|
94
|
+
retry_interval: Optional[int] = 300
|
95
|
+
headers: Optional[Dict[str, str]] = None
|
96
|
+
authentication: Optional[Dict[str, Any]] = None
|
97
|
+
filters: Optional[Dict[str, Any]] = None
|
98
|
+
|
99
|
+
|
100
|
+
class UpdateEventSubscriptionRequest(AIRBaseModel):
|
101
|
+
"""Request model for updating event subscriptions."""
|
102
|
+
|
103
|
+
name: Optional[str] = None
|
104
|
+
description: Optional[str] = None
|
105
|
+
event_types: Optional[List[EventType]] = None
|
106
|
+
delivery_method: Optional[DeliveryMethod] = None
|
107
|
+
endpoint_url: Optional[str] = None
|
108
|
+
email_addresses: Optional[List[str]] = None
|
109
|
+
syslog_server: Optional[str] = None
|
110
|
+
status: Optional[SubscriptionStatus] = None
|
111
|
+
retry_count: Optional[int] = None
|
112
|
+
retry_interval: Optional[int] = None
|
113
|
+
headers: Optional[Dict[str, str]] = None
|
114
|
+
authentication: Optional[Dict[str, Any]] = None
|
115
|
+
filters: Optional[Dict[str, Any]] = None
|
116
|
+
|
117
|
+
|
118
|
+
class EventSubscriptionFilter(Filter):
|
119
|
+
"""Filter for event subscription queries."""
|
120
|
+
|
121
|
+
name: Optional[str] = None
|
122
|
+
event_type: Optional[EventType] = None
|
123
|
+
delivery_method: Optional[DeliveryMethod] = None
|
124
|
+
status: Optional[SubscriptionStatus] = None
|
125
|
+
created_by: Optional[str] = None
|
126
|
+
is_active: Optional[bool] = None # API uses isActive
|
127
|
+
url: Optional[str] = None # API supports URL filtering
|
128
|
+
|
129
|
+
def to_params(self) -> Dict[str, Any]:
|
130
|
+
"""Convert filter to API parameters with proper field mapping."""
|
131
|
+
params = {}
|
132
|
+
|
133
|
+
# Pagination parameters (not in filter namespace)
|
134
|
+
if self.page_number is not None:
|
135
|
+
params["pageNumber"] = self.page_number
|
136
|
+
if self.page_size is not None:
|
137
|
+
params["pageSize"] = self.page_size
|
138
|
+
if self.sort_by is not None:
|
139
|
+
params["sortBy"] = self.sort_by
|
140
|
+
if self.sort_type is not None:
|
141
|
+
params["sortType"] = self.sort_type
|
142
|
+
|
143
|
+
# Filter parameters with proper field mapping
|
144
|
+
field_mappings = {
|
145
|
+
"search_term": "searchTerm",
|
146
|
+
"organization_ids": "organizationId", # API expects single organizationId in filter
|
147
|
+
"name": "name",
|
148
|
+
"event_type": "eventType",
|
149
|
+
"delivery_method": "deliveryMethod",
|
150
|
+
"status": "status",
|
151
|
+
"created_by": "createdBy",
|
152
|
+
"is_active": "isActive",
|
153
|
+
"url": "url"
|
154
|
+
}
|
155
|
+
|
156
|
+
for field_name, field_value in self.model_dump(exclude_none=True).items():
|
157
|
+
# Skip pagination/sorting fields as they're handled above
|
158
|
+
if field_name in ["page_number", "page_size", "sort_by", "sort_type"]:
|
159
|
+
continue
|
160
|
+
|
161
|
+
if field_value is not None:
|
162
|
+
api_field_name = field_mappings.get(field_name, field_name)
|
163
|
+
|
164
|
+
# Special handling for organization_ids - use first ID for organizationId filter
|
165
|
+
if field_name == "organization_ids" and isinstance(field_value, list) and len(field_value) > 0:
|
166
|
+
params[f"filter[{api_field_name}]"] = str(field_value[0])
|
167
|
+
elif isinstance(field_value, list):
|
168
|
+
params[f"filter[{api_field_name}]"] = ",".join(map(str, field_value))
|
169
|
+
else:
|
170
|
+
params[f"filter[{api_field_name}]"] = str(field_value)
|
171
|
+
|
172
|
+
return params
|
@@ -0,0 +1,66 @@
|
|
1
|
+
"""
|
2
|
+
Evidence-related data models for the Binalyze AIR SDK.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from typing import Optional, List, Dict, Any
|
6
|
+
from datetime import datetime
|
7
|
+
|
8
|
+
from ..base import AIRBaseModel
|
9
|
+
|
10
|
+
|
11
|
+
class EvidencePPC(AIRBaseModel):
|
12
|
+
"""Evidence PPC (Portable Pre-processor Configuration) model for binary file downloads."""
|
13
|
+
|
14
|
+
endpoint_id: str
|
15
|
+
task_id: str
|
16
|
+
content: bytes # Binary content of the PPC file
|
17
|
+
content_type: Optional[str] = None # MIME type of the file
|
18
|
+
content_length: Optional[int] = None # Size of the file in bytes
|
19
|
+
filename: Optional[str] = None # Suggested filename
|
20
|
+
|
21
|
+
def save_to_file(self, filepath: str) -> bool:
|
22
|
+
"""Save the PPC content to a file."""
|
23
|
+
try:
|
24
|
+
with open(filepath, 'wb') as f:
|
25
|
+
f.write(self.content)
|
26
|
+
return True
|
27
|
+
except Exception:
|
28
|
+
return False
|
29
|
+
|
30
|
+
|
31
|
+
class EvidenceReportFileInfo(AIRBaseModel):
|
32
|
+
"""Evidence report file info model."""
|
33
|
+
|
34
|
+
endpoint_id: str
|
35
|
+
task_id: str
|
36
|
+
file_name: Optional[str] = None
|
37
|
+
file_size: Optional[int] = None
|
38
|
+
created_at: Optional[datetime] = None
|
39
|
+
status: Optional[str] = None
|
40
|
+
# Additional fields from API
|
41
|
+
file_path: Optional[str] = None # Full path to the file
|
42
|
+
encoding: Optional[str] = None # File encoding (e.g., "7bit")
|
43
|
+
mime_type: Optional[str] = None # MIME type (e.g., "application/octet-stream")
|
44
|
+
file_hash: Optional[str] = None # File hash/checksum
|
45
|
+
organization_id: Optional[int] = None # Organization ID
|
46
|
+
is_purged: Optional[bool] = None # Whether file has been purged
|
47
|
+
|
48
|
+
|
49
|
+
class EvidenceReport(AIRBaseModel):
|
50
|
+
"""Evidence report model."""
|
51
|
+
|
52
|
+
endpoint_id: str
|
53
|
+
task_id: str
|
54
|
+
content: bytes # Binary content of the report file
|
55
|
+
content_type: Optional[str] = None
|
56
|
+
content_length: Optional[int] = None
|
57
|
+
filename: Optional[str] = None
|
58
|
+
|
59
|
+
def save_to_file(self, filepath: str) -> bool:
|
60
|
+
"""Save the report content to a file."""
|
61
|
+
try:
|
62
|
+
with open(filepath, 'wb') as f:
|
63
|
+
f.write(self.content)
|
64
|
+
return True
|
65
|
+
except Exception:
|
66
|
+
return False
|