@iobroker/db-objects-redis 7.2.3 → 8.0.0-alpha.1-20260921-e5941ca8a
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.
- package/build/cjs/index.d.ts +1 -1
- package/build/cjs/index.js +5 -3
- package/build/cjs/index.js.map +2 -2
- package/build/cjs/lib/objects/constants.js.map +2 -2
- package/build/cjs/lib/objects/interview.js +2 -0
- package/build/cjs/lib/objects/interview.js.map +1 -1
- package/build/cjs/lib/objects/lua-v3/custom.lua +23 -1
- package/build/cjs/lib/objects/lua-v3/filter.lua +23 -1
- package/build/cjs/lib/objects/lua-v3/programs.lua +23 -1
- package/build/cjs/lib/objects/lua-v3/script.lua +23 -1
- package/build/cjs/lib/objects/lua-v3/variables.lua +23 -1
- package/build/cjs/lib/objects/lua-v4/custom.lua +23 -1
- package/build/cjs/lib/objects/lua-v4/filter.lua +23 -1
- package/build/cjs/lib/objects/lua-v4/programs.lua +23 -1
- package/build/cjs/lib/objects/lua-v4/script.lua +23 -1
- package/build/cjs/lib/objects/lua-v4/variables.lua +23 -1
- package/build/cjs/lib/objects/lua-v4-no-sets/custom.lua +23 -1
- package/build/cjs/lib/objects/lua-v4-no-sets/filter.lua +23 -1
- package/build/cjs/lib/objects/lua-v4-no-sets/programs.lua +23 -1
- package/build/cjs/lib/objects/lua-v4-no-sets/script.lua +23 -1
- package/build/cjs/lib/objects/lua-v4-no-sets/variables.lua +23 -1
- package/build/cjs/lib/objects/objectsInRedisClient.d.ts +961 -125
- package/build/cjs/lib/objects/objectsInRedisClient.js +1092 -776
- package/build/cjs/lib/objects/objectsInRedisClient.js.map +3 -3
- package/build/cjs/lib/objects/objectsUtils.d.ts +139 -17
- package/build/cjs/lib/objects/objectsUtils.js +212 -192
- package/build/cjs/lib/objects/objectsUtils.js.map +3 -3
- package/build/esm/index.d.ts +1 -1
- package/build/esm/index.d.ts.map +1 -1
- package/build/esm/index.js.map +1 -1
- package/build/esm/lib/objects/constants.d.ts.map +1 -1
- package/build/esm/lib/objects/constants.js.map +1 -1
- package/build/esm/lib/objects/lua-v3/custom.lua +23 -1
- package/build/esm/lib/objects/lua-v3/filter.lua +23 -1
- package/build/esm/lib/objects/lua-v3/programs.lua +23 -1
- package/build/esm/lib/objects/lua-v3/script.lua +23 -1
- package/build/esm/lib/objects/lua-v3/variables.lua +23 -1
- package/build/esm/lib/objects/lua-v4/custom.lua +23 -1
- package/build/esm/lib/objects/lua-v4/filter.lua +23 -1
- package/build/esm/lib/objects/lua-v4/programs.lua +23 -1
- package/build/esm/lib/objects/lua-v4/script.lua +23 -1
- package/build/esm/lib/objects/lua-v4/variables.lua +23 -1
- package/build/esm/lib/objects/lua-v4-no-sets/custom.lua +23 -1
- package/build/esm/lib/objects/lua-v4-no-sets/filter.lua +23 -1
- package/build/esm/lib/objects/lua-v4-no-sets/programs.lua +23 -1
- package/build/esm/lib/objects/lua-v4-no-sets/script.lua +23 -1
- package/build/esm/lib/objects/lua-v4-no-sets/variables.lua +23 -1
- package/build/esm/lib/objects/objectsInRedisClient.d.ts +961 -125
- package/build/esm/lib/objects/objectsInRedisClient.d.ts.map +1 -1
- package/build/esm/lib/objects/objectsInRedisClient.js +880 -571
- package/build/esm/lib/objects/objectsInRedisClient.js.map +1 -1
- package/build/esm/lib/objects/objectsUtils.d.ts +139 -17
- package/build/esm/lib/objects/objectsUtils.d.ts.map +1 -1
- package/build/esm/lib/objects/objectsUtils.js +273 -221
- package/build/esm/lib/objects/objectsUtils.js.map +1 -1
- package/build/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +9 -9
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Common functions between client and server
|
|
3
3
|
*
|
|
4
|
-
* Copyright 2013-
|
|
4
|
+
* Copyright 2013-2026 bluefox <dogafox@gmail.com>
|
|
5
5
|
*
|
|
6
6
|
* MIT License
|
|
7
7
|
*
|
|
8
8
|
*/
|
|
9
9
|
import path from 'node:path';
|
|
10
10
|
import deepClone from 'deep-clone';
|
|
11
|
+
import mime from 'mime-types';
|
|
11
12
|
import { tools } from '@iobroker/db-base';
|
|
12
13
|
import * as CONSTS from '../../lib/objects/constants.js';
|
|
13
|
-
import
|
|
14
|
+
import { SYSTEM_ADMIN_GROUP, SYSTEM_ADMIN_USER } from '../../lib/objects/constants.js';
|
|
14
15
|
export * as CONSTS from '../../lib/objects/constants.js';
|
|
15
16
|
export const ERRORS = CONSTS.ERRORS;
|
|
16
17
|
export const REG_CHECK_ID = CONSTS.REG_CHECK_ID;
|
|
@@ -88,31 +89,36 @@ export function getMimeType(ext, isTextData) {
|
|
|
88
89
|
}
|
|
89
90
|
return { mimeType: isTextData ? 'text/plain' : 'application/octet-stream', isBinary: !isTextData };
|
|
90
91
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
92
|
+
/**
|
|
93
|
+
* Check if the given options have the required rights on a file according to its ACL
|
|
94
|
+
*
|
|
95
|
+
* @param fileOptions The stored file options including its ACL
|
|
96
|
+
* @param fileOptions.mimeType The mime type of the file
|
|
97
|
+
* @param fileOptions.notExists Whether the file does not exist yet
|
|
98
|
+
* @param fileOptions.acl The access control list stored for the file
|
|
99
|
+
* @param userContext The current request options including the user and group
|
|
100
|
+
* @param flag The access flag(s) to check for
|
|
101
|
+
* @param defaultNewAcl The default ACL to use if the file has none yet
|
|
102
|
+
*/
|
|
103
|
+
export function checkFile(fileOptions, userContext, flag, defaultNewAcl) {
|
|
104
|
+
// convert string to structure
|
|
105
|
+
fileOptions ||= {};
|
|
106
|
+
fileOptions.acl ||= {
|
|
107
|
+
owner: defaultNewAcl?.owner || CONSTS.SYSTEM_ADMIN_USER,
|
|
108
|
+
ownerGroup: defaultNewAcl?.ownerGroup || CONSTS.SYSTEM_ADMIN_GROUP,
|
|
109
|
+
permissions: defaultNewAcl?.file || CONSTS.ACCESS_USER_RW | CONSTS.ACCESS_GROUP_READ | CONSTS.ACCESS_EVERY_READ, // '0644'
|
|
110
|
+
};
|
|
102
111
|
// Set default owner group
|
|
103
|
-
fileOptions.acl.
|
|
104
|
-
|
|
105
|
-
fileOptions.acl.
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
CONSTS.ACCESS_USER_RW | CONSTS.ACCESS_GROUP_READ | CONSTS.ACCESS_EVERY_READ; // '0644'
|
|
110
|
-
if (options.user !== CONSTS.SYSTEM_ADMIN_USER &&
|
|
111
|
-
options.groups.indexOf(CONSTS.SYSTEM_ADMIN_GROUP) === -1 &&
|
|
112
|
+
fileOptions.acl.owner ||= defaultNewAcl?.owner || CONSTS.SYSTEM_ADMIN_USER;
|
|
113
|
+
fileOptions.acl.ownerGroup ||= defaultNewAcl?.ownerGroup || CONSTS.SYSTEM_ADMIN_GROUP;
|
|
114
|
+
fileOptions.acl.permissions ||=
|
|
115
|
+
defaultNewAcl?.file || CONSTS.ACCESS_USER_RW | CONSTS.ACCESS_GROUP_READ | CONSTS.ACCESS_EVERY_READ; // '0644'
|
|
116
|
+
if (userContext.user !== CONSTS.SYSTEM_ADMIN_USER &&
|
|
117
|
+
!userContext.groups.includes(CONSTS.SYSTEM_ADMIN_GROUP) &&
|
|
112
118
|
fileOptions.acl) {
|
|
113
|
-
if (fileOptions.acl.owner !==
|
|
119
|
+
if (fileOptions.acl.owner !== userContext.user) {
|
|
114
120
|
// Check if the user is in the group
|
|
115
|
-
if (
|
|
121
|
+
if (userContext.groups.includes(fileOptions.acl.ownerGroup)) {
|
|
116
122
|
// Check group rights
|
|
117
123
|
if (!(fileOptions.acl.permissions & (flag << 4))) {
|
|
118
124
|
return false;
|
|
@@ -134,40 +140,50 @@ export function checkFile(fileOptions, options, flag, defaultNewAcl) {
|
|
|
134
140
|
}
|
|
135
141
|
return true;
|
|
136
142
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
143
|
+
/**
|
|
144
|
+
* Check whether the given user is allowed to access a file and call back with the effective options
|
|
145
|
+
*
|
|
146
|
+
* @param objects The objects database client
|
|
147
|
+
* @param id The id of the object owning the file
|
|
148
|
+
* @param name The file name, or null for the whole namespace
|
|
149
|
+
* @param options The current request options including the user
|
|
150
|
+
* @param flag The access flag(s) to check for
|
|
151
|
+
*/
|
|
152
|
+
export async function checkFileRightsAsync(objects, id, name, options, flag) {
|
|
153
|
+
let userContext;
|
|
154
|
+
if (!options?.user) {
|
|
140
155
|
// Before files converted, lets think: if no options it is admin
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
_options.acl = acl || {};
|
|
148
|
-
_options.groups = groups;
|
|
149
|
-
_options.group = groups ? groups[0] : null;
|
|
150
|
-
checkFileRights(objects, id, name, _options, flag, callback);
|
|
151
|
-
});
|
|
152
|
-
return;
|
|
156
|
+
userContext = {
|
|
157
|
+
user: SYSTEM_ADMIN_USER,
|
|
158
|
+
group: SYSTEM_ADMIN_GROUP,
|
|
159
|
+
groups: [SYSTEM_ADMIN_GROUP],
|
|
160
|
+
acl: getDefaultAdminRights(),
|
|
161
|
+
};
|
|
153
162
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
163
|
+
else {
|
|
164
|
+
const [, groups, acl] = await getUserGroupAsync(objects, options.user);
|
|
165
|
+
userContext = {
|
|
166
|
+
user: options.user,
|
|
167
|
+
group: groups?.[0] || null,
|
|
168
|
+
groups,
|
|
169
|
+
acl,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
if (flag === CONSTS.ACCESS_WRITE && !userContext.acl.file.write) {
|
|
173
|
+
// If user may write
|
|
174
|
+
throw new Error(ERRORS.ERROR_PERMISSION);
|
|
158
175
|
}
|
|
159
176
|
// If user may read
|
|
160
|
-
if (flag === CONSTS.ACCESS_READ && !
|
|
177
|
+
if (flag === CONSTS.ACCESS_READ && !userContext.acl.file.read) {
|
|
161
178
|
// read
|
|
162
|
-
|
|
179
|
+
throw new Error(ERRORS.ERROR_PERMISSION);
|
|
163
180
|
}
|
|
164
|
-
|
|
165
|
-
objects.
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
});
|
|
181
|
+
userContext.checked = true;
|
|
182
|
+
const fileOptions = await objects.checkFileAsync(id, name, userContext, flag);
|
|
183
|
+
if (!fileOptions) {
|
|
184
|
+
throw new Error(ERRORS.ERROR_PERMISSION);
|
|
185
|
+
}
|
|
186
|
+
return { fileOptions, userContext };
|
|
171
187
|
}
|
|
172
188
|
// For users and groups
|
|
173
189
|
function getDefaultAdminRights(acl, _isState) {
|
|
@@ -208,156 +224,157 @@ function getDefaultAdminRights(acl, _isState) {
|
|
|
208
224
|
},
|
|
209
225
|
};
|
|
210
226
|
}
|
|
227
|
+
/**
|
|
228
|
+
* Determine the groups and effective ACL of the given user
|
|
229
|
+
*
|
|
230
|
+
* @param objects The objects database client
|
|
231
|
+
* @param user The id of the user to look up
|
|
232
|
+
* @param callback Called with the user, its groups and the effective ACL
|
|
233
|
+
*/
|
|
211
234
|
export function getUserGroup(objects, user, callback) {
|
|
235
|
+
try {
|
|
236
|
+
getUserGroupAsync(objects, user)
|
|
237
|
+
.then(result => tools.maybeCallbackWithError(callback, null, result[0], result[1], result[2]))
|
|
238
|
+
.catch(err => tools.maybeCallbackWithError(callback, err, deepClone(user), [], deepClone(defaultAcl.acl)));
|
|
239
|
+
}
|
|
240
|
+
catch (err) {
|
|
241
|
+
return tools.maybeCallbackWithError(callback, err, deepClone(user), [], deepClone(defaultAcl.acl));
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Determine the groups and effective ACL of the given user
|
|
246
|
+
*
|
|
247
|
+
* @param objects The objects database client
|
|
248
|
+
* @param user The id of the user to look up
|
|
249
|
+
*/
|
|
250
|
+
export async function getUserGroupAsync(objects, user) {
|
|
212
251
|
if (!user || typeof user !== 'string' || !user.startsWith(USER_STARTS_WITH)) {
|
|
213
252
|
console.log(`invalid user name: ${user}`);
|
|
214
|
-
|
|
253
|
+
throw new Error(`invalid user name: ${user}`);
|
|
215
254
|
}
|
|
216
255
|
if (users[user]) {
|
|
217
|
-
return
|
|
256
|
+
return [user, users[user].groups, users[user].acl];
|
|
218
257
|
}
|
|
219
258
|
let error;
|
|
259
|
+
groups = [];
|
|
220
260
|
// Read all groups
|
|
221
|
-
objects.
|
|
222
|
-
|
|
223
|
-
|
|
261
|
+
const groupList = await objects.getObjectListAsync({ startkey: 'system.group.', endkey: 'system.group.\u9999' }, { checked: true });
|
|
262
|
+
if (groupList) {
|
|
263
|
+
// Read all groups
|
|
264
|
+
for (let g = 0; g < groupList.rows.length; g++) {
|
|
265
|
+
const val = groupList.rows[g].value;
|
|
266
|
+
if (!val) {
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
groups[g] = val;
|
|
270
|
+
if (groups[g]._id === CONSTS.SYSTEM_ADMIN_GROUP) {
|
|
271
|
+
groups[g].common.acl = getDefaultAdminRights(groups[g].common.acl);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
users = {};
|
|
276
|
+
const userList = await objects.getObjectListAsync({ startkey: 'system.user.', endkey: 'system.user.\u9999' }, { checked: true });
|
|
277
|
+
if (userList) {
|
|
278
|
+
for (const row of userList.rows) {
|
|
279
|
+
// cannot use here Object.assign, because required deep copy
|
|
280
|
+
users[row.value._id] = deepClone(defaultAcl);
|
|
224
281
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
282
|
+
}
|
|
283
|
+
users[CONSTS.SYSTEM_ADMIN_USER] ||= deepClone(defaultAcl);
|
|
284
|
+
users[CONSTS.SYSTEM_ADMIN_USER].acl = getDefaultAdminRights(users[CONSTS.SYSTEM_ADMIN_USER].acl);
|
|
285
|
+
for (let g = 0; g < groups.length; g++) {
|
|
286
|
+
if (!groups[g]?.common?.members) {
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
for (let m = 0; m < groups[g].common.members.length; m++) {
|
|
290
|
+
const u = groups[g].common.members[m];
|
|
291
|
+
if (!users[u]) {
|
|
292
|
+
error ||= `Unknown user in group "${groups[g]._id.replace('system.group.', '')}": ${u}`;
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
users[u].groups.push(groups[g]._id);
|
|
296
|
+
if (groups[g].common.acl?.file) {
|
|
297
|
+
if (!users[u].acl?.file) {
|
|
298
|
+
users[u].acl ||= {};
|
|
299
|
+
users[u].acl.file ||= {};
|
|
300
|
+
users[u].acl.file.create = groups[g].common.acl.file.create;
|
|
301
|
+
users[u].acl.file.read = groups[g].common.acl.file.read;
|
|
302
|
+
users[u].acl.file.write = groups[g].common.acl.file.write;
|
|
303
|
+
users[u].acl.file.delete = groups[g].common.acl.file.delete;
|
|
304
|
+
users[u].acl.file.list = groups[g].common.acl.file.list;
|
|
232
305
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
306
|
+
else {
|
|
307
|
+
users[u].acl.file.create ||= groups[g].common.acl.file.create;
|
|
308
|
+
users[u].acl.file.read ||= groups[g].common.acl.file.read;
|
|
309
|
+
users[u].acl.file.write ||= groups[g].common.acl.file.write;
|
|
310
|
+
users[u].acl.file.delete ||= groups[g].common.acl.file.delete;
|
|
311
|
+
users[u].acl.file.list ||= groups[g].common.acl.file.list;
|
|
236
312
|
}
|
|
237
313
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
314
|
+
if (groups[g].common.acl?.object) {
|
|
315
|
+
if (!users[u].acl?.object) {
|
|
316
|
+
users[u].acl ||= {};
|
|
317
|
+
users[u].acl.object ||= {};
|
|
318
|
+
users[u].acl.object.create = groups[g].common.acl.object.create;
|
|
319
|
+
users[u].acl.object.read = groups[g].common.acl.object.read;
|
|
320
|
+
users[u].acl.object.write = groups[g].common.acl.object.write;
|
|
321
|
+
users[u].acl.object.delete = groups[g].common.acl.object.delete;
|
|
322
|
+
users[u].acl.object.list = groups[g].common.acl.object.list;
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
users[u].acl.object.create ||= groups[g].common.acl.object.create;
|
|
326
|
+
users[u].acl.object.read ||= groups[g].common.acl.object.read;
|
|
327
|
+
users[u].acl.object.write ||= groups[g].common.acl.object.write;
|
|
328
|
+
users[u].acl.object.delete ||= groups[g].common.acl.object.delete;
|
|
329
|
+
users[u].acl.object.list ||= groups[g].common.acl.object.list;
|
|
330
|
+
}
|
|
242
331
|
}
|
|
243
|
-
users
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
users[
|
|
332
|
+
if (groups[g].common.acl?.users) {
|
|
333
|
+
if (!users[u].acl?.users) {
|
|
334
|
+
users[u].acl ||= {};
|
|
335
|
+
users[u].acl.users ||= {};
|
|
336
|
+
users[u].acl.users.create = groups[g].common.acl.users.create;
|
|
337
|
+
users[u].acl.users.read = groups[g].common.acl.users.read;
|
|
338
|
+
users[u].acl.users.write = groups[g].common.acl.users.write;
|
|
339
|
+
users[u].acl.users.delete = groups[g].common.acl.users.delete;
|
|
340
|
+
users[u].acl.users.list = groups[g].common.acl.users.list;
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
users[u].acl.users.create ||= groups[g].common.acl.users.create;
|
|
344
|
+
users[u].acl.users.read ||= groups[g].common.acl.users.read;
|
|
345
|
+
users[u].acl.users.write ||= groups[g].common.acl.users.write;
|
|
346
|
+
users[u].acl.users.delete ||= groups[g].common.acl.users.delete;
|
|
347
|
+
users[u].acl.users.list ||= groups[g].common.acl.users.list;
|
|
248
348
|
}
|
|
249
349
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
350
|
+
if (groups[g].common.acl?.state) {
|
|
351
|
+
if (!users[u].acl?.state) {
|
|
352
|
+
users[u].acl ||= {};
|
|
353
|
+
users[u].acl.state ||= {};
|
|
354
|
+
users[u].acl.state.create = groups[g].common.acl.state.create;
|
|
355
|
+
users[u].acl.state.read = groups[g].common.acl.state.read;
|
|
356
|
+
users[u].acl.state.write = groups[g].common.acl.state.write;
|
|
357
|
+
users[u].acl.state.delete = groups[g].common.acl.state.delete;
|
|
358
|
+
users[u].acl.state.list = groups[g].common.acl.state.list;
|
|
255
359
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
continue;
|
|
263
|
-
}
|
|
264
|
-
users[u].groups.push(groups[g]._id);
|
|
265
|
-
if (groups[g].common.acl && groups[g].common.acl.file) {
|
|
266
|
-
if (!users[u].acl || !users[u].acl.file) {
|
|
267
|
-
users[u].acl = users[u].acl || {};
|
|
268
|
-
users[u].acl.file = users[u].acl.file || {};
|
|
269
|
-
users[u].acl.file.create = groups[g].common.acl.file.create;
|
|
270
|
-
users[u].acl.file.read = groups[g].common.acl.file.read;
|
|
271
|
-
users[u].acl.file.write = groups[g].common.acl.file.write;
|
|
272
|
-
users[u].acl.file.delete = groups[g].common.acl.file.delete;
|
|
273
|
-
users[u].acl.file.list = groups[g].common.acl.file.list;
|
|
274
|
-
}
|
|
275
|
-
else {
|
|
276
|
-
users[u].acl.file.create =
|
|
277
|
-
users[u].acl.file.create || groups[g].common.acl.file.create;
|
|
278
|
-
users[u].acl.file.read = users[u].acl.file.read || groups[g].common.acl.file.read;
|
|
279
|
-
users[u].acl.file.write =
|
|
280
|
-
users[u].acl.file.write || groups[g].common.acl.file.write;
|
|
281
|
-
users[u].acl.file.delete =
|
|
282
|
-
users[u].acl.file.delete || groups[g].common.acl.file.delete;
|
|
283
|
-
users[u].acl.file.list = users[u].acl.file.list || groups[g].common.acl.file.list;
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
if (groups[g].common.acl && groups[g].common.acl.object) {
|
|
287
|
-
if (!users[u].acl || !users[u].acl.object) {
|
|
288
|
-
users[u].acl = users[u].acl || {};
|
|
289
|
-
users[u].acl.object = users[u].acl.object || {};
|
|
290
|
-
users[u].acl.object.create = groups[g].common.acl.object.create;
|
|
291
|
-
users[u].acl.object.read = groups[g].common.acl.object.read;
|
|
292
|
-
users[u].acl.object.write = groups[g].common.acl.object.write;
|
|
293
|
-
users[u].acl.object.delete = groups[g].common.acl.object.delete;
|
|
294
|
-
users[u].acl.object.list = groups[g].common.acl.object.list;
|
|
295
|
-
}
|
|
296
|
-
else {
|
|
297
|
-
users[u].acl.object.create =
|
|
298
|
-
users[u].acl.object.create || groups[g].common.acl.object.create;
|
|
299
|
-
users[u].acl.object.read =
|
|
300
|
-
users[u].acl.object.read || groups[g].common.acl.object.read;
|
|
301
|
-
users[u].acl.object.write =
|
|
302
|
-
users[u].acl.object.write || groups[g].common.acl.object.write;
|
|
303
|
-
users[u].acl.object.delete =
|
|
304
|
-
users[u].acl.object.delete || groups[g].common.acl.object.delete;
|
|
305
|
-
users[u].acl.object.list =
|
|
306
|
-
users[u].acl.object.list || groups[g].common.acl.object.list;
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
if (groups[g].common.acl && groups[g].common.acl.users) {
|
|
310
|
-
if (!users[u].acl || !users[u].acl.users) {
|
|
311
|
-
users[u].acl = users[u].acl || {};
|
|
312
|
-
users[u].acl.users = users[u].acl.users || {};
|
|
313
|
-
users[u].acl.users.create = groups[g].common.acl.users.create;
|
|
314
|
-
users[u].acl.users.read = groups[g].common.acl.users.read;
|
|
315
|
-
users[u].acl.users.write = groups[g].common.acl.users.write;
|
|
316
|
-
users[u].acl.users.delete = groups[g].common.acl.users.delete;
|
|
317
|
-
users[u].acl.users.list = groups[g].common.acl.users.list;
|
|
318
|
-
}
|
|
319
|
-
else {
|
|
320
|
-
users[u].acl.users.create =
|
|
321
|
-
users[u].acl.users.create || groups[g].common.acl.users.create;
|
|
322
|
-
users[u].acl.users.read =
|
|
323
|
-
users[u].acl.users.read || groups[g].common.acl.users.read;
|
|
324
|
-
users[u].acl.users.write =
|
|
325
|
-
users[u].acl.users.write || groups[g].common.acl.users.write;
|
|
326
|
-
users[u].acl.users.delete =
|
|
327
|
-
users[u].acl.users.delete || groups[g].common.acl.users.delete;
|
|
328
|
-
users[u].acl.users.list =
|
|
329
|
-
users[u].acl.users.list || groups[g].common.acl.users.list;
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
if (groups[g].common.acl && groups[g].common.acl.state) {
|
|
333
|
-
if (!users[u].acl || !users[u].acl.state) {
|
|
334
|
-
users[u].acl = users[u].acl || {};
|
|
335
|
-
users[u].acl.state = users[u].acl.state || {};
|
|
336
|
-
users[u].acl.state.create = groups[g].common.acl.state?.create;
|
|
337
|
-
users[u].acl.state.read = groups[g].common.acl.state?.read;
|
|
338
|
-
users[u].acl.state.write = groups[g].common.acl.state?.write;
|
|
339
|
-
users[u].acl.state.delete = groups[g].common.acl.state?.delete;
|
|
340
|
-
users[u].acl.state.list = groups[g].common.acl.state?.list;
|
|
341
|
-
}
|
|
342
|
-
else {
|
|
343
|
-
users[u].acl.state.create =
|
|
344
|
-
users[u].acl.state.create || groups[g].common.acl.state?.create;
|
|
345
|
-
users[u].acl.state.read =
|
|
346
|
-
users[u].acl.state.read || groups[g].common.acl.state?.read;
|
|
347
|
-
users[u].acl.state.write =
|
|
348
|
-
users[u].acl.state.write || groups[g].common.acl.state?.write;
|
|
349
|
-
users[u].acl.state.delete =
|
|
350
|
-
users[u].acl.state.delete || groups[g].common.acl.state?.delete;
|
|
351
|
-
users[u].acl.state.list =
|
|
352
|
-
users[u].acl.state.list || groups[g].common.acl.state?.list;
|
|
353
|
-
}
|
|
354
|
-
}
|
|
360
|
+
else {
|
|
361
|
+
users[u].acl.state.create ||= groups[g].common.acl.state.create;
|
|
362
|
+
users[u].acl.state.read ||= groups[g].common.acl.state.read;
|
|
363
|
+
users[u].acl.state.write ||= groups[g].common.acl.state.write;
|
|
364
|
+
users[u].acl.state.delete ||= groups[g].common.acl.state.delete;
|
|
365
|
+
users[u].acl.state.list ||= groups[g].common.acl.state.list;
|
|
355
366
|
}
|
|
356
367
|
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return [user, users[user]?.groups || [], users[user]?.acl || deepClone(defaultAcl.acl)];
|
|
360
371
|
}
|
|
372
|
+
/**
|
|
373
|
+
* Sanitize an object id and file name so they cannot escape the intended directory
|
|
374
|
+
*
|
|
375
|
+
* @param id The object id owning the file
|
|
376
|
+
* @param name The file name to sanitize
|
|
377
|
+
*/
|
|
361
378
|
export function sanitizePath(id, name) {
|
|
362
379
|
if (!name) {
|
|
363
380
|
name = '';
|
|
@@ -384,6 +401,13 @@ export function sanitizePath(id, name) {
|
|
|
384
401
|
} // do not allow absolute paths
|
|
385
402
|
return { id: id, name: name };
|
|
386
403
|
}
|
|
404
|
+
/**
|
|
405
|
+
* Check if the given options have the required rights on an object according to its ACL
|
|
406
|
+
*
|
|
407
|
+
* @param obj The object (or file object) to check, or null
|
|
408
|
+
* @param options The current request options including the user and group
|
|
409
|
+
* @param flag The access flag(s) to check for
|
|
410
|
+
*/
|
|
387
411
|
export function checkObject(obj, options, flag) {
|
|
388
412
|
// read rights of object
|
|
389
413
|
if (!obj || !('common' in obj) || !obj.acl || flag === CONSTS.ACCESS_LIST) {
|
|
@@ -425,60 +449,88 @@ export function checkObject(obj, options, flag) {
|
|
|
425
449
|
}
|
|
426
450
|
return true; // ALL OK
|
|
427
451
|
}
|
|
452
|
+
/**
|
|
453
|
+
* Check whether the given user is allowed to access an object and call back with the effective options
|
|
454
|
+
*
|
|
455
|
+
* @param objects The objects database client
|
|
456
|
+
* @param id The id of the object, or null
|
|
457
|
+
* @param object The object to check, or null
|
|
458
|
+
* @param options The current request options including the user
|
|
459
|
+
* @param flag The access flag(s) to check for
|
|
460
|
+
* @param callback Called with the effective options once the rights have been checked
|
|
461
|
+
*/
|
|
428
462
|
export function checkObjectRights(objects, id, object, options, flag, callback) {
|
|
429
|
-
|
|
430
|
-
|
|
463
|
+
try {
|
|
464
|
+
checkObjectRightsAsync(objects, id, object, options, flag)
|
|
465
|
+
.then(userContext => tools.maybeCallbackWithError(callback, null, userContext))
|
|
466
|
+
.catch(error => tools.maybeCallbackWithError(callback, error));
|
|
467
|
+
}
|
|
468
|
+
catch (error) {
|
|
469
|
+
tools.maybeCallbackWithError(callback, error);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Check whether the given user is allowed to access an object and call back with the effective options
|
|
474
|
+
*
|
|
475
|
+
* @param objects The objects database client
|
|
476
|
+
* @param id The id of the object, or null
|
|
477
|
+
* @param object The object to check, or null
|
|
478
|
+
* @param options The current request options including the user
|
|
479
|
+
* @param flag The access flag(s) to check for
|
|
480
|
+
*/
|
|
481
|
+
export async function checkObjectRightsAsync(objects, id, object, options, flag) {
|
|
482
|
+
let userContext;
|
|
483
|
+
options ||= {};
|
|
484
|
+
if (!options?.user) {
|
|
431
485
|
// Before files converted, lets think: if no options it is admin
|
|
432
|
-
|
|
486
|
+
userContext = {
|
|
433
487
|
user: CONSTS.SYSTEM_ADMIN_USER,
|
|
434
|
-
params: options,
|
|
435
488
|
group: CONSTS.SYSTEM_ADMIN_GROUP,
|
|
436
489
|
groups: [CONSTS.SYSTEM_ADMIN_GROUP],
|
|
437
490
|
acl: getDefaultAdminRights(),
|
|
438
491
|
};
|
|
439
492
|
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
});
|
|
493
|
+
else {
|
|
494
|
+
const [, groups, acl] = await getUserGroupAsync(objects, options.user);
|
|
495
|
+
userContext = {
|
|
496
|
+
user: options.user,
|
|
497
|
+
groups,
|
|
498
|
+
acl: acl || {},
|
|
499
|
+
group: groups?.[0] || null,
|
|
500
|
+
};
|
|
449
501
|
}
|
|
450
502
|
// now options are filled and we can go
|
|
451
|
-
if (
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
return
|
|
503
|
+
if (userContext.user === CONSTS.SYSTEM_ADMIN_USER ||
|
|
504
|
+
userContext.group === CONSTS.SYSTEM_ADMIN_GROUP ||
|
|
505
|
+
userContext.groups?.includes(CONSTS.SYSTEM_ADMIN_GROUP)) {
|
|
506
|
+
return userContext;
|
|
455
507
|
}
|
|
456
508
|
// if user or group objects
|
|
457
509
|
if (typeof id === 'string' && (id.startsWith(USER_STARTS_WITH) || id.startsWith(GROUP_STARTS_WITH))) {
|
|
458
510
|
// If user may write
|
|
459
|
-
if (flag === CONSTS.ACCESS_WRITE && !
|
|
511
|
+
if (flag === CONSTS.ACCESS_WRITE && !userContext.acl.users.write) {
|
|
460
512
|
// write
|
|
461
|
-
|
|
513
|
+
throw new Error(ERRORS.ERROR_PERMISSION);
|
|
462
514
|
}
|
|
463
515
|
// If user may read
|
|
464
|
-
if (flag === CONSTS.ACCESS_READ && !
|
|
516
|
+
if (flag === CONSTS.ACCESS_READ && !userContext.acl.users.read) {
|
|
465
517
|
// read
|
|
466
|
-
|
|
518
|
+
throw new Error(ERRORS.ERROR_PERMISSION);
|
|
467
519
|
}
|
|
468
520
|
// If user may delete
|
|
469
|
-
if (flag === CONSTS.ACCESS_DELETE && !
|
|
521
|
+
if (flag === CONSTS.ACCESS_DELETE && !userContext.acl.users.delete) {
|
|
470
522
|
// delete
|
|
471
|
-
|
|
523
|
+
throw new Error(ERRORS.ERROR_PERMISSION);
|
|
472
524
|
}
|
|
473
525
|
// If user may list
|
|
474
|
-
if (flag === CONSTS.ACCESS_LIST && !
|
|
526
|
+
if (flag === CONSTS.ACCESS_LIST && !userContext.acl.users.list) {
|
|
475
527
|
// list
|
|
476
|
-
|
|
528
|
+
throw new Error(ERRORS.ERROR_PERMISSION);
|
|
477
529
|
}
|
|
478
530
|
// If user may create
|
|
479
|
-
if (flag === CONSTS.ACCESS_CREATE && !
|
|
531
|
+
if (flag === CONSTS.ACCESS_CREATE && !userContext.acl.users.create) {
|
|
480
532
|
// create
|
|
481
|
-
|
|
533
|
+
throw new Error(ERRORS.ERROR_PERMISSION);
|
|
482
534
|
}
|
|
483
535
|
// If user may write
|
|
484
536
|
if (flag === CONSTS.ACCESS_DELETE) {
|
|
@@ -487,32 +539,32 @@ export function checkObjectRights(objects, id, object, options, flag, callback)
|
|
|
487
539
|
}
|
|
488
540
|
}
|
|
489
541
|
// If user may write
|
|
490
|
-
if (flag === CONSTS.ACCESS_WRITE && !
|
|
542
|
+
if (flag === CONSTS.ACCESS_WRITE && !userContext.acl.object.write) {
|
|
491
543
|
// write
|
|
492
|
-
|
|
544
|
+
throw new Error(ERRORS.ERROR_PERMISSION);
|
|
493
545
|
}
|
|
494
546
|
// If user may read
|
|
495
|
-
if (flag === CONSTS.ACCESS_READ && !
|
|
547
|
+
if (flag === CONSTS.ACCESS_READ && !userContext.acl.object.read) {
|
|
496
548
|
// read
|
|
497
|
-
|
|
549
|
+
throw new Error(ERRORS.ERROR_PERMISSION);
|
|
498
550
|
}
|
|
499
551
|
// If user may delete
|
|
500
|
-
if (flag === CONSTS.ACCESS_DELETE && !
|
|
552
|
+
if (flag === CONSTS.ACCESS_DELETE && !userContext.acl.object.delete) {
|
|
501
553
|
// delete
|
|
502
|
-
|
|
554
|
+
throw new Error(ERRORS.ERROR_PERMISSION);
|
|
503
555
|
}
|
|
504
556
|
// If user may list
|
|
505
|
-
if (flag === CONSTS.ACCESS_LIST && !
|
|
557
|
+
if (flag === CONSTS.ACCESS_LIST && !userContext.acl.object.list) {
|
|
506
558
|
// list
|
|
507
|
-
|
|
559
|
+
throw new Error(ERRORS.ERROR_PERMISSION);
|
|
508
560
|
}
|
|
509
561
|
if (flag === CONSTS.ACCESS_DELETE) {
|
|
510
562
|
// write
|
|
511
563
|
flag = CONSTS.ACCESS_WRITE;
|
|
512
564
|
}
|
|
513
|
-
if (id && !checkObject(object,
|
|
514
|
-
|
|
565
|
+
if (id && !checkObject(object, userContext, flag)) {
|
|
566
|
+
throw new Error(ERRORS.ERROR_PERMISSION);
|
|
515
567
|
}
|
|
516
|
-
return
|
|
568
|
+
return userContext;
|
|
517
569
|
}
|
|
518
570
|
//# sourceMappingURL=objectsUtils.js.map
|