@xen-orchestra/rest-api 0.28.2 → 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 (55) hide show
  1. package/README.md +108 -1
  2. package/dist/abstract-classes/base-controller.mjs +28 -3
  3. package/dist/abstract-classes/listener.mjs +124 -15
  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 +25 -11
  7. package/dist/alarms/alarm.service.mjs +8 -0
  8. package/dist/backup-archives/backup-archive.controller.mjs +33 -23
  9. package/dist/backup-archives/backup-archive.service.mjs +21 -0
  10. package/dist/backup-jobs/backup-job.controller.mjs +74 -25
  11. package/dist/backup-jobs/backup-job.service.mjs +7 -0
  12. package/dist/backup-logs/backup-log.controller.mjs +28 -13
  13. package/dist/backup-logs/backup-log.service.mjs +19 -0
  14. package/dist/backup-repositories/backup-repositories.controller.mjs +24 -5
  15. package/dist/events/event.class.mjs +36 -18
  16. package/dist/events/event.controller.mjs +3 -0
  17. package/dist/events/event.service.mjs +4 -4
  18. package/dist/groups/group.controller.mjs +99 -12
  19. package/dist/helpers/markdown.helper.mjs +20 -0
  20. package/dist/helpers/object-wrapper.helper.mjs +3 -3
  21. package/dist/hosts/host.controller.mjs +90 -15
  22. package/dist/ioc/ioc.mjs +13 -4
  23. package/dist/messages/message.controller.mjs +32 -10
  24. package/dist/middlewares/acl.middleware.mjs +202 -0
  25. package/dist/middlewares/authentication.middleware.mjs +15 -6
  26. package/dist/middlewares/tsoa-to-xo-error.middleware.mjs +19 -1
  27. package/dist/networks/network.controller.mjs +72 -17
  28. package/dist/open-api/oa-examples/acl-privilege.oa-example.mjs +25 -0
  29. package/dist/open-api/oa-examples/acl-role.oa-example.mjs +22 -0
  30. package/dist/open-api/oa-examples/backup-archive.oa-example.mjs +6 -6
  31. package/dist/open-api/oa-examples/common.oa-example.mjs +3 -0
  32. package/dist/open-api/routes/routes.js +856 -172
  33. package/dist/pbds/pbd.controller.mjs +20 -5
  34. package/dist/pcis/pci.controller.mjs +19 -5
  35. package/dist/pgpus/pgpu.controller.mjs +19 -5
  36. package/dist/pifs/pif.controller.mjs +56 -16
  37. package/dist/pools/pool.controller.mjs +166 -17
  38. package/dist/proxies/proxy.controller.mjs +25 -6
  39. package/dist/restore-logs/restore-log.controller.mjs +42 -23
  40. package/dist/schedules/schedule.controller.mjs +36 -5
  41. package/dist/servers/server.controller.mjs +71 -9
  42. package/dist/sms/sm.controller.mjs +17 -4
  43. package/dist/srs/sr.controller.mjs +74 -18
  44. package/dist/tasks/task.controller.mjs +74 -13
  45. package/dist/users/user.controller.mjs +124 -22
  46. package/dist/vbds/vbd.controller.mjs +76 -38
  47. package/dist/vdi-snapshots/vdi-snapshot.controller.mjs +48 -14
  48. package/dist/vdis/vdi.controller.mjs +81 -16
  49. package/dist/vifs/vif.controller.mjs +118 -16
  50. package/dist/vm-controller/vm-controller.controller.mjs +77 -19
  51. package/dist/vm-snapshots/vm-snapshot.controller.mjs +85 -18
  52. package/dist/vm-templates/vm-template.controller.mjs +86 -18
  53. package/dist/vms/vm.controller.mjs +182 -24
  54. package/open-api/spec/swagger.json +12112 -3537
  55. package/package.json +12 -11
@@ -13,8 +13,9 @@ import { invalidParameters } from 'xo-common/api-errors.js';
13
13
  import { PassThrough } from 'node:stream';
14
14
  import { provide } from 'inversify-binding-decorators';
15
15
  import { json } from 'express';
16
+ import { acl } from '../middlewares/acl.middleware.mjs';
16
17
  import { RestApi } from '../rest-api/rest-api.mjs';
17
- import { asynchronousActionResp, badRequestResp, createdResp, featureUnauthorized, internalServerErrorResp, invalidParameters as invalidParametersResp, noContentResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
18
+ import { asynchronousActionResp, badRequestResp, createdResp, featureUnauthorized, forbiddenOperationResp, internalServerErrorResp, invalidParameters as invalidParametersResp, noContentResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
18
19
  import { XapiXoController } from '../abstract-classes/xapi-xo-controller.mjs';
19
20
  import { AlarmService } from '../alarms/alarm.service.mjs';
20
21
  import { genericAlarmsExample } from '../open-api/oa-examples/alarm.oa-example.mjs';
@@ -40,21 +41,33 @@ let PoolController = class PoolController extends XapiXoController {
40
41
  this.#networkService = networkService;
41
42
  }
42
43
  /**
44
+ * Returns all pools that match the following privilege:
45
+ * - resource: pool, action: read
43
46
  *
44
47
  * @example fields "auto_poweron,name_label,id"
45
48
  * @example filter "auto_poweron?"
46
49
  * @example limit 42
47
50
  */
48
- getPools(req, fields, ndjson, filter, limit) {
49
- return this.sendObjects(Object.values(this.getObjects({ filter, limit })), req);
51
+ getPools(req, fields, ndjson, markdown, filter, limit) {
52
+ return this.sendObjects(Object.values(this.getObjects({ filter })), req, {
53
+ limit,
54
+ privilege: { action: 'read', resource: 'pool' },
55
+ });
50
56
  }
51
57
  /**
58
+ * Required privilege:
59
+ * - resource: pool, action: read
60
+ *
52
61
  * @example id "355ee47d-ff4c-4924-3db2-fd86ae629676"
53
62
  */
54
63
  getPool(id) {
55
64
  return this.getObject(id);
56
65
  }
57
66
  /**
67
+ * Required privilege:
68
+ * - resource: pool, action: create:network
69
+ * - resource: network, action: create
70
+ *
58
71
  * @example id "355ee47d-ff4c-4924-3db2-fd86ae629676"
59
72
  * @example body {
60
73
  * "name": "awes0me_network",
@@ -130,6 +143,9 @@ let PoolController = class PoolController extends XapiXoController {
130
143
  });
131
144
  }
132
145
  /**
146
+ * Required privilege:
147
+ * - resource: pool, action: emergency-shutdown
148
+ *
133
149
  * @example id "355ee47d-ff4c-4924-3db2-fd86ae629677"
134
150
  */
135
151
  emergencyShutdown(id, sync) {
@@ -148,6 +164,9 @@ let PoolController = class PoolController extends XapiXoController {
148
164
  });
149
165
  }
150
166
  /**
167
+ * Required privilege:
168
+ * - resource: pool, action: rolling-reboot
169
+ *
151
170
  * @example id "355ee47d-ff4c-4924-3db2-fd86ae629677"
152
171
  */
153
172
  rollingReboot(id, sync) {
@@ -167,6 +186,9 @@ let PoolController = class PoolController extends XapiXoController {
167
186
  });
168
187
  }
169
188
  /**
189
+ * Required privilege:
190
+ * - resource: pool, action: rolling-update
191
+ *
170
192
  * @example id "355ee47d-ff4c-4924-3db2-fd86ae629677"
171
193
  */
172
194
  rollingUpdate(id, sync) {
@@ -189,6 +211,9 @@ let PoolController = class PoolController extends XapiXoController {
189
211
  /**
190
212
  * Import an XVA VM into a pool
191
213
  *
214
+ * Required privilege:
215
+ * - resource: sr, action: import:vm
216
+ *
192
217
  * @example id "355ee47d-ff4c-4924-3db2-fd86ae629677"
193
218
  * @example sr "c787b75c-3e0d-70fa-d0c3-cbfd382d7e33"
194
219
  *
@@ -206,6 +231,14 @@ let PoolController = class PoolController extends XapiXoController {
206
231
  return { id: vmId };
207
232
  }
208
233
  /**
234
+ * Required privilege:
235
+ * - resource: pool, action: create:vm
236
+ * - resource: vm-template, action: instantiate
237
+ * - resource: vdi, action: create (if vdis is passed)
238
+ * - resource: vdi, action: boot (if install.repository is passed)
239
+ * - resource: vif, action: create (if vifs is passed)
240
+ * - resource: host, action: allow-vm (if affinity is passed)
241
+ *
209
242
  * @example id "355ee47d-ff4c-4924-3db2-fd86ae629677"
210
243
  * @example body {
211
244
  * "name_label": "new VM from REST API",
@@ -241,12 +274,18 @@ let PoolController = class PoolController extends XapiXoController {
241
274
  });
242
275
  }
243
276
  /**
277
+ * Required privilege:
278
+ * - resource: pool, action: read
279
+ *
244
280
  * @example id "355ee47d-ff4c-4924-3db2-fd86ae629677"
245
281
  */
246
282
  getStats(id, granularity) {
247
283
  return this.restApi.xoApp.getXapiPoolStats(id, granularity);
248
284
  }
249
285
  /**
286
+ * Required privilege:
287
+ * - resource: pool, action: read
288
+ *
250
289
  * @example id "355ee47d-ff4c-4924-3db2-fd86ae629677"
251
290
  */
252
291
  async getPoolDashboard(req, id, ndjson) {
@@ -269,20 +308,29 @@ let PoolController = class PoolController extends XapiXoController {
269
308
  }
270
309
  }
271
310
  /**
311
+ * Returns all alarms that match the following privilege:
312
+ * - resource: alarm, action: read
313
+ *
272
314
  * @example id "355ee47d-ff4c-4924-3db2-fd86ae629676"
273
315
  * @example fields "id,time"
274
316
  * @example filter "time:>1747053793"
275
317
  * @example limit 42
276
318
  */
277
- getPoolAlarms(req, id, fields, ndjson, filter, limit) {
319
+ getPoolAlarms(req, id, fields, ndjson, markdown, filter, limit) {
278
320
  const pool = this.getObject(id);
279
321
  const alarms = this.#alarmService.getAlarms({
280
322
  filter: `${escapeUnsafeComplexMatcher(filter) ?? ''} object:uuid:${pool.uuid}`,
323
+ });
324
+ return this.sendObjects(Object.values(alarms), req, {
325
+ path: 'alarms',
281
326
  limit,
327
+ privilege: { action: 'read', resource: 'alarm' },
282
328
  });
283
- return this.sendObjects(Object.values(alarms), req, 'alarms');
284
329
  }
285
330
  /**
331
+ * Required privilege:
332
+ * - resource: pool, action: read
333
+ *
286
334
  * @example id "355ee47d-ff4c-4924-3db2-fd86ae629676"
287
335
  */
288
336
  async getPoolMissingPatches(id) {
@@ -291,16 +339,26 @@ let PoolController = class PoolController extends XapiXoController {
291
339
  return missingPatches;
292
340
  }
293
341
  /**
342
+ * Returns all messages that match the following privilege:
343
+ * - resource: message, action: read
344
+ *
294
345
  * @example id "355ee47d-ff4c-4924-3db2-fd86ae629676"
295
346
  * @example fields "name,id,$object"
296
347
  * @example filter "name:IP_CONFIGURED_PIF_CAN_UNPLUG"
297
348
  * @example limit 42
298
349
  */
299
- getPoolMessages(req, id, fields, ndjson, filter, limit) {
300
- const messages = this.getMessagesForObject(id, { filter, limit });
301
- return this.sendObjects(Object.values(messages), req, 'messages');
350
+ getPoolMessages(req, id, fields, ndjson, markdown, filter, limit) {
351
+ const messages = this.getMessagesForObject(id, { filter });
352
+ return this.sendObjects(Object.values(messages), req, {
353
+ path: 'messages',
354
+ limit,
355
+ privilege: { action: 'read', resource: 'message' },
356
+ });
302
357
  }
303
358
  /**
359
+ * Required privilege:
360
+ * - resource: pool, action: update:tags
361
+ *
304
362
  * @example id "355ee47d-ff4c-4924-3db2-fd86ae629676"
305
363
  * @example tag "from-rest-api"
306
364
  */
@@ -309,6 +367,9 @@ let PoolController = class PoolController extends XapiXoController {
309
367
  await pool.$call('add_tags', tag);
310
368
  }
311
369
  /**
370
+ * Required privilege:
371
+ * - resource: pool, action: update:tags
372
+ *
312
373
  * @example id "355ee47d-ff4c-4924-3db2-fd86ae629676"
313
374
  * @example tag "from-rest-api"
314
375
  */
@@ -317,13 +378,20 @@ let PoolController = class PoolController extends XapiXoController {
317
378
  await pool.$call('remove_tags', tag);
318
379
  }
319
380
  /**
381
+ * Returns all tasks that match the following privilege:
382
+ * - resource: task, action: read
383
+ *
320
384
  * @example fields "id,status,properties"
321
385
  * @example filter "status:failure"
322
386
  * @example limit 42
323
387
  */
324
- async getPoolTasks(req, id, fields, ndjson, filter, limit) {
325
- const tasks = await this.getTasksForObject(id, { filter, limit });
326
- return this.sendObjects(Object.values(tasks), req, 'tasks');
388
+ async getPoolTasks(req, id, fields, ndjson, markdown, filter, limit) {
389
+ const tasks = await this.getTasksForObject(id, { filter });
390
+ return this.sendObjects(Object.values(tasks), req, {
391
+ path: 'tasks',
392
+ limit,
393
+ privilege: { action: 'read', resource: 'task' },
394
+ });
327
395
  }
328
396
  /**
329
397
  * Reconfigure the management interface for all hosts in the pool to use the given network.
@@ -360,15 +428,19 @@ __decorate([
360
428
  Example(poolIds),
361
429
  Example(partialPools),
362
430
  Get(''),
431
+ Security('*', ['acl']),
363
432
  __param(0, Request()),
364
433
  __param(1, Query()),
365
434
  __param(2, Query()),
366
435
  __param(3, Query()),
367
- __param(4, Query())
436
+ __param(4, Query()),
437
+ __param(5, Query())
368
438
  ], PoolController.prototype, "getPools", null);
369
439
  __decorate([
370
440
  Example(pool),
371
441
  Get('{id}'),
442
+ Middlewares(acl({ resource: 'pool', action: 'read', objectId: 'params.id' })),
443
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
372
444
  Response(notFoundResp.status, notFoundResp.description),
373
445
  __param(0, Path())
374
446
  ], PoolController.prototype, "getPool", null);
@@ -376,9 +448,17 @@ __decorate([
376
448
  Example(taskLocation),
377
449
  Example(createNetwork),
378
450
  Post('{id}/actions/create_network'),
379
- Middlewares(json()),
451
+ Middlewares([
452
+ json(),
453
+ acl([
454
+ // these two rights are a bit redundant, but for now this is the only way to restrict network creation on a given pool
455
+ { resource: 'pool', action: 'create:network', objectId: 'params.id' },
456
+ { resource: 'network', action: 'create', object: ({ req }) => req.body },
457
+ ]),
458
+ ]),
380
459
  Tags('networks'),
381
460
  SuccessResponse(createdResp.status, createdResp.description),
461
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
382
462
  Response(asynchronousActionResp.status, asynchronousActionResp.description),
383
463
  Response(notFoundResp.status, notFoundResp.description),
384
464
  Response(invalidParametersResp.status, invalidParametersResp.description),
@@ -420,7 +500,9 @@ __decorate([
420
500
  __decorate([
421
501
  Example(taskLocation),
422
502
  Post('{id}/actions/emergency_shutdown'),
503
+ Middlewares(acl({ resource: 'pool', action: 'emergency-shutdown', objectId: 'params.id' })),
423
504
  SuccessResponse(asynchronousActionResp.status, asynchronousActionResp.description),
505
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
424
506
  Response(noContentResp.status, noContentResp.description),
425
507
  Response(featureUnauthorized.status, featureUnauthorized.description),
426
508
  Response(notFoundResp.status, notFoundResp.description),
@@ -430,7 +512,9 @@ __decorate([
430
512
  __decorate([
431
513
  Example(taskLocation),
432
514
  Post('{id}/actions/rolling_reboot'),
515
+ Middlewares(acl({ resource: 'pool', action: 'rolling-reboot', objectId: 'params.id' })),
433
516
  SuccessResponse(asynchronousActionResp.status, asynchronousActionResp.description),
517
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
434
518
  Response(noContentResp.status, noContentResp.description),
435
519
  Response(featureUnauthorized.status, featureUnauthorized.description),
436
520
  Response(notFoundResp.status, notFoundResp.description),
@@ -440,7 +524,9 @@ __decorate([
440
524
  __decorate([
441
525
  Example(taskLocation),
442
526
  Post('{id}/actions/rolling_update'),
527
+ Middlewares(acl({ resource: 'pool', action: 'rolling-update', objectId: 'params.id' })),
443
528
  SuccessResponse(asynchronousActionResp.status, asynchronousActionResp.description),
529
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
444
530
  Response(noContentResp.status, noContentResp.description),
445
531
  Response(featureUnauthorized.status, featureUnauthorized.description),
446
532
  Response(notFoundResp.status, notFoundResp.description),
@@ -450,8 +536,24 @@ __decorate([
450
536
  __decorate([
451
537
  Example(importVm),
452
538
  Post('{id}/vms'),
539
+ Middlewares(acl([
540
+ {
541
+ resource: 'sr',
542
+ action: 'import:vm',
543
+ objectId: ({ req, restApi }) => {
544
+ if (req.query.sr) {
545
+ return req.query.sr;
546
+ }
547
+ else {
548
+ const pool = restApi.getObject(req.params.id, 'pool');
549
+ return pool.default_SR;
550
+ }
551
+ },
552
+ },
553
+ ])),
453
554
  Tags('vms'),
454
555
  SuccessResponse(createdResp.status, 'VM imported'),
556
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
455
557
  Response(notFoundResp.status, notFoundResp.description),
456
558
  Response(internalServerErrorResp.status, internalServerErrorResp.description),
457
559
  __param(0, Request()),
@@ -462,9 +564,40 @@ __decorate([
462
564
  Example(taskLocation),
463
565
  Example(createVm),
464
566
  Post('{id}/actions/create_vm'),
465
- Middlewares(json()),
567
+ Middlewares([
568
+ json(),
569
+ acl([
570
+ { resource: 'pool', action: 'create:vm', objectId: 'params.id' },
571
+ {
572
+ resource: 'vm-template',
573
+ action: 'instantiate',
574
+ objectId: ({ req, restApi }) => {
575
+ const pool = restApi.getXapiObject(req.params.id, 'pool');
576
+ const template = pool.$xapi.getObject(req.body.template);
577
+ if (template.is_default_template) {
578
+ return `${pool.uuid}-${template.uuid}`;
579
+ }
580
+ return req.body.template;
581
+ },
582
+ },
583
+ {
584
+ resource: 'vdi',
585
+ action: 'boot',
586
+ objectId: ({ req }) => {
587
+ const repository = req.body.install?.repository;
588
+ if (repository !== '') {
589
+ return repository;
590
+ }
591
+ },
592
+ },
593
+ { resource: 'vdi', action: 'create', objects: ({ req }) => req.body.vdis },
594
+ { resource: 'vif', action: 'create', objects: ({ req }) => req.body.vifs },
595
+ { resource: 'host', action: 'allow-vm', objectId: 'body.affinity' },
596
+ ]),
597
+ ]),
466
598
  Tags('vms'),
467
599
  SuccessResponse(createdResp.status, createdResp.description),
600
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
468
601
  Response(asynchronousActionResp.status, asynchronousActionResp.description),
469
602
  Response(notFoundResp.status, notFoundResp.description),
470
603
  Response(internalServerErrorResp.status, internalServerErrorResp.description),
@@ -475,6 +608,8 @@ __decorate([
475
608
  __decorate([
476
609
  Example(poolStats),
477
610
  Get('{id}/stats'),
611
+ Middlewares(acl({ resource: 'pool', action: 'read', objectId: 'params.id' })),
612
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
478
613
  Response(notFoundResp.status, notFoundResp.description),
479
614
  Response(422, 'Invalid granularity'),
480
615
  __param(0, Path()),
@@ -483,6 +618,8 @@ __decorate([
483
618
  __decorate([
484
619
  Example(poolDashboard),
485
620
  Get('{id}/dashboard'),
621
+ Middlewares(acl({ resource: 'pool', action: 'read', objectId: 'params.id' })),
622
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
486
623
  Response(notFoundResp.status, notFoundResp.description),
487
624
  __param(0, Request()),
488
625
  __param(1, Path()),
@@ -491,6 +628,7 @@ __decorate([
491
628
  __decorate([
492
629
  Example(genericAlarmsExample),
493
630
  Get('{id}/alarms'),
631
+ Security('*', ['acl']),
494
632
  Tags('alarms'),
495
633
  Response(notFoundResp.status, notFoundResp.description),
496
634
  __param(0, Request()),
@@ -498,11 +636,14 @@ __decorate([
498
636
  __param(2, Query()),
499
637
  __param(3, Query()),
500
638
  __param(4, Query()),
501
- __param(5, Query())
639
+ __param(5, Query()),
640
+ __param(6, Query())
502
641
  ], PoolController.prototype, "getPoolAlarms", null);
503
642
  __decorate([
504
643
  Example(poolMissingPatches),
505
644
  Get('{id}/missing_patches'),
645
+ Middlewares(acl({ resource: 'pool', action: 'read', objectId: 'params.id' })),
646
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
506
647
  Response(notFoundResp.status, notFoundResp.description),
507
648
  Response(featureUnauthorized.status, featureUnauthorized.description),
508
649
  __param(0, Path())
@@ -511,6 +652,7 @@ __decorate([
511
652
  Example(messageIds),
512
653
  Example(partialMessages),
513
654
  Get('{id}/messages'),
655
+ Security('*', ['acl']),
514
656
  Tags('messages'),
515
657
  Response(notFoundResp.status, notFoundResp.description),
516
658
  __param(0, Request()),
@@ -518,18 +660,23 @@ __decorate([
518
660
  __param(2, Query()),
519
661
  __param(3, Query()),
520
662
  __param(4, Query()),
521
- __param(5, Query())
663
+ __param(5, Query()),
664
+ __param(6, Query())
522
665
  ], PoolController.prototype, "getPoolMessages", null);
523
666
  __decorate([
524
667
  Put('{id}/tags/{tag}'),
668
+ Middlewares(acl({ resource: 'pool', action: 'update:tags', objectId: 'params.id' })),
525
669
  SuccessResponse(noContentResp.status, noContentResp.description),
670
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
526
671
  Response(notFoundResp.status, notFoundResp.description),
527
672
  __param(0, Path()),
528
673
  __param(1, Path())
529
674
  ], PoolController.prototype, "putPoolTag", null);
530
675
  __decorate([
531
676
  Delete('{id}/tags/{tag}'),
677
+ Middlewares(acl({ resource: 'pool', action: 'update:tags', objectId: 'params.id' })),
532
678
  SuccessResponse(noContentResp.status, noContentResp.description),
679
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
533
680
  Response(notFoundResp.status, notFoundResp.description),
534
681
  __param(0, Path()),
535
682
  __param(1, Path())
@@ -538,6 +685,7 @@ __decorate([
538
685
  Example(taskIds),
539
686
  Example(partialTasks),
540
687
  Get('{id}/tasks'),
688
+ Security('*', ['acl']),
541
689
  Tags('tasks'),
542
690
  Response(notFoundResp.status, notFoundResp.description),
543
691
  __param(0, Request()),
@@ -545,7 +693,8 @@ __decorate([
545
693
  __param(2, Query()),
546
694
  __param(3, Query()),
547
695
  __param(4, Query()),
548
- __param(5, Query())
696
+ __param(5, Query()),
697
+ __param(6, Query())
549
698
  ], PoolController.prototype, "getPoolTasks", null);
550
699
  __decorate([
551
700
  Example(taskLocation),
@@ -7,10 +7,11 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __param = (this && this.__param) || function (paramIndex, decorator) {
8
8
  return function (target, key) { decorator(target, key, paramIndex); }
9
9
  };
10
- import { Example, Get, Path, Query, Request, Response, Route, Security, Tags } from 'tsoa';
10
+ import { Example, Get, Middlewares, Path, Query, Request, Response, Route, Security, Tags } from 'tsoa';
11
11
  import { inject } from 'inversify';
12
12
  import { provide } from 'inversify-binding-decorators';
13
- import { badRequestResp, notFoundResp, unauthorizedResp } from '../open-api/common/response.common.mjs';
13
+ import { acl } from '../middlewares/acl.middleware.mjs';
14
+ import { badRequestResp, forbiddenOperationResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
14
15
  import { partialProxies, proxy, proxyIds } from '../open-api/oa-examples/proxy.oa-example.mjs';
15
16
  import { XoController } from '../abstract-classes/xo-controller.mjs';
16
17
  import { RestApi } from '../rest-api/rest-api.mjs';
@@ -25,15 +26,24 @@ let ProxyController = class ProxyController extends XoController {
25
26
  return this.restApi.xoApp.getProxy(id);
26
27
  }
27
28
  /**
29
+ * Returns all proxies that match the following privilege:
30
+ * - resource: proxy, action: read
31
+ *
28
32
  * @example fields "vmUuid,id,name"
29
33
  * @example filter "vmUuid?"
30
34
  * @example limit 42
31
35
  */
32
- async getProxies(req, fields, ndjson, filter, limit) {
33
- const proxies = Object.values(await this.getObjects({ filter, limit }));
34
- return this.sendObjects(proxies, req);
36
+ async getProxies(req, fields, ndjson, markdown, filter, limit) {
37
+ const proxies = Object.values(await this.getObjects({ filter }));
38
+ return this.sendObjects(proxies, req, {
39
+ limit,
40
+ privilege: { action: 'read', resource: 'proxy' },
41
+ });
35
42
  }
36
43
  /**
44
+ * Required privilege:
45
+ * - resource: proxy, action: read
46
+ *
37
47
  * @example id "e625ea0c-a876-405a-b838-109d762efe88"
38
48
  */
39
49
  getProxy(id) {
@@ -44,15 +54,24 @@ __decorate([
44
54
  Example(proxyIds),
45
55
  Example(partialProxies),
46
56
  Get(''),
57
+ Security('*', ['acl']),
47
58
  __param(0, Request()),
48
59
  __param(1, Query()),
49
60
  __param(2, Query()),
50
61
  __param(3, Query()),
51
- __param(4, Query())
62
+ __param(4, Query()),
63
+ __param(5, Query())
52
64
  ], ProxyController.prototype, "getProxies", null);
53
65
  __decorate([
54
66
  Example(proxy),
55
67
  Get('{id}'),
68
+ Middlewares(acl({
69
+ resource: 'proxy',
70
+ action: 'read',
71
+ objectId: 'params.id',
72
+ getObject: ({ restApi }) => restApi.xoApp.getProxy,
73
+ })),
74
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
56
75
  Response(notFoundResp.status, notFoundResp.description),
57
76
  __param(0, Path())
58
77
  ], ProxyController.prototype, "getProxy", null);
@@ -10,11 +10,11 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
10
10
  import { createLogger } from '@xen-orchestra/log';
11
11
  import { Deprecated, Example, Get, Middlewares, Path, Query, Request, Response, Route, Security, Tags } from 'tsoa';
12
12
  import { inject } from 'inversify';
13
- import { noSuchObject } from 'xo-common/api-errors.js';
14
13
  import { provide } from 'inversify-binding-decorators';
14
+ import { acl, autoBindService } from '../middlewares/acl.middleware.mjs';
15
15
  import { BackupLogService } from '../backup-logs/backup-log.service.mjs';
16
16
  import { RestApi } from '../rest-api/rest-api.mjs';
17
- import { badRequestResp, unauthorizedResp } from '../open-api/common/response.common.mjs';
17
+ import { badRequestResp, forbiddenOperationResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
18
18
  import { XoController } from '../abstract-classes/xo-controller.mjs';
19
19
  import { partialRestoreLogs, restoreLog, restoreLogIds } from '../open-api/oa-examples/restore-log.oa-example.mjs';
20
20
  const log = createLogger('xo:rest-api:restoreLog-controller');
@@ -28,24 +28,29 @@ let RestoreLogController = class RestoreLogController extends XoController {
28
28
  const filter = log => !this.#backupLogService.isBackupLog(log);
29
29
  return this.restApi.xoApp.getBackupNgLogsSorted({ filter });
30
30
  }
31
- async getCollectionObject(id) {
32
- const log = await this.restApi.xoApp.getBackupNgLogs(id);
33
- if (this.#backupLogService.isBackupLog(log)) {
34
- throw noSuchObject('restore-log');
35
- }
36
- return log;
31
+ getCollectionObject(id) {
32
+ return this.#backupLogService.getRestoreLog(id);
37
33
  }
38
34
  /**
35
+ * Returns all restore logs that match the following privilege:
36
+ * - resource: restore-log, action: read
37
+ *
39
38
  * @example fields "jobName,status,data"
40
39
  * @example filter "status:success"
41
40
  * @example limit 42
42
41
  */
43
- async getRestoreLogs(req, fields, ndjson, filter, limit) {
44
- const restoreLogs = await this.getObjects({ filter, limit });
45
- return this.sendObjects(Object.values(restoreLogs), req);
42
+ async getRestoreLogs(req, fields, ndjson, markdown, filter, limit) {
43
+ const restoreLogs = await this.getObjects({ filter });
44
+ return this.sendObjects(Object.values(restoreLogs), req, {
45
+ limit,
46
+ privilege: { action: 'read', resource: 'restore-log' },
47
+ });
46
48
  }
47
49
  /**
48
- * @example id "fo"
50
+ * Required privilege:
51
+ * - resource: restore-log, action: read
52
+ *
53
+ * @example id "1758180544428"
49
54
  */
50
55
  getRestoreLog(id) {
51
56
  return this.getObject(id);
@@ -55,15 +60,25 @@ __decorate([
55
60
  Example(restoreLogIds),
56
61
  Example(partialRestoreLogs),
57
62
  Get(''),
63
+ Security('*', ['acl']),
58
64
  __param(0, Request()),
59
65
  __param(1, Query()),
60
66
  __param(2, Query()),
61
67
  __param(3, Query()),
62
- __param(4, Query())
68
+ __param(4, Query()),
69
+ __param(5, Query())
63
70
  ], RestoreLogController.prototype, "getRestoreLogs", null);
64
71
  __decorate([
65
72
  Example(restoreLog),
66
73
  Get('{id}'),
74
+ Middlewares(acl({
75
+ resource: 'restore-log',
76
+ action: 'read',
77
+ objectId: 'params.id',
78
+ getObject: autoBindService(BackupLogService, 'getRestoreLog'),
79
+ })),
80
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
81
+ Response(notFoundResp.status, notFoundResp.description),
67
82
  __param(0, Path())
68
83
  ], RestoreLogController.prototype, "getRestoreLog", null);
69
84
  RestoreLogController = __decorate([
@@ -88,21 +103,24 @@ let DeprecatedRestoreController = class DeprecatedRestoreController extends XoCo
88
103
  const filter = log => !this.#backupLogService.isBackupLog(log);
89
104
  return this.restApi.xoApp.getBackupNgLogsSorted({ filter });
90
105
  }
91
- async getCollectionObject(id) {
92
- const log = await this.restApi.xoApp.getBackupNgLogs(id);
93
- if (this.#backupLogService.isBackupLog(log)) {
94
- throw noSuchObject('restore-log');
95
- }
96
- return log;
106
+ getCollectionObject(id) {
107
+ return this.#backupLogService.getRestoreLog(id);
97
108
  }
98
109
  /**
110
+ * Returns all restore logs that match the following privilege:
111
+ * - resource: restore-log, action: read
112
+ *
99
113
  * @example fields "jobName,status,data"
100
114
  * @example filter "status:success"
101
115
  * @example limit 42
102
116
  */
103
- async getDeprecatedRestoreLogs(req, fields, ndjson, filter, limit) {
104
- const restoreLogs = await this.getObjects({ filter, limit });
105
- return this.sendObjects(Object.values(restoreLogs), req, 'restore-logs');
117
+ async getDeprecatedRestoreLogs(req, fields, ndjson, markdown, filter, limit) {
118
+ const restoreLogs = await this.getObjects({ filter });
119
+ return this.sendObjects(Object.values(restoreLogs), req, {
120
+ path: 'restore-logs',
121
+ limit,
122
+ privilege: { action: 'read', resource: 'restore-log' },
123
+ });
106
124
  }
107
125
  /**
108
126
  * @example id "1758180544428"
@@ -120,7 +138,8 @@ __decorate([
120
138
  __param(1, Query()),
121
139
  __param(2, Query()),
122
140
  __param(3, Query()),
123
- __param(4, Query())
141
+ __param(4, Query()),
142
+ __param(5, Query())
124
143
  ], DeprecatedRestoreController.prototype, "getDeprecatedRestoreLogs", null);
125
144
  __decorate([
126
145
  Example(restoreLog),