@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
@@ -12,9 +12,10 @@ import { inject } from 'inversify';
12
12
  import { noSuchObject } from 'xo-common/api-errors.js';
13
13
  import { Deprecated, Example, Get, Hidden, Middlewares, Path, Query, Request, Response, Route, Security, Tags, } from 'tsoa';
14
14
  import { provide } from 'inversify-binding-decorators';
15
+ import { acl, autoBindService } from '../middlewares/acl.middleware.mjs';
15
16
  import { backupLog, backupLogIds, partialBackupLogs } from '../open-api/oa-examples/backup-log.oa-example.mjs';
16
17
  import { BackupLogService } from '../backup-logs/backup-log.service.mjs';
17
- import { badRequestResp, notFoundResp, unauthorizedResp } from '../open-api/common/response.common.mjs';
18
+ import { badRequestResp, forbiddenOperationResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
18
19
  import { RestApi } from '../rest-api/rest-api.mjs';
19
20
  import { limitAndFilterArray, safeParseComplexMatcher } from '../helpers/utils.helper.mjs';
20
21
  import { XoController } from '../abstract-classes/xo-controller.mjs';
@@ -33,24 +34,30 @@ let BackupJobController = class BackupJobController extends XoController {
33
34
  const backupJobs = allJobs.filter(job => this.#backupJobService.isBackupJob(job));
34
35
  return backupJobs;
35
36
  }
36
- async getCollectionObject(id) {
37
- const job = await this.restApi.xoApp.getJob(id);
38
- if (!this.#backupJobService.isBackupJob(job)) {
39
- throw noSuchObject(id, 'backup-job');
40
- }
41
- return job;
37
+ getCollectionObject(id) {
38
+ return this.#backupJobService.getBackupJob(id);
42
39
  }
43
40
  /**
41
+ * Returns all backup jobs that match the following privilege:
42
+ * - resource: backup-job, action: read
44
43
  *
45
44
  * @example fields "name,mode,type,id"
46
45
  * @example filter "type:backup"
47
46
  * @example limit 42
48
47
  */
49
48
  async getBackupJobs(req, fields, ndjson, markdown, filter, limit) {
50
- const backupJobs = await this.getObjects({ filter, limit });
51
- return this.sendObjects(Object.values(backupJobs), req, 'backup-jobs');
49
+ const backupJobs = await this.getObjects({ filter });
50
+ return this.sendObjects(Object.values(backupJobs), req, {
51
+ path: 'backup-jobs',
52
+ limit,
53
+ privilege: { action: 'read', resource: 'backup-job' },
54
+ });
52
55
  }
53
56
  /**
57
+ *
58
+ * Required privilege:
59
+ * - resource: backup-job, action: read
60
+ *
54
61
  * @example id "d33f3dc1-92b4-469c-ad58-4c2a106a4721"
55
62
  */
56
63
  getBackupJob(id) {
@@ -61,6 +68,7 @@ __decorate([
61
68
  Example(vmBackupJobIds),
62
69
  Example(partialVmBackupJobs),
63
70
  Get(''),
71
+ Security('*', ['acl']),
64
72
  __param(0, Request()),
65
73
  __param(1, Query()),
66
74
  __param(2, Query()),
@@ -70,8 +78,15 @@ __decorate([
70
78
  ], BackupJobController.prototype, "getBackupJobs", null);
71
79
  __decorate([
72
80
  Example(vmBackupJob),
73
- Response(notFoundResp.status, notFoundResp.description),
74
81
  Get('{id}'),
82
+ Middlewares(acl({
83
+ resource: 'backup-job',
84
+ action: 'read',
85
+ objectId: 'params.id',
86
+ getObject: autoBindService(BackupJobService, 'getBackupJob'),
87
+ })),
88
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
89
+ Response(notFoundResp.status, notFoundResp.description),
75
90
  __param(0, Path())
76
91
  ], BackupJobController.prototype, "getBackupJob", null);
77
92
  BackupJobController = __decorate([
@@ -113,6 +128,8 @@ let DeprecatedBackupController = class DeprecatedBackupController extends XoCont
113
128
  return backupJob;
114
129
  }
115
130
  /**
131
+ * Returns all VM backup jobs that match the following privilege:
132
+ * - resource: backup-job, action: read
116
133
  *
117
134
  * @example fields "name,mode,id"
118
135
  * @example filter "mode:delta"
@@ -120,7 +137,11 @@ let DeprecatedBackupController = class DeprecatedBackupController extends XoCont
120
137
  */
121
138
  async getVmBackupJobs(req, fields, ndjson, markdown, filter, limit) {
122
139
  const vmBackupJobs = await this.restApi.xoApp.getAllJobs('backup');
123
- return this.sendObjects(limitAndFilterArray(vmBackupJobs, { filter, limit }), req, 'backup-jobs');
140
+ return this.sendObjects(limitAndFilterArray(vmBackupJobs, { filter }), req, {
141
+ path: 'backup-jobs',
142
+ limit,
143
+ privilege: { action: 'read', resource: 'backup-job' },
144
+ });
124
145
  }
125
146
  // For compatibility, redirect /backup/jobs/:id to /backup/jobs/vm/:id
126
147
  async redirectToVmBackupJob(req, id) {
@@ -134,6 +155,8 @@ let DeprecatedBackupController = class DeprecatedBackupController extends XoCont
134
155
  return this.getObject(id, 'backup');
135
156
  }
136
157
  /**
158
+ * Returns all metadata backup jobs that match the following privilege:
159
+ * - resource: backup-job, action: read
137
160
  *
138
161
  * @example fields "name,xoMetadata,id"
139
162
  * @example filter "xoMetadata?"
@@ -141,7 +164,11 @@ let DeprecatedBackupController = class DeprecatedBackupController extends XoCont
141
164
  */
142
165
  async getMetadataBackupJobs(req, fields, ndjson, markdown, filter, limit) {
143
166
  const metadataBackupJobs = await this.restApi.xoApp.getAllJobs('metadataBackup');
144
- return this.sendObjects(limitAndFilterArray(metadataBackupJobs, { filter, limit }), req, 'backup-jobs');
167
+ return this.sendObjects(limitAndFilterArray(metadataBackupJobs, { filter }), req, {
168
+ path: 'backup-jobs',
169
+ limit,
170
+ privilege: { action: 'read', resource: 'backup-job' },
171
+ });
145
172
  }
146
173
  /**
147
174
  * @example id "b50f95fd-f6b7-4027-87b6-6a02c7dcd5f5"
@@ -150,6 +177,8 @@ let DeprecatedBackupController = class DeprecatedBackupController extends XoCont
150
177
  return this.getObject(id, 'metadataBackup');
151
178
  }
152
179
  /**
180
+ * Returns all mirror backup jobs that match the following privilege:
181
+ * - resource: backup-job, action: read
153
182
  *
154
183
  * @example fields "name,mode,id"
155
184
  * @example filter "mode:delta"
@@ -157,7 +186,11 @@ let DeprecatedBackupController = class DeprecatedBackupController extends XoCont
157
186
  */
158
187
  async getMirrorBackupJobs(req, fields, ndjson, markdown, filter, limit) {
159
188
  const mirrorBackupJobs = await this.restApi.xoApp.getAllJobs('mirrorBackup');
160
- return this.sendObjects(limitAndFilterArray(mirrorBackupJobs, { filter, limit }), req, 'backup-jobs');
189
+ return this.sendObjects(limitAndFilterArray(mirrorBackupJobs, { filter }), req, {
190
+ path: 'backup-jobs',
191
+ limit,
192
+ privilege: { action: 'read', resource: 'backup-job' },
193
+ });
161
194
  }
162
195
  /**
163
196
  * @example id "e680c14c-ab52-45c8-bb0e-bd4ca12ea8f9"
@@ -166,6 +199,9 @@ let DeprecatedBackupController = class DeprecatedBackupController extends XoCont
166
199
  return this.getObject(id, 'mirrorBackup');
167
200
  }
168
201
  /**
202
+ * Returns all backup logs that match the following privilege:
203
+ * - resource: backup-log, action: read
204
+ *
169
205
  * @example fields "jobName,status,data"
170
206
  * @example filter "status:success"
171
207
  * @example limit 42
@@ -178,8 +214,12 @@ let DeprecatedBackupController = class DeprecatedBackupController extends XoCont
178
214
  }
179
215
  return userFilter(log);
180
216
  };
181
- const logs = (await this.restApi.xoApp.getBackupNgLogsSorted({ filter: predicate, limit }));
182
- return this.sendObjects(logs, req, 'backup-logs');
217
+ const logs = (await this.restApi.xoApp.getBackupNgLogsSorted({ filter: predicate }));
218
+ return this.sendObjects(logs, req, {
219
+ path: 'backup-logs',
220
+ limit,
221
+ privilege: { action: 'read', resource: 'backup-log' },
222
+ });
183
223
  }
184
224
  /**
185
225
  * @example id "1753776067468"
@@ -197,6 +237,7 @@ __decorate([
197
237
  Example(partialVmBackupJobs),
198
238
  Deprecated(),
199
239
  Get('jobs/vm'),
240
+ Security('*', ['acl']),
200
241
  Tags('backup-jobs'),
201
242
  __param(0, Request()),
202
243
  __param(1, Query()),
@@ -225,6 +266,7 @@ __decorate([
225
266
  Example(partialMetadataBackupJobs),
226
267
  Deprecated(),
227
268
  Get('jobs/metadata'),
269
+ Security('*', ['acl']),
228
270
  Tags('backup-jobs'),
229
271
  __param(0, Request()),
230
272
  __param(1, Query()),
@@ -246,6 +288,7 @@ __decorate([
246
288
  Example(partialMirrorBackupJobs),
247
289
  Deprecated(),
248
290
  Get('jobs/mirror'),
291
+ Security('*', ['acl']),
249
292
  Tags('backup-jobs'),
250
293
  __param(0, Request()),
251
294
  __param(1, Query()),
@@ -267,6 +310,7 @@ __decorate([
267
310
  Example(partialBackupLogs),
268
311
  Deprecated(),
269
312
  Get('logs'),
313
+ Security('*', ['acl']),
270
314
  Tags('backup-logs'),
271
315
  __param(0, Request()),
272
316
  __param(1, Query()),
@@ -8,6 +8,13 @@ export class BackupJobService {
8
8
  constructor(restApi) {
9
9
  this.#restApi = restApi;
10
10
  }
11
+ async getBackupJob(id) {
12
+ const job = await this.#restApi.xoApp.getJob(id);
13
+ if (!this.isBackupJob(job)) {
14
+ throw noSuchObject(id, 'backup-job');
15
+ }
16
+ return job;
17
+ }
11
18
  isBackupJob(anyJob) {
12
19
  return this.#backupJobTypes.includes(anyJob.type);
13
20
  }
@@ -7,15 +7,15 @@ 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
- import { noSuchObject } from 'xo-common/api-errors.js';
13
12
  import { provide } from 'inversify-binding-decorators';
14
13
  import { backupLog, backupLogIds, partialBackupLogs } from '../open-api/oa-examples/backup-log.oa-example.mjs';
15
14
  import { BackupLogService } from './backup-log.service.mjs';
16
15
  import { RestApi } from '../rest-api/rest-api.mjs';
17
- import { badRequestResp, unauthorizedResp } from '../open-api/common/response.common.mjs';
16
+ import { badRequestResp, forbiddenOperationResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
18
17
  import { XoController } from '../abstract-classes/xo-controller.mjs';
18
+ import { acl, autoBindService } from '../middlewares/acl.middleware.mjs';
19
19
  let BackupLogController = class BackupLogController extends XoController {
20
20
  #backupLogService;
21
21
  constructor(restApi, backupLogService) {
@@ -25,23 +25,28 @@ let BackupLogController = class BackupLogController extends XoController {
25
25
  getAllCollectionObjects() {
26
26
  return this.restApi.xoApp.getBackupNgLogsSorted({ filter: this.#backupLogService.isBackupLog });
27
27
  }
28
- async getCollectionObject(id) {
29
- const log = await this.restApi.xoApp.getBackupNgLogs(id);
30
- if (!this.#backupLogService.isBackupLog(log)) {
31
- throw noSuchObject('backup-log');
32
- }
33
- return log;
28
+ getCollectionObject(id) {
29
+ return this.#backupLogService.getBackupLog(id);
34
30
  }
35
31
  /**
32
+ * Returns all backup logs that match the following privilege:
33
+ * - resource: backup-log, action: read
34
+ *
36
35
  * @example fields "jobName,status,data"
37
36
  * @example filter "status:success"
38
37
  * @example limit 42
39
38
  */
40
39
  async getBackupLogs(req, fields, ndjson, markdown, filter, limit) {
41
- const backupLogs = await this.getObjects({ filter, limit });
42
- return this.sendObjects(Object.values(backupLogs), req);
40
+ const backupLogs = await this.getObjects({ filter });
41
+ return this.sendObjects(Object.values(backupLogs), req, {
42
+ limit,
43
+ privilege: { action: 'read', resource: 'backup-log' },
44
+ });
43
45
  }
44
46
  /**
47
+ * Required privilege:
48
+ * - resource: backup-log, action: read
49
+ *
45
50
  * @example id "1753776067468"
46
51
  */
47
52
  getBackupLog(id) {
@@ -52,6 +57,7 @@ __decorate([
52
57
  Example(backupLogIds),
53
58
  Example(partialBackupLogs),
54
59
  Get(''),
60
+ Security('*', ['acl']),
55
61
  __param(0, Request()),
56
62
  __param(1, Query()),
57
63
  __param(2, Query()),
@@ -62,6 +68,14 @@ __decorate([
62
68
  __decorate([
63
69
  Example(backupLog),
64
70
  Get('{id}'),
71
+ Middlewares(acl({
72
+ resource: 'backup-log',
73
+ action: 'read',
74
+ objectId: 'params.id',
75
+ getObject: autoBindService(BackupLogService, 'getBackupLog'),
76
+ })),
77
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
78
+ Response(notFoundResp.status, notFoundResp.description),
65
79
  __param(0, Path())
66
80
  ], BackupLogController.prototype, "getBackupLog", null);
67
81
  BackupLogController = __decorate([
@@ -1,7 +1,26 @@
1
+ import { noSuchObject } from 'xo-common/api-errors.js';
1
2
  export class BackupLogService {
3
+ #restApi;
4
+ constructor(restApi) {
5
+ this.#restApi = restApi;
6
+ }
2
7
  isBackupLog(log) {
3
8
  return log.message === 'backup';
4
9
  }
10
+ async getBackupLog(id) {
11
+ const log = await this.#restApi.xoApp.getBackupNgLogs(id);
12
+ if (!this.isBackupLog(log)) {
13
+ throw noSuchObject('backup-log');
14
+ }
15
+ return log;
16
+ }
17
+ async getRestoreLog(id) {
18
+ const log = await this.#restApi.xoApp.getBackupNgLogs(id);
19
+ if (this.isBackupLog(log)) {
20
+ throw noSuchObject('restore-log');
21
+ }
22
+ return log;
23
+ }
5
24
  getVmBackupTaskLog(log, vmId) {
6
25
  return log.tasks?.find(task => task.data?.id === vmId);
7
26
  }
@@ -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 { backupRepositoryIds, partialBackupRepositories, backupRepository, } from '../open-api/oa-examples/backup-repository.oa-example.mjs';
15
16
  import { XoController } from '../abstract-classes/xo-controller.mjs';
16
17
  import { RestApi } from '../rest-api/rest-api.mjs';
@@ -26,14 +27,23 @@ let BackupRepositoryController = class BackupRepositoryController extends XoCont
26
27
  return this.restApi.xoApp.getRemote(id);
27
28
  }
28
29
  /**
30
+ * Returns all backup repositories that match the following privilege:
31
+ * - resource: backup-repository, action: read
32
+ *
29
33
  * @example fields "id,name,enabled"
30
34
  * @example filter "enabled?"
31
35
  * @example limit 42
32
36
  */
33
37
  async getRepositories(req, fields, ndjson, markdown, filter, limit) {
34
- return this.sendObjects(Object.values(await this.getObjects({ filter, limit })), req);
38
+ return this.sendObjects(Object.values(await this.getObjects({ filter })), req, {
39
+ limit,
40
+ privilege: { action: 'read', resource: 'backup-repository' },
41
+ });
35
42
  }
36
43
  /**
44
+ * Required privilege:
45
+ * - resource: backup-repository, action: read
46
+ *
37
47
  * @example id "c4284e12-37c9-7967-b9e8-83ef229c3e03"
38
48
  */
39
49
  getRepository(id) {
@@ -44,6 +54,7 @@ __decorate([
44
54
  Example(backupRepositoryIds),
45
55
  Example(partialBackupRepositories),
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(backupRepository),
56
67
  Get('{id}'),
68
+ Middlewares(acl({
69
+ resource: 'backup-repository',
70
+ action: 'read',
71
+ objectId: 'params.id',
72
+ getObject: ({ restApi }) => restApi.xoApp.getRemote,
73
+ })),
74
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
57
75
  Response(notFoundResp.status, notFoundResp.description),
58
76
  __param(0, Path())
59
77
  ], BackupRepositoryController.prototype, "getRepository", null);
@@ -11,6 +11,7 @@ export class Subscriber {
11
11
  #connection;
12
12
  #isAlive;
13
13
  #cleanupCallbacks = new Set();
14
+ #userId;
14
15
  get id() {
15
16
  return this.#id;
16
17
  }
@@ -20,13 +21,17 @@ export class Subscriber {
20
21
  get connection() {
21
22
  return this.#connection;
22
23
  }
23
- constructor(connection, manager) {
24
+ get userId() {
25
+ return this.#userId;
26
+ }
27
+ constructor(connection, manager, userId) {
24
28
  this.#id = crypto.randomUUID();
25
29
  connection.on('close', () => this.clear());
26
30
  manager.addSubscriber(this);
27
31
  this.#connection = connection;
28
32
  this.#manager = manager;
29
33
  this.#isAlive = true;
34
+ this.#userId = userId;
30
35
  }
31
36
  #safeWrite(payload) {
32
37
  const ok = this.#connection.write(payload);
@@ -60,24 +65,23 @@ export class Subscriber {
60
65
  }
61
66
  }
62
67
  export class XoListener extends Listener {
63
- #type;
64
68
  #alarmService;
65
69
  constructor(type, eventEmitter, alarmService) {
66
- super(eventEmitter, ['add', 'update', 'remove']);
67
- this.#type = type;
70
+ super(eventEmitter, ['add', 'update', 'remove'], type);
68
71
  this.#alarmService = alarmService;
69
72
  }
70
- handleData({ fields, event }, object, previousObj) {
73
+ async handleData({ fields, event, subscriber }, object, previousObj) {
71
74
  let _object = object;
72
75
  let _prevObject = previousObj;
73
- if (this.#type === 'alarm' || this.#type === 'message') {
76
+ ///
77
+ if (this.type === 'alarm' || this.type === 'message') {
74
78
  const isAlarm = (object) => object !== undefined && 'type' in object && object.type === 'message' && this.#alarmService.isAlarm(object);
75
79
  const objectIsAlarm = isAlarm(object);
76
80
  const prevObjectIsAlarm = isAlarm(previousObj);
77
81
  // If we are in an alarm listener and the objects are messages
78
82
  // we clean them to ensure they are not sent via the SSE
79
83
  // Same if we are in a message listener and the objects are alarms
80
- if (this.#type === 'alarm') {
84
+ if (this.type === 'alarm') {
81
85
  _object = objectIsAlarm ? this.#alarmService.parseAlarm(object) : undefined;
82
86
  _prevObject = prevObjectIsAlarm ? this.#alarmService.parseAlarm(previousObj) : undefined;
83
87
  }
@@ -89,6 +93,17 @@ export class XoListener extends Listener {
89
93
  if (_object === undefined && _prevObject === undefined) {
90
94
  return;
91
95
  }
96
+ const aclEvent = await this.getAclEvent({
97
+ event,
98
+ object: _object,
99
+ previousObject: _prevObject,
100
+ userId: subscriber.userId,
101
+ });
102
+ // If the user has no 'read' privileges for the changes, don't send the update
103
+ if (aclEvent === undefined) {
104
+ return;
105
+ }
106
+ event = aclEvent;
92
107
  if (fields !== '*') {
93
108
  if (_object !== undefined) {
94
109
  _object = pick(_object, fields);
@@ -102,7 +117,7 @@ export class XoListener extends Listener {
102
117
  return;
103
118
  }
104
119
  // if _object === undefined, this means we are on a remove event, so _prevObject will not be undefined
105
- return { $subscription: this.#type, ...(_object ?? _prevObject) };
120
+ return { $subscription: this.type, event, ...(_object ?? _prevObject) };
106
121
  }
107
122
  }
108
123
  export class PingListener extends Listener {
@@ -113,7 +128,7 @@ export class PingListener extends Listener {
113
128
  this.eventEmitter.emit('ping');
114
129
  }, 1000 * 30);
115
130
  }
116
- handleData() {
131
+ async handleData() {
117
132
  return { ping: Date.now() };
118
133
  }
119
134
  clear() {
@@ -70,12 +70,14 @@ let EventController = class EventController extends Controller {
70
70
  };
71
71
  __decorate([
72
72
  Get(''),
73
+ Security('*', ['acl']),
73
74
  SuccessResponse(200, 'OK'),
74
75
  __param(0, Request())
75
76
  ], EventController.prototype, "openSseConnection", null);
76
77
  __decorate([
77
78
  Example(addSubscription),
78
79
  Post('{id}/subscriptions'),
80
+ Security('*', ['acl']),
79
81
  Middlewares(json()),
80
82
  SuccessResponse(createdResp.status, createdResp.description),
81
83
  Response(notFoundResp.status, notFoundResp.description),
@@ -84,6 +86,7 @@ __decorate([
84
86
  ], EventController.prototype, "addSubscription", null);
85
87
  __decorate([
86
88
  Delete('{id}/subscriptions/{subscriptionId}'),
89
+ Security('*', ['acl']),
87
90
  SuccessResponse(noContentResp.status, noContentResp.description),
88
91
  Response(notFoundResp.status, notFoundResp.description),
89
92
  __param(0, Path()),
@@ -58,7 +58,8 @@ export class EventService {
58
58
  log.error(error);
59
59
  }
60
60
  });
61
- const subscriber = new Subscriber(connection, this.#subscriberManager);
61
+ const user = this.#restApi.getCurrentUser();
62
+ const subscriber = new Subscriber(connection, this.#subscriberManager, user.id);
62
63
  subscriber.broadcast('init', { id: subscriber.id });
63
64
  this.addListenerFor(subscriber.id, { type: 'ping' });
64
65
  log.debug(`new SSE subscriber added: ${subscriber.id}`);