@xen-orchestra/rest-api 0.29.0 → 0.30.1

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 +101 -1
  2. package/dist/abstract-classes/base-controller.mjs +20 -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 +206 -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 +75 -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
@@ -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
51
  getPools(req, fields, ndjson, markdown, filter, limit) {
49
- return this.sendObjects(Object.values(this.getObjects({ filter, limit })), req);
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,6 +308,9 @@ 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"
@@ -278,11 +320,17 @@ let PoolController = class PoolController extends XapiXoController {
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
350
  getPoolMessages(req, id, fields, ndjson, markdown, filter, limit) {
300
- const messages = this.getMessagesForObject(id, { filter, limit });
301
- return this.sendObjects(Object.values(messages), req, 'messages');
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
388
  async getPoolTasks(req, id, fields, ndjson, markdown, filter, limit) {
325
- const tasks = await this.getTasksForObject(id, { filter, limit });
326
- return this.sendObjects(Object.values(tasks), req, 'tasks');
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,6 +428,7 @@ __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()),
@@ -370,6 +439,8 @@ __decorate([
370
439
  __decorate([
371
440
  Example(pool),
372
441
  Get('{id}'),
442
+ Middlewares(acl({ resource: 'pool', action: 'read', objectId: 'params.id' })),
443
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
373
444
  Response(notFoundResp.status, notFoundResp.description),
374
445
  __param(0, Path())
375
446
  ], PoolController.prototype, "getPool", null);
@@ -377,9 +448,17 @@ __decorate([
377
448
  Example(taskLocation),
378
449
  Example(createNetwork),
379
450
  Post('{id}/actions/create_network'),
380
- 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
+ ]),
381
459
  Tags('networks'),
382
460
  SuccessResponse(createdResp.status, createdResp.description),
461
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
383
462
  Response(asynchronousActionResp.status, asynchronousActionResp.description),
384
463
  Response(notFoundResp.status, notFoundResp.description),
385
464
  Response(invalidParametersResp.status, invalidParametersResp.description),
@@ -421,7 +500,9 @@ __decorate([
421
500
  __decorate([
422
501
  Example(taskLocation),
423
502
  Post('{id}/actions/emergency_shutdown'),
503
+ Middlewares(acl({ resource: 'pool', action: 'emergency-shutdown', objectId: 'params.id' })),
424
504
  SuccessResponse(asynchronousActionResp.status, asynchronousActionResp.description),
505
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
425
506
  Response(noContentResp.status, noContentResp.description),
426
507
  Response(featureUnauthorized.status, featureUnauthorized.description),
427
508
  Response(notFoundResp.status, notFoundResp.description),
@@ -431,7 +512,9 @@ __decorate([
431
512
  __decorate([
432
513
  Example(taskLocation),
433
514
  Post('{id}/actions/rolling_reboot'),
515
+ Middlewares(acl({ resource: 'pool', action: 'rolling-reboot', objectId: 'params.id' })),
434
516
  SuccessResponse(asynchronousActionResp.status, asynchronousActionResp.description),
517
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
435
518
  Response(noContentResp.status, noContentResp.description),
436
519
  Response(featureUnauthorized.status, featureUnauthorized.description),
437
520
  Response(notFoundResp.status, notFoundResp.description),
@@ -441,7 +524,9 @@ __decorate([
441
524
  __decorate([
442
525
  Example(taskLocation),
443
526
  Post('{id}/actions/rolling_update'),
527
+ Middlewares(acl({ resource: 'pool', action: 'rolling-update', objectId: 'params.id' })),
444
528
  SuccessResponse(asynchronousActionResp.status, asynchronousActionResp.description),
529
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
445
530
  Response(noContentResp.status, noContentResp.description),
446
531
  Response(featureUnauthorized.status, featureUnauthorized.description),
447
532
  Response(notFoundResp.status, notFoundResp.description),
@@ -451,8 +536,24 @@ __decorate([
451
536
  __decorate([
452
537
  Example(importVm),
453
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
+ ])),
454
554
  Tags('vms'),
455
555
  SuccessResponse(createdResp.status, 'VM imported'),
556
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
456
557
  Response(notFoundResp.status, notFoundResp.description),
457
558
  Response(internalServerErrorResp.status, internalServerErrorResp.description),
458
559
  __param(0, Request()),
@@ -463,9 +564,40 @@ __decorate([
463
564
  Example(taskLocation),
464
565
  Example(createVm),
465
566
  Post('{id}/actions/create_vm'),
466
- 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
+ ]),
467
598
  Tags('vms'),
468
599
  SuccessResponse(createdResp.status, createdResp.description),
600
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
469
601
  Response(asynchronousActionResp.status, asynchronousActionResp.description),
470
602
  Response(notFoundResp.status, notFoundResp.description),
471
603
  Response(internalServerErrorResp.status, internalServerErrorResp.description),
@@ -476,6 +608,8 @@ __decorate([
476
608
  __decorate([
477
609
  Example(poolStats),
478
610
  Get('{id}/stats'),
611
+ Middlewares(acl({ resource: 'pool', action: 'read', objectId: 'params.id' })),
612
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
479
613
  Response(notFoundResp.status, notFoundResp.description),
480
614
  Response(422, 'Invalid granularity'),
481
615
  __param(0, Path()),
@@ -484,6 +618,8 @@ __decorate([
484
618
  __decorate([
485
619
  Example(poolDashboard),
486
620
  Get('{id}/dashboard'),
621
+ Middlewares(acl({ resource: 'pool', action: 'read', objectId: 'params.id' })),
622
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
487
623
  Response(notFoundResp.status, notFoundResp.description),
488
624
  __param(0, Request()),
489
625
  __param(1, Path()),
@@ -492,6 +628,7 @@ __decorate([
492
628
  __decorate([
493
629
  Example(genericAlarmsExample),
494
630
  Get('{id}/alarms'),
631
+ Security('*', ['acl']),
495
632
  Tags('alarms'),
496
633
  Response(notFoundResp.status, notFoundResp.description),
497
634
  __param(0, Request()),
@@ -505,6 +642,8 @@ __decorate([
505
642
  __decorate([
506
643
  Example(poolMissingPatches),
507
644
  Get('{id}/missing_patches'),
645
+ Middlewares(acl({ resource: 'pool', action: 'read', objectId: 'params.id' })),
646
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
508
647
  Response(notFoundResp.status, notFoundResp.description),
509
648
  Response(featureUnauthorized.status, featureUnauthorized.description),
510
649
  __param(0, Path())
@@ -513,6 +652,7 @@ __decorate([
513
652
  Example(messageIds),
514
653
  Example(partialMessages),
515
654
  Get('{id}/messages'),
655
+ Security('*', ['acl']),
516
656
  Tags('messages'),
517
657
  Response(notFoundResp.status, notFoundResp.description),
518
658
  __param(0, Request()),
@@ -525,14 +665,18 @@ __decorate([
525
665
  ], PoolController.prototype, "getPoolMessages", null);
526
666
  __decorate([
527
667
  Put('{id}/tags/{tag}'),
668
+ Middlewares(acl({ resource: 'pool', action: 'update:tags', objectId: 'params.id' })),
528
669
  SuccessResponse(noContentResp.status, noContentResp.description),
670
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
529
671
  Response(notFoundResp.status, notFoundResp.description),
530
672
  __param(0, Path()),
531
673
  __param(1, Path())
532
674
  ], PoolController.prototype, "putPoolTag", null);
533
675
  __decorate([
534
676
  Delete('{id}/tags/{tag}'),
677
+ Middlewares(acl({ resource: 'pool', action: 'update:tags', objectId: 'params.id' })),
535
678
  SuccessResponse(noContentResp.status, noContentResp.description),
679
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
536
680
  Response(notFoundResp.status, notFoundResp.description),
537
681
  __param(0, Path()),
538
682
  __param(1, Path())
@@ -541,6 +685,7 @@ __decorate([
541
685
  Example(taskIds),
542
686
  Example(partialTasks),
543
687
  Get('{id}/tasks'),
688
+ Security('*', ['acl']),
544
689
  Tags('tasks'),
545
690
  Response(notFoundResp.status, notFoundResp.description),
546
691
  __param(0, Request()),
@@ -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
36
  async getProxies(req, fields, ndjson, markdown, filter, limit) {
33
- const proxies = Object.values(await this.getObjects({ filter, limit }));
34
- return this.sendObjects(proxies, req);
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,6 +54,7 @@ __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()),
@@ -54,6 +65,13 @@ __decorate([
54
65
  __decorate([
55
66
  Example(proxy),
56
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),
57
75
  Response(notFoundResp.status, notFoundResp.description),
58
76
  __param(0, Path())
59
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
42
  async getRestoreLogs(req, fields, ndjson, markdown, filter, limit) {
44
- const restoreLogs = await this.getObjects({ filter, limit });
45
- return this.sendObjects(Object.values(restoreLogs), req);
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,6 +60,7 @@ __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()),
@@ -65,6 +71,14 @@ __decorate([
65
71
  __decorate([
66
72
  Example(restoreLog),
67
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),
68
82
  __param(0, Path())
69
83
  ], RestoreLogController.prototype, "getRestoreLog", null);
70
84
  RestoreLogController = __decorate([
@@ -89,21 +103,24 @@ let DeprecatedRestoreController = class DeprecatedRestoreController extends XoCo
89
103
  const filter = log => !this.#backupLogService.isBackupLog(log);
90
104
  return this.restApi.xoApp.getBackupNgLogsSorted({ filter });
91
105
  }
92
- async getCollectionObject(id) {
93
- const log = await this.restApi.xoApp.getBackupNgLogs(id);
94
- if (this.#backupLogService.isBackupLog(log)) {
95
- throw noSuchObject('restore-log');
96
- }
97
- return log;
106
+ getCollectionObject(id) {
107
+ return this.#backupLogService.getRestoreLog(id);
98
108
  }
99
109
  /**
110
+ * Returns all restore logs that match the following privilege:
111
+ * - resource: restore-log, action: read
112
+ *
100
113
  * @example fields "jobName,status,data"
101
114
  * @example filter "status:success"
102
115
  * @example limit 42
103
116
  */
104
117
  async getDeprecatedRestoreLogs(req, fields, ndjson, markdown, filter, limit) {
105
- const restoreLogs = await this.getObjects({ filter, limit });
106
- return this.sendObjects(Object.values(restoreLogs), req, 'restore-logs');
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
+ });
107
124
  }
108
125
  /**
109
126
  * @example id "1758180544428"
@@ -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, Post, Query, Request, Response, Route, Security, SuccessResponse, Tags } from 'tsoa';
10
+ import { Example, Get, Middlewares, Path, Post, Query, Request, Response, Route, Security, SuccessResponse, Tags, } from 'tsoa';
11
11
  import { inject } from 'inversify';
12
12
  import { provide } from 'inversify-binding-decorators';
13
- import { asynchronousActionResp, badRequestResp, featureUnauthorized, internalServerErrorResp, noContentResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
13
+ import { acl } from '../middlewares/acl.middleware.mjs';
14
+ import { asynchronousActionResp, badRequestResp, featureUnauthorized, forbiddenOperationResp, internalServerErrorResp, noContentResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
14
15
  import { partialSchedules, schedule, scheduleIds } from '../open-api/oa-examples/schedule.oa-example.mjs';
15
16
  import { taskLocation } from '../open-api/oa-examples/task.oa-example.mjs';
16
17
  import { XoController } from '../abstract-classes/xo-controller.mjs';
@@ -27,20 +28,34 @@ let ScheduleController = class ScheduleController extends XoController {
27
28
  return this.restApi.xoApp.getSchedule(id);
28
29
  }
29
30
  /**
31
+ * Returns all schedules that match the following privilege:
32
+ * - resource: schedule, action: read
33
+ *
30
34
  * @example fields "enabled,jobId,cron,id"
31
35
  * @example filter "enabled?"
32
36
  * @example limit 42
33
37
  */
34
38
  async getSchedules(req, fields, ndjson, markdown, filter, limit) {
35
- return this.sendObjects(Object.values(await this.getObjects({ filter, limit })), req);
39
+ return this.sendObjects(Object.values(await this.getObjects({ filter })), req, {
40
+ limit,
41
+ privilege: { action: 'read', resource: 'schedule' },
42
+ });
36
43
  }
37
44
  /**
45
+ *
46
+ * Required privilege:
47
+ * - resource: schedule, action: read
48
+ *
38
49
  * @example id "cf7249f8-d20b-494f-97f4-b1f32f94e780"
39
50
  */
40
51
  async getSchedule(id) {
41
52
  return this.getObject(id);
42
53
  }
43
54
  /**
55
+ *
56
+ * Required privilege:
57
+ * - resource: schedule, action: run
58
+ *
44
59
  * @example id "cf7249f8-d20b-494f-97f4-b1f32f94e780"
45
60
  */
46
61
  async runSchedule(id, sync) {
@@ -62,6 +77,7 @@ __decorate([
62
77
  Example(scheduleIds),
63
78
  Example(partialSchedules),
64
79
  Get(''),
80
+ Security('*', ['acl']),
65
81
  __param(0, Request()),
66
82
  __param(1, Query()),
67
83
  __param(2, Query()),
@@ -72,15 +88,29 @@ __decorate([
72
88
  __decorate([
73
89
  Example(schedule),
74
90
  Get('{id}'),
91
+ Middlewares(acl({
92
+ resource: 'schedule',
93
+ action: 'read',
94
+ objectId: 'params.id',
95
+ getObject: ({ restApi }) => id => restApi.xoApp.getSchedule(id),
96
+ })),
97
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
75
98
  Response(notFoundResp.status, notFoundResp.description),
76
99
  __param(0, Path())
77
100
  ], ScheduleController.prototype, "getSchedule", null);
78
101
  __decorate([
79
102
  Example(taskLocation),
80
103
  Post('{id}/actions/run'),
104
+ Middlewares(acl({
105
+ resource: 'schedule',
106
+ action: 'run',
107
+ objectId: 'params.id',
108
+ getObject: ({ restApi }) => id => restApi.xoApp.getSchedule(id),
109
+ })),
81
110
  SuccessResponse(asynchronousActionResp.status, asynchronousActionResp.description),
82
111
  Response(noContentResp.status, noContentResp.description),
83
112
  Response(featureUnauthorized.status, featureUnauthorized.description),
113
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
84
114
  Response(notFoundResp.status, notFoundResp.description),
85
115
  Response(internalServerErrorResp.status, internalServerErrorResp.description),
86
116
  __param(0, Path()),