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
@@ -1,387 +1,661 @@
|
|
1
|
-
"""
|
2
|
-
Acquisition-related commands for the Binalyze AIR SDK.
|
3
|
-
Fixed to match API documentation exactly.
|
4
|
-
"""
|
5
|
-
|
6
|
-
from typing import List, Dict, Any
|
7
|
-
|
8
|
-
from ..base import Command
|
9
|
-
from ..models.acquisitions import (
|
10
|
-
AcquisitionTaskRequest, ImageAcquisitionTaskRequest, CreateAcquisitionProfileRequest,
|
11
|
-
CreateAcquisitionRequest, CreateImageAcquisitionRequest
|
12
|
-
)
|
13
|
-
from ..models.assets import AssetFilter
|
14
|
-
from ..http_client import HTTPClient
|
15
|
-
|
16
|
-
|
17
|
-
class AssignAcquisitionTaskCommand(Command[List[Dict[str, Any]]]):
|
18
|
-
"""Command to assign acquisition task - FIXED to match API documentation exactly."""
|
19
|
-
|
20
|
-
def __init__(self, http_client: HTTPClient, request: AcquisitionTaskRequest):
|
21
|
-
self.http_client = http_client
|
22
|
-
self.request = request
|
23
|
-
|
24
|
-
def execute(self) -> List[Dict[str, Any]]:
|
25
|
-
"""Execute the acquisition task assignment with correct payload structure."""
|
26
|
-
# FIXED: Use proper API payload structure as per documentation
|
27
|
-
payload = {
|
28
|
-
"caseId": self.request.case_id,
|
29
|
-
"acquisitionProfileId": self.request.acquisition_profile_id,
|
30
|
-
"droneConfig": {
|
31
|
-
"autoPilot": self.request.drone_config.auto_pilot if self.request.drone_config else False,
|
32
|
-
"enabled": self.request.drone_config.enabled if self.request.drone_config else False,
|
33
|
-
"analyzers": self.request.drone_config.analyzers if self.request.drone_config else ["bha", "wsa", "aa", "ara"],
|
34
|
-
"keywords": self.request.drone_config.keywords if self.request.drone_config else []
|
35
|
-
},
|
36
|
-
"taskConfig": {
|
37
|
-
"choice": self.request.task_config.choice if self.request.task_config else "use-custom-options",
|
38
|
-
"saveTo": {
|
39
|
-
"windows": {
|
40
|
-
"location": "local",
|
41
|
-
"useMostFreeVolume": True,
|
42
|
-
"repositoryId": None,
|
43
|
-
"path": "Binalyze\\AIR\\",
|
44
|
-
"volume": "C:",
|
45
|
-
"tmp": "Binalyze\\AIR\\tmp",
|
46
|
-
"directCollection": False
|
47
|
-
},
|
48
|
-
"linux": {
|
49
|
-
"location": "local",
|
50
|
-
"useMostFreeVolume": True,
|
51
|
-
"repositoryId": None,
|
52
|
-
"path": "opt/binalyze/air",
|
53
|
-
"tmp": "opt/binalyze/air/tmp",
|
54
|
-
"directCollection": False
|
55
|
-
},
|
56
|
-
"macos": {
|
57
|
-
"location": "local",
|
58
|
-
"useMostFreeVolume": False,
|
59
|
-
"repositoryId": None,
|
60
|
-
"path": "opt/binalyze/air",
|
61
|
-
"volume": "/",
|
62
|
-
"tmp": "opt/binalyze/air/tmp",
|
63
|
-
"directCollection": False
|
64
|
-
},
|
65
|
-
"aix": {
|
66
|
-
"location": "local",
|
67
|
-
"useMostFreeVolume": True,
|
68
|
-
"path": "opt/binalyze/air",
|
69
|
-
"volume": "/",
|
70
|
-
"tmp": "opt/binalyze/air/tmp",
|
71
|
-
"directCollection": False
|
72
|
-
}
|
73
|
-
},
|
74
|
-
"cpu": self.request.task_config.cpu if self.request.task_config else {"limit": 80},
|
75
|
-
"compression": self.request.task_config.compression if self.request.task_config else {
|
76
|
-
"enabled": True,
|
77
|
-
"encryption": {
|
78
|
-
"enabled": False,
|
79
|
-
"password": ""
|
80
|
-
}
|
81
|
-
}
|
82
|
-
},
|
83
|
-
"filter": {
|
84
|
-
"searchTerm": self.request.filter.search_term or "",
|
85
|
-
"name": self.request.filter.name or "",
|
86
|
-
"ipAddress": self.request.filter.ip_address or "",
|
87
|
-
"groupId": self.request.filter.group_id or "",
|
88
|
-
"groupFullPath": self.request.filter.group_full_path or "",
|
89
|
-
"managedStatus": self.request.filter.managed_status or [],
|
90
|
-
"isolationStatus": self.request.filter.isolation_status or [],
|
91
|
-
"platform": self.request.filter.platform or [],
|
92
|
-
"issue": self.request.filter.issue or "",
|
93
|
-
"onlineStatus": self.request.filter.online_status or [],
|
94
|
-
"tags": self.request.filter.tags or [],
|
95
|
-
"version": self.request.filter.version or "",
|
96
|
-
"policy": self.request.filter.policy or "",
|
97
|
-
"includedEndpointIds": self.request.filter.included_endpoint_ids or [],
|
98
|
-
"excludedEndpointIds": self.request.filter.excluded_endpoint_ids or [],
|
99
|
-
"organizationIds": self.request.filter.organization_ids or [0]
|
100
|
-
},
|
101
|
-
"schedulerConfig": {
|
102
|
-
"when": "now"
|
103
|
-
}
|
104
|
-
}
|
105
|
-
|
106
|
-
# FIXED: Correct endpoint URL
|
107
|
-
response = self.http_client.post("acquisitions/acquire", json_data=payload)
|
108
|
-
|
109
|
-
return response.get("result", [])
|
110
|
-
|
111
|
-
|
112
|
-
class CreateAcquisitionCommand(Command[Dict[str, Any]]):
|
113
|
-
"""Command to create acquisition task using simplified request - FIXED to match API."""
|
114
|
-
|
115
|
-
def __init__(self, http_client: HTTPClient, request: CreateAcquisitionRequest):
|
116
|
-
self.http_client = http_client
|
117
|
-
self.request = request
|
118
|
-
|
119
|
-
def execute(self) -> Dict[str, Any]:
|
120
|
-
"""Execute the acquisition task assignment with correct structure."""
|
121
|
-
# FIXED: Use proper filter structure instead of direct filter object
|
122
|
-
payload = {
|
123
|
-
"caseId": getattr(self.request, 'case_id', None),
|
124
|
-
"acquisitionProfileId": self.request.profileId,
|
125
|
-
"droneConfig": {
|
126
|
-
"autoPilot": False,
|
127
|
-
"enabled": False,
|
128
|
-
"analyzers": ["bha", "wsa", "aa", "ara"],
|
129
|
-
"keywords": []
|
130
|
-
},
|
131
|
-
"taskConfig": {
|
132
|
-
"choice": "use-custom-options",
|
133
|
-
"saveTo": {
|
134
|
-
"windows": {
|
135
|
-
"location": "local",
|
136
|
-
"useMostFreeVolume": True,
|
137
|
-
"repositoryId": None,
|
138
|
-
"path": "Binalyze\\AIR\\",
|
139
|
-
"volume": "C:",
|
140
|
-
"tmp": "Binalyze\\AIR\\tmp",
|
141
|
-
"directCollection": False
|
142
|
-
},
|
143
|
-
"linux": {
|
144
|
-
"location": "local",
|
145
|
-
"useMostFreeVolume": True,
|
146
|
-
"repositoryId": None,
|
147
|
-
"path": "opt/binalyze/air",
|
148
|
-
"tmp": "opt/binalyze/air/tmp",
|
149
|
-
"directCollection": False
|
150
|
-
},
|
151
|
-
"macos": {
|
152
|
-
"location": "local",
|
153
|
-
"useMostFreeVolume": False,
|
154
|
-
"repositoryId": None,
|
155
|
-
"path": "opt/binalyze/air",
|
156
|
-
"volume": "/",
|
157
|
-
"tmp": "opt/binalyze/air/tmp",
|
158
|
-
"directCollection": False
|
159
|
-
},
|
160
|
-
"aix": {
|
161
|
-
"location": "local",
|
162
|
-
"useMostFreeVolume": True,
|
163
|
-
"path": "opt/binalyze/air",
|
164
|
-
"volume": "/",
|
165
|
-
"tmp": "opt/binalyze/air/tmp",
|
166
|
-
"directCollection": False
|
167
|
-
}
|
168
|
-
},
|
169
|
-
"cpu": {
|
170
|
-
"limit": 80
|
171
|
-
},
|
172
|
-
"compression": {
|
173
|
-
"enabled": True,
|
174
|
-
"encryption": {
|
175
|
-
"enabled": False,
|
176
|
-
"password": ""
|
177
|
-
}
|
178
|
-
}
|
179
|
-
},
|
180
|
-
"filter": self.request.filter.to_filter_dict() if isinstance(self.request.filter, AssetFilter) else self.request.filter,
|
181
|
-
"schedulerConfig": {
|
182
|
-
"when": "now"
|
183
|
-
}
|
184
|
-
}
|
185
|
-
|
186
|
-
if hasattr(self.request, 'name') and self.request.name:
|
187
|
-
payload["taskName"] = self.request.name
|
188
|
-
|
189
|
-
return self.http_client.post("acquisitions/acquire", json_data=payload)
|
190
|
-
|
191
|
-
|
192
|
-
class AssignImageAcquisitionTaskCommand(Command[List[Dict[str, Any]]]):
|
193
|
-
"""Command to assign image acquisition task
|
194
|
-
|
195
|
-
def __init__(self, http_client: HTTPClient, request: ImageAcquisitionTaskRequest):
|
196
|
-
self.http_client = http_client
|
197
|
-
self.request = request
|
198
|
-
|
199
|
-
def execute(self) -> List[Dict[str, Any]]:
|
200
|
-
"""Execute the image acquisition task assignment."""
|
201
|
-
|
202
|
-
payload
|
203
|
-
|
204
|
-
"
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
"
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
}
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
if
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
"
|
360
|
-
"
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
if
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
1
|
+
"""
|
2
|
+
Acquisition-related commands for the Binalyze AIR SDK.
|
3
|
+
Fixed to match API documentation exactly.
|
4
|
+
"""
|
5
|
+
|
6
|
+
from typing import List, Dict, Any
|
7
|
+
|
8
|
+
from ..base import Command
|
9
|
+
from ..models.acquisitions import (
|
10
|
+
AcquisitionTaskRequest, ImageAcquisitionTaskRequest, CreateAcquisitionProfileRequest,
|
11
|
+
CreateAcquisitionRequest, CreateImageAcquisitionRequest
|
12
|
+
)
|
13
|
+
from ..models.assets import AssetFilter
|
14
|
+
from ..http_client import HTTPClient
|
15
|
+
|
16
|
+
|
17
|
+
class AssignAcquisitionTaskCommand(Command[List[Dict[str, Any]]]):
|
18
|
+
"""Command to assign acquisition task - FIXED to match API documentation exactly."""
|
19
|
+
|
20
|
+
def __init__(self, http_client: HTTPClient, request: AcquisitionTaskRequest):
|
21
|
+
self.http_client = http_client
|
22
|
+
self.request = request
|
23
|
+
|
24
|
+
def execute(self) -> List[Dict[str, Any]]:
|
25
|
+
"""Execute the acquisition task assignment with correct payload structure."""
|
26
|
+
# FIXED: Use proper API payload structure as per documentation
|
27
|
+
payload = {
|
28
|
+
"caseId": self.request.case_id,
|
29
|
+
"acquisitionProfileId": self.request.acquisition_profile_id,
|
30
|
+
"droneConfig": {
|
31
|
+
"autoPilot": self.request.drone_config.auto_pilot if self.request.drone_config else False,
|
32
|
+
"enabled": self.request.drone_config.enabled if self.request.drone_config else False,
|
33
|
+
"analyzers": self.request.drone_config.analyzers if self.request.drone_config else ["bha", "wsa", "aa", "ara"],
|
34
|
+
"keywords": self.request.drone_config.keywords if self.request.drone_config else []
|
35
|
+
},
|
36
|
+
"taskConfig": {
|
37
|
+
"choice": self.request.task_config.choice if self.request.task_config else "use-custom-options",
|
38
|
+
"saveTo": {
|
39
|
+
"windows": {
|
40
|
+
"location": "local",
|
41
|
+
"useMostFreeVolume": True,
|
42
|
+
"repositoryId": None,
|
43
|
+
"path": "Binalyze\\AIR\\",
|
44
|
+
"volume": "C:",
|
45
|
+
"tmp": "Binalyze\\AIR\\tmp",
|
46
|
+
"directCollection": False
|
47
|
+
},
|
48
|
+
"linux": {
|
49
|
+
"location": "local",
|
50
|
+
"useMostFreeVolume": True,
|
51
|
+
"repositoryId": None,
|
52
|
+
"path": "opt/binalyze/air",
|
53
|
+
"tmp": "opt/binalyze/air/tmp",
|
54
|
+
"directCollection": False
|
55
|
+
},
|
56
|
+
"macos": {
|
57
|
+
"location": "local",
|
58
|
+
"useMostFreeVolume": False,
|
59
|
+
"repositoryId": None,
|
60
|
+
"path": "opt/binalyze/air",
|
61
|
+
"volume": "/",
|
62
|
+
"tmp": "opt/binalyze/air/tmp",
|
63
|
+
"directCollection": False
|
64
|
+
},
|
65
|
+
"aix": {
|
66
|
+
"location": "local",
|
67
|
+
"useMostFreeVolume": True,
|
68
|
+
"path": "opt/binalyze/air",
|
69
|
+
"volume": "/",
|
70
|
+
"tmp": "opt/binalyze/air/tmp",
|
71
|
+
"directCollection": False
|
72
|
+
}
|
73
|
+
},
|
74
|
+
"cpu": self.request.task_config.cpu if self.request.task_config else {"limit": 80},
|
75
|
+
"compression": self.request.task_config.compression if self.request.task_config else {
|
76
|
+
"enabled": True,
|
77
|
+
"encryption": {
|
78
|
+
"enabled": False,
|
79
|
+
"password": ""
|
80
|
+
}
|
81
|
+
}
|
82
|
+
},
|
83
|
+
"filter": {
|
84
|
+
"searchTerm": self.request.filter.search_term or "",
|
85
|
+
"name": self.request.filter.name or "",
|
86
|
+
"ipAddress": self.request.filter.ip_address or "",
|
87
|
+
"groupId": self.request.filter.group_id or "",
|
88
|
+
"groupFullPath": self.request.filter.group_full_path or "",
|
89
|
+
"managedStatus": self.request.filter.managed_status or [],
|
90
|
+
"isolationStatus": self.request.filter.isolation_status or [],
|
91
|
+
"platform": self.request.filter.platform or [],
|
92
|
+
"issue": self.request.filter.issue or "",
|
93
|
+
"onlineStatus": self.request.filter.online_status or [],
|
94
|
+
"tags": self.request.filter.tags or [],
|
95
|
+
"version": self.request.filter.version or "",
|
96
|
+
"policy": self.request.filter.policy or "",
|
97
|
+
"includedEndpointIds": self.request.filter.included_endpoint_ids or [],
|
98
|
+
"excludedEndpointIds": self.request.filter.excluded_endpoint_ids or [],
|
99
|
+
"organizationIds": self.request.filter.organization_ids or [0]
|
100
|
+
},
|
101
|
+
"schedulerConfig": {
|
102
|
+
"when": "now"
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
# FIXED: Correct endpoint URL
|
107
|
+
response = self.http_client.post("acquisitions/acquire", json_data=payload)
|
108
|
+
|
109
|
+
return response.get("result", [])
|
110
|
+
|
111
|
+
|
112
|
+
class CreateAcquisitionCommand(Command[Dict[str, Any]]):
|
113
|
+
"""Command to create acquisition task using simplified request - FIXED to match API."""
|
114
|
+
|
115
|
+
def __init__(self, http_client: HTTPClient, request: CreateAcquisitionRequest):
|
116
|
+
self.http_client = http_client
|
117
|
+
self.request = request
|
118
|
+
|
119
|
+
def execute(self) -> Dict[str, Any]:
|
120
|
+
"""Execute the acquisition task assignment with correct structure."""
|
121
|
+
# FIXED: Use proper filter structure instead of direct filter object
|
122
|
+
payload = {
|
123
|
+
"caseId": getattr(self.request, 'case_id', None),
|
124
|
+
"acquisitionProfileId": self.request.profileId,
|
125
|
+
"droneConfig": {
|
126
|
+
"autoPilot": False,
|
127
|
+
"enabled": False,
|
128
|
+
"analyzers": ["bha", "wsa", "aa", "ara"],
|
129
|
+
"keywords": []
|
130
|
+
},
|
131
|
+
"taskConfig": {
|
132
|
+
"choice": "use-custom-options",
|
133
|
+
"saveTo": {
|
134
|
+
"windows": {
|
135
|
+
"location": "local",
|
136
|
+
"useMostFreeVolume": True,
|
137
|
+
"repositoryId": None,
|
138
|
+
"path": "Binalyze\\AIR\\",
|
139
|
+
"volume": "C:",
|
140
|
+
"tmp": "Binalyze\\AIR\\tmp",
|
141
|
+
"directCollection": False
|
142
|
+
},
|
143
|
+
"linux": {
|
144
|
+
"location": "local",
|
145
|
+
"useMostFreeVolume": True,
|
146
|
+
"repositoryId": None,
|
147
|
+
"path": "opt/binalyze/air",
|
148
|
+
"tmp": "opt/binalyze/air/tmp",
|
149
|
+
"directCollection": False
|
150
|
+
},
|
151
|
+
"macos": {
|
152
|
+
"location": "local",
|
153
|
+
"useMostFreeVolume": False,
|
154
|
+
"repositoryId": None,
|
155
|
+
"path": "opt/binalyze/air",
|
156
|
+
"volume": "/",
|
157
|
+
"tmp": "opt/binalyze/air/tmp",
|
158
|
+
"directCollection": False
|
159
|
+
},
|
160
|
+
"aix": {
|
161
|
+
"location": "local",
|
162
|
+
"useMostFreeVolume": True,
|
163
|
+
"path": "opt/binalyze/air",
|
164
|
+
"volume": "/",
|
165
|
+
"tmp": "opt/binalyze/air/tmp",
|
166
|
+
"directCollection": False
|
167
|
+
}
|
168
|
+
},
|
169
|
+
"cpu": {
|
170
|
+
"limit": 80
|
171
|
+
},
|
172
|
+
"compression": {
|
173
|
+
"enabled": True,
|
174
|
+
"encryption": {
|
175
|
+
"enabled": False,
|
176
|
+
"password": ""
|
177
|
+
}
|
178
|
+
}
|
179
|
+
},
|
180
|
+
"filter": self.request.filter.to_filter_dict() if isinstance(self.request.filter, AssetFilter) else self.request.filter,
|
181
|
+
"schedulerConfig": {
|
182
|
+
"when": "now"
|
183
|
+
}
|
184
|
+
}
|
185
|
+
|
186
|
+
if hasattr(self.request, 'name') and self.request.name:
|
187
|
+
payload["taskName"] = self.request.name
|
188
|
+
|
189
|
+
return self.http_client.post("acquisitions/acquire", json_data=payload)
|
190
|
+
|
191
|
+
|
192
|
+
class AssignImageAcquisitionTaskCommand(Command[List[Dict[str, Any]]]):
|
193
|
+
"""Command to assign image acquisition task by filter."""
|
194
|
+
|
195
|
+
def __init__(self, http_client: HTTPClient, request: ImageAcquisitionTaskRequest):
|
196
|
+
self.http_client = http_client
|
197
|
+
self.request = request
|
198
|
+
|
199
|
+
def execute(self) -> List[Dict[str, Any]]:
|
200
|
+
"""Execute the image acquisition task assignment."""
|
201
|
+
|
202
|
+
# Build payload with proper API field names (camelCase)
|
203
|
+
payload = {
|
204
|
+
"caseId": self.request.case_id,
|
205
|
+
"taskConfig": {
|
206
|
+
"choice": self.request.task_config.choice,
|
207
|
+
"saveTo": {},
|
208
|
+
"cpu": self.request.task_config.cpu,
|
209
|
+
"bandwidth": getattr(self.request.task_config, 'bandwidth', {"limit": 100000}),
|
210
|
+
"compression": self.request.task_config.compression
|
211
|
+
},
|
212
|
+
"diskImageOptions": {
|
213
|
+
"startOffset": self.request.disk_image_options.startOffset,
|
214
|
+
"chunkSize": self.request.disk_image_options.chunkSize,
|
215
|
+
"chunkCount": self.request.disk_image_options.chunkCount,
|
216
|
+
"imageType": getattr(self.request.disk_image_options, 'imageType', 'dd'),
|
217
|
+
"singleFile": getattr(self.request.disk_image_options, 'singleFile', False),
|
218
|
+
"endpoints": [
|
219
|
+
{
|
220
|
+
"endpointId": ep.endpointId,
|
221
|
+
"volumes": ep.volumes
|
222
|
+
}
|
223
|
+
for ep in self.request.disk_image_options.endpoints
|
224
|
+
]
|
225
|
+
},
|
226
|
+
"filter": {
|
227
|
+
"searchTerm": getattr(self.request.filter, 'search_term', '') or '',
|
228
|
+
"name": getattr(self.request.filter, 'name', '') or '',
|
229
|
+
"ipAddress": getattr(self.request.filter, 'ip_address', '') or '',
|
230
|
+
"groupId": getattr(self.request.filter, 'group_id', '') or '',
|
231
|
+
"groupFullPath": getattr(self.request.filter, 'group_full_path', '') or '',
|
232
|
+
"managedStatus": getattr(self.request.filter, 'managed_status', []),
|
233
|
+
"isolationStatus": getattr(self.request.filter, 'isolation_status', []),
|
234
|
+
"platform": getattr(self.request.filter, 'platform', []),
|
235
|
+
"issue": getattr(self.request.filter, 'issue', '') or '',
|
236
|
+
"onlineStatus": getattr(self.request.filter, 'online_status', []),
|
237
|
+
"tags": getattr(self.request.filter, 'tags', []),
|
238
|
+
"version": getattr(self.request.filter, 'version', '') or '',
|
239
|
+
"policy": getattr(self.request.filter, 'policy', '') or '',
|
240
|
+
"includedEndpointIds": getattr(self.request.filter, 'included_endpoint_ids', []),
|
241
|
+
"excludedEndpointIds": getattr(self.request.filter, 'excluded_endpoint_ids', []),
|
242
|
+
"organizationIds": getattr(self.request.filter, 'organization_ids', [0])
|
243
|
+
}
|
244
|
+
}
|
245
|
+
|
246
|
+
# Build saveTo configuration with proper API field names
|
247
|
+
for platform, config in self.request.task_config.save_to.items():
|
248
|
+
if hasattr(config, 'location'):
|
249
|
+
platform_config = {
|
250
|
+
"location": config.location,
|
251
|
+
"useMostFreeVolume": config.use_most_free_volume, # FIXED: camelCase
|
252
|
+
"path": config.path,
|
253
|
+
"tmp": config.tmp,
|
254
|
+
"directCollection": config.direct_collection # FIXED: camelCase
|
255
|
+
}
|
256
|
+
|
257
|
+
# Add optional fields with proper names
|
258
|
+
if hasattr(config, 'repository_id') and config.repository_id:
|
259
|
+
platform_config["repositoryId"] = config.repository_id # FIXED: camelCase
|
260
|
+
if hasattr(config, 'volume') and config.volume:
|
261
|
+
platform_config["volume"] = config.volume
|
262
|
+
|
263
|
+
payload["taskConfig"]["saveTo"][platform] = platform_config
|
264
|
+
else:
|
265
|
+
# Handle dict-based config
|
266
|
+
payload["taskConfig"]["saveTo"][platform] = config
|
267
|
+
|
268
|
+
# Add scheduler config if present (matching API spec)
|
269
|
+
if hasattr(self.request, 'scheduler_config') and self.request.scheduler_config:
|
270
|
+
payload["schedulerConfig"] = {
|
271
|
+
"when": getattr(self.request.scheduler_config, 'when', 'now')
|
272
|
+
}
|
273
|
+
# Add other scheduler fields if present
|
274
|
+
for field in ['timezone_type', 'timezone', 'start_date', 'recurrence', 'repeat_every', 'repeat_on_week', 'repeat_on_month', 'end_repeat_type', 'end_date', 'limit']:
|
275
|
+
if hasattr(self.request.scheduler_config, field) and getattr(self.request.scheduler_config, field) is not None:
|
276
|
+
# Convert snake_case to camelCase for API
|
277
|
+
api_field = field.replace('_', '')
|
278
|
+
if field == 'timezone_type':
|
279
|
+
api_field = 'timezoneType'
|
280
|
+
elif field == 'start_date':
|
281
|
+
api_field = 'startDate'
|
282
|
+
elif field == 'repeat_every':
|
283
|
+
api_field = 'repeatEvery'
|
284
|
+
elif field == 'repeat_on_week':
|
285
|
+
api_field = 'repeatOnWeek'
|
286
|
+
elif field == 'repeat_on_month':
|
287
|
+
api_field = 'repeatOnMonth'
|
288
|
+
elif field == 'end_repeat_type':
|
289
|
+
api_field = 'endRepeatType'
|
290
|
+
elif field == 'end_date':
|
291
|
+
api_field = 'endDate'
|
292
|
+
payload["schedulerConfig"][api_field] = getattr(self.request.scheduler_config, field)
|
293
|
+
else:
|
294
|
+
# Default scheduler config as per API spec
|
295
|
+
payload["schedulerConfig"] = {"when": "now"}
|
296
|
+
|
297
|
+
response = self.http_client.post("acquisitions/acquire/image", json_data=payload)
|
298
|
+
|
299
|
+
# Extract result list from response
|
300
|
+
if isinstance(response, dict) and "result" in response:
|
301
|
+
return response["result"] if isinstance(response["result"], list) else [response["result"]]
|
302
|
+
return []
|
303
|
+
|
304
|
+
|
305
|
+
class CreateImageAcquisitionCommand(Command[Dict[str, Any]]):
|
306
|
+
"""Command to create image acquisition task - FIXED with required fields."""
|
307
|
+
|
308
|
+
def __init__(self, http_client: HTTPClient, request: CreateImageAcquisitionRequest):
|
309
|
+
self.http_client = http_client
|
310
|
+
self.request = request
|
311
|
+
|
312
|
+
def execute(self) -> Dict[str, Any]:
|
313
|
+
"""Execute the image acquisition task creation with proper API structure."""
|
314
|
+
|
315
|
+
# Build complete payload structure matching API specification
|
316
|
+
payload = {
|
317
|
+
"caseId": getattr(self.request, 'case_id', None)
|
318
|
+
}
|
319
|
+
|
320
|
+
# Use task_config from request if provided, otherwise use defaults
|
321
|
+
if hasattr(self.request, 'task_config') and self.request.task_config:
|
322
|
+
if isinstance(self.request.task_config, dict):
|
323
|
+
payload["taskConfig"] = self.request.task_config
|
324
|
+
else:
|
325
|
+
payload["taskConfig"] = self.request.task_config.model_dump()
|
326
|
+
else:
|
327
|
+
# Default task config
|
328
|
+
payload["taskConfig"] = {
|
329
|
+
"choice": "use-custom-options",
|
330
|
+
"saveTo": {
|
331
|
+
"windows": {
|
332
|
+
"location": "repository",
|
333
|
+
"path": "Binalyze\\AIR",
|
334
|
+
"useMostFreeVolume": True,
|
335
|
+
"repositoryId": "DEFAULT_REPOSITORY_ID",
|
336
|
+
"tmp": "Binalyze\\AIR\\tmp",
|
337
|
+
"directCollection": False
|
338
|
+
},
|
339
|
+
"linux": {
|
340
|
+
"location": "repository",
|
341
|
+
"path": "opt/binalyze/air",
|
342
|
+
"useMostFreeVolume": False,
|
343
|
+
"repositoryId": "DEFAULT_REPOSITORY_ID",
|
344
|
+
"tmp": "opt/binalyze/air/tmp",
|
345
|
+
"directCollection": False
|
346
|
+
},
|
347
|
+
"macos": {
|
348
|
+
"location": "repository",
|
349
|
+
"path": "opt/binalyze/air",
|
350
|
+
"useMostFreeVolume": False,
|
351
|
+
"repositoryId": "DEFAULT_REPOSITORY_ID",
|
352
|
+
"tmp": "opt/binalyze/air/tmp",
|
353
|
+
"directCollection": False
|
354
|
+
}
|
355
|
+
},
|
356
|
+
"cpu": {"limit": 50},
|
357
|
+
"bandwidth": {"limit": 100000},
|
358
|
+
"compression": {
|
359
|
+
"enabled": True,
|
360
|
+
"encryption": {
|
361
|
+
"enabled": False,
|
362
|
+
"password": ""
|
363
|
+
}
|
364
|
+
}
|
365
|
+
}
|
366
|
+
|
367
|
+
# Use disk_image_options from request if provided, otherwise use defaults
|
368
|
+
if hasattr(self.request, 'disk_image_options') and self.request.disk_image_options:
|
369
|
+
if isinstance(self.request.disk_image_options, dict):
|
370
|
+
payload["diskImageOptions"] = self.request.disk_image_options
|
371
|
+
else:
|
372
|
+
payload["diskImageOptions"] = self.request.disk_image_options.model_dump()
|
373
|
+
else:
|
374
|
+
# Default disk image options
|
375
|
+
payload["diskImageOptions"] = {
|
376
|
+
"chunkSize": 1048576,
|
377
|
+
"chunkCount": 0,
|
378
|
+
"startOffset": 0,
|
379
|
+
"imageType": "dd",
|
380
|
+
"singleFile": False,
|
381
|
+
"endpoints": [{
|
382
|
+
"endpointId": "SDK_TEST_NONEXISTENT_ENDPOINT",
|
383
|
+
"volumes": ["/dev/test"]
|
384
|
+
}]
|
385
|
+
}
|
386
|
+
|
387
|
+
# Use scheduler_config from request if provided, otherwise use default
|
388
|
+
if hasattr(self.request, 'scheduler_config') and self.request.scheduler_config:
|
389
|
+
if isinstance(self.request.scheduler_config, dict):
|
390
|
+
payload["schedulerConfig"] = self.request.scheduler_config
|
391
|
+
else:
|
392
|
+
payload["schedulerConfig"] = self.request.scheduler_config.model_dump()
|
393
|
+
else:
|
394
|
+
payload["schedulerConfig"] = {"when": "now"}
|
395
|
+
|
396
|
+
# Use the filter from request
|
397
|
+
if hasattr(self.request, 'filter') and self.request.filter:
|
398
|
+
if isinstance(self.request.filter, dict):
|
399
|
+
payload["filter"] = self.request.filter
|
400
|
+
else:
|
401
|
+
payload["filter"] = self.request.filter.model_dump()
|
402
|
+
|
403
|
+
# Add task name if provided
|
404
|
+
if hasattr(self.request, 'name') and self.request.name:
|
405
|
+
payload["taskName"] = self.request.name
|
406
|
+
|
407
|
+
return self.http_client.post("acquisitions/acquire/image", json_data=payload)
|
408
|
+
|
409
|
+
|
410
|
+
class CreateAcquisitionProfileCommand(Command[Dict[str, Any]]):
|
411
|
+
"""Command to create acquisition profile - FIXED field conversion."""
|
412
|
+
|
413
|
+
def __init__(self, http_client: HTTPClient, request: CreateAcquisitionProfileRequest):
|
414
|
+
self.http_client = http_client
|
415
|
+
self.request = request
|
416
|
+
|
417
|
+
def execute(self) -> Dict[str, Any]:
|
418
|
+
"""Execute the create acquisition profile command."""
|
419
|
+
# Build the payload
|
420
|
+
payload = {
|
421
|
+
"name": self.request.name,
|
422
|
+
"organizationIds": self.request.organizationIds if self.request.organizationIds else []
|
423
|
+
}
|
424
|
+
|
425
|
+
# Convert platform configuration to API format - FIXED conversion logic
|
426
|
+
def convert_platform_to_api(platform_data, platform_name=""):
|
427
|
+
if not platform_data:
|
428
|
+
return None
|
429
|
+
|
430
|
+
# FIXED: Use model_dump() for reliable field access
|
431
|
+
api_data = platform_data.model_dump()
|
432
|
+
|
433
|
+
# Remove networkCapture from AIX platform as per API spec
|
434
|
+
if platform_name.lower() == "aix" and "networkCapture" in api_data:
|
435
|
+
del api_data["networkCapture"]
|
436
|
+
|
437
|
+
return api_data
|
438
|
+
|
439
|
+
# Add platform configurations with proper platform names
|
440
|
+
if self.request.windows:
|
441
|
+
payload["windows"] = convert_platform_to_api(self.request.windows, "windows")
|
442
|
+
if self.request.linux:
|
443
|
+
payload["linux"] = convert_platform_to_api(self.request.linux, "linux")
|
444
|
+
if self.request.macos:
|
445
|
+
payload["macos"] = convert_platform_to_api(self.request.macos, "macos")
|
446
|
+
if self.request.aix:
|
447
|
+
payload["aix"] = convert_platform_to_api(self.request.aix, "aix")
|
448
|
+
|
449
|
+
# Handle eDiscovery field if present
|
450
|
+
if hasattr(self.request, 'eDiscovery') and self.request.eDiscovery:
|
451
|
+
# Convert EDiscoveryConfig to the expected dict format for API
|
452
|
+
if hasattr(self.request.eDiscovery, 'patterns'):
|
453
|
+
payload["eDiscovery"] = {
|
454
|
+
"patterns": [
|
455
|
+
pattern.model_dump()
|
456
|
+
for pattern in self.request.eDiscovery.patterns
|
457
|
+
]
|
458
|
+
}
|
459
|
+
elif hasattr(self.request.eDiscovery, 'model_dump'):
|
460
|
+
# Handle as pydantic model
|
461
|
+
payload["eDiscovery"] = self.request.eDiscovery.model_dump()
|
462
|
+
elif isinstance(self.request.eDiscovery, dict):
|
463
|
+
# Handle as dictionary
|
464
|
+
payload["eDiscovery"] = self.request.eDiscovery
|
465
|
+
|
466
|
+
return self.http_client.post("acquisitions/profiles", json_data=payload)
|
467
|
+
|
468
|
+
|
469
|
+
class UpdateAcquisitionProfileCommand(Command[Dict[str, Any]]):
|
470
|
+
"""Command to update acquisition profile by ID - FIXED field conversion."""
|
471
|
+
|
472
|
+
def __init__(self, http_client: HTTPClient, profile_id: str, request: CreateAcquisitionProfileRequest):
|
473
|
+
self.http_client = http_client
|
474
|
+
self.profile_id = profile_id
|
475
|
+
self.request = request
|
476
|
+
|
477
|
+
def execute(self) -> Dict[str, Any]:
|
478
|
+
"""Execute the update acquisition profile command."""
|
479
|
+
# Build the payload (same structure as create)
|
480
|
+
payload = {
|
481
|
+
"name": self.request.name,
|
482
|
+
"organizationIds": self.request.organizationIds if self.request.organizationIds else []
|
483
|
+
}
|
484
|
+
|
485
|
+
# Convert platform configuration to API format - FIXED conversion logic
|
486
|
+
def convert_platform_to_api(platform_data, platform_name=""):
|
487
|
+
if not platform_data:
|
488
|
+
return None
|
489
|
+
|
490
|
+
# FIXED: Use model_dump() for reliable field access
|
491
|
+
api_data = platform_data.model_dump()
|
492
|
+
|
493
|
+
# Remove networkCapture from AIX platform as per API spec
|
494
|
+
if platform_name.lower() == "aix" and "networkCapture" in api_data:
|
495
|
+
del api_data["networkCapture"]
|
496
|
+
|
497
|
+
return api_data
|
498
|
+
|
499
|
+
# Add platform configurations with proper platform names
|
500
|
+
if self.request.windows:
|
501
|
+
payload["windows"] = convert_platform_to_api(self.request.windows, "windows")
|
502
|
+
if self.request.linux:
|
503
|
+
payload["linux"] = convert_platform_to_api(self.request.linux, "linux")
|
504
|
+
if self.request.macos:
|
505
|
+
payload["macos"] = convert_platform_to_api(self.request.macos, "macos")
|
506
|
+
if self.request.aix:
|
507
|
+
payload["aix"] = convert_platform_to_api(self.request.aix, "aix")
|
508
|
+
|
509
|
+
# Handle eDiscovery field if present
|
510
|
+
if hasattr(self.request, 'eDiscovery') and self.request.eDiscovery:
|
511
|
+
# Convert EDiscoveryConfig to the expected dict format for API
|
512
|
+
if hasattr(self.request.eDiscovery, 'patterns'):
|
513
|
+
payload["eDiscovery"] = {
|
514
|
+
"patterns": [
|
515
|
+
pattern.model_dump()
|
516
|
+
for pattern in self.request.eDiscovery.patterns
|
517
|
+
]
|
518
|
+
}
|
519
|
+
elif hasattr(self.request.eDiscovery, 'model_dump'):
|
520
|
+
# Handle as pydantic model
|
521
|
+
payload["eDiscovery"] = self.request.eDiscovery.model_dump()
|
522
|
+
elif isinstance(self.request.eDiscovery, dict):
|
523
|
+
# Handle as dictionary
|
524
|
+
payload["eDiscovery"] = self.request.eDiscovery
|
525
|
+
|
526
|
+
return self.http_client.put(f"acquisitions/profiles/{self.profile_id}", json_data=payload)
|
527
|
+
|
528
|
+
|
529
|
+
class DeleteAcquisitionProfileCommand(Command[Dict[str, Any]]):
|
530
|
+
"""Command to delete acquisition profile by ID."""
|
531
|
+
|
532
|
+
def __init__(self, http_client: HTTPClient, profile_id: str):
|
533
|
+
self.http_client = http_client
|
534
|
+
self.profile_id = profile_id
|
535
|
+
|
536
|
+
def execute(self) -> Dict[str, Any]:
|
537
|
+
"""Execute the delete acquisition profile command."""
|
538
|
+
return self.http_client.delete(f"acquisitions/profiles/{self.profile_id}")
|
539
|
+
|
540
|
+
|
541
|
+
class CreateOffNetworkAcquisitionCommand(Command[Dict[str, Any]]):
|
542
|
+
"""Command to create evidence acquisition off-network task."""
|
543
|
+
|
544
|
+
def __init__(self, http_client: HTTPClient, request: CreateAcquisitionRequest):
|
545
|
+
self.http_client = http_client
|
546
|
+
self.request = request
|
547
|
+
|
548
|
+
def execute(self) -> Dict[str, Any]:
|
549
|
+
"""Execute the off-network acquisition task creation."""
|
550
|
+
# Build payload structure matching the API specification
|
551
|
+
payload = {
|
552
|
+
"caseId": getattr(self.request, 'case_id', None),
|
553
|
+
"acquisitionProfileId": self.request.profileId,
|
554
|
+
"droneConfig": {
|
555
|
+
"autoPilot": False,
|
556
|
+
"enabled": False,
|
557
|
+
"analyzers": ["bha", "wsa", "aa", "ara"],
|
558
|
+
"keywords": []
|
559
|
+
},
|
560
|
+
"eventLogRecordsConfig": {
|
561
|
+
"startDate": None,
|
562
|
+
"endDate": None,
|
563
|
+
"maxEventCount": 1000
|
564
|
+
},
|
565
|
+
"taskConfig": {
|
566
|
+
"choice": "use-custom-options",
|
567
|
+
"saveTo": {
|
568
|
+
"windows": {
|
569
|
+
"location": "local",
|
570
|
+
"useMostFreeVolume": True,
|
571
|
+
"repositoryId": None,
|
572
|
+
"path": "Binalyze\\AIR\\",
|
573
|
+
"volume": "C:",
|
574
|
+
"tmp": "Binalyze\\AIR\\tmp",
|
575
|
+
"directCollection": False
|
576
|
+
},
|
577
|
+
"linux": {
|
578
|
+
"location": "local",
|
579
|
+
"useMostFreeVolume": True,
|
580
|
+
"repositoryId": None,
|
581
|
+
"path": "opt/binalyze/air",
|
582
|
+
"tmp": "opt/binalyze/air/tmp",
|
583
|
+
"directCollection": False
|
584
|
+
},
|
585
|
+
"macos": {
|
586
|
+
"location": "local",
|
587
|
+
"useMostFreeVolume": False,
|
588
|
+
"repositoryId": None,
|
589
|
+
"path": "opt/binalyze/air",
|
590
|
+
"volume": "/",
|
591
|
+
"tmp": "opt/binalyze/air/tmp",
|
592
|
+
"directCollection": False
|
593
|
+
},
|
594
|
+
"aix": {
|
595
|
+
"location": "local",
|
596
|
+
"useMostFreeVolume": True,
|
597
|
+
"path": "opt/binalyze/air",
|
598
|
+
"volume": "/",
|
599
|
+
"tmp": "opt/binalyze/air/tmp",
|
600
|
+
"directCollection": False
|
601
|
+
}
|
602
|
+
},
|
603
|
+
"cpu": {
|
604
|
+
"limit": 80
|
605
|
+
},
|
606
|
+
"compression": {
|
607
|
+
"enabled": True,
|
608
|
+
"encryption": {
|
609
|
+
"enabled": False,
|
610
|
+
"password": ""
|
611
|
+
}
|
612
|
+
}
|
613
|
+
},
|
614
|
+
"filter": self.request.filter.to_filter_dict() if isinstance(self.request.filter, AssetFilter) else self.request.filter,
|
615
|
+
"schedulerConfig": {
|
616
|
+
"when": "now"
|
617
|
+
}
|
618
|
+
}
|
619
|
+
|
620
|
+
if hasattr(self.request, 'name') and self.request.name:
|
621
|
+
payload["taskName"] = self.request.name
|
622
|
+
|
623
|
+
return self.http_client.post("acquisitions/acquire/off-network", json_data=payload)
|
624
|
+
|
625
|
+
|
626
|
+
class UpdateScheduledEvidenceAcquisitionCommand(Command[Dict[str, Any]]):
|
627
|
+
"""Command to update scheduled evidence acquisition."""
|
628
|
+
|
629
|
+
def __init__(self, http_client: HTTPClient, task_id: str, request: Dict[str, Any]):
|
630
|
+
self.http_client = http_client
|
631
|
+
self.task_id = task_id
|
632
|
+
self.request = request
|
633
|
+
|
634
|
+
def execute(self) -> Dict[str, Any]:
|
635
|
+
"""Execute the update scheduled evidence acquisition command."""
|
636
|
+
return self.http_client.put(f"acquisitions/schedule/evidence-acquisition/{self.task_id}", json_data=self.request)
|
637
|
+
|
638
|
+
|
639
|
+
class UpdateScheduledImageAcquisitionCommand(Command[Dict[str, Any]]):
|
640
|
+
"""Command to update scheduled image acquisition."""
|
641
|
+
|
642
|
+
def __init__(self, http_client: HTTPClient, task_id: str, request: Dict[str, Any]):
|
643
|
+
self.http_client = http_client
|
644
|
+
self.task_id = task_id
|
645
|
+
self.request = request
|
646
|
+
|
647
|
+
def execute(self) -> Dict[str, Any]:
|
648
|
+
"""Execute the update scheduled image acquisition command."""
|
649
|
+
return self.http_client.put(f"acquisitions/schedule/image-acquisition/{self.task_id}", json_data=self.request)
|
650
|
+
|
651
|
+
|
652
|
+
class ValidateOsqueryCommand(Command[Dict[str, Any]]):
|
653
|
+
"""Command to validate osquery."""
|
654
|
+
|
655
|
+
def __init__(self, http_client: HTTPClient, request: List[Dict[str, Any]]):
|
656
|
+
self.http_client = http_client
|
657
|
+
self.request = request
|
658
|
+
|
659
|
+
def execute(self) -> Dict[str, Any]:
|
660
|
+
"""Execute the validate osquery command."""
|
661
|
+
return self.http_client.post("acquisitions/profiles/osquery/validate", json_data=self.request) # type: ignore
|