@nymphjs/tilmeld 1.0.0-alpha.9 → 1.0.0-beta.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.
- package/CHANGELOG.md +174 -0
- package/dist/Group.d.ts +1 -1
- package/dist/Group.js +309 -357
- package/dist/Group.js.map +1 -1
- package/dist/Group.test.js +12 -23
- package/dist/Group.test.js.map +1 -1
- package/dist/Tilmeld.js +137 -91
- package/dist/Tilmeld.js.map +1 -1
- package/dist/Tilmeld.types.d.ts +1 -1
- package/dist/User.d.ts +41 -3
- package/dist/User.js +798 -759
- package/dist/User.js.map +1 -1
- package/dist/User.test.js +15 -26
- package/dist/User.test.js.map +1 -1
- package/dist/conf/d.d.ts +2 -1
- package/dist/conf/defaults.js +96 -57
- package/dist/conf/defaults.js.map +1 -1
- package/dist/errors/index.js +5 -1
- package/dist/errors/index.js.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/tilmeldJoiProps.d.ts +6 -6
- package/jest.config.js +1 -1
- package/package.json +20 -22
- package/src/Group.ts +2 -1
- package/src/Tilmeld.ts +137 -43
- package/src/User.ts +229 -16
- package/src/conf/d.ts +13 -1
- package/src/conf/defaults.ts +15 -18
- package/tsconfig.json +2 -0
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA,yCAAuB;AAEvB,2CAAyB;AAEzB,8DAAsC;AAC7B,qBADF,oBAAU,CACE;AAEnB,0CAAwB;AACxB,oDAA4B;AACnB,gBADF,eAAK,CACE;AAEd,wDAAgC;AACvB,kBADF,iBAAO,CACE;AAEhB,kDAAgC;AAEhC,wEAAgD;AACvC,0BADF,yBAAe,CACE;AAExB,yCAAuB;AACvB,kDAA0B;AACjB,eADF,cAAI,CACE"}
|
|
@@ -2,11 +2,11 @@ import Joi from 'joi';
|
|
|
2
2
|
declare const _default: {
|
|
3
3
|
user: Joi.ObjectSchema<any>;
|
|
4
4
|
group: Joi.ObjectSchema<any>;
|
|
5
|
-
acUser: Joi.NumberSchema
|
|
6
|
-
acGroup: Joi.NumberSchema
|
|
7
|
-
acOther: Joi.NumberSchema
|
|
8
|
-
acRead: Joi.ArraySchema
|
|
9
|
-
acWrite: Joi.ArraySchema
|
|
10
|
-
acFull: Joi.ArraySchema
|
|
5
|
+
acUser: Joi.NumberSchema<number>;
|
|
6
|
+
acGroup: Joi.NumberSchema<number>;
|
|
7
|
+
acOther: Joi.NumberSchema<number>;
|
|
8
|
+
acRead: Joi.ArraySchema<any[]>;
|
|
9
|
+
acWrite: Joi.ArraySchema<any[]>;
|
|
10
|
+
acFull: Joi.ArraySchema<any[]>;
|
|
11
11
|
};
|
|
12
12
|
export default _default;
|
package/jest.config.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nymphjs/tilmeld",
|
|
3
|
-
"version": "1.0.0-
|
|
3
|
+
"version": "1.0.0-beta.1",
|
|
4
4
|
"description": "NymphJS - Tilmeld User and Group System",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -31,34 +31,32 @@
|
|
|
31
31
|
},
|
|
32
32
|
"license": "Apache-2.0",
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@nymphjs/
|
|
34
|
+
"@nymphjs/guid": "^1.0.0-beta.1",
|
|
35
|
+
"@nymphjs/nymph": "^1.0.0-beta.1",
|
|
35
36
|
"crypto-js": "^4.1.1",
|
|
36
|
-
"email-templates": "^
|
|
37
|
-
"express": "^4.
|
|
38
|
-
"joi": "^17.
|
|
37
|
+
"email-templates": "^10.0.1",
|
|
38
|
+
"express": "^4.18.2",
|
|
39
|
+
"joi": "^17.7.0",
|
|
39
40
|
"jsonwebtoken": "^8.5.1",
|
|
40
|
-
"locutus": "^2.0.
|
|
41
|
+
"locutus": "^2.0.16",
|
|
41
42
|
"lodash": "^4.17.21",
|
|
42
|
-
"nanoid": "^3.1.25",
|
|
43
|
-
"nanoid-dictionary": "^4.3.0",
|
|
44
43
|
"pug": "^3.0.2"
|
|
45
44
|
},
|
|
46
45
|
"devDependencies": {
|
|
47
|
-
"@nymphjs/client": "^1.0.0-
|
|
48
|
-
"@nymphjs/client-node": "^1.0.0-
|
|
49
|
-
"@nymphjs/driver-sqlite3": "^1.0.0-
|
|
46
|
+
"@nymphjs/client": "^1.0.0-beta.1",
|
|
47
|
+
"@nymphjs/client-node": "^1.0.0-beta.1",
|
|
48
|
+
"@nymphjs/driver-sqlite3": "^1.0.0-beta.1",
|
|
50
49
|
"@tsconfig/recommended": "^1.0.1",
|
|
51
|
-
"@types/crypto-js": "^4.
|
|
52
|
-
"@types/email-templates": "^
|
|
53
|
-
"@types/express": "^4.17.
|
|
54
|
-
"@types/jest": "^
|
|
55
|
-
"@types/jsonwebtoken": "^8.5.
|
|
50
|
+
"@types/crypto-js": "^4.1.1",
|
|
51
|
+
"@types/email-templates": "^10.0.1",
|
|
52
|
+
"@types/express": "^4.17.14",
|
|
53
|
+
"@types/jest": "^29.2.3",
|
|
54
|
+
"@types/jsonwebtoken": "^8.5.9",
|
|
56
55
|
"@types/locutus": "^0.0.6",
|
|
57
|
-
"@types/lodash": "^4.14.
|
|
58
|
-
"
|
|
59
|
-
"jest": "^
|
|
60
|
-
"
|
|
61
|
-
"typescript": "^4.3.5"
|
|
56
|
+
"@types/lodash": "^4.14.189",
|
|
57
|
+
"jest": "^29.3.1",
|
|
58
|
+
"ts-jest": "^29.0.3",
|
|
59
|
+
"typescript": "^4.9.3"
|
|
62
60
|
},
|
|
63
|
-
"gitHead": "
|
|
61
|
+
"gitHead": "648d901c504d57f2d439cd751b60af0ebd4d63b8"
|
|
64
62
|
}
|
package/src/Group.ts
CHANGED
|
@@ -746,7 +746,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
746
746
|
}
|
|
747
747
|
|
|
748
748
|
public async $delete() {
|
|
749
|
-
|
|
749
|
+
let tilmeld = this.$nymph.tilmeld as Tilmeld;
|
|
750
750
|
if (!tilmeld.gatekeeper('tilmeld/admin')) {
|
|
751
751
|
throw new BadDataError("You don't have the authority to delete groups.");
|
|
752
752
|
}
|
|
@@ -755,6 +755,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
755
755
|
const nymph = this.$nymph;
|
|
756
756
|
const tnymph = await nymph.startTransaction(transaction);
|
|
757
757
|
this.$nymph = tnymph;
|
|
758
|
+
tilmeld = this.$nymph.tilmeld as Tilmeld;
|
|
758
759
|
|
|
759
760
|
// Delete descendants.
|
|
760
761
|
const descendants = await this.$getDescendants();
|
package/src/Tilmeld.ts
CHANGED
|
@@ -6,7 +6,9 @@ import {
|
|
|
6
6
|
TilmeldInterface,
|
|
7
7
|
TilmeldAccessLevels,
|
|
8
8
|
} from '@nymphjs/nymph';
|
|
9
|
+
import { URL } from 'url';
|
|
9
10
|
import { Request, Response } from 'express';
|
|
11
|
+
import { xor } from 'lodash';
|
|
10
12
|
|
|
11
13
|
import { Config, ConfigDefaults as defaults } from './conf';
|
|
12
14
|
import { AccessControlError } from './errors';
|
|
@@ -201,7 +203,7 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
201
203
|
return;
|
|
202
204
|
}
|
|
203
205
|
// Test for permissions.
|
|
204
|
-
if (tilmeld.checkPermissions(entity, TilmeldAccessLevels.FULL_ACCESS)) {
|
|
206
|
+
if (!tilmeld.checkPermissions(entity, TilmeldAccessLevels.FULL_ACCESS)) {
|
|
205
207
|
throw new AccessControlError('No permission to delete.');
|
|
206
208
|
}
|
|
207
209
|
};
|
|
@@ -245,15 +247,15 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
245
247
|
// allowing a change to ac properties.
|
|
246
248
|
|
|
247
249
|
const originalAc = entity.$getOriginalAcValues();
|
|
248
|
-
const newAc = {
|
|
249
|
-
user: entity.user ??
|
|
250
|
-
group: entity.group ??
|
|
251
|
-
acUser: entity.acUser ??
|
|
252
|
-
acGroup: entity.acGroup ??
|
|
253
|
-
acOther: entity.acOther ??
|
|
254
|
-
acRead: entity.acRead ??
|
|
255
|
-
acWrite: entity.acWrite ??
|
|
256
|
-
acFull: entity.acFull ??
|
|
250
|
+
const newAc: AccessControlData = {
|
|
251
|
+
user: entity.user ?? undefined,
|
|
252
|
+
group: entity.group ?? undefined,
|
|
253
|
+
acUser: entity.acUser ?? undefined,
|
|
254
|
+
acGroup: entity.acGroup ?? undefined,
|
|
255
|
+
acOther: entity.acOther ?? undefined,
|
|
256
|
+
acRead: entity.acRead ?? undefined,
|
|
257
|
+
acWrite: entity.acWrite ?? undefined,
|
|
258
|
+
acFull: entity.acFull ?? undefined,
|
|
257
259
|
};
|
|
258
260
|
|
|
259
261
|
const setAcProperties = (acValues: { [k: string]: any }) => {
|
|
@@ -269,10 +271,102 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
269
271
|
|
|
270
272
|
// Restore original AC properties and check permissions.
|
|
271
273
|
setAcProperties(originalAc);
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
274
|
+
|
|
275
|
+
function areAcPropertiesChanged(
|
|
276
|
+
a: AccessControlData,
|
|
277
|
+
b: AccessControlData
|
|
278
|
+
) {
|
|
279
|
+
for (const name of ['user', 'group'] as ('user' | 'group')[]) {
|
|
280
|
+
const aVal = a[name];
|
|
281
|
+
const bVal = b[name];
|
|
282
|
+
if (aVal == null && bVal == null) {
|
|
283
|
+
continue;
|
|
284
|
+
} else if (aVal == null || bVal == null) {
|
|
285
|
+
return true;
|
|
286
|
+
}
|
|
287
|
+
if (!aVal.$is(bVal)) {
|
|
288
|
+
return true;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
for (const name of ['acUser', 'acGroup', 'acOther'] as (
|
|
292
|
+
| 'acUser'
|
|
293
|
+
| 'acGroup'
|
|
294
|
+
| 'acOther'
|
|
295
|
+
)[]) {
|
|
296
|
+
const aVal = a[name];
|
|
297
|
+
const bVal = b[name];
|
|
298
|
+
if (aVal == null && bVal == null) {
|
|
299
|
+
continue;
|
|
300
|
+
} else if (aVal == null || bVal == null) {
|
|
301
|
+
return true;
|
|
302
|
+
}
|
|
303
|
+
if (aVal !== bVal) {
|
|
304
|
+
return true;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
for (const name of ['acRead', 'acWrite', 'acFull'] as (
|
|
308
|
+
| 'acRead'
|
|
309
|
+
| 'acWrite'
|
|
310
|
+
| 'acFull'
|
|
311
|
+
)[]) {
|
|
312
|
+
const aVal = a[name];
|
|
313
|
+
const bVal = b[name];
|
|
314
|
+
if (aVal == null && bVal == null) {
|
|
315
|
+
continue;
|
|
316
|
+
} else if (aVal == null || bVal == null) {
|
|
317
|
+
return true;
|
|
318
|
+
}
|
|
319
|
+
if (aVal.length !== bVal.length) {
|
|
320
|
+
return true;
|
|
321
|
+
}
|
|
322
|
+
if (
|
|
323
|
+
xor(
|
|
324
|
+
aVal.map((entity) => entity.guid),
|
|
325
|
+
bVal.map((entity) => entity.guid)
|
|
326
|
+
).length
|
|
327
|
+
) {
|
|
328
|
+
return true;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (areAcPropertiesChanged(originalAc, newAc)) {
|
|
335
|
+
if (
|
|
336
|
+
!tilmeld.checkPermissions(entity, TilmeldAccessLevels.FULL_ACCESS)
|
|
337
|
+
) {
|
|
338
|
+
// Only allow changes to AC properties if the user has full access.
|
|
339
|
+
throw new AccessControlError(
|
|
340
|
+
'No permission to change access control properties.'
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (
|
|
345
|
+
((originalAc.user && !originalAc.user.$is(newAc.user)) ||
|
|
346
|
+
(!originalAc.user &&
|
|
347
|
+
newAc.user &&
|
|
348
|
+
!newAc.user.$is(tilmeld.currentUser))) &&
|
|
349
|
+
!tilmeld.gatekeeper('tilmeld/admin')
|
|
350
|
+
) {
|
|
351
|
+
throw new AccessControlError(
|
|
352
|
+
'No permission to assign to another user.'
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (
|
|
357
|
+
newAc.group &&
|
|
358
|
+
!newAc.group.$is(originalAc.group) &&
|
|
359
|
+
!(
|
|
360
|
+
newAc.group.$is(tilmeld.currentUser?.group) ||
|
|
361
|
+
newAc.group.$inArray(tilmeld.currentUser?.groups ?? [])
|
|
362
|
+
) &&
|
|
363
|
+
!tilmeld.gatekeeper('tilmeld/admin')
|
|
364
|
+
) {
|
|
365
|
+
throw new AccessControlError(
|
|
366
|
+
'No permission to assign to another group.'
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
|
|
276
370
|
setAcProperties(newAc);
|
|
277
371
|
}
|
|
278
372
|
}
|
|
@@ -455,7 +549,7 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
455
549
|
return;
|
|
456
550
|
}
|
|
457
551
|
|
|
458
|
-
if (user
|
|
552
|
+
if (user == null || user.guid == null) {
|
|
459
553
|
selectors.push({
|
|
460
554
|
type: '|',
|
|
461
555
|
// Other access control is sufficient.
|
|
@@ -464,7 +558,7 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
464
558
|
selector: [
|
|
465
559
|
{
|
|
466
560
|
type: '&',
|
|
467
|
-
'!defined': ['user', 'group'],
|
|
561
|
+
'!defined': [['user', 'group']],
|
|
468
562
|
},
|
|
469
563
|
],
|
|
470
564
|
});
|
|
@@ -472,56 +566,43 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
472
566
|
const subSelectors: FormattedSelector[] = [
|
|
473
567
|
{
|
|
474
568
|
type: '&',
|
|
475
|
-
'!defined': ['user', 'group'],
|
|
569
|
+
'!defined': [['user', 'group']],
|
|
476
570
|
},
|
|
477
571
|
// It is owned by the user.
|
|
478
572
|
{
|
|
479
573
|
type: '&',
|
|
480
|
-
ref: [['user', user]],
|
|
574
|
+
ref: [['user', user.guid]],
|
|
481
575
|
gte: [['acUser', TilmeldAccessLevels.READ_ACCESS]],
|
|
482
576
|
},
|
|
483
577
|
];
|
|
484
|
-
const selector: FormattedSelector = {
|
|
485
|
-
type: '|',
|
|
486
|
-
// Other access control is sufficient.
|
|
487
|
-
gte: [['acOther', TilmeldAccessLevels.READ_ACCESS]],
|
|
488
|
-
// The user and group are not set.
|
|
489
|
-
selector: subSelectors,
|
|
490
|
-
// The user is listed in acRead, acWrite, or acFull.
|
|
491
|
-
ref: [
|
|
492
|
-
['acRead', user],
|
|
493
|
-
['acWrite', user],
|
|
494
|
-
['acFull', user],
|
|
495
|
-
],
|
|
496
|
-
};
|
|
497
578
|
const groupRefs: FormattedSelector['ref'] = [];
|
|
498
579
|
const acRefs: FormattedSelector['ref'] = [];
|
|
499
580
|
if (user.group != null && user.group.guid != null) {
|
|
500
581
|
// It belongs to the user's primary group.
|
|
501
|
-
groupRefs.push(['group', user.group]);
|
|
582
|
+
groupRefs.push(['group', user.group.guid]);
|
|
502
583
|
// User's primary group is listed in acRead, acWrite, or acFull.
|
|
503
|
-
acRefs.push(['acRead', user.group]);
|
|
504
|
-
acRefs.push(['acWrite', user.group]);
|
|
505
|
-
acRefs.push(['acFull', user.group]);
|
|
584
|
+
acRefs.push(['acRead', user.group.guid]);
|
|
585
|
+
acRefs.push(['acWrite', user.group.guid]);
|
|
586
|
+
acRefs.push(['acFull', user.group.guid]);
|
|
506
587
|
}
|
|
507
588
|
for (let curSecondaryGroup of user.groups ?? []) {
|
|
508
589
|
if (curSecondaryGroup != null && curSecondaryGroup.guid != null) {
|
|
509
590
|
// It belongs to the user's secondary group.
|
|
510
|
-
groupRefs.push(['group', curSecondaryGroup]);
|
|
591
|
+
groupRefs.push(['group', curSecondaryGroup.guid]);
|
|
511
592
|
// User's secondary group is listed in acRead, acWrite, or acFull.
|
|
512
|
-
acRefs.push(['acRead', curSecondaryGroup]);
|
|
513
|
-
acRefs.push(['acWrite', curSecondaryGroup]);
|
|
514
|
-
acRefs.push(['acFull', curSecondaryGroup]);
|
|
593
|
+
acRefs.push(['acRead', curSecondaryGroup.guid]);
|
|
594
|
+
acRefs.push(['acWrite', curSecondaryGroup.guid]);
|
|
595
|
+
acRefs.push(['acFull', curSecondaryGroup.guid]);
|
|
515
596
|
}
|
|
516
597
|
}
|
|
517
598
|
for (let curDescendantGroup of user.$getDescendantGroupsSync()) {
|
|
518
599
|
if (curDescendantGroup != null && curDescendantGroup.guid != null) {
|
|
519
600
|
// It belongs to the user's secondary group.
|
|
520
|
-
groupRefs.push(['group', curDescendantGroup]);
|
|
601
|
+
groupRefs.push(['group', curDescendantGroup.guid]);
|
|
521
602
|
// User's secondary group is listed in acRead, acWrite, or acFull.
|
|
522
|
-
acRefs.push(['acRead', curDescendantGroup]);
|
|
523
|
-
acRefs.push(['acWrite', curDescendantGroup]);
|
|
524
|
-
acRefs.push(['acFull', curDescendantGroup]);
|
|
603
|
+
acRefs.push(['acRead', curDescendantGroup.guid]);
|
|
604
|
+
acRefs.push(['acWrite', curDescendantGroup.guid]);
|
|
605
|
+
acRefs.push(['acFull', curDescendantGroup.guid]);
|
|
525
606
|
}
|
|
526
607
|
}
|
|
527
608
|
// All the group refs.
|
|
@@ -544,6 +625,19 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
544
625
|
ref: acRefs,
|
|
545
626
|
});
|
|
546
627
|
}
|
|
628
|
+
const selector: FormattedSelector = {
|
|
629
|
+
type: '|',
|
|
630
|
+
// Other access control is sufficient.
|
|
631
|
+
gte: [['acOther', TilmeldAccessLevels.READ_ACCESS]],
|
|
632
|
+
// The user and group are not set.
|
|
633
|
+
selector: subSelectors,
|
|
634
|
+
// The user is listed in acRead, acWrite, or acFull.
|
|
635
|
+
ref: [
|
|
636
|
+
['acRead', user.guid],
|
|
637
|
+
['acWrite', user.guid],
|
|
638
|
+
['acFull', user.guid],
|
|
639
|
+
],
|
|
640
|
+
};
|
|
547
641
|
selectors.push(selector);
|
|
548
642
|
}
|
|
549
643
|
}
|