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