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,146 @@
|
|
1
|
+
"""
|
2
|
+
Command implementations for the Binalyze AIR SDK (CQRS pattern).
|
3
|
+
"""
|
4
|
+
|
5
|
+
from .assets import (
|
6
|
+
IsolateAssetsCommand,
|
7
|
+
UnisolateAssetsCommand,
|
8
|
+
RebootAssetsCommand,
|
9
|
+
ShutdownAssetsCommand,
|
10
|
+
AddTagsToAssetsCommand,
|
11
|
+
RemoveTagsFromAssetsCommand,
|
12
|
+
UninstallAssetsCommand,
|
13
|
+
)
|
14
|
+
from .cases import (
|
15
|
+
CreateCaseCommand,
|
16
|
+
UpdateCaseCommand,
|
17
|
+
CloseCaseCommand,
|
18
|
+
OpenCaseCommand,
|
19
|
+
ArchiveCaseCommand,
|
20
|
+
ChangeCaseOwnerCommand,
|
21
|
+
RemoveEndpointsFromCaseCommand,
|
22
|
+
RemoveTaskAssignmentFromCaseCommand,
|
23
|
+
ImportTaskAssignmentsToCaseCommand,
|
24
|
+
)
|
25
|
+
from .tasks import (
|
26
|
+
CancelTaskCommand,
|
27
|
+
DeleteTaskCommand,
|
28
|
+
)
|
29
|
+
from .acquisitions import (
|
30
|
+
AssignAcquisitionTaskCommand,
|
31
|
+
AssignImageAcquisitionTaskCommand,
|
32
|
+
CreateAcquisitionProfileCommand,
|
33
|
+
)
|
34
|
+
from .policies import (
|
35
|
+
CreatePolicyCommand,
|
36
|
+
UpdatePolicyCommand,
|
37
|
+
DeletePolicyCommand,
|
38
|
+
ActivatePolicyCommand,
|
39
|
+
DeactivatePolicyCommand,
|
40
|
+
AssignPolicyCommand,
|
41
|
+
UnassignPolicyCommand,
|
42
|
+
ExecutePolicyCommand,
|
43
|
+
)
|
44
|
+
from .organizations import (
|
45
|
+
CreateOrganizationCommand,
|
46
|
+
UpdateOrganizationCommand,
|
47
|
+
AddUserToOrganizationCommand,
|
48
|
+
UpdateOrganizationSettingsCommand,
|
49
|
+
)
|
50
|
+
from .triage import (
|
51
|
+
CreateTriageRuleCommand,
|
52
|
+
UpdateTriageRuleCommand,
|
53
|
+
DeleteTriageRuleCommand,
|
54
|
+
EnableTriageRuleCommand,
|
55
|
+
DisableTriageRuleCommand,
|
56
|
+
CreateTriageTagCommand,
|
57
|
+
DeleteTriageTagCommand,
|
58
|
+
CreateTriageProfileCommand,
|
59
|
+
UpdateTriageProfileCommand,
|
60
|
+
DeleteTriageProfileCommand,
|
61
|
+
)
|
62
|
+
from .baseline import (
|
63
|
+
CreateBaselineCommand,
|
64
|
+
UpdateBaselineCommand,
|
65
|
+
DeleteBaselineCommand,
|
66
|
+
CompareBaselineCommand,
|
67
|
+
CreateBaselineProfileCommand,
|
68
|
+
UpdateBaselineProfileCommand,
|
69
|
+
DeleteBaselineProfileCommand,
|
70
|
+
CreateBaselineScheduleCommand,
|
71
|
+
DeleteBaselineScheduleCommand,
|
72
|
+
RefreshBaselineCommand,
|
73
|
+
)
|
74
|
+
|
75
|
+
# TODO: Add imports when implementing other endpoints
|
76
|
+
|
77
|
+
__all__ = [
|
78
|
+
# Asset commands
|
79
|
+
"IsolateAssetsCommand",
|
80
|
+
"UnisolateAssetsCommand",
|
81
|
+
"RebootAssetsCommand",
|
82
|
+
"ShutdownAssetsCommand",
|
83
|
+
"AddTagsToAssetsCommand",
|
84
|
+
"RemoveTagsFromAssetsCommand",
|
85
|
+
"UninstallAssetsCommand",
|
86
|
+
|
87
|
+
# Case commands
|
88
|
+
"CreateCaseCommand",
|
89
|
+
"UpdateCaseCommand",
|
90
|
+
"CloseCaseCommand",
|
91
|
+
"OpenCaseCommand",
|
92
|
+
"ArchiveCaseCommand",
|
93
|
+
"ChangeCaseOwnerCommand",
|
94
|
+
"RemoveEndpointsFromCaseCommand",
|
95
|
+
"RemoveTaskAssignmentFromCaseCommand",
|
96
|
+
"ImportTaskAssignmentsToCaseCommand",
|
97
|
+
|
98
|
+
# Task commands
|
99
|
+
"CancelTaskCommand",
|
100
|
+
"DeleteTaskCommand",
|
101
|
+
|
102
|
+
# Acquisition commands
|
103
|
+
"AssignAcquisitionTaskCommand",
|
104
|
+
"AssignImageAcquisitionTaskCommand",
|
105
|
+
"CreateAcquisitionProfileCommand",
|
106
|
+
|
107
|
+
# Policy commands
|
108
|
+
"CreatePolicyCommand",
|
109
|
+
"UpdatePolicyCommand",
|
110
|
+
"DeletePolicyCommand",
|
111
|
+
"ActivatePolicyCommand",
|
112
|
+
"DeactivatePolicyCommand",
|
113
|
+
"AssignPolicyCommand",
|
114
|
+
"UnassignPolicyCommand",
|
115
|
+
"ExecutePolicyCommand",
|
116
|
+
|
117
|
+
# Organization commands
|
118
|
+
"CreateOrganizationCommand",
|
119
|
+
"UpdateOrganizationCommand",
|
120
|
+
"AddUserToOrganizationCommand",
|
121
|
+
"UpdateOrganizationSettingsCommand",
|
122
|
+
|
123
|
+
# Triage commands
|
124
|
+
"CreateTriageRuleCommand",
|
125
|
+
"UpdateTriageRuleCommand",
|
126
|
+
"DeleteTriageRuleCommand",
|
127
|
+
"EnableTriageRuleCommand",
|
128
|
+
"DisableTriageRuleCommand",
|
129
|
+
"CreateTriageTagCommand",
|
130
|
+
"DeleteTriageTagCommand",
|
131
|
+
"CreateTriageProfileCommand",
|
132
|
+
"UpdateTriageProfileCommand",
|
133
|
+
"DeleteTriageProfileCommand",
|
134
|
+
|
135
|
+
# Baseline commands
|
136
|
+
"CreateBaselineCommand",
|
137
|
+
"UpdateBaselineCommand",
|
138
|
+
"DeleteBaselineCommand",
|
139
|
+
"CompareBaselineCommand",
|
140
|
+
"CreateBaselineProfileCommand",
|
141
|
+
"UpdateBaselineProfileCommand",
|
142
|
+
"DeleteBaselineProfileCommand",
|
143
|
+
"CreateBaselineScheduleCommand",
|
144
|
+
"DeleteBaselineScheduleCommand",
|
145
|
+
"RefreshBaselineCommand",
|
146
|
+
]
|
@@ -0,0 +1,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 - FIXED endpoint URL."""
|
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
|
+
# Convert request to API payload using correct model attributes
|
202
|
+
payload = {
|
203
|
+
"caseId": self.request.case_id,
|
204
|
+
"endpoints": [
|
205
|
+
{
|
206
|
+
"endpointId": endpoint.endpoint_id,
|
207
|
+
"volumes": endpoint.volumes
|
208
|
+
}
|
209
|
+
for endpoint in self.request.disk_image_options.endpoints
|
210
|
+
],
|
211
|
+
"organizationIds": self.request.filter.organization_ids,
|
212
|
+
"startOffset": self.request.disk_image_options.start_offset,
|
213
|
+
"chunkSize": self.request.disk_image_options.chunk_size,
|
214
|
+
"chunkCount": self.request.disk_image_options.chunk_count,
|
215
|
+
"enableCompression": self.request.task_config.compression.get("enabled", False) if self.request.task_config else False,
|
216
|
+
"enableEncryption": self.request.task_config.compression.get("encryption", {}).get("enabled", False) if self.request.task_config else False,
|
217
|
+
}
|
218
|
+
|
219
|
+
if self.request.task_config and self.request.task_config.compression.get("encryption", {}).get("password"):
|
220
|
+
payload["encryptionPassword"] = self.request.task_config.compression["encryption"]["password"]
|
221
|
+
|
222
|
+
# FIXED: Correct endpoint URL
|
223
|
+
response = self.http_client.post("acquisitions/acquire/image", json_data=payload)
|
224
|
+
|
225
|
+
return response.get("result", [])
|
226
|
+
|
227
|
+
|
228
|
+
class CreateImageAcquisitionCommand(Command[Dict[str, Any]]):
|
229
|
+
"""Command to create image acquisition task using simplified request - FIXED structure."""
|
230
|
+
|
231
|
+
def __init__(self, http_client: HTTPClient, request: CreateImageAcquisitionRequest):
|
232
|
+
self.http_client = http_client
|
233
|
+
self.request = request
|
234
|
+
|
235
|
+
def execute(self) -> Dict[str, Any]:
|
236
|
+
"""Execute the image acquisition task assignment with correct structure."""
|
237
|
+
# Extract repository ID from request if available (for now use a placeholder)
|
238
|
+
# This should be enhanced to get actual repository ID dynamically
|
239
|
+
repository_id = getattr(self.request, 'repository_id', None)
|
240
|
+
|
241
|
+
# Build the complete payload structure that matches the API specification
|
242
|
+
payload = {
|
243
|
+
"caseId": getattr(self.request, 'case_id', None),
|
244
|
+
"taskConfig": {
|
245
|
+
"choice": "use-custom-options",
|
246
|
+
"saveTo": {
|
247
|
+
"windows": {
|
248
|
+
"location": "repository",
|
249
|
+
"path": "Binalyze\\AIR\\",
|
250
|
+
"useMostFreeVolume": True,
|
251
|
+
"repositoryId": repository_id,
|
252
|
+
"tmp": "Binalyze\\AIR\\tmp",
|
253
|
+
"directCollection": False
|
254
|
+
},
|
255
|
+
"linux": {
|
256
|
+
"location": "repository",
|
257
|
+
"path": "opt/binalyze/air",
|
258
|
+
"useMostFreeVolume": False,
|
259
|
+
"repositoryId": repository_id,
|
260
|
+
"tmp": "opt/binalyze/air/tmp",
|
261
|
+
"directCollection": False
|
262
|
+
},
|
263
|
+
"macos": {
|
264
|
+
"location": "repository",
|
265
|
+
"path": "opt/binalyze/air",
|
266
|
+
"useMostFreeVolume": False,
|
267
|
+
"repositoryId": repository_id,
|
268
|
+
"tmp": "opt/binalyze/air/tmp",
|
269
|
+
"directCollection": False
|
270
|
+
}
|
271
|
+
},
|
272
|
+
"bandwidth": {
|
273
|
+
"limit": 100000
|
274
|
+
},
|
275
|
+
"compression": {
|
276
|
+
"enabled": True,
|
277
|
+
"encryption": {
|
278
|
+
"enabled": False,
|
279
|
+
"password": ""
|
280
|
+
}
|
281
|
+
}
|
282
|
+
},
|
283
|
+
"diskImageOptions": {
|
284
|
+
"imageType": "dd",
|
285
|
+
"chunkSize": 1048576,
|
286
|
+
"chunkCount": 0,
|
287
|
+
"startOffset": 0,
|
288
|
+
"singleFile": False,
|
289
|
+
"endpoints": [
|
290
|
+
{
|
291
|
+
"endpointId": "placeholder", # Will be replaced with actual endpoint IDs
|
292
|
+
"volumes": ["/"] # Default volumes, should be replaced with actual volumes
|
293
|
+
}
|
294
|
+
]
|
295
|
+
},
|
296
|
+
"filter": self.request.filter.to_filter_dict() if isinstance(self.request.filter, AssetFilter) else self.request.filter,
|
297
|
+
"schedulerConfig": {
|
298
|
+
"when": "now"
|
299
|
+
}
|
300
|
+
}
|
301
|
+
|
302
|
+
# Extract endpoint IDs from filter and use them in diskImageOptions
|
303
|
+
if isinstance(self.request.filter, dict):
|
304
|
+
included_endpoints = self.request.filter.get('includedEndpointIds', [])
|
305
|
+
else:
|
306
|
+
included_endpoints = getattr(self.request.filter, 'included_endpoint_ids', [])
|
307
|
+
|
308
|
+
# Get volumes from request or use defaults
|
309
|
+
volumes = getattr(self.request, 'volumes', None) or ["/", "C:"]
|
310
|
+
|
311
|
+
if included_endpoints:
|
312
|
+
payload["diskImageOptions"]["endpoints"] = [
|
313
|
+
{
|
314
|
+
"endpointId": endpoint_id,
|
315
|
+
"volumes": volumes # Use actual discovered volumes
|
316
|
+
}
|
317
|
+
for endpoint_id in included_endpoints
|
318
|
+
]
|
319
|
+
|
320
|
+
if hasattr(self.request, 'name') and self.request.name:
|
321
|
+
payload["taskName"] = self.request.name
|
322
|
+
|
323
|
+
return self.http_client.post("acquisitions/acquire/image", json_data=payload)
|
324
|
+
|
325
|
+
|
326
|
+
class CreateAcquisitionProfileCommand(Command[Dict[str, Any]]):
|
327
|
+
"""Command to create acquisition profile - FIXED endpoint URL."""
|
328
|
+
|
329
|
+
def __init__(self, http_client: HTTPClient, request: CreateAcquisitionProfileRequest):
|
330
|
+
self.http_client = http_client
|
331
|
+
self.request = request
|
332
|
+
|
333
|
+
def execute(self) -> Dict[str, Any]:
|
334
|
+
"""Execute the create acquisition profile command."""
|
335
|
+
# Build the payload
|
336
|
+
payload = {
|
337
|
+
"name": self.request.name,
|
338
|
+
"organizationIds": self.request.organization_ids
|
339
|
+
}
|
340
|
+
|
341
|
+
# Convert platform configuration to API format (snake_case -> camelCase)
|
342
|
+
def convert_platform_to_api(platform_data):
|
343
|
+
if not platform_data:
|
344
|
+
return None
|
345
|
+
|
346
|
+
api_data = {}
|
347
|
+
if platform_data.get("evidence_list"):
|
348
|
+
api_data["evidenceList"] = platform_data["evidence_list"]
|
349
|
+
if platform_data.get("artifact_list"):
|
350
|
+
api_data["artifactList"] = platform_data["artifact_list"]
|
351
|
+
if platform_data.get("custom_content_profiles") is not None:
|
352
|
+
api_data["customContentProfiles"] = platform_data["custom_content_profiles"]
|
353
|
+
|
354
|
+
# Convert network capture configuration
|
355
|
+
if platform_data.get("network_capture"):
|
356
|
+
nc = platform_data["network_capture"]
|
357
|
+
api_data["networkCapture"] = {
|
358
|
+
"enabled": nc.get("enabled", False),
|
359
|
+
"duration": nc.get("duration", 600),
|
360
|
+
"pcap": nc.get("pcap", {"enabled": False}),
|
361
|
+
"networkFlow": nc.get("network_flow", {"enabled": False})
|
362
|
+
}
|
363
|
+
|
364
|
+
return api_data
|
365
|
+
|
366
|
+
# Only add platform configurations if they have content
|
367
|
+
if self.request.windows:
|
368
|
+
payload["windows"] = convert_platform_to_api(self.request.windows.model_dump())
|
369
|
+
if self.request.linux:
|
370
|
+
payload["linux"] = convert_platform_to_api(self.request.linux.model_dump())
|
371
|
+
if self.request.macos:
|
372
|
+
payload["macos"] = convert_platform_to_api(self.request.macos.model_dump())
|
373
|
+
if self.request.aix:
|
374
|
+
payload["aix"] = convert_platform_to_api(self.request.aix.model_dump())
|
375
|
+
|
376
|
+
# Only add eDiscovery if it has content
|
377
|
+
if self.request.e_discovery:
|
378
|
+
payload["eDiscovery"] = self.request.e_discovery
|
379
|
+
|
380
|
+
if self.request.description:
|
381
|
+
payload["description"] = self.request.description
|
382
|
+
|
383
|
+
if self.request.artifacts:
|
384
|
+
payload["artifacts"] = self.request.artifacts
|
385
|
+
|
386
|
+
# FIXED: Correct endpoint URL
|
387
|
+
return self.http_client.post("acquisitions/profiles", json_data=payload)
|