binalyze-air-sdk 1.0.1__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.1.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.1.dist-info/METADATA +0 -635
- binalyze_air_sdk-1.0.1.dist-info/RECORD +0 -82
- {binalyze_air_sdk-1.0.1.dist-info → binalyze_air_sdk-1.0.3.dist-info}/top_level.txt +0 -0
binalyze_air/models/assets.py
CHANGED
@@ -1,439 +1,439 @@
|
|
1
|
-
"""
|
2
|
-
Asset-related data models for the Binalyze AIR SDK.
|
3
|
-
"""
|
4
|
-
|
5
|
-
from typing import List, Optional, Dict, Any, Union
|
6
|
-
from datetime import datetime
|
7
|
-
from enum import Enum
|
8
|
-
from pydantic import Field
|
9
|
-
|
10
|
-
from ..base import AIRBaseModel, Filter
|
11
|
-
|
12
|
-
|
13
|
-
class OnlineStatus(str, Enum):
|
14
|
-
"""Asset online status."""
|
15
|
-
ONLINE = "online"
|
16
|
-
OFFLINE = "offline"
|
17
|
-
|
18
|
-
|
19
|
-
class Platform(str, Enum):
|
20
|
-
"""Asset platform."""
|
21
|
-
WINDOWS = "windows"
|
22
|
-
LINUX = "linux"
|
23
|
-
DARWIN = "darwin" # Fixed: API uses 'darwin' not 'macos'
|
24
|
-
AIX = "aix"
|
25
|
-
DISK_IMAGE = "disk-image" # API also returns this value
|
26
|
-
|
27
|
-
|
28
|
-
class IsolationStatus(str, Enum):
|
29
|
-
"""Asset isolation status."""
|
30
|
-
ISOLATING = "isolating"
|
31
|
-
ISOLATED = "isolated"
|
32
|
-
UNISOLATING = "unisolating"
|
33
|
-
UNISOLATED = "unisolated"
|
34
|
-
|
35
|
-
|
36
|
-
class ManagedStatus(str, Enum):
|
37
|
-
"""Asset managed status."""
|
38
|
-
MANAGED = "managed"
|
39
|
-
UNMANAGED = "unmanaged"
|
40
|
-
OFF_NETWORK = "off-network" # Added missing status
|
41
|
-
|
42
|
-
|
43
|
-
class IssueType(str, Enum):
|
44
|
-
"""Asset issue types."""
|
45
|
-
UNREACHABLE = "unreachable"
|
46
|
-
OLD_VERSION = "old-version"
|
47
|
-
UPDATE_REQUIRED = "update-required"
|
48
|
-
|
49
|
-
|
50
|
-
class Tag(AIRBaseModel):
|
51
|
-
"""Tag model for assets."""
|
52
|
-
id: Optional[str] = Field(alias="_id", default=None)
|
53
|
-
name: str
|
54
|
-
color: Optional[str] = None
|
55
|
-
assignee_count: Optional[int] = Field(alias="assigneeCount", default=None) # NEW
|
56
|
-
organization_id: Optional[int] = Field(alias="organizationId", default=None)
|
57
|
-
created_at: Optional[datetime] = Field(alias="createdAt", default=None) # NEW
|
58
|
-
updated_at: Optional[datetime] = Field(alias="updatedAt", default=None) # NEW
|
59
|
-
|
60
|
-
|
61
|
-
class SystemResources(AIRBaseModel):
|
62
|
-
"""System resources information."""
|
63
|
-
cpu: Optional[Dict[str, Any]] = None
|
64
|
-
ram: Optional[Dict[str, Any]] = None
|
65
|
-
disks: Optional[List[Dict[str, Any]]] = None
|
66
|
-
|
67
|
-
|
68
|
-
class NetworkInterface(AIRBaseModel):
|
69
|
-
"""Network interface information."""
|
70
|
-
name: str
|
71
|
-
mac_addr: Optional[str] = Field(alias="macAddr", default=None)
|
72
|
-
ipv4_addrs: Optional[List[str]] = Field(alias="ipv4Addrs", default_factory=list)
|
73
|
-
ipv6_addrs: Optional[List[str]] = Field(alias="ipv6Addrs", default_factory=list)
|
74
|
-
|
75
|
-
|
76
|
-
class AssetFeatures(AIRBaseModel):
|
77
|
-
"""Asset feature capabilities."""
|
78
|
-
isolation_supported: Optional[bool] = Field(alias="isolationSupported", default=None)
|
79
|
-
full_disk_access_enabled: Optional[bool] = Field(alias="fullDiskAccessEnabled", default=None)
|
80
|
-
|
81
|
-
|
82
|
-
class CloudInfo(AIRBaseModel):
|
83
|
-
"""Cloud provider information."""
|
84
|
-
# This will be populated based on actual API response structure
|
85
|
-
provider: Optional[str] = None
|
86
|
-
region: Optional[str] = None
|
87
|
-
instance_id: Optional[str] = None
|
88
|
-
|
89
|
-
|
90
|
-
class Asset(AIRBaseModel):
|
91
|
-
"""Asset (endpoint) model."""
|
92
|
-
|
93
|
-
# Basic identification
|
94
|
-
id: str = Field(alias="_id")
|
95
|
-
name: str
|
96
|
-
os: Optional[str] = None # Make optional since some assets don't have this
|
97
|
-
platform: Platform
|
98
|
-
ip_address: Optional[str] = Field(alias="ipAddress", default=None)
|
99
|
-
organization_id: int = Field(alias="organizationId", default=0)
|
100
|
-
|
101
|
-
# Group and labeling
|
102
|
-
group_id: Optional[str] = Field(alias="groupId", default=None)
|
103
|
-
group_full_path: Optional[str] = Field(alias="groupFullPath", default=None)
|
104
|
-
label: Optional[str] = None
|
105
|
-
|
106
|
-
# Server and management status
|
107
|
-
is_server: bool = Field(alias="isServer", default=False)
|
108
|
-
is_managed: bool = Field(alias="isManaged", default=True)
|
109
|
-
agent_installed: Optional[bool] = Field(alias="agentInstalled", default=None)
|
110
|
-
managed_status: ManagedStatus = Field(alias="managedStatus", default=ManagedStatus.MANAGED)
|
111
|
-
|
112
|
-
# Network information
|
113
|
-
net_interfaces: Optional[List[NetworkInterface]] = Field(alias="netInterfaces", default_factory=list)
|
114
|
-
|
115
|
-
# Timestamps
|
116
|
-
last_seen: Optional[datetime] = Field(alias="lastSeen", default=None)
|
117
|
-
registered_at: Optional[datetime] = Field(alias="registeredAt", default=None)
|
118
|
-
created_at: Optional[datetime] = Field(alias="createdAt", default=None)
|
119
|
-
updated_at: Optional[datetime] = Field(alias="updatedAt", default=None)
|
120
|
-
|
121
|
-
# Version and architecture
|
122
|
-
version: Optional[str] = None
|
123
|
-
version_no: Optional[int] = Field(alias="versionNo", default=None)
|
124
|
-
build_arch: Optional[str] = Field(alias="buildArch", default=None)
|
125
|
-
|
126
|
-
# Security and authentication
|
127
|
-
security_token: Optional[str] = Field(alias="securityToken", default=None)
|
128
|
-
online_status: OnlineStatus = Field(alias="onlineStatus", default=OnlineStatus.OFFLINE)
|
129
|
-
isolation_status: IsolationStatus = Field(alias="isolationStatus", default=IsolationStatus.UNISOLATED)
|
130
|
-
|
131
|
-
# System resources and capabilities
|
132
|
-
system_resources: Optional[SystemResources] = Field(alias="systemResources", default=None)
|
133
|
-
features: Optional[AssetFeatures] = None
|
134
|
-
|
135
|
-
# Cloud and infrastructure
|
136
|
-
cloud: Optional[CloudInfo] = None
|
137
|
-
has_evidence: Optional[bool] = Field(alias="hasEvidence", default=None)
|
138
|
-
relay_server_id: Optional[str] = Field(alias="relayServerId", default=None)
|
139
|
-
connection_route: Optional[str] = Field(alias="connectionRoute", default=None)
|
140
|
-
|
141
|
-
# Asset classification
|
142
|
-
asset_id: Optional[str] = Field(alias="assetId", default=None)
|
143
|
-
asset_type: Optional[str] = Field(alias="assetType", default=None)
|
144
|
-
timezone_offset: Optional[int] = Field(alias="timezoneOffset", default=None)
|
145
|
-
|
146
|
-
# Vendor information
|
147
|
-
vendor_id: Optional[str] = Field(alias="vendorId", default=None)
|
148
|
-
vendor_device_id: Optional[str] = Field(alias="vendorDeviceId", default=None)
|
149
|
-
responder_id: Optional[str] = Field(alias="responderId", default=None)
|
150
|
-
|
151
|
-
# Update management
|
152
|
-
excluded_from_updates: Optional[bool] = Field(alias="excludedFromUpdates", default=None)
|
153
|
-
unsupported_os_to_update: Optional[bool] = Field(alias="unsupportedOsToUpdate", default=None)
|
154
|
-
version_updating: Optional[bool] = Field(alias="versionUpdating", default=None)
|
155
|
-
deploying: Optional[bool] = Field(alias="deploying", default=None)
|
156
|
-
waiting_for_version_update_fix: bool = Field(alias="waitingForVersionUpdateFix", default=False)
|
157
|
-
|
158
|
-
# Issues, tags, and policies
|
159
|
-
issues: List[str] = []
|
160
|
-
tags: List[Union[str, Tag]] = []
|
161
|
-
policies: List[Any] = []
|
162
|
-
|
163
|
-
|
164
|
-
class AssetDetail(Asset):
|
165
|
-
"""Detailed asset information."""
|
166
|
-
pass # Same as Asset for now, can be extended
|
167
|
-
|
168
|
-
|
169
|
-
class TaskDurations(AIRBaseModel):
|
170
|
-
"""Task duration information."""
|
171
|
-
processing: Optional[int] = None
|
172
|
-
uploading: Optional[int] = None
|
173
|
-
analyzing: Optional[int] = None
|
174
|
-
compressing: Optional[int] = None
|
175
|
-
|
176
|
-
|
177
|
-
class TaskMetadata(AIRBaseModel):
|
178
|
-
"""Task metadata information."""
|
179
|
-
purged: Optional[bool] = None
|
180
|
-
has_case_db: Optional[bool] = Field(alias="hasCaseDb", default=None)
|
181
|
-
has_case_ppc: Optional[bool] = Field(alias="hasCasePpc", default=None)
|
182
|
-
has_drone_data: Optional[bool] = Field(alias="hasDroneData", default=None)
|
183
|
-
isolation: Optional[bool] = None
|
184
|
-
import_status: Optional[str] = Field(alias="importStatus", default=None)
|
185
|
-
disk_usage_in_bytes: Optional[int] = Field(alias="diskUsageInBytes", default=None)
|
186
|
-
|
187
|
-
|
188
|
-
class TaskResponse(AIRBaseModel):
|
189
|
-
"""Task response information."""
|
190
|
-
error_message: Optional[str] = Field(alias="errorMessage", default=None)
|
191
|
-
case_directory: Optional[str] = Field(alias="caseDirectory", default=None)
|
192
|
-
match_count: Optional[int] = Field(alias="matchCount", default=None)
|
193
|
-
result: Optional[Dict[str, Any]] = None
|
194
|
-
|
195
|
-
|
196
|
-
class AssetTask(AIRBaseModel):
|
197
|
-
"""Task associated with an asset."""
|
198
|
-
|
199
|
-
# Basic identification
|
200
|
-
id: str = Field(alias="_id")
|
201
|
-
task_id: str = Field(alias="taskId")
|
202
|
-
name: str
|
203
|
-
type: str
|
204
|
-
endpoint_id: str = Field(alias="endpointId")
|
205
|
-
endpoint_name: str = Field(alias="endpointName")
|
206
|
-
organization_id: int = Field(alias="organizationId", default=0)
|
207
|
-
|
208
|
-
# Status and progress
|
209
|
-
status: str
|
210
|
-
recurrence: Optional[str] = None
|
211
|
-
progress: int = 0
|
212
|
-
|
213
|
-
# Duration information
|
214
|
-
duration: Optional[int] = None # Legacy single duration field
|
215
|
-
durations: Optional[TaskDurations] = None # NEW - Complex duration object
|
216
|
-
|
217
|
-
# Task metadata
|
218
|
-
metadata: Optional[TaskMetadata] = None # NEW - Task metadata
|
219
|
-
|
220
|
-
# Relationships
|
221
|
-
case_ids: Optional[List[str]] = Field(alias="caseIds", default_factory=list)
|
222
|
-
|
223
|
-
# Timestamps and users
|
224
|
-
created_at: Optional[datetime] = Field(alias="createdAt", default=None)
|
225
|
-
created_by: Optional[str] = Field(alias="createdBy", default=None) # NEW
|
226
|
-
updated_at: Optional[datetime] = Field(alias="updatedAt", default=None)
|
227
|
-
updated_by: Optional[str] = Field(alias="updatedBy", default=None) # NEW - Not in response but likely exists
|
228
|
-
|
229
|
-
# Response data
|
230
|
-
response: Optional[TaskResponse] = None # Enhanced response structure
|
231
|
-
|
232
|
-
|
233
|
-
class AssetFilter(Filter):
|
234
|
-
"""Filter for asset queries - matches API documentation exactly."""
|
235
|
-
|
236
|
-
# Basic search and identification
|
237
|
-
search_term: Optional[str] = None
|
238
|
-
name: Optional[str] = None
|
239
|
-
ip_address: Optional[str] = None
|
240
|
-
|
241
|
-
# Group and organization
|
242
|
-
group_id: Optional[str] = None
|
243
|
-
group_full_path: Optional[str] = None
|
244
|
-
organization_ids: List[int] = [] # Required by API
|
245
|
-
|
246
|
-
# Status filters (arrays as per API)
|
247
|
-
managed_status: Optional[List[str]] = None # ["managed", "unmanaged", "off-network"]
|
248
|
-
isolation_status: Optional[List[str]] = None # ["isolating", "isolated", "unisolating", "unisolated"]
|
249
|
-
online_status: Optional[List[str]] = None # ["online", "offline"]
|
250
|
-
|
251
|
-
# Platform and technical details
|
252
|
-
platform: Optional[List[str]] = None # ["windows", "linux", "darwin"]
|
253
|
-
issue: Optional[List[str]] = None # ["unreachable", "old-version", "update-required"] - Changed to List
|
254
|
-
version: Optional[str] = None
|
255
|
-
policy: Optional[str] = None
|
256
|
-
|
257
|
-
# Tags and labels
|
258
|
-
tags: Optional[List[str]] = None
|
259
|
-
tag_id: Optional[str] = None # Added missing field - required by some endpoints
|
260
|
-
label: Optional[str] = None # Added missing field
|
261
|
-
|
262
|
-
# Endpoint targeting
|
263
|
-
included_endpoint_ids: Optional[List[str]] = None
|
264
|
-
excluded_endpoint_ids: Optional[List[str]] = None
|
265
|
-
|
266
|
-
# Date/time filters - Added missing fields
|
267
|
-
last_seen_before: Optional[str] = None # ISO 8601 format
|
268
|
-
last_seen_after: Optional[str] = None # ISO 8601 format
|
269
|
-
last_seen_between: Optional[str] = None # Comma-separated range
|
270
|
-
last_seen: Optional[str] = None # For backward compatibility
|
271
|
-
|
272
|
-
# Cloud provider filters - Added missing fields
|
273
|
-
aws_regions: Optional[List[str]] = None
|
274
|
-
azure_regions: Optional[List[str]] = None
|
275
|
-
|
276
|
-
# Special filters - Added missing field
|
277
|
-
unisolated: Optional[str] = None # Added per API docs
|
278
|
-
|
279
|
-
def to_params(self) -> Dict[str, Any]:
|
280
|
-
"""Convert filter to API parameters."""
|
281
|
-
# Start with base pagination/sorting parameters from parent class
|
282
|
-
params = super().to_params()
|
283
|
-
|
284
|
-
# Add asset-specific filter parameters
|
285
|
-
if self.search_term is not None:
|
286
|
-
params["filter[searchTerm]"] = self.search_term
|
287
|
-
if self.name is not None:
|
288
|
-
params["filter[name]"] = self.name
|
289
|
-
if self.ip_address is not None:
|
290
|
-
params["filter[ipAddress]"] = self.ip_address
|
291
|
-
|
292
|
-
# Group parameters
|
293
|
-
if self.group_id is not None:
|
294
|
-
params["filter[groupId]"] = self.group_id
|
295
|
-
if self.group_full_path is not None:
|
296
|
-
params["filter[groupFullPath]"] = self.group_full_path
|
297
|
-
|
298
|
-
# Organization IDs (required)
|
299
|
-
if self.organization_ids:
|
300
|
-
params["filter[organizationIds]"] = ",".join(
|
301
|
-
|
302
|
-
# Status arrays
|
303
|
-
if self.managed_status:
|
304
|
-
params["filter[managedStatus]"] = ",".join(self.managed_status)
|
305
|
-
if self.isolation_status:
|
306
|
-
params["filter[isolationStatus]"] = ",".join(self.isolation_status)
|
307
|
-
if self.online_status:
|
308
|
-
params["filter[onlineStatus]"] = ",".join(self.online_status)
|
309
|
-
|
310
|
-
# Platform and technical
|
311
|
-
if self.platform:
|
312
|
-
params["filter[platform]"] = ",".join(self.platform)
|
313
|
-
if self.issue:
|
314
|
-
params["filter[issue]"] = ",".join(self.issue)
|
315
|
-
if self.version is not None:
|
316
|
-
params["filter[version]"] = self.version
|
317
|
-
if self.policy is not None:
|
318
|
-
params["filter[policy]"] = self.policy
|
319
|
-
|
320
|
-
# Tags and labels
|
321
|
-
if self.tags:
|
322
|
-
params["filter[tags]"] = ",".join(self.tags)
|
323
|
-
if self.tag_id is not None:
|
324
|
-
params["filter[tagId]"] = self.tag_id
|
325
|
-
if self.label is not None:
|
326
|
-
params["filter[label]"] = self.label
|
327
|
-
|
328
|
-
# Endpoint targeting
|
329
|
-
if self.included_endpoint_ids:
|
330
|
-
params["filter[includedEndpointIds]"] = ",".join(self.included_endpoint_ids)
|
331
|
-
if self.excluded_endpoint_ids:
|
332
|
-
params["filter[excludedEndpointIds]"] = ",".join(self.excluded_endpoint_ids)
|
333
|
-
|
334
|
-
# Date/time filters
|
335
|
-
if self.last_seen_before is not None:
|
336
|
-
params["filter[lastSeenBefore]"] = self.last_seen_before
|
337
|
-
if self.last_seen_after is not None:
|
338
|
-
params["filter[lastSeenAfter]"] = self.last_seen_after
|
339
|
-
if self.last_seen_between is not None:
|
340
|
-
params["filter[lastSeenBetween]"] = self.last_seen_between
|
341
|
-
if self.last_seen is not None:
|
342
|
-
params["filter[lastSeen]"] = self.last_seen
|
343
|
-
|
344
|
-
# Cloud provider filters
|
345
|
-
if self.aws_regions:
|
346
|
-
params["filter[awsRegions]"] = ",".join(self.aws_regions)
|
347
|
-
if self.azure_regions:
|
348
|
-
params["filter[azureRegions]"] = ",".join(self.azure_regions)
|
349
|
-
|
350
|
-
# Special filters
|
351
|
-
if self.unisolated is not None:
|
352
|
-
params["filter[unisolated]"] = self.unisolated
|
353
|
-
|
354
|
-
return params
|
355
|
-
|
356
|
-
def to_filter_dict(self) -> Dict[str, Any]:
|
357
|
-
"""Convert filter to dictionary for command payloads - matches API specification exactly."""
|
358
|
-
# Include ALL fields as per API specification, with empty defaults
|
359
|
-
filter_dict = {
|
360
|
-
# Basic search fields (empty strings as defaults)
|
361
|
-
"searchTerm": self.search_term or "",
|
362
|
-
"name": self.name or "",
|
363
|
-
"ipAddress": self.ip_address or "",
|
364
|
-
"groupId": self.group_id or "",
|
365
|
-
"groupFullPath": self.group_full_path or "",
|
366
|
-
|
367
|
-
# Required array fields (with proper defaults)
|
368
|
-
"organizationIds": self.organization_ids or [0], # Keep as integers
|
369
|
-
"managedStatus": self.managed_status or ["managed"], # Default to managed
|
370
|
-
"isolationStatus": self.isolation_status or [],
|
371
|
-
"onlineStatus": self.online_status or [],
|
372
|
-
"platform": self.platform or [],
|
373
|
-
"tags": self.tags or [],
|
374
|
-
|
375
|
-
# Technical fields (empty strings as defaults)
|
376
|
-
"issue": self.issue[0] if self.issue and len(self.issue) > 0 else "", # API expects string not array
|
377
|
-
"version": self.version or "",
|
378
|
-
"policy": self.policy or "",
|
379
|
-
"tagId": self.tag_id or "", # Added missing field
|
380
|
-
|
381
|
-
# Endpoint targeting (with proper defaults)
|
382
|
-
"includedEndpointIds": self.included_endpoint_ids or [],
|
383
|
-
"excludedEndpointIds": self.excluded_endpoint_ids or [],
|
384
|
-
}
|
385
|
-
|
386
|
-
return filter_dict
|
387
|
-
|
388
|
-
|
389
|
-
class AssetTaskFilter(Filter):
|
390
|
-
"""Filter for asset task queries - matches API specification exactly."""
|
391
|
-
|
392
|
-
# Search and identification
|
393
|
-
search_term: Optional[str] = None
|
394
|
-
name: Optional[str] = None
|
395
|
-
endpoint_ids: Optional[List[str]] = None
|
396
|
-
|
397
|
-
# Task properties
|
398
|
-
status: Optional[List[str]] = None # scheduled, assigned, processing, completed, failed, expired, cancelled, compressing, uploading, analyzing, partially-completed
|
399
|
-
type: Optional[List[str]] = None # acquisition, offline-acquisition, triage, offline-triage, investigation, interact-shell, baseline-comparison, baseline-acquisition, acquire-image
|
400
|
-
execution_type: Optional[List[str]] = None # instant, scheduled
|
401
|
-
|
402
|
-
# Task metadata
|
403
|
-
has_drone_data: Optional[str] = None # yes, no
|
404
|
-
|
405
|
-
def to_params(self) -> Dict[str, Any]:
|
406
|
-
"""Convert filter to API parameters."""
|
407
|
-
params = {}
|
408
|
-
|
409
|
-
# Pagination parameters (not in filter namespace) - only if set
|
410
|
-
if self.page_number is not None:
|
411
|
-
params["pageNumber"] = self.page_number
|
412
|
-
if self.page_size is not None:
|
413
|
-
params["pageSize"] = self.page_size
|
414
|
-
if self.sort_by is not None:
|
415
|
-
params["sortBy"] = self.sort_by
|
416
|
-
if self.sort_type is not None:
|
417
|
-
params["sortType"] = self.sort_type
|
418
|
-
|
419
|
-
# Add task-specific filter parameters (use API field names)
|
420
|
-
if self.search_term is not None:
|
421
|
-
params["filter[searchTerm]"] = self.search_term
|
422
|
-
if self.name is not None:
|
423
|
-
params["filter[name]"] = self.name
|
424
|
-
if self.endpoint_ids:
|
425
|
-
params["filter[endpointIds]"] = ",".join(self.endpoint_ids)
|
426
|
-
|
427
|
-
# Status and type arrays
|
428
|
-
if self.status:
|
429
|
-
params["filter[status]"] = ",".join(self.status)
|
430
|
-
if self.type:
|
431
|
-
params["filter[type]"] = ",".join(self.type)
|
432
|
-
if self.execution_type:
|
433
|
-
params["filter[executionType]"] = ",".join(self.execution_type)
|
434
|
-
|
435
|
-
# Special filters
|
436
|
-
if self.has_drone_data is not None:
|
437
|
-
params["filter[hasDroneData]"] = self.has_drone_data
|
438
|
-
|
1
|
+
"""
|
2
|
+
Asset-related data models for the Binalyze AIR SDK.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from typing import List, Optional, Dict, Any, Union
|
6
|
+
from datetime import datetime
|
7
|
+
from enum import Enum
|
8
|
+
from pydantic import Field
|
9
|
+
|
10
|
+
from ..base import AIRBaseModel, Filter
|
11
|
+
|
12
|
+
|
13
|
+
class OnlineStatus(str, Enum):
|
14
|
+
"""Asset online status."""
|
15
|
+
ONLINE = "online"
|
16
|
+
OFFLINE = "offline"
|
17
|
+
|
18
|
+
|
19
|
+
class Platform(str, Enum):
|
20
|
+
"""Asset platform."""
|
21
|
+
WINDOWS = "windows"
|
22
|
+
LINUX = "linux"
|
23
|
+
DARWIN = "darwin" # Fixed: API uses 'darwin' not 'macos'
|
24
|
+
AIX = "aix"
|
25
|
+
DISK_IMAGE = "disk-image" # API also returns this value
|
26
|
+
|
27
|
+
|
28
|
+
class IsolationStatus(str, Enum):
|
29
|
+
"""Asset isolation status."""
|
30
|
+
ISOLATING = "isolating"
|
31
|
+
ISOLATED = "isolated"
|
32
|
+
UNISOLATING = "unisolating"
|
33
|
+
UNISOLATED = "unisolated"
|
34
|
+
|
35
|
+
|
36
|
+
class ManagedStatus(str, Enum):
|
37
|
+
"""Asset managed status."""
|
38
|
+
MANAGED = "managed"
|
39
|
+
UNMANAGED = "unmanaged"
|
40
|
+
OFF_NETWORK = "off-network" # Added missing status
|
41
|
+
|
42
|
+
|
43
|
+
class IssueType(str, Enum):
|
44
|
+
"""Asset issue types."""
|
45
|
+
UNREACHABLE = "unreachable"
|
46
|
+
OLD_VERSION = "old-version"
|
47
|
+
UPDATE_REQUIRED = "update-required"
|
48
|
+
|
49
|
+
|
50
|
+
class Tag(AIRBaseModel):
|
51
|
+
"""Tag model for assets."""
|
52
|
+
id: Optional[str] = Field(alias="_id", default=None)
|
53
|
+
name: str
|
54
|
+
color: Optional[str] = None
|
55
|
+
assignee_count: Optional[int] = Field(alias="assigneeCount", default=None) # NEW
|
56
|
+
organization_id: Optional[int] = Field(alias="organizationId", default=None)
|
57
|
+
created_at: Optional[datetime] = Field(alias="createdAt", default=None) # NEW
|
58
|
+
updated_at: Optional[datetime] = Field(alias="updatedAt", default=None) # NEW
|
59
|
+
|
60
|
+
|
61
|
+
class SystemResources(AIRBaseModel):
|
62
|
+
"""System resources information."""
|
63
|
+
cpu: Optional[Dict[str, Any]] = None
|
64
|
+
ram: Optional[Dict[str, Any]] = None
|
65
|
+
disks: Optional[List[Dict[str, Any]]] = None
|
66
|
+
|
67
|
+
|
68
|
+
class NetworkInterface(AIRBaseModel):
|
69
|
+
"""Network interface information."""
|
70
|
+
name: str
|
71
|
+
mac_addr: Optional[str] = Field(alias="macAddr", default=None)
|
72
|
+
ipv4_addrs: Optional[List[str]] = Field(alias="ipv4Addrs", default_factory=list)
|
73
|
+
ipv6_addrs: Optional[List[str]] = Field(alias="ipv6Addrs", default_factory=list)
|
74
|
+
|
75
|
+
|
76
|
+
class AssetFeatures(AIRBaseModel):
|
77
|
+
"""Asset feature capabilities."""
|
78
|
+
isolation_supported: Optional[bool] = Field(alias="isolationSupported", default=None)
|
79
|
+
full_disk_access_enabled: Optional[bool] = Field(alias="fullDiskAccessEnabled", default=None)
|
80
|
+
|
81
|
+
|
82
|
+
class CloudInfo(AIRBaseModel):
|
83
|
+
"""Cloud provider information."""
|
84
|
+
# This will be populated based on actual API response structure
|
85
|
+
provider: Optional[str] = None
|
86
|
+
region: Optional[str] = None
|
87
|
+
instance_id: Optional[str] = None
|
88
|
+
|
89
|
+
|
90
|
+
class Asset(AIRBaseModel):
|
91
|
+
"""Asset (endpoint) model."""
|
92
|
+
|
93
|
+
# Basic identification
|
94
|
+
id: str = Field(alias="_id")
|
95
|
+
name: str
|
96
|
+
os: Optional[str] = None # Make optional since some assets don't have this
|
97
|
+
platform: Platform
|
98
|
+
ip_address: Optional[str] = Field(alias="ipAddress", default=None)
|
99
|
+
organization_id: int = Field(alias="organizationId", default=0)
|
100
|
+
|
101
|
+
# Group and labeling
|
102
|
+
group_id: Optional[str] = Field(alias="groupId", default=None)
|
103
|
+
group_full_path: Optional[str] = Field(alias="groupFullPath", default=None)
|
104
|
+
label: Optional[str] = None
|
105
|
+
|
106
|
+
# Server and management status
|
107
|
+
is_server: bool = Field(alias="isServer", default=False)
|
108
|
+
is_managed: bool = Field(alias="isManaged", default=True)
|
109
|
+
agent_installed: Optional[bool] = Field(alias="agentInstalled", default=None)
|
110
|
+
managed_status: ManagedStatus = Field(alias="managedStatus", default=ManagedStatus.MANAGED)
|
111
|
+
|
112
|
+
# Network information
|
113
|
+
net_interfaces: Optional[List[NetworkInterface]] = Field(alias="netInterfaces", default_factory=list)
|
114
|
+
|
115
|
+
# Timestamps
|
116
|
+
last_seen: Optional[datetime] = Field(alias="lastSeen", default=None)
|
117
|
+
registered_at: Optional[datetime] = Field(alias="registeredAt", default=None)
|
118
|
+
created_at: Optional[datetime] = Field(alias="createdAt", default=None)
|
119
|
+
updated_at: Optional[datetime] = Field(alias="updatedAt", default=None)
|
120
|
+
|
121
|
+
# Version and architecture
|
122
|
+
version: Optional[str] = None
|
123
|
+
version_no: Optional[int] = Field(alias="versionNo", default=None)
|
124
|
+
build_arch: Optional[str] = Field(alias="buildArch", default=None)
|
125
|
+
|
126
|
+
# Security and authentication
|
127
|
+
security_token: Optional[str] = Field(alias="securityToken", default=None)
|
128
|
+
online_status: OnlineStatus = Field(alias="onlineStatus", default=OnlineStatus.OFFLINE)
|
129
|
+
isolation_status: IsolationStatus = Field(alias="isolationStatus", default=IsolationStatus.UNISOLATED)
|
130
|
+
|
131
|
+
# System resources and capabilities
|
132
|
+
system_resources: Optional[SystemResources] = Field(alias="systemResources", default=None)
|
133
|
+
features: Optional[AssetFeatures] = None
|
134
|
+
|
135
|
+
# Cloud and infrastructure
|
136
|
+
cloud: Optional[CloudInfo] = None
|
137
|
+
has_evidence: Optional[bool] = Field(alias="hasEvidence", default=None)
|
138
|
+
relay_server_id: Optional[str] = Field(alias="relayServerId", default=None)
|
139
|
+
connection_route: Optional[str] = Field(alias="connectionRoute", default=None)
|
140
|
+
|
141
|
+
# Asset classification
|
142
|
+
asset_id: Optional[str] = Field(alias="assetId", default=None)
|
143
|
+
asset_type: Optional[str] = Field(alias="assetType", default=None)
|
144
|
+
timezone_offset: Optional[int] = Field(alias="timezoneOffset", default=None)
|
145
|
+
|
146
|
+
# Vendor information
|
147
|
+
vendor_id: Optional[str] = Field(alias="vendorId", default=None)
|
148
|
+
vendor_device_id: Optional[str] = Field(alias="vendorDeviceId", default=None)
|
149
|
+
responder_id: Optional[str] = Field(alias="responderId", default=None)
|
150
|
+
|
151
|
+
# Update management
|
152
|
+
excluded_from_updates: Optional[bool] = Field(alias="excludedFromUpdates", default=None)
|
153
|
+
unsupported_os_to_update: Optional[bool] = Field(alias="unsupportedOsToUpdate", default=None)
|
154
|
+
version_updating: Optional[bool] = Field(alias="versionUpdating", default=None)
|
155
|
+
deploying: Optional[bool] = Field(alias="deploying", default=None)
|
156
|
+
waiting_for_version_update_fix: bool = Field(alias="waitingForVersionUpdateFix", default=False)
|
157
|
+
|
158
|
+
# Issues, tags, and policies
|
159
|
+
issues: List[str] = []
|
160
|
+
tags: List[Union[str, Tag]] = []
|
161
|
+
policies: List[Any] = []
|
162
|
+
|
163
|
+
|
164
|
+
class AssetDetail(Asset):
|
165
|
+
"""Detailed asset information."""
|
166
|
+
pass # Same as Asset for now, can be extended
|
167
|
+
|
168
|
+
|
169
|
+
class TaskDurations(AIRBaseModel):
|
170
|
+
"""Task duration information."""
|
171
|
+
processing: Optional[int] = None
|
172
|
+
uploading: Optional[int] = None
|
173
|
+
analyzing: Optional[int] = None
|
174
|
+
compressing: Optional[int] = None
|
175
|
+
|
176
|
+
|
177
|
+
class TaskMetadata(AIRBaseModel):
|
178
|
+
"""Task metadata information."""
|
179
|
+
purged: Optional[bool] = None
|
180
|
+
has_case_db: Optional[bool] = Field(alias="hasCaseDb", default=None)
|
181
|
+
has_case_ppc: Optional[bool] = Field(alias="hasCasePpc", default=None)
|
182
|
+
has_drone_data: Optional[bool] = Field(alias="hasDroneData", default=None)
|
183
|
+
isolation: Optional[bool] = None
|
184
|
+
import_status: Optional[str] = Field(alias="importStatus", default=None)
|
185
|
+
disk_usage_in_bytes: Optional[int] = Field(alias="diskUsageInBytes", default=None)
|
186
|
+
|
187
|
+
|
188
|
+
class TaskResponse(AIRBaseModel):
|
189
|
+
"""Task response information."""
|
190
|
+
error_message: Optional[str] = Field(alias="errorMessage", default=None)
|
191
|
+
case_directory: Optional[str] = Field(alias="caseDirectory", default=None)
|
192
|
+
match_count: Optional[int] = Field(alias="matchCount", default=None)
|
193
|
+
result: Optional[Dict[str, Any]] = None
|
194
|
+
|
195
|
+
|
196
|
+
class AssetTask(AIRBaseModel):
|
197
|
+
"""Task associated with an asset."""
|
198
|
+
|
199
|
+
# Basic identification
|
200
|
+
id: str = Field(alias="_id")
|
201
|
+
task_id: str = Field(alias="taskId")
|
202
|
+
name: str
|
203
|
+
type: str
|
204
|
+
endpoint_id: str = Field(alias="endpointId")
|
205
|
+
endpoint_name: str = Field(alias="endpointName")
|
206
|
+
organization_id: int = Field(alias="organizationId", default=0)
|
207
|
+
|
208
|
+
# Status and progress
|
209
|
+
status: str
|
210
|
+
recurrence: Optional[str] = None
|
211
|
+
progress: int = 0
|
212
|
+
|
213
|
+
# Duration information
|
214
|
+
duration: Optional[int] = None # Legacy single duration field
|
215
|
+
durations: Optional[TaskDurations] = None # NEW - Complex duration object
|
216
|
+
|
217
|
+
# Task metadata
|
218
|
+
metadata: Optional[TaskMetadata] = None # NEW - Task metadata
|
219
|
+
|
220
|
+
# Relationships
|
221
|
+
case_ids: Optional[List[str]] = Field(alias="caseIds", default_factory=list)
|
222
|
+
|
223
|
+
# Timestamps and users
|
224
|
+
created_at: Optional[datetime] = Field(alias="createdAt", default=None)
|
225
|
+
created_by: Optional[str] = Field(alias="createdBy", default=None) # NEW
|
226
|
+
updated_at: Optional[datetime] = Field(alias="updatedAt", default=None)
|
227
|
+
updated_by: Optional[str] = Field(alias="updatedBy", default=None) # NEW - Not in response but likely exists
|
228
|
+
|
229
|
+
# Response data
|
230
|
+
response: Optional[TaskResponse] = None # Enhanced response structure
|
231
|
+
|
232
|
+
|
233
|
+
class AssetFilter(Filter):
|
234
|
+
"""Filter for asset queries - matches API documentation exactly."""
|
235
|
+
|
236
|
+
# Basic search and identification
|
237
|
+
search_term: Optional[str] = None
|
238
|
+
name: Optional[str] = None
|
239
|
+
ip_address: Optional[str] = None
|
240
|
+
|
241
|
+
# Group and organization
|
242
|
+
group_id: Optional[str] = None
|
243
|
+
group_full_path: Optional[str] = None
|
244
|
+
organization_ids: List[int] = [] # Required by API
|
245
|
+
|
246
|
+
# Status filters (arrays as per API)
|
247
|
+
managed_status: Optional[List[str]] = None # ["managed", "unmanaged", "off-network"]
|
248
|
+
isolation_status: Optional[List[str]] = None # ["isolating", "isolated", "unisolating", "unisolated"]
|
249
|
+
online_status: Optional[List[str]] = None # ["online", "offline"]
|
250
|
+
|
251
|
+
# Platform and technical details
|
252
|
+
platform: Optional[List[str]] = None # ["windows", "linux", "darwin"]
|
253
|
+
issue: Optional[List[str]] = None # ["unreachable", "old-version", "update-required"] - Changed to List
|
254
|
+
version: Optional[str] = None
|
255
|
+
policy: Optional[str] = None
|
256
|
+
|
257
|
+
# Tags and labels
|
258
|
+
tags: Optional[List[str]] = None
|
259
|
+
tag_id: Optional[str] = None # Added missing field - required by some endpoints
|
260
|
+
label: Optional[str] = None # Added missing field
|
261
|
+
|
262
|
+
# Endpoint targeting
|
263
|
+
included_endpoint_ids: Optional[List[str]] = None
|
264
|
+
excluded_endpoint_ids: Optional[List[str]] = None
|
265
|
+
|
266
|
+
# Date/time filters - Added missing fields
|
267
|
+
last_seen_before: Optional[str] = None # ISO 8601 format
|
268
|
+
last_seen_after: Optional[str] = None # ISO 8601 format
|
269
|
+
last_seen_between: Optional[str] = None # Comma-separated range
|
270
|
+
last_seen: Optional[str] = None # For backward compatibility
|
271
|
+
|
272
|
+
# Cloud provider filters - Added missing fields
|
273
|
+
aws_regions: Optional[List[str]] = None
|
274
|
+
azure_regions: Optional[List[str]] = None
|
275
|
+
|
276
|
+
# Special filters - Added missing field
|
277
|
+
unisolated: Optional[str] = None # Added per API docs
|
278
|
+
|
279
|
+
def to_params(self) -> Dict[str, Any]:
|
280
|
+
"""Convert filter to API parameters."""
|
281
|
+
# Start with base pagination/sorting parameters from parent class
|
282
|
+
params = super().to_params()
|
283
|
+
|
284
|
+
# Add asset-specific filter parameters
|
285
|
+
if self.search_term is not None:
|
286
|
+
params["filter[searchTerm]"] = self.search_term
|
287
|
+
if self.name is not None:
|
288
|
+
params["filter[name]"] = self.name
|
289
|
+
if self.ip_address is not None:
|
290
|
+
params["filter[ipAddress]"] = self.ip_address
|
291
|
+
|
292
|
+
# Group parameters
|
293
|
+
if self.group_id is not None:
|
294
|
+
params["filter[groupId]"] = self.group_id
|
295
|
+
if self.group_full_path is not None:
|
296
|
+
params["filter[groupFullPath]"] = self.group_full_path
|
297
|
+
|
298
|
+
# Organization IDs (required)
|
299
|
+
if self.organization_ids:
|
300
|
+
params["filter[organizationIds]"] = ",".join([str(x) for x in self.organization_ids])
|
301
|
+
|
302
|
+
# Status arrays
|
303
|
+
if self.managed_status:
|
304
|
+
params["filter[managedStatus]"] = ",".join(self.managed_status)
|
305
|
+
if self.isolation_status:
|
306
|
+
params["filter[isolationStatus]"] = ",".join(self.isolation_status)
|
307
|
+
if self.online_status:
|
308
|
+
params["filter[onlineStatus]"] = ",".join(self.online_status)
|
309
|
+
|
310
|
+
# Platform and technical
|
311
|
+
if self.platform:
|
312
|
+
params["filter[platform]"] = ",".join(self.platform)
|
313
|
+
if self.issue:
|
314
|
+
params["filter[issue]"] = ",".join(self.issue)
|
315
|
+
if self.version is not None:
|
316
|
+
params["filter[version]"] = self.version
|
317
|
+
if self.policy is not None:
|
318
|
+
params["filter[policy]"] = self.policy
|
319
|
+
|
320
|
+
# Tags and labels
|
321
|
+
if self.tags:
|
322
|
+
params["filter[tags]"] = ",".join(self.tags)
|
323
|
+
if self.tag_id is not None:
|
324
|
+
params["filter[tagId]"] = self.tag_id
|
325
|
+
if self.label is not None:
|
326
|
+
params["filter[label]"] = self.label
|
327
|
+
|
328
|
+
# Endpoint targeting
|
329
|
+
if self.included_endpoint_ids:
|
330
|
+
params["filter[includedEndpointIds]"] = ",".join(self.included_endpoint_ids)
|
331
|
+
if self.excluded_endpoint_ids:
|
332
|
+
params["filter[excludedEndpointIds]"] = ",".join(self.excluded_endpoint_ids)
|
333
|
+
|
334
|
+
# Date/time filters
|
335
|
+
if self.last_seen_before is not None:
|
336
|
+
params["filter[lastSeenBefore]"] = self.last_seen_before
|
337
|
+
if self.last_seen_after is not None:
|
338
|
+
params["filter[lastSeenAfter]"] = self.last_seen_after
|
339
|
+
if self.last_seen_between is not None:
|
340
|
+
params["filter[lastSeenBetween]"] = self.last_seen_between
|
341
|
+
if self.last_seen is not None:
|
342
|
+
params["filter[lastSeen]"] = self.last_seen
|
343
|
+
|
344
|
+
# Cloud provider filters
|
345
|
+
if self.aws_regions:
|
346
|
+
params["filter[awsRegions]"] = ",".join(self.aws_regions)
|
347
|
+
if self.azure_regions:
|
348
|
+
params["filter[azureRegions]"] = ",".join(self.azure_regions)
|
349
|
+
|
350
|
+
# Special filters
|
351
|
+
if self.unisolated is not None:
|
352
|
+
params["filter[unisolated]"] = self.unisolated
|
353
|
+
|
354
|
+
return params
|
355
|
+
|
356
|
+
def to_filter_dict(self) -> Dict[str, Any]:
|
357
|
+
"""Convert filter to dictionary for command payloads - matches API specification exactly."""
|
358
|
+
# Include ALL fields as per API specification, with empty defaults
|
359
|
+
filter_dict = {
|
360
|
+
# Basic search fields (empty strings as defaults)
|
361
|
+
"searchTerm": self.search_term or "",
|
362
|
+
"name": self.name or "",
|
363
|
+
"ipAddress": self.ip_address or "",
|
364
|
+
"groupId": self.group_id or "",
|
365
|
+
"groupFullPath": self.group_full_path or "",
|
366
|
+
|
367
|
+
# Required array fields (with proper defaults)
|
368
|
+
"organizationIds": self.organization_ids or [0], # Keep as integers
|
369
|
+
"managedStatus": self.managed_status or ["managed"], # Default to managed
|
370
|
+
"isolationStatus": self.isolation_status or [],
|
371
|
+
"onlineStatus": self.online_status or [],
|
372
|
+
"platform": self.platform or [],
|
373
|
+
"tags": self.tags or [],
|
374
|
+
|
375
|
+
# Technical fields (empty strings as defaults)
|
376
|
+
"issue": self.issue[0] if self.issue and len(self.issue) > 0 else "", # API expects string not array
|
377
|
+
"version": self.version or "",
|
378
|
+
"policy": self.policy or "",
|
379
|
+
"tagId": self.tag_id or "", # Added missing field
|
380
|
+
|
381
|
+
# Endpoint targeting (with proper defaults)
|
382
|
+
"includedEndpointIds": self.included_endpoint_ids or [],
|
383
|
+
"excludedEndpointIds": self.excluded_endpoint_ids or [],
|
384
|
+
}
|
385
|
+
|
386
|
+
return filter_dict
|
387
|
+
|
388
|
+
|
389
|
+
class AssetTaskFilter(Filter):
|
390
|
+
"""Filter for asset task queries - matches API specification exactly."""
|
391
|
+
|
392
|
+
# Search and identification
|
393
|
+
search_term: Optional[str] = None
|
394
|
+
name: Optional[str] = None
|
395
|
+
endpoint_ids: Optional[List[str]] = None
|
396
|
+
|
397
|
+
# Task properties
|
398
|
+
status: Optional[List[str]] = None # scheduled, assigned, processing, completed, failed, expired, cancelled, compressing, uploading, analyzing, partially-completed
|
399
|
+
type: Optional[List[str]] = None # acquisition, offline-acquisition, triage, offline-triage, investigation, interact-shell, baseline-comparison, baseline-acquisition, acquire-image
|
400
|
+
execution_type: Optional[List[str]] = None # instant, scheduled
|
401
|
+
|
402
|
+
# Task metadata
|
403
|
+
has_drone_data: Optional[str] = None # yes, no
|
404
|
+
|
405
|
+
def to_params(self) -> Dict[str, Any]:
|
406
|
+
"""Convert filter to API parameters."""
|
407
|
+
params = {}
|
408
|
+
|
409
|
+
# Pagination parameters (not in filter namespace) - only if set
|
410
|
+
if self.page_number is not None:
|
411
|
+
params["pageNumber"] = self.page_number
|
412
|
+
if self.page_size is not None:
|
413
|
+
params["pageSize"] = self.page_size
|
414
|
+
if self.sort_by is not None:
|
415
|
+
params["sortBy"] = self.sort_by
|
416
|
+
if self.sort_type is not None:
|
417
|
+
params["sortType"] = self.sort_type
|
418
|
+
|
419
|
+
# Add task-specific filter parameters (use API field names)
|
420
|
+
if self.search_term is not None:
|
421
|
+
params["filter[searchTerm]"] = self.search_term
|
422
|
+
if self.name is not None:
|
423
|
+
params["filter[name]"] = self.name
|
424
|
+
if self.endpoint_ids:
|
425
|
+
params["filter[endpointIds]"] = ",".join(self.endpoint_ids)
|
426
|
+
|
427
|
+
# Status and type arrays
|
428
|
+
if self.status:
|
429
|
+
params["filter[status]"] = ",".join(self.status)
|
430
|
+
if self.type:
|
431
|
+
params["filter[type]"] = ",".join(self.type)
|
432
|
+
if self.execution_type:
|
433
|
+
params["filter[executionType]"] = ",".join(self.execution_type)
|
434
|
+
|
435
|
+
# Special filters
|
436
|
+
if self.has_drone_data is not None:
|
437
|
+
params["filter[hasDroneData]"] = self.has_drone_data
|
438
|
+
|
439
439
|
return params
|