@xen-orchestra/rest-api 0.29.0 → 0.30.0

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 (53) hide show
  1. package/README.md +108 -1
  2. package/dist/abstract-classes/base-controller.mjs +18 -3
  3. package/dist/abstract-classes/listener.mjs +116 -12
  4. package/dist/acl-privileges/acl-privilege.controller.mjs +172 -0
  5. package/dist/acl-roles/acl-role.controller.mjs +384 -0
  6. package/dist/alarms/alarm.controller.mjs +22 -9
  7. package/dist/alarms/alarm.service.mjs +8 -0
  8. package/dist/backup-archives/backup-archive.controller.mjs +30 -21
  9. package/dist/backup-archives/backup-archive.service.mjs +21 -0
  10. package/dist/backup-jobs/backup-job.controller.mjs +59 -15
  11. package/dist/backup-jobs/backup-job.service.mjs +7 -0
  12. package/dist/backup-logs/backup-log.controller.mjs +25 -11
  13. package/dist/backup-logs/backup-log.service.mjs +19 -0
  14. package/dist/backup-repositories/backup-repositories.controller.mjs +21 -3
  15. package/dist/events/event.class.mjs +24 -9
  16. package/dist/events/event.controller.mjs +3 -0
  17. package/dist/events/event.service.mjs +2 -1
  18. package/dist/groups/group.controller.mjs +90 -6
  19. package/dist/hosts/host.controller.mjs +78 -7
  20. package/dist/ioc/ioc.mjs +13 -4
  21. package/dist/messages/message.controller.mjs +29 -8
  22. package/dist/middlewares/acl.middleware.mjs +202 -0
  23. package/dist/middlewares/authentication.middleware.mjs +15 -6
  24. package/dist/middlewares/tsoa-to-xo-error.middleware.mjs +19 -1
  25. package/dist/networks/network.controller.mjs +60 -9
  26. package/dist/open-api/oa-examples/acl-privilege.oa-example.mjs +25 -0
  27. package/dist/open-api/oa-examples/acl-role.oa-example.mjs +22 -0
  28. package/dist/open-api/oa-examples/backup-archive.oa-example.mjs +6 -6
  29. package/dist/open-api/oa-examples/common.oa-example.mjs +3 -0
  30. package/dist/open-api/routes/routes.js +676 -132
  31. package/dist/pbds/pbd.controller.mjs +17 -3
  32. package/dist/pcis/pci.controller.mjs +16 -3
  33. package/dist/pgpus/pgpu.controller.mjs +16 -3
  34. package/dist/pifs/pif.controller.mjs +44 -8
  35. package/dist/pools/pool.controller.mjs +154 -9
  36. package/dist/proxies/proxy.controller.mjs +22 -4
  37. package/dist/restore-logs/restore-log.controller.mjs +36 -19
  38. package/dist/schedules/schedule.controller.mjs +33 -3
  39. package/dist/servers/server.controller.mjs +65 -5
  40. package/dist/sms/sm.controller.mjs +14 -2
  41. package/dist/srs/sr.controller.mjs +62 -10
  42. package/dist/tasks/task.controller.mjs +71 -11
  43. package/dist/users/user.controller.mjs +115 -16
  44. package/dist/vbds/vbd.controller.mjs +65 -31
  45. package/dist/vdi-snapshots/vdi-snapshot.controller.mjs +36 -6
  46. package/dist/vdis/vdi.controller.mjs +69 -8
  47. package/dist/vifs/vif.controller.mjs +43 -7
  48. package/dist/vm-controller/vm-controller.controller.mjs +62 -9
  49. package/dist/vm-snapshots/vm-snapshot.controller.mjs +70 -8
  50. package/dist/vm-templates/vm-template.controller.mjs +71 -8
  51. package/dist/vms/vm.controller.mjs +164 -12
  52. package/open-api/spec/swagger.json +10907 -3265
  53. package/package.json +4 -3
@@ -9,11 +9,12 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
9
9
  };
10
10
  import { Body, Delete, Deprecated, Example, Get, Middlewares, Patch, Path, Post, Query, Request, Response, Route, Security, SuccessResponse, Tags, } from 'tsoa';
11
11
  import { createLogger } from '@xen-orchestra/log';
12
+ import { forbiddenOperation } from 'xo-common/api-errors.js';
12
13
  import { inject } from 'inversify';
13
14
  import { json } from 'express';
14
15
  import { provide } from 'inversify-binding-decorators';
16
+ import { acl, actionIfNotSelfUser, actionsFromBody } from '../middlewares/acl.middleware.mjs';
15
17
  import { badRequestResp, createdResp, forbiddenOperationResp, internalServerErrorResp, invalidParameters, noContentResp, notFoundResp, resourceAlreadyExists, unauthorizedResp, } from '../open-api/common/response.common.mjs';
16
- import { forbiddenOperation } from 'xo-common/api-errors.js';
17
18
  import { partialUsers, user, authenticationTokens, userId, userIds, authenticationToken, } from '../open-api/oa-examples/user.oa-example.mjs';
18
19
  import { RestApi } from '../rest-api/rest-api.mjs';
19
20
  import { limitAndFilterArray } from '../helpers/utils.helper.mjs';
@@ -22,6 +23,7 @@ import { XoController } from '../abstract-classes/xo-controller.mjs';
22
23
  import { groupIds, partialGroups } from '../open-api/oa-examples/group.oa-example.mjs';
23
24
  import { partialTasks, taskIds } from '../open-api/oa-examples/task.oa-example.mjs';
24
25
  import { redirectMeAlias } from './user.middleware.mjs';
26
+ import { aclPrivilegeIds, partialAclPrivileges } from '../open-api/oa-examples/acl-privilege.oa-example.mjs';
25
27
  const log = createLogger('xo:rest-api:user-controller');
26
28
  let UserController = class UserController extends XoController {
27
29
  #userService;
@@ -37,21 +39,39 @@ let UserController = class UserController extends XoController {
37
39
  return this.#userService.getUser(id);
38
40
  }
39
41
  /**
42
+ * Returns all users that match the following privilege:
43
+ * - resource: user, action: read
44
+ *
40
45
  * @example fields "permission,name,id"
41
46
  * @example filter "permission:none"
42
47
  * @example limit 42
43
48
  */
44
49
  async getUsers(req, fields, ndjson, markdown, filter, limit) {
45
- const users = Object.values(await this.getObjects({ filter, limit }));
46
- return this.sendObjects(users, req);
50
+ const users = Object.values(await this.getObjects({ filter }));
51
+ return this.sendObjects(users, req, {
52
+ limit,
53
+ privilege: { action: 'read', resource: 'user' },
54
+ });
47
55
  }
48
56
  /**
57
+ * Required privilege:
58
+ * - resource: user, action: read (if not self)
59
+ *
49
60
  * @example id "722d17b9-699b-49d2-8193-be1ac573d3de"
50
61
  */
51
62
  getUser(id) {
52
63
  return this.getObject(id);
53
64
  }
54
65
  /**
66
+ * You cannot change your own `permission` (even with the right privilege)
67
+ *
68
+ * Required privileges:
69
+ * - resource: user, action: update (grants all fields)
70
+ * - resource: user, action: update:name (if name is passed)
71
+ * - resource: user, action: update:password (if password is passed)
72
+ * - resource: user, action: update:permission (if permission is passed)
73
+ * - resource: user, action: update:preferences (if preferences is passed)
74
+ *
55
75
  * @example id "722d17b9-699b-49d2-8193-be1ac573d3de"
56
76
  * @example body {
57
77
  * "name": "updated user name",
@@ -62,14 +82,8 @@ let UserController = class UserController extends XoController {
62
82
  */
63
83
  async updateUser(id, body) {
64
84
  const currentUser = this.restApi.getCurrentUser();
65
- const isAdmin = currentUser.permission === 'admin';
66
- if (isAdmin) {
67
- if (body.permission !== undefined && currentUser.id === id) {
68
- throw forbiddenOperation('update user', 'cannot change own permission');
69
- }
70
- }
71
- else if (body.name !== undefined || body.password !== undefined || body.permission !== undefined) {
72
- throw forbiddenOperation('update user', 'cannot change these fields without admin rights');
85
+ if (body.permission !== undefined && currentUser.id === id) {
86
+ throw forbiddenOperation('update user', 'cannot change own permission');
73
87
  }
74
88
  const user = await this.getObject(id);
75
89
  if (user.authProviders !== undefined &&
@@ -80,6 +94,9 @@ let UserController = class UserController extends XoController {
80
94
  await this.restApi.xoApp.updateUser(user.id, body);
81
95
  }
82
96
  /**
97
+ * Required privilege:
98
+ * - resource: user, action: create
99
+ *
83
100
  * @example body { "name": "new user", "password": "password", "permission": "none" }
84
101
  */
85
102
  async createUser(body) {
@@ -87,12 +104,18 @@ let UserController = class UserController extends XoController {
87
104
  return { id: user.id };
88
105
  }
89
106
  /**
107
+ * Required privilege:
108
+ * - resource: user, action: delete
109
+ *
90
110
  * @example id "722d17b9-699b-49d2-8193-be1ac573d3de"
91
111
  */
92
112
  async deleteUser(id) {
93
113
  await this.restApi.xoApp.deleteUser(id);
94
114
  }
95
115
  /**
116
+ * Returns all groups that match the following privilege:
117
+ * - resource: group, action: read
118
+ *
96
119
  * @example id "722d17b9-699b-49d2-8193-be1ac573d3de"
97
120
  * @example fields "name,id,users"
98
121
  * @example filter "users:length:>0"
@@ -101,9 +124,15 @@ let UserController = class UserController extends XoController {
101
124
  async getUserGroups(req, id, fields, ndjson, markdown, filter, limit) {
102
125
  const user = await this.getObject(id);
103
126
  const groups = await Promise.all(user.groups.map(group => this.restApi.xoApp.getGroup(group)));
104
- return this.sendObjects(limitAndFilterArray(groups, { filter, limit }), req, 'groups');
127
+ return this.sendObjects(limitAndFilterArray(groups, { filter }), req, {
128
+ path: 'groups',
129
+ limit,
130
+ privilege: { action: 'read', resource: 'group' },
131
+ });
105
132
  }
106
133
  /**
134
+ * You can only see your own authentication tokens
135
+ *
107
136
  * @example id "722d17b9-699b-49d2-8193-be1ac573d3de"
108
137
  * @example filter "expiration:>1757371582496"
109
138
  * @example limit 42
@@ -118,14 +147,21 @@ let UserController = class UserController extends XoController {
118
147
  return limitAndFilterArray(tokens, { filter, limit });
119
148
  }
120
149
  /**
150
+ * Returns all tasks that match the following privilege:
151
+ * - resource: task, action: read
152
+ *
121
153
  * @example id "722d17b9-699b-49d2-8193-be1ac573d3de"
122
154
  * @example fields "id,status,properties"
123
155
  * @example filter "status:failure"
124
156
  * @example limit 42
125
157
  */
126
158
  async getUserTasks(req, id, fields, ndjson, markdown, filter, limit) {
127
- const tasks = await this.getTasksForObject(id, { filter, limit });
128
- return this.sendObjects(Object.values(tasks), req, 'tasks');
159
+ const tasks = await this.getTasksForObject(id, { filter });
160
+ return this.sendObjects(Object.values(tasks), req, {
161
+ path: 'tasks',
162
+ limit,
163
+ privilege: { action: 'read', resource: 'task' },
164
+ });
129
165
  }
130
166
  // ----------- DEPRECATED TO BE REMOVED IN ONE YEAR (10-13-2026)--------------------
131
167
  /**
@@ -142,6 +178,8 @@ let UserController = class UserController extends XoController {
142
178
  }
143
179
  // ----------- DEPRECATED TO BE REMOVED IN ONE YEAR (10-13-2026)--------------------
144
180
  /**
181
+ * You can only create authentication token for yourself
182
+ *
145
183
  * @example id "me"
146
184
  * @example body {"client": {"id": "my-fav-client"}, "description": "token for CLI usage", "expiresIn": "1 hour"}
147
185
  */
@@ -156,11 +194,31 @@ let UserController = class UserController extends XoController {
156
194
  });
157
195
  return { token };
158
196
  }
197
+ /**
198
+ * Returns all ACL privileges that match the following privilege:
199
+ * - resource: acl-privilege, action: read (if not self)
200
+ *
201
+ * @example id "me"
202
+ * @example fields "id,action,resource"
203
+ * @example filter "action:create"
204
+ * @example limit 42
205
+ */
206
+ async getUserPrivileges(req, id, fields, ndjson, filter, limit) {
207
+ const user = await this.getObject(id);
208
+ const currentUser = this.restApi.getCurrentUser();
209
+ const userPrivileges = (await this.restApi.xoApp.getAclV2UserPrivileges(user.id));
210
+ return this.sendObjects(limitAndFilterArray(userPrivileges, { filter }), req, {
211
+ path: 'acl-privileges',
212
+ limit,
213
+ privilege: currentUser.id === user.id ? undefined : { action: 'read', resource: 'acl-privilege' },
214
+ });
215
+ }
159
216
  };
160
217
  __decorate([
161
218
  Example(userIds),
162
219
  Example(partialUsers),
163
220
  Get(''),
221
+ Security('*', ['acl']),
164
222
  __param(0, Request()),
165
223
  __param(1, Query()),
166
224
  __param(2, Query()),
@@ -171,12 +229,27 @@ __decorate([
171
229
  __decorate([
172
230
  Example(user),
173
231
  Get('{id}'),
232
+ Middlewares(acl({
233
+ resource: 'user',
234
+ action: actionIfNotSelfUser('read'),
235
+ objectId: 'params.id',
236
+ getObject: ({ restApi }) => restApi.xoApp.getUser,
237
+ })),
238
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
174
239
  Response(notFoundResp.status, notFoundResp.description),
175
240
  __param(0, Path())
176
241
  ], UserController.prototype, "getUser", null);
177
242
  __decorate([
178
243
  Patch('{id}'),
179
- Middlewares(json()),
244
+ Middlewares([
245
+ json(),
246
+ acl({
247
+ resource: 'user',
248
+ actions: actionsFromBody(['update:name', 'update:password', 'update:permission', 'update:preferences']),
249
+ objectId: 'params.id',
250
+ getObject: ({ restApi }) => restApi.xoApp.getUser,
251
+ }),
252
+ ]),
180
253
  SuccessResponse(noContentResp.status, noContentResp.description),
181
254
  Response(notFoundResp.status, notFoundResp.description),
182
255
  Response(resourceAlreadyExists.status, resourceAlreadyExists.description),
@@ -187,15 +260,23 @@ __decorate([
187
260
  __decorate([
188
261
  Example(userId),
189
262
  Post(''),
190
- Middlewares(json()),
263
+ Middlewares([json(), acl({ resource: 'user', action: 'create', object: ({ req }) => req.body })]),
191
264
  SuccessResponse(createdResp.status, createdResp.description),
192
265
  Response(unauthorizedResp.status, unauthorizedResp.description),
266
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
193
267
  Response(invalidParameters.status, invalidParameters.description),
194
268
  __param(0, Body())
195
269
  ], UserController.prototype, "createUser", null);
196
270
  __decorate([
197
271
  Delete('{id}'),
272
+ Middlewares(acl({
273
+ resource: 'user',
274
+ action: 'delete',
275
+ objectId: 'params.id',
276
+ getObject: ({ restApi }) => restApi.xoApp.getUser,
277
+ })),
198
278
  SuccessResponse(noContentResp.status, noContentResp.description),
279
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
199
280
  Response(notFoundResp.status, notFoundResp.description),
200
281
  __param(0, Path())
201
282
  ], UserController.prototype, "deleteUser", null);
@@ -203,6 +284,7 @@ __decorate([
203
284
  Example(groupIds),
204
285
  Example(partialGroups),
205
286
  Get('{id}/groups'),
287
+ Security('*', ['acl']),
206
288
  Tags('groups'),
207
289
  Response(notFoundResp.status, notFoundResp.description),
208
290
  __param(0, Request()),
@@ -216,6 +298,7 @@ __decorate([
216
298
  __decorate([
217
299
  Example(authenticationTokens),
218
300
  Get('{id}/authentication_tokens'),
301
+ Security('*', ['acl']),
219
302
  Response(notFoundResp.status, notFoundResp.description),
220
303
  Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
221
304
  __param(0, Request()),
@@ -227,6 +310,7 @@ __decorate([
227
310
  Example(taskIds),
228
311
  Example(partialTasks),
229
312
  Get('{id}/tasks'),
313
+ Security('*', ['acl']),
230
314
  Tags('tasks'),
231
315
  Response(notFoundResp.status, notFoundResp.description),
232
316
  __param(0, Request()),
@@ -250,12 +334,27 @@ __decorate([
250
334
  Example(authenticationToken),
251
335
  Post('{id}/authentication_tokens'),
252
336
  Middlewares(json()),
337
+ Security('*', ['acl']),
253
338
  SuccessResponse(createdResp.status, createdResp.description),
254
339
  Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
255
340
  Response(internalServerErrorResp.status, internalServerErrorResp.description),
256
341
  __param(0, Body()),
257
342
  __param(1, Path())
258
343
  ], UserController.prototype, "postAuthenticationTokens", null);
344
+ __decorate([
345
+ Example(aclPrivilegeIds),
346
+ Example(partialAclPrivileges),
347
+ Get('{id}/acl-privileges'),
348
+ Security('*', ['acl']),
349
+ Tags('acls'),
350
+ Response(notFoundResp.status, notFoundResp.description),
351
+ __param(0, Request()),
352
+ __param(1, Path()),
353
+ __param(2, Query()),
354
+ __param(3, Query()),
355
+ __param(4, Query()),
356
+ __param(5, Query())
357
+ ], UserController.prototype, "getUserPrivileges", null);
259
358
  UserController = __decorate([
260
359
  Route('users'),
261
360
  Security('*'),
@@ -12,10 +12,11 @@ import { json } from 'express';
12
12
  import { inject } from 'inversify';
13
13
  import { invalidParameters as invalidParametersError } from 'xo-common/api-errors.js';
14
14
  import { provide } from 'inversify-binding-decorators';
15
+ import { acl } from '../middlewares/acl.middleware.mjs';
15
16
  import { AlarmService } from '../alarms/alarm.service.mjs';
16
17
  import { escapeUnsafeComplexMatcher } from '../helpers/utils.helper.mjs';
17
18
  import { genericAlarmsExample } from '../open-api/oa-examples/alarm.oa-example.mjs';
18
- import { asynchronousActionResp, badRequestResp, createdResp, internalServerErrorResp, invalidParameters, noContentResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
19
+ import { asynchronousActionResp, badRequestResp, createdResp, internalServerErrorResp, invalidParameters, noContentResp, forbiddenOperationResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
19
20
  import { BASE_URL } from '../index.mjs';
20
21
  import { partialVbds, vbd, vbdId, vbdIds } from '../open-api/oa-examples/vbd.oa-example.mjs';
21
22
  import { RestApi } from '../rest-api/rest-api.mjs';
@@ -28,6 +29,29 @@ let VbdController = class VbdController extends XapiXoController {
28
29
  super('VBD', restApi);
29
30
  this.#alarmService = alarmService;
30
31
  }
32
+ /**
33
+ * Returns all VBDs that match the following privilege:
34
+ * - resource: vbd, action: read
35
+ *
36
+ * @example fields "device,bootable,uuid"
37
+ * @example filter "!bootable?"
38
+ * @example limit 42
39
+ */
40
+ getVbds(req, fields, ndjson, markdown, filter, limit) {
41
+ return this.sendObjects(Object.values(this.getObjects({ filter })), req, {
42
+ limit,
43
+ privilege: { action: 'read', resource: 'vbd' },
44
+ });
45
+ }
46
+ /**
47
+ * Required privilege:
48
+ * - resource: vbd, action: read
49
+ *
50
+ * @example id "f07ab729-c0e8-721c-45ec-f11276377030"
51
+ */
52
+ getVbd(id) {
53
+ return this.getObject(id);
54
+ }
31
55
  /**
32
56
  * Create a VBD to attach a VDI to a VM
33
57
  *
@@ -51,22 +75,6 @@ let VbdController = class VbdController extends XapiXoController {
51
75
  this.setHeader('Location', `${BASE_URL}/vbds/${vbdUuid}`);
52
76
  return { id: vbdUuid };
53
77
  }
54
- /**
55
- *
56
- * @example fields "device,bootable,uuid"
57
- * @example filter "!bootable?"
58
- * @example limit 42
59
- */
60
- getVbds(req, fields, ndjson, markdown, filter, limit) {
61
- return this.sendObjects(Object.values(this.getObjects({ filter, limit })), req);
62
- }
63
- /**
64
- *
65
- * @example id "f07ab729-c0e8-721c-45ec-f11276377030"
66
- */
67
- getVbd(id) {
68
- return this.getObject(id);
69
- }
70
78
  /**
71
79
  * Delete a VBD
72
80
  *
@@ -80,6 +88,9 @@ let VbdController = class VbdController extends XapiXoController {
80
88
  await xapiVbd.$xapi.VBD_destroy(xapiVbd.$ref);
81
89
  }
82
90
  /**
91
+ * Returns all alarms that match the following privilege:
92
+ * - resource: alarm, action: read
93
+ *
83
94
  * @example id "f07ab729-c0e8-721c-45ec-f11276377030"
84
95
  * @example fields "id,time"
85
96
  * @example filter "time:>1747053793"
@@ -89,29 +100,46 @@ let VbdController = class VbdController extends XapiXoController {
89
100
  const vbd = this.getObject(id);
90
101
  const alarms = this.#alarmService.getAlarms({
91
102
  filter: `${escapeUnsafeComplexMatcher(filter) ?? ''} object:uuid:${vbd.uuid}`,
103
+ });
104
+ return this.sendObjects(Object.values(alarms), req, {
105
+ path: 'alarms',
92
106
  limit,
107
+ privilege: { action: 'read', resource: 'alarm' },
93
108
  });
94
- return this.sendObjects(Object.values(alarms), req, 'alarms');
95
109
  }
96
110
  /**
111
+ * Returns all messages that match the following privilege:
112
+ * - resource: message, action: read
113
+ *
97
114
  * @example id "f07ab729-c0e8-721c-45ec-f11276377030"
98
115
  * @example fields "name,id,$object"
99
116
  * @example filter "name:VM_STARTED"
100
117
  * @example limit 42
101
118
  */
102
119
  getVbdMessages(req, id, fields, ndjson, markdown, filter, limit) {
103
- const messages = this.getMessagesForObject(id, { filter, limit });
104
- return this.sendObjects(Object.values(messages), req, 'messages');
120
+ const messages = this.getMessagesForObject(id, { filter });
121
+ return this.sendObjects(Object.values(messages), req, {
122
+ path: 'messages',
123
+ limit,
124
+ privilege: { action: 'read', resource: 'message' },
125
+ });
105
126
  }
106
127
  /**
128
+ * Returns all tasks that match the following privilege:
129
+ * - resource: task, action: read
130
+ *
107
131
  * @example id "f07ab729-c0e8-721c-45ec-f11276377030"
108
132
  * @example fields "id,status,properties"
109
133
  * @example filter "status:failure"
110
134
  * @example limit 42
111
135
  */
112
136
  async getVbdTasks(req, id, fields, ndjson, markdown, filter, limit) {
113
- const tasks = await this.getTasksForObject(id, { filter, limit });
114
- return this.sendObjects(Object.values(tasks), req, 'tasks');
137
+ const tasks = await this.getTasksForObject(id, { filter });
138
+ return this.sendObjects(Object.values(tasks), req, {
139
+ path: 'tasks',
140
+ limit,
141
+ privilege: { action: 'read', resource: 'task' },
142
+ });
115
143
  }
116
144
  /**
117
145
  * Hotplug the VBD, dynamically attaching it to the running VM
@@ -152,19 +180,11 @@ let VbdController = class VbdController extends XapiXoController {
152
180
  });
153
181
  }
154
182
  };
155
- __decorate([
156
- Example(vbdId),
157
- Post(''),
158
- Middlewares(json()),
159
- SuccessResponse(createdResp.status, createdResp.description),
160
- Response(notFoundResp.status, notFoundResp.description),
161
- Response(invalidParameters.status, invalidParameters.description),
162
- __param(0, Body())
163
- ], VbdController.prototype, "createVbd", null);
164
183
  __decorate([
165
184
  Example(vbdIds),
166
185
  Example(partialVbds),
167
186
  Get(''),
187
+ Security('*', ['acl']),
168
188
  __param(0, Request()),
169
189
  __param(1, Query()),
170
190
  __param(2, Query()),
@@ -175,9 +195,20 @@ __decorate([
175
195
  __decorate([
176
196
  Example(vbd),
177
197
  Get('{id}'),
198
+ Middlewares(acl({ resource: 'vbd', action: 'read', objectId: 'params.id' })),
199
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
178
200
  Response(notFoundResp.status, notFoundResp.description),
179
201
  __param(0, Path())
180
202
  ], VbdController.prototype, "getVbd", null);
203
+ __decorate([
204
+ Example(vbdId),
205
+ Post(''),
206
+ Middlewares(json()),
207
+ SuccessResponse(createdResp.status, createdResp.description),
208
+ Response(notFoundResp.status, notFoundResp.description),
209
+ Response(invalidParameters.status, invalidParameters.description),
210
+ __param(0, Body())
211
+ ], VbdController.prototype, "createVbd", null);
181
212
  __decorate([
182
213
  Delete('{id}'),
183
214
  SuccessResponse(noContentResp.status, noContentResp.description),
@@ -187,6 +218,7 @@ __decorate([
187
218
  __decorate([
188
219
  Example(genericAlarmsExample),
189
220
  Get('{id}/alarms'),
221
+ Security('*', ['acl']),
190
222
  Tags('alarms'),
191
223
  Response(notFoundResp.status, notFoundResp.description),
192
224
  __param(0, Request()),
@@ -201,6 +233,7 @@ __decorate([
201
233
  Example(messageIds),
202
234
  Example(partialMessages),
203
235
  Get('{id}/messages'),
236
+ Security('*', ['acl']),
204
237
  Tags('messages'),
205
238
  Response(notFoundResp.status, notFoundResp.description),
206
239
  __param(0, Request()),
@@ -215,6 +248,7 @@ __decorate([
215
248
  Example(taskIds),
216
249
  Example(partialTasks),
217
250
  Get('{id}/tasks'),
251
+ Security('*', ['acl']),
218
252
  Tags('tasks'),
219
253
  Response(notFoundResp.status, notFoundResp.description),
220
254
  __param(0, Request()),
@@ -29,12 +29,18 @@ let VdiSnapshotController = class VdiSnapshotController extends XapiXoController
29
29
  this.#vdiService = vdiService;
30
30
  }
31
31
  /**
32
+ * Returns all VDI snapshots that match the following privilege:
33
+ * - resource: vdi-snapshot, action: read
34
+ *
32
35
  * @example fields "uuid,snapshot_time,$snapshot_of"
33
36
  * @example filter "snapshot_time:>1725020038"
34
37
  * @example limit 42
35
38
  */
36
39
  getVdiSnapshots(req, fields, ndjson, markdown, filter, limit) {
37
- return this.sendObjects(Object.values(this.getObjects({ filter, limit })), req);
40
+ return this.sendObjects(Object.values(this.getObjects({ filter })), req, {
41
+ limit,
42
+ privilege: { action: 'read', resource: 'vdi-snapshot' },
43
+ });
38
44
  }
39
45
  /**
40
46
  *
@@ -59,6 +65,9 @@ let VdiSnapshotController = class VdiSnapshotController extends XapiXoController
59
65
  return this.getObject(id);
60
66
  }
61
67
  /**
68
+ * Returns all alarms that match the following privilege:
69
+ * - resource: alarm, action: read
70
+ *
62
71
  * @example id "d2727772-735b-478f-b6f9-11e7db56dfd0"
63
72
  * @example fields "id,time"
64
73
  * @example filter "time:>1747053793"
@@ -68,9 +77,12 @@ let VdiSnapshotController = class VdiSnapshotController extends XapiXoController
68
77
  const vdiSnapshot = this.getObject(id);
69
78
  const alarms = this.#alarmService.getAlarms({
70
79
  filter: `${escapeUnsafeComplexMatcher(filter) ?? ''} object:uuid:${vdiSnapshot.uuid}`,
80
+ });
81
+ return this.sendObjects(Object.values(alarms), req, {
82
+ path: 'alarms',
71
83
  limit,
84
+ privilege: { action: 'read', resource: 'alarm' },
72
85
  });
73
- return this.sendObjects(Object.values(alarms), req, 'alarms');
74
86
  }
75
87
  /**
76
88
  * @example id "d2727772-735b-478f-b6f9-11e7db56dfd0"
@@ -80,24 +92,38 @@ let VdiSnapshotController = class VdiSnapshotController extends XapiXoController
80
92
  await xapiVdiSnapshot.$xapi.VDI_destroy(xapiVdiSnapshot.$ref);
81
93
  }
82
94
  /**
95
+ * Returns all messages that match the following privilege:
96
+ * - resource: message, action: read
97
+ *
83
98
  * @example id "d2727772-735b-478f-b6f9-11e7db56dfd0"
84
99
  * @example fields "name,id,$object"
85
100
  * @example filter "name:VM_STARTED"
86
101
  * @example limit 42
87
102
  */
88
103
  getVdiSnapshotMessages(req, id, fields, ndjson, markdown, filter, limit) {
89
- const messages = this.getMessagesForObject(id, { filter, limit });
90
- return this.sendObjects(Object.values(messages), req, 'messages');
104
+ const messages = this.getMessagesForObject(id, { filter });
105
+ return this.sendObjects(Object.values(messages), req, {
106
+ path: 'messages',
107
+ limit,
108
+ privilege: { action: 'read', resource: 'message' },
109
+ });
91
110
  }
92
111
  /**
112
+ * Returns all tasks that match the following privilege:
113
+ * - resource: task, action: read
114
+ *
93
115
  * @example id "d2727772-735b-478f-b6f9-11e7db56dfd0"
94
116
  * @example fields "id,status,properties"
95
117
  * @example filter "status:failure"
96
118
  * @example limit 42
97
119
  */
98
120
  async getVdiSnapshotTasks(req, id, fields, ndjson, markdown, filter, limit) {
99
- const tasks = await this.getTasksForObject(id, { filter, limit });
100
- return this.sendObjects(Object.values(tasks), req, 'tasks');
121
+ const tasks = await this.getTasksForObject(id, { filter });
122
+ return this.sendObjects(Object.values(tasks), req, {
123
+ path: 'tasks',
124
+ limit,
125
+ privilege: { action: 'read', resource: 'task' },
126
+ });
101
127
  }
102
128
  /**
103
129
  * @example id "d2727772-735b-478f-b6f9-11e7db56dfd0"
@@ -120,6 +146,7 @@ __decorate([
120
146
  Example(vdiSnapshotIds),
121
147
  Example(partialVdiSnapshots),
122
148
  Get(''),
149
+ Security('*', ['acl']),
123
150
  __param(0, Request()),
124
151
  __param(1, Query()),
125
152
  __param(2, Query()),
@@ -145,6 +172,7 @@ __decorate([
145
172
  __decorate([
146
173
  Example(genericAlarmsExample),
147
174
  Get('{id}/alarms'),
175
+ Security('*', ['acl']),
148
176
  Tags('alarms'),
149
177
  Response(notFoundResp.status, notFoundResp.description),
150
178
  __param(0, Request()),
@@ -165,6 +193,7 @@ __decorate([
165
193
  Example(messageIds),
166
194
  Example(partialMessages),
167
195
  Get('{id}/messages'),
196
+ Security('*', ['acl']),
168
197
  Tags('messages'),
169
198
  Response(notFoundResp.status, notFoundResp.description),
170
199
  __param(0, Request()),
@@ -179,6 +208,7 @@ __decorate([
179
208
  Example(taskIds),
180
209
  Example(partialTasks),
181
210
  Get('{id}/tasks'),
211
+ Security('*', ['acl']),
182
212
  Tags('tasks'),
183
213
  Response(notFoundResp.status, notFoundResp.description),
184
214
  __param(0, Request()),