binalyze-air-sdk 1.0.2__py3-none-any.whl → 1.0.3__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 -77
- binalyze_air/apis/__init__.py +67 -27
- binalyze_air/apis/acquisitions.py +107 -0
- binalyze_air/apis/api_tokens.py +49 -0
- binalyze_air/apis/assets.py +161 -0
- binalyze_air/apis/audit_logs.py +26 -0
- binalyze_air/apis/{authentication.py → auth.py} +29 -27
- binalyze_air/apis/auto_asset_tags.py +79 -75
- binalyze_air/apis/backup.py +177 -0
- binalyze_air/apis/baseline.py +46 -0
- binalyze_air/apis/cases.py +225 -0
- binalyze_air/apis/cloud_forensics.py +116 -0
- binalyze_air/apis/event_subscription.py +96 -96
- binalyze_air/apis/evidence.py +249 -53
- binalyze_air/apis/interact.py +153 -36
- binalyze_air/apis/investigation_hub.py +234 -0
- binalyze_air/apis/license.py +104 -0
- binalyze_air/apis/logger.py +83 -0
- binalyze_air/apis/multipart_upload.py +201 -0
- binalyze_air/apis/notifications.py +115 -0
- binalyze_air/apis/organizations.py +267 -0
- binalyze_air/apis/params.py +44 -39
- binalyze_air/apis/policies.py +186 -0
- binalyze_air/apis/preset_filters.py +79 -0
- binalyze_air/apis/recent_activities.py +71 -0
- binalyze_air/apis/relay_server.py +104 -0
- binalyze_air/apis/settings.py +395 -27
- binalyze_air/apis/tasks.py +80 -0
- binalyze_air/apis/triage.py +197 -0
- binalyze_air/apis/user_management.py +183 -74
- binalyze_air/apis/webhook_executions.py +50 -0
- binalyze_air/apis/webhooks.py +322 -230
- binalyze_air/base.py +207 -133
- binalyze_air/client.py +217 -1337
- binalyze_air/commands/__init__.py +175 -145
- binalyze_air/commands/acquisitions.py +661 -387
- binalyze_air/commands/api_tokens.py +55 -0
- binalyze_air/commands/assets.py +324 -362
- binalyze_air/commands/{authentication.py → auth.py} +36 -36
- binalyze_air/commands/auto_asset_tags.py +230 -230
- binalyze_air/commands/backup.py +47 -0
- binalyze_air/commands/baseline.py +32 -396
- binalyze_air/commands/cases.py +609 -602
- binalyze_air/commands/cloud_forensics.py +88 -0
- binalyze_air/commands/event_subscription.py +101 -101
- binalyze_air/commands/evidences.py +918 -988
- binalyze_air/commands/interact.py +172 -58
- binalyze_air/commands/investigation_hub.py +315 -0
- binalyze_air/commands/license.py +183 -0
- binalyze_air/commands/logger.py +126 -0
- binalyze_air/commands/multipart_upload.py +363 -0
- binalyze_air/commands/notifications.py +45 -0
- binalyze_air/commands/organizations.py +200 -221
- binalyze_air/commands/policies.py +175 -203
- binalyze_air/commands/preset_filters.py +55 -0
- binalyze_air/commands/recent_activities.py +32 -0
- binalyze_air/commands/relay_server.py +144 -0
- binalyze_air/commands/settings.py +431 -29
- binalyze_air/commands/tasks.py +95 -56
- binalyze_air/commands/triage.py +224 -360
- binalyze_air/commands/user_management.py +351 -126
- binalyze_air/commands/webhook_executions.py +77 -0
- binalyze_air/config.py +244 -244
- binalyze_air/exceptions.py +49 -49
- binalyze_air/http_client.py +426 -305
- binalyze_air/models/__init__.py +287 -285
- binalyze_air/models/acquisitions.py +365 -250
- binalyze_air/models/api_tokens.py +73 -0
- binalyze_air/models/assets.py +438 -438
- binalyze_air/models/audit.py +247 -272
- binalyze_air/models/audit_logs.py +14 -0
- binalyze_air/models/{authentication.py → auth.py} +69 -69
- binalyze_air/models/auto_asset_tags.py +227 -116
- binalyze_air/models/backup.py +138 -0
- binalyze_air/models/baseline.py +231 -231
- binalyze_air/models/cases.py +275 -275
- binalyze_air/models/cloud_forensics.py +145 -0
- binalyze_air/models/event_subscription.py +170 -171
- binalyze_air/models/evidence.py +65 -65
- binalyze_air/models/evidences.py +367 -348
- binalyze_air/models/interact.py +266 -135
- binalyze_air/models/investigation_hub.py +265 -0
- binalyze_air/models/license.py +150 -0
- binalyze_air/models/logger.py +83 -0
- binalyze_air/models/multipart_upload.py +352 -0
- binalyze_air/models/notifications.py +138 -0
- binalyze_air/models/organizations.py +293 -293
- binalyze_air/models/params.py +153 -127
- binalyze_air/models/policies.py +260 -249
- binalyze_air/models/preset_filters.py +79 -0
- binalyze_air/models/recent_activities.py +70 -0
- binalyze_air/models/relay_server.py +121 -0
- binalyze_air/models/settings.py +538 -84
- binalyze_air/models/tasks.py +215 -149
- binalyze_air/models/triage.py +141 -142
- binalyze_air/models/user_management.py +200 -97
- binalyze_air/models/webhook_executions.py +33 -0
- binalyze_air/queries/__init__.py +121 -133
- binalyze_air/queries/acquisitions.py +155 -155
- binalyze_air/queries/api_tokens.py +46 -0
- binalyze_air/queries/assets.py +186 -105
- binalyze_air/queries/audit.py +400 -416
- binalyze_air/queries/{authentication.py → auth.py} +55 -55
- binalyze_air/queries/auto_asset_tags.py +59 -59
- binalyze_air/queries/backup.py +66 -0
- binalyze_air/queries/baseline.py +21 -185
- binalyze_air/queries/cases.py +292 -292
- binalyze_air/queries/cloud_forensics.py +137 -0
- binalyze_air/queries/event_subscription.py +54 -54
- binalyze_air/queries/evidence.py +139 -139
- binalyze_air/queries/evidences.py +279 -279
- binalyze_air/queries/interact.py +140 -28
- binalyze_air/queries/investigation_hub.py +329 -0
- binalyze_air/queries/license.py +85 -0
- binalyze_air/queries/logger.py +58 -0
- binalyze_air/queries/multipart_upload.py +180 -0
- binalyze_air/queries/notifications.py +71 -0
- binalyze_air/queries/organizations.py +222 -222
- binalyze_air/queries/params.py +154 -115
- binalyze_air/queries/policies.py +149 -149
- binalyze_air/queries/preset_filters.py +60 -0
- binalyze_air/queries/recent_activities.py +44 -0
- binalyze_air/queries/relay_server.py +42 -0
- binalyze_air/queries/settings.py +533 -20
- binalyze_air/queries/tasks.py +125 -81
- binalyze_air/queries/triage.py +230 -230
- binalyze_air/queries/user_management.py +193 -83
- binalyze_air/queries/webhook_executions.py +39 -0
- binalyze_air_sdk-1.0.3.dist-info/METADATA +752 -0
- binalyze_air_sdk-1.0.3.dist-info/RECORD +132 -0
- {binalyze_air_sdk-1.0.2.dist-info → binalyze_air_sdk-1.0.3.dist-info}/WHEEL +1 -1
- binalyze_air/apis/endpoints.py +0 -22
- binalyze_air/apis/evidences.py +0 -216
- binalyze_air/apis/users.py +0 -68
- binalyze_air/commands/users.py +0 -101
- binalyze_air/models/endpoints.py +0 -76
- binalyze_air/models/users.py +0 -82
- binalyze_air/queries/endpoints.py +0 -25
- binalyze_air/queries/users.py +0 -69
- binalyze_air_sdk-1.0.2.dist-info/METADATA +0 -706
- binalyze_air_sdk-1.0.2.dist-info/RECORD +0 -82
- {binalyze_air_sdk-1.0.2.dist-info → binalyze_air_sdk-1.0.3.dist-info}/top_level.txt +0 -0
binalyze_air/commands/triage.py
CHANGED
@@ -1,360 +1,224 @@
|
|
1
|
-
"""
|
2
|
-
Triage-related commands for the Binalyze AIR SDK.
|
3
|
-
"""
|
4
|
-
|
5
|
-
from typing import Dict, Any, Union
|
6
|
-
|
7
|
-
from ..base import Command
|
8
|
-
from ..models.triage import (
|
9
|
-
TriageRule, TriageTag, TriageProfile, CreateTriageRuleRequest,
|
10
|
-
UpdateTriageRuleRequest, CreateTriageTagRequest, CreateTriageProfileRequest
|
11
|
-
)
|
12
|
-
from ..http_client import HTTPClient
|
13
|
-
|
14
|
-
|
15
|
-
class CreateTriageRuleCommand(Command[TriageRule]):
|
16
|
-
"""Command to create a new triage rule."""
|
17
|
-
|
18
|
-
def __init__(self, http_client: HTTPClient, request: Union[CreateTriageRuleRequest, Dict[str, Any]]):
|
19
|
-
self.http_client = http_client
|
20
|
-
self.request = request
|
21
|
-
|
22
|
-
def execute(self) -> TriageRule:
|
23
|
-
"""Execute the command to create a triage rule."""
|
24
|
-
# Handle both dict and model objects
|
25
|
-
if isinstance(self.request, dict):
|
26
|
-
data = self.request.copy()
|
27
|
-
else:
|
28
|
-
# Convert SDK model fields to API fields
|
29
|
-
request_dict = self.request.model_dump(exclude_none=True)
|
30
|
-
data = {
|
31
|
-
"description": request_dict.get("description") or request_dict.get("name", ""),
|
32
|
-
"rule": request_dict.get("rule_content", ""),
|
33
|
-
"engine": request_dict.get("type", "yara"),
|
34
|
-
"searchIn": request_dict.get("search_in", "filesystem"),
|
35
|
-
"organizationIds": [request_dict.get("organization_id", 0)]
|
36
|
-
}
|
37
|
-
|
38
|
-
response = self.http_client.post("triages/rules", json_data=data)
|
39
|
-
|
40
|
-
entity_data = response.get("result", {})
|
41
|
-
|
42
|
-
mapped_data = {
|
43
|
-
"id": entity_data.get("_id"),
|
44
|
-
"name": entity_data.get("description", ""), # API uses description as name
|
45
|
-
"description": entity_data.get("description"),
|
46
|
-
"type": entity_data.get("engine"), # API uses engine field
|
47
|
-
"rule_content": entity_data.get("rule", ""),
|
48
|
-
"search_in": entity_data.get("searchIn"),
|
49
|
-
"enabled": entity_data.get("enabled", True),
|
50
|
-
"severity": entity_data.get("severity", "medium"),
|
51
|
-
"tags": entity_data.get("tags", []),
|
52
|
-
"organization_id": entity_data.get("organizationIds", [0])[0] if entity_data.get("organizationIds") else 0,
|
53
|
-
"organization_ids": entity_data.get("organizationIds", []),
|
54
|
-
"created_at": entity_data.get("createdAt"),
|
55
|
-
"updated_at": entity_data.get("updatedAt"),
|
56
|
-
"created_by": entity_data.get("createdBy"),
|
57
|
-
"updated_by": entity_data.get("updatedBy"),
|
58
|
-
"match_count": entity_data.get("matchCount", 0),
|
59
|
-
"last_match": entity_data.get("lastMatch"),
|
60
|
-
"deletable": entity_data.get("deletable"),
|
61
|
-
}
|
62
|
-
|
63
|
-
# Remove None values
|
64
|
-
mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
|
65
|
-
|
66
|
-
return TriageRule(**mapped_data)
|
67
|
-
|
68
|
-
|
69
|
-
class UpdateTriageRuleCommand(Command[TriageRule]):
|
70
|
-
"""Command to update an existing triage rule."""
|
71
|
-
|
72
|
-
def __init__(self, http_client: HTTPClient, rule_id: str, request: Union[UpdateTriageRuleRequest, Dict[str, Any]]):
|
73
|
-
self.http_client = http_client
|
74
|
-
self.rule_id = rule_id
|
75
|
-
self.request = request
|
76
|
-
|
77
|
-
def execute(self) -> TriageRule:
|
78
|
-
"""Execute the command to update a triage rule."""
|
79
|
-
# Handle both dict and model objects
|
80
|
-
if isinstance(self.request, dict):
|
81
|
-
data = self.request.copy()
|
82
|
-
else:
|
83
|
-
# Convert SDK model fields to API fields
|
84
|
-
request_dict = self.request.model_dump(exclude_none=True)
|
85
|
-
data = {}
|
86
|
-
|
87
|
-
# Map SDK fields to API fields for update
|
88
|
-
if "description" in request_dict or "name" in request_dict:
|
89
|
-
data["description"] = request_dict.get("description") or request_dict.get("name", "")
|
90
|
-
if "rule_content" in request_dict:
|
91
|
-
data["rule"] = request_dict.get("rule_content")
|
92
|
-
if "type" in request_dict:
|
93
|
-
data["engine"] = request_dict.get("type")
|
94
|
-
if "search_in" in request_dict:
|
95
|
-
data["searchIn"] = request_dict.get("search_in")
|
96
|
-
if "organization_id" in request_dict:
|
97
|
-
data["organizationIds"] = [request_dict.get("organization_id")]
|
98
|
-
if "enabled" in request_dict:
|
99
|
-
data["enabled"] = request_dict.get("enabled")
|
100
|
-
|
101
|
-
response = self.http_client.put(f"triages/rules/{self.rule_id}", json_data=data)
|
102
|
-
|
103
|
-
entity_data = response.get("result", {})
|
104
|
-
|
105
|
-
mapped_data = {
|
106
|
-
"id": entity_data.get("_id"),
|
107
|
-
"name": entity_data.get("description", ""), # API uses description as name
|
108
|
-
"description": entity_data.get("description"),
|
109
|
-
"type": entity_data.get("engine"), # API uses engine field
|
110
|
-
"rule_content": entity_data.get("rule", ""),
|
111
|
-
"search_in": entity_data.get("searchIn"),
|
112
|
-
"enabled": entity_data.get("enabled", True),
|
113
|
-
"severity": entity_data.get("severity", "medium"),
|
114
|
-
"tags": entity_data.get("tags", []),
|
115
|
-
"organization_id": entity_data.get("organizationIds", [0])[0] if entity_data.get("organizationIds") else 0,
|
116
|
-
"organization_ids": entity_data.get("organizationIds", []),
|
117
|
-
"created_at": entity_data.get("createdAt"),
|
118
|
-
"updated_at": entity_data.get("updatedAt"),
|
119
|
-
"created_by": entity_data.get("createdBy"),
|
120
|
-
"updated_by": entity_data.get("updatedBy"),
|
121
|
-
"match_count": entity_data.get("matchCount", 0),
|
122
|
-
"last_match": entity_data.get("lastMatch"),
|
123
|
-
"deletable": entity_data.get("deletable"),
|
124
|
-
}
|
125
|
-
|
126
|
-
# Remove None values
|
127
|
-
mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
|
128
|
-
|
129
|
-
return TriageRule(**mapped_data)
|
130
|
-
|
131
|
-
|
132
|
-
class DeleteTriageRuleCommand(Command[Dict[str, Any]]):
|
133
|
-
"""Command to delete a triage rule."""
|
134
|
-
|
135
|
-
def __init__(self, http_client: HTTPClient, rule_id: str):
|
136
|
-
self.http_client = http_client
|
137
|
-
self.rule_id = rule_id
|
138
|
-
|
139
|
-
def execute(self) -> Dict[str, Any]:
|
140
|
-
"""Execute the command to delete a triage rule."""
|
141
|
-
response = self.http_client.delete(f"triages/rules/{self.rule_id}")
|
142
|
-
return response
|
143
|
-
|
144
|
-
|
145
|
-
class EnableTriageRuleCommand(Command[TriageRule]):
|
146
|
-
"""Command to enable a triage rule."""
|
147
|
-
|
148
|
-
def __init__(self, http_client: HTTPClient, rule_id: str):
|
149
|
-
self.http_client = http_client
|
150
|
-
self.rule_id = rule_id
|
151
|
-
|
152
|
-
def execute(self) -> TriageRule:
|
153
|
-
"""Execute the command to enable a triage rule."""
|
154
|
-
data = {"enabled": True}
|
155
|
-
|
156
|
-
response = self.http_client.put(f"triages/rules/{self.rule_id}", json_data=data)
|
157
|
-
|
158
|
-
entity_data = response.get("result", {})
|
159
|
-
|
160
|
-
mapped_data = {
|
161
|
-
"id": entity_data.get("_id"),
|
162
|
-
"name": entity_data.get("name"),
|
163
|
-
"description": entity_data.get("description"),
|
164
|
-
"type": entity_data.get("type"),
|
165
|
-
"rule_content": entity_data.get("ruleContent", ""),
|
166
|
-
"enabled": entity_data.get("enabled", True),
|
167
|
-
"severity": entity_data.get("severity", "medium"),
|
168
|
-
"tags": entity_data.get("tags", []),
|
169
|
-
"organization_id": entity_data.get("organizationId", 0),
|
170
|
-
"created_at": entity_data.get("createdAt"),
|
171
|
-
"updated_at": entity_data.get("updatedAt"),
|
172
|
-
"created_by": entity_data.get("createdBy"),
|
173
|
-
"updated_by": entity_data.get("updatedBy"),
|
174
|
-
"match_count": entity_data.get("matchCount", 0),
|
175
|
-
"last_match": entity_data.get("lastMatch"),
|
176
|
-
}
|
177
|
-
|
178
|
-
# Remove None values
|
179
|
-
mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
|
180
|
-
|
181
|
-
return TriageRule(**mapped_data)
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
"
|
208
|
-
"
|
209
|
-
"
|
210
|
-
"
|
211
|
-
"
|
212
|
-
"
|
213
|
-
"
|
214
|
-
"
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
def __init__(self, http_client: HTTPClient, request: Union[CreateTriageTagRequest, Dict[str, Any]]):
|
227
|
-
self.http_client = http_client
|
228
|
-
self.request = request
|
229
|
-
|
230
|
-
def execute(self) -> TriageTag:
|
231
|
-
"""Execute the command to create a triage tag."""
|
232
|
-
# Handle both dict and model objects
|
233
|
-
if isinstance(self.request, dict):
|
234
|
-
data = self.request
|
235
|
-
else:
|
236
|
-
data = self.request.model_dump(exclude_none=True)
|
237
|
-
|
238
|
-
response = self.http_client.post("triages/tags", json_data=data)
|
239
|
-
|
240
|
-
entity_data = response.get("result", {})
|
241
|
-
|
242
|
-
mapped_data = {
|
243
|
-
"id": entity_data.get("id") or entity_data.get("_id"), # Handle both id and _id
|
244
|
-
"name": entity_data.get("name"),
|
245
|
-
"description": entity_data.get("description"),
|
246
|
-
"color": entity_data.get("color", "#3498db"),
|
247
|
-
"organization_id": entity_data.get("organizationId", 0),
|
248
|
-
"created_at": entity_data.get("createdAt"),
|
249
|
-
"updated_at": entity_data.get("updatedAt"),
|
250
|
-
"created_by": entity_data.get("createdBy", "Unknown"), # Provide default for required field
|
251
|
-
"usage_count": entity_data.get("usageCount") or entity_data.get("count", 0), # Handle both count and usageCount
|
252
|
-
}
|
253
|
-
|
254
|
-
# Remove None values but keep defaults for required fields
|
255
|
-
mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
|
256
|
-
|
257
|
-
return TriageTag(**mapped_data)
|
258
|
-
|
259
|
-
|
260
|
-
class DeleteTriageTagCommand(Command[Dict[str, Any]]):
|
261
|
-
"""Command to delete a triage tag."""
|
262
|
-
|
263
|
-
def __init__(self, http_client: HTTPClient, tag_id: str):
|
264
|
-
self.http_client = http_client
|
265
|
-
self.tag_id = tag_id
|
266
|
-
|
267
|
-
def execute(self) -> Dict[str, Any]:
|
268
|
-
"""Execute the command to delete a triage tag."""
|
269
|
-
response = self.http_client.delete(f"triage/tags/{self.tag_id}")
|
270
|
-
return response
|
271
|
-
|
272
|
-
|
273
|
-
class CreateTriageProfileCommand(Command[TriageProfile]):
|
274
|
-
"""Command to create a new triage profile."""
|
275
|
-
|
276
|
-
def __init__(self, http_client: HTTPClient, request: Union[CreateTriageProfileRequest, Dict[str, Any]]):
|
277
|
-
self.http_client = http_client
|
278
|
-
self.request = request
|
279
|
-
|
280
|
-
def execute(self) -> TriageProfile:
|
281
|
-
"""Execute the command to create a triage profile."""
|
282
|
-
# Handle both dict and model objects
|
283
|
-
if isinstance(self.request, dict):
|
284
|
-
data = self.request
|
285
|
-
else:
|
286
|
-
data = self.request.model_dump(exclude_none=True)
|
287
|
-
|
288
|
-
response = self.http_client.post("triage/profiles", json_data=data)
|
289
|
-
|
290
|
-
entity_data = response.get("result", {})
|
291
|
-
|
292
|
-
mapped_data = {
|
293
|
-
"id": entity_data.get("_id"),
|
294
|
-
"name": entity_data.get("name"),
|
295
|
-
"description": entity_data.get("description"),
|
296
|
-
"rules": entity_data.get("rules", []),
|
297
|
-
"enabled": entity_data.get("enabled", True),
|
298
|
-
"organization_id": entity_data.get("organizationId", 0),
|
299
|
-
"created_at": entity_data.get("createdAt"),
|
300
|
-
"updated_at": entity_data.get("updatedAt"),
|
301
|
-
"created_by": entity_data.get("createdBy"),
|
302
|
-
"updated_by": entity_data.get("updatedBy"),
|
303
|
-
}
|
304
|
-
|
305
|
-
# Remove None values
|
306
|
-
mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
|
307
|
-
|
308
|
-
return TriageProfile(**mapped_data)
|
309
|
-
|
310
|
-
|
311
|
-
class UpdateTriageProfileCommand(Command[TriageProfile]):
|
312
|
-
"""Command to update an existing triage profile."""
|
313
|
-
|
314
|
-
def __init__(self, http_client: HTTPClient, profile_id: str, request: Union[CreateTriageProfileRequest, Dict[str, Any]]):
|
315
|
-
self.http_client = http_client
|
316
|
-
self.profile_id = profile_id
|
317
|
-
self.request = request
|
318
|
-
|
319
|
-
def execute(self) -> TriageProfile:
|
320
|
-
"""Execute the command to update a triage profile."""
|
321
|
-
# Handle both dict and model objects
|
322
|
-
if isinstance(self.request, dict):
|
323
|
-
data = self.request
|
324
|
-
else:
|
325
|
-
data = self.request.model_dump(exclude_none=True)
|
326
|
-
|
327
|
-
response = self.http_client.put(f"triage/profiles/{self.profile_id}", json_data=data)
|
328
|
-
|
329
|
-
entity_data = response.get("result", {})
|
330
|
-
|
331
|
-
mapped_data = {
|
332
|
-
"id": entity_data.get("_id"),
|
333
|
-
"name": entity_data.get("name"),
|
334
|
-
"description": entity_data.get("description"),
|
335
|
-
"rules": entity_data.get("rules", []),
|
336
|
-
"enabled": entity_data.get("enabled", True),
|
337
|
-
"organization_id": entity_data.get("organizationId", 0),
|
338
|
-
"created_at": entity_data.get("createdAt"),
|
339
|
-
"updated_at": entity_data.get("updatedAt"),
|
340
|
-
"created_by": entity_data.get("createdBy"),
|
341
|
-
"updated_by": entity_data.get("updatedBy"),
|
342
|
-
}
|
343
|
-
|
344
|
-
# Remove None values
|
345
|
-
mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
|
346
|
-
|
347
|
-
return TriageProfile(**mapped_data)
|
348
|
-
|
349
|
-
|
350
|
-
class DeleteTriageProfileCommand(Command[Dict[str, Any]]):
|
351
|
-
"""Command to delete a triage profile."""
|
352
|
-
|
353
|
-
def __init__(self, http_client: HTTPClient, profile_id: str):
|
354
|
-
self.http_client = http_client
|
355
|
-
self.profile_id = profile_id
|
356
|
-
|
357
|
-
def execute(self) -> Dict[str, Any]:
|
358
|
-
"""Execute the command to delete a triage profile."""
|
359
|
-
response = self.http_client.delete(f"triage/profiles/{self.profile_id}")
|
360
|
-
return response
|
1
|
+
"""
|
2
|
+
Triage-related commands for the Binalyze AIR SDK.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from typing import Dict, Any, Union
|
6
|
+
|
7
|
+
from ..base import Command
|
8
|
+
from ..models.triage import (
|
9
|
+
TriageRule, TriageTag, TriageProfile, CreateTriageRuleRequest,
|
10
|
+
UpdateTriageRuleRequest, CreateTriageTagRequest, CreateTriageProfileRequest
|
11
|
+
)
|
12
|
+
from ..http_client import HTTPClient
|
13
|
+
|
14
|
+
|
15
|
+
class CreateTriageRuleCommand(Command[TriageRule]):
|
16
|
+
"""Command to create a new triage rule."""
|
17
|
+
|
18
|
+
def __init__(self, http_client: HTTPClient, request: Union[CreateTriageRuleRequest, Dict[str, Any]]):
|
19
|
+
self.http_client = http_client
|
20
|
+
self.request = request
|
21
|
+
|
22
|
+
def execute(self) -> TriageRule:
|
23
|
+
"""Execute the command to create a triage rule."""
|
24
|
+
# Handle both dict and model objects
|
25
|
+
if isinstance(self.request, dict):
|
26
|
+
data = self.request.copy()
|
27
|
+
else:
|
28
|
+
# Convert SDK model fields to API fields
|
29
|
+
request_dict = self.request.model_dump(exclude_none=True)
|
30
|
+
data = {
|
31
|
+
"description": request_dict.get("description") or request_dict.get("name", ""),
|
32
|
+
"rule": request_dict.get("rule_content", ""),
|
33
|
+
"engine": request_dict.get("type", "yara"),
|
34
|
+
"searchIn": request_dict.get("search_in", "filesystem"),
|
35
|
+
"organizationIds": [request_dict.get("organization_id", 0)]
|
36
|
+
}
|
37
|
+
|
38
|
+
response = self.http_client.post("triages/rules", json_data=data)
|
39
|
+
|
40
|
+
entity_data = response.get("result", {})
|
41
|
+
|
42
|
+
mapped_data = {
|
43
|
+
"id": entity_data.get("_id"),
|
44
|
+
"name": entity_data.get("description", ""), # API uses description as name
|
45
|
+
"description": entity_data.get("description"),
|
46
|
+
"type": entity_data.get("engine"), # API uses engine field
|
47
|
+
"rule_content": entity_data.get("rule", ""),
|
48
|
+
"search_in": entity_data.get("searchIn"),
|
49
|
+
"enabled": entity_data.get("enabled", True),
|
50
|
+
"severity": entity_data.get("severity", "medium"),
|
51
|
+
"tags": entity_data.get("tags", []),
|
52
|
+
"organization_id": entity_data.get("organizationIds", [0])[0] if entity_data.get("organizationIds") else 0,
|
53
|
+
"organization_ids": entity_data.get("organizationIds", []),
|
54
|
+
"created_at": entity_data.get("createdAt"),
|
55
|
+
"updated_at": entity_data.get("updatedAt"),
|
56
|
+
"created_by": entity_data.get("createdBy"),
|
57
|
+
"updated_by": entity_data.get("updatedBy"),
|
58
|
+
"match_count": entity_data.get("matchCount", 0),
|
59
|
+
"last_match": entity_data.get("lastMatch"),
|
60
|
+
"deletable": entity_data.get("deletable"),
|
61
|
+
}
|
62
|
+
|
63
|
+
# Remove None values
|
64
|
+
mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
|
65
|
+
|
66
|
+
return TriageRule(**mapped_data)
|
67
|
+
|
68
|
+
|
69
|
+
class UpdateTriageRuleCommand(Command[TriageRule]):
|
70
|
+
"""Command to update an existing triage rule."""
|
71
|
+
|
72
|
+
def __init__(self, http_client: HTTPClient, rule_id: str, request: Union[UpdateTriageRuleRequest, Dict[str, Any]]):
|
73
|
+
self.http_client = http_client
|
74
|
+
self.rule_id = rule_id
|
75
|
+
self.request = request
|
76
|
+
|
77
|
+
def execute(self) -> TriageRule:
|
78
|
+
"""Execute the command to update a triage rule."""
|
79
|
+
# Handle both dict and model objects
|
80
|
+
if isinstance(self.request, dict):
|
81
|
+
data = self.request.copy()
|
82
|
+
else:
|
83
|
+
# Convert SDK model fields to API fields
|
84
|
+
request_dict = self.request.model_dump(exclude_none=True)
|
85
|
+
data = {}
|
86
|
+
|
87
|
+
# Map SDK fields to API fields for update
|
88
|
+
if "description" in request_dict or "name" in request_dict:
|
89
|
+
data["description"] = request_dict.get("description") or request_dict.get("name", "")
|
90
|
+
if "rule_content" in request_dict:
|
91
|
+
data["rule"] = request_dict.get("rule_content")
|
92
|
+
if "type" in request_dict:
|
93
|
+
data["engine"] = request_dict.get("type")
|
94
|
+
if "search_in" in request_dict:
|
95
|
+
data["searchIn"] = request_dict.get("search_in")
|
96
|
+
if "organization_id" in request_dict:
|
97
|
+
data["organizationIds"] = [request_dict.get("organization_id")]
|
98
|
+
if "enabled" in request_dict:
|
99
|
+
data["enabled"] = request_dict.get("enabled")
|
100
|
+
|
101
|
+
response = self.http_client.put(f"triages/rules/{self.rule_id}", json_data=data)
|
102
|
+
|
103
|
+
entity_data = response.get("result", {})
|
104
|
+
|
105
|
+
mapped_data = {
|
106
|
+
"id": entity_data.get("_id"),
|
107
|
+
"name": entity_data.get("description", ""), # API uses description as name
|
108
|
+
"description": entity_data.get("description"),
|
109
|
+
"type": entity_data.get("engine"), # API uses engine field
|
110
|
+
"rule_content": entity_data.get("rule", ""),
|
111
|
+
"search_in": entity_data.get("searchIn"),
|
112
|
+
"enabled": entity_data.get("enabled", True),
|
113
|
+
"severity": entity_data.get("severity", "medium"),
|
114
|
+
"tags": entity_data.get("tags", []),
|
115
|
+
"organization_id": entity_data.get("organizationIds", [0])[0] if entity_data.get("organizationIds") else 0,
|
116
|
+
"organization_ids": entity_data.get("organizationIds", []),
|
117
|
+
"created_at": entity_data.get("createdAt"),
|
118
|
+
"updated_at": entity_data.get("updatedAt"),
|
119
|
+
"created_by": entity_data.get("createdBy"),
|
120
|
+
"updated_by": entity_data.get("updatedBy"),
|
121
|
+
"match_count": entity_data.get("matchCount", 0),
|
122
|
+
"last_match": entity_data.get("lastMatch"),
|
123
|
+
"deletable": entity_data.get("deletable"),
|
124
|
+
}
|
125
|
+
|
126
|
+
# Remove None values
|
127
|
+
mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
|
128
|
+
|
129
|
+
return TriageRule(**mapped_data)
|
130
|
+
|
131
|
+
|
132
|
+
class DeleteTriageRuleCommand(Command[Dict[str, Any]]):
|
133
|
+
"""Command to delete a triage rule."""
|
134
|
+
|
135
|
+
def __init__(self, http_client: HTTPClient, rule_id: str):
|
136
|
+
self.http_client = http_client
|
137
|
+
self.rule_id = rule_id
|
138
|
+
|
139
|
+
def execute(self) -> Dict[str, Any]:
|
140
|
+
"""Execute the command to delete a triage rule."""
|
141
|
+
response = self.http_client.delete(f"triages/rules/{self.rule_id}")
|
142
|
+
return response
|
143
|
+
|
144
|
+
|
145
|
+
class EnableTriageRuleCommand(Command[TriageRule]):
|
146
|
+
"""Command to enable a triage rule."""
|
147
|
+
|
148
|
+
def __init__(self, http_client: HTTPClient, rule_id: str):
|
149
|
+
self.http_client = http_client
|
150
|
+
self.rule_id = rule_id
|
151
|
+
|
152
|
+
def execute(self) -> TriageRule:
|
153
|
+
"""Execute the command to enable a triage rule."""
|
154
|
+
data = {"enabled": True}
|
155
|
+
|
156
|
+
response = self.http_client.put(f"triages/rules/{self.rule_id}", json_data=data)
|
157
|
+
|
158
|
+
entity_data = response.get("result", {})
|
159
|
+
|
160
|
+
mapped_data = {
|
161
|
+
"id": entity_data.get("_id"),
|
162
|
+
"name": entity_data.get("name"),
|
163
|
+
"description": entity_data.get("description"),
|
164
|
+
"type": entity_data.get("type"),
|
165
|
+
"rule_content": entity_data.get("ruleContent", ""),
|
166
|
+
"enabled": entity_data.get("enabled", True),
|
167
|
+
"severity": entity_data.get("severity", "medium"),
|
168
|
+
"tags": entity_data.get("tags", []),
|
169
|
+
"organization_id": entity_data.get("organizationId", 0),
|
170
|
+
"created_at": entity_data.get("createdAt"),
|
171
|
+
"updated_at": entity_data.get("updatedAt"),
|
172
|
+
"created_by": entity_data.get("createdBy"),
|
173
|
+
"updated_by": entity_data.get("updatedBy"),
|
174
|
+
"match_count": entity_data.get("matchCount", 0),
|
175
|
+
"last_match": entity_data.get("lastMatch"),
|
176
|
+
}
|
177
|
+
|
178
|
+
# Remove None values
|
179
|
+
mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
|
180
|
+
|
181
|
+
return TriageRule(**mapped_data)
|
182
|
+
|
183
|
+
|
184
|
+
|
185
|
+
|
186
|
+
|
187
|
+
class CreateTriageTagCommand(Command[TriageTag]):
|
188
|
+
"""Command to create a new triage tag."""
|
189
|
+
|
190
|
+
def __init__(self, http_client: HTTPClient, request: Union[CreateTriageTagRequest, Dict[str, Any]]):
|
191
|
+
self.http_client = http_client
|
192
|
+
self.request = request
|
193
|
+
|
194
|
+
def execute(self) -> TriageTag:
|
195
|
+
"""Execute the command to create a triage tag."""
|
196
|
+
# Handle both dict and model objects
|
197
|
+
if isinstance(self.request, dict):
|
198
|
+
data = self.request
|
199
|
+
else:
|
200
|
+
data = self.request.model_dump(exclude_none=True, by_alias=True)
|
201
|
+
|
202
|
+
response = self.http_client.post("triages/tags", json_data=data)
|
203
|
+
|
204
|
+
entity_data = response.get("result", {})
|
205
|
+
|
206
|
+
mapped_data = {
|
207
|
+
"id": entity_data.get("id") or entity_data.get("_id"), # Handle both id and _id
|
208
|
+
"name": entity_data.get("name"),
|
209
|
+
"description": entity_data.get("description"),
|
210
|
+
"color": entity_data.get("color", "#3498db"),
|
211
|
+
"organization_id": entity_data.get("organizationId", 0),
|
212
|
+
"created_at": entity_data.get("createdAt"),
|
213
|
+
"updated_at": entity_data.get("updatedAt"),
|
214
|
+
"created_by": entity_data.get("createdBy", "Unknown"), # Provide default for required field
|
215
|
+
"usage_count": entity_data.get("usageCount") or entity_data.get("count", 0), # Handle both count and usageCount
|
216
|
+
}
|
217
|
+
|
218
|
+
# Remove None values but keep defaults for required fields
|
219
|
+
mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
|
220
|
+
|
221
|
+
return TriageTag(**mapped_data)
|
222
|
+
|
223
|
+
|
224
|
+
|