@nymphjs/tilmeld 1.0.0-beta.139 → 1.0.0-beta.140
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 +12 -0
- package/dist/Group.d.ts +2 -4
- package/dist/Group.js +37 -20
- package/dist/Group.js.map +1 -1
- package/dist/Tilmeld.d.ts +2 -3
- package/dist/Tilmeld.js +50 -27
- package/dist/Tilmeld.js.map +1 -1
- package/dist/User.d.ts +3 -5
- package/dist/User.js +50 -32
- package/dist/User.js.map +1 -1
- package/dist/conf/defaults.js +11 -0
- package/dist/conf/defaults.js.map +1 -1
- package/package.json +5 -5
- package/src/Group.ts +47 -22
- package/src/Tilmeld.ts +73 -27
- package/src/User.ts +59 -34
- package/src/conf/defaults.ts +15 -0
package/src/Group.ts
CHANGED
|
@@ -342,6 +342,12 @@ export class Group extends AbleObject<GroupData> {
|
|
|
342
342
|
|
|
343
343
|
if ('abilities' in input.data) {
|
|
344
344
|
this.$checkIncomingAbilities(input.data.abilities);
|
|
345
|
+
} else if (
|
|
346
|
+
(this.$allowlistData == null ||
|
|
347
|
+
this.$allowlistData.includes('abilities')) &&
|
|
348
|
+
(this.$privateData == null || !this.$privateData.includes('abilities'))
|
|
349
|
+
) {
|
|
350
|
+
this.$checkIncomingAbilities(undefined);
|
|
345
351
|
}
|
|
346
352
|
|
|
347
353
|
super.$jsonAcceptData(input, allowConflict);
|
|
@@ -354,6 +360,10 @@ export class Group extends AbleObject<GroupData> {
|
|
|
354
360
|
this.$checkIncomingAbilities(patch.set.abilities);
|
|
355
361
|
}
|
|
356
362
|
|
|
363
|
+
if (patch.unset.includes('abilities')) {
|
|
364
|
+
this.$checkIncomingAbilities(undefined);
|
|
365
|
+
}
|
|
366
|
+
|
|
357
367
|
super.$jsonAcceptPatch(patch, allowConflict);
|
|
358
368
|
}
|
|
359
369
|
|
|
@@ -378,6 +388,20 @@ export class Group extends AbleObject<GroupData> {
|
|
|
378
388
|
);
|
|
379
389
|
}
|
|
380
390
|
|
|
391
|
+
if (
|
|
392
|
+
xor(
|
|
393
|
+
incoming.filter((ability) => ability.startsWith('system/')),
|
|
394
|
+
this.abilities?.filter((ability) => ability.startsWith('system/')) ??
|
|
395
|
+
[],
|
|
396
|
+
).length &&
|
|
397
|
+
(!tilmeld.currentUser ||
|
|
398
|
+
!tilmeld.currentUser.abilities?.includes('system/admin'))
|
|
399
|
+
) {
|
|
400
|
+
throw new BadDataError(
|
|
401
|
+
"You don't have the authority to grant or revoke system abilities.",
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
|
|
381
405
|
if (
|
|
382
406
|
incoming.includes('tilmeld/admin') !==
|
|
383
407
|
this.abilities?.includes('tilmeld/admin') &&
|
|
@@ -402,10 +426,9 @@ export class Group extends AbleObject<GroupData> {
|
|
|
402
426
|
|
|
403
427
|
if (
|
|
404
428
|
xor(
|
|
405
|
-
incoming.filter((ability
|
|
406
|
-
this.abilities?.filter((ability
|
|
407
|
-
|
|
408
|
-
) ?? [],
|
|
429
|
+
incoming.filter((ability) => ability.startsWith('tilmeld/')),
|
|
430
|
+
this.abilities?.filter((ability) => ability.startsWith('tilmeld/')) ??
|
|
431
|
+
[],
|
|
409
432
|
).length &&
|
|
410
433
|
(!tilmeld.currentUser ||
|
|
411
434
|
(!tilmeld.currentUser.abilities?.includes('system/admin') &&
|
|
@@ -422,14 +445,21 @@ export class Group extends AbleObject<GroupData> {
|
|
|
422
445
|
sdata?: SerializedEntityData,
|
|
423
446
|
source?: 'server',
|
|
424
447
|
) {
|
|
425
|
-
|
|
448
|
+
let newData = { ...data };
|
|
449
|
+
let newSdata = sdata && { ...sdata };
|
|
426
450
|
// TODO: Fix these being added by the drivers.
|
|
427
451
|
// @ts-ignore
|
|
428
|
-
delete
|
|
452
|
+
delete newData.acRead;
|
|
429
453
|
// @ts-ignore
|
|
430
|
-
delete
|
|
454
|
+
delete newData.acWrite;
|
|
431
455
|
// @ts-ignore
|
|
432
|
-
delete
|
|
456
|
+
delete newData.acFull;
|
|
457
|
+
if (newSdata) {
|
|
458
|
+
delete newSdata.acRead;
|
|
459
|
+
delete newSdata.acWrite;
|
|
460
|
+
delete newSdata.acFull;
|
|
461
|
+
}
|
|
462
|
+
super.$putData(newData, newSdata, source);
|
|
433
463
|
if (source === 'server') {
|
|
434
464
|
this.$originalGroupname = this.groupname;
|
|
435
465
|
}
|
|
@@ -437,13 +467,10 @@ export class Group extends AbleObject<GroupData> {
|
|
|
437
467
|
}
|
|
438
468
|
|
|
439
469
|
/**
|
|
440
|
-
* Update the data protection arrays for
|
|
441
|
-
*
|
|
442
|
-
* @param givenUser User to update protection for. If undefined, will use the currently logged in user.
|
|
470
|
+
* Update the data protection arrays for the current user.
|
|
443
471
|
*/
|
|
444
|
-
public $updateDataProtection(
|
|
472
|
+
public $updateDataProtection() {
|
|
445
473
|
const tilmeld = enforceTilmeld(this);
|
|
446
|
-
let user = givenUser ?? tilmeld.User.current();
|
|
447
474
|
let [_groupname, domain] = tilmeld.config.domainSupport
|
|
448
475
|
? splitn(this.groupname ?? '', '@', 2)
|
|
449
476
|
: [this.groupname, null];
|
|
@@ -460,25 +487,23 @@ export class Group extends AbleObject<GroupData> {
|
|
|
460
487
|
}
|
|
461
488
|
|
|
462
489
|
if (
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
user.abilities?.includes('system/admin'))
|
|
490
|
+
tilmeld.gatekeeper('tilmeld/admin') ||
|
|
491
|
+
tilmeld.gatekeeper('system/admin')
|
|
466
492
|
) {
|
|
467
493
|
// Users who can edit groups can see their data.
|
|
468
494
|
this.$privateData = [];
|
|
469
495
|
this.$allowlistData = undefined;
|
|
470
496
|
} else if (
|
|
471
497
|
this.user != null &&
|
|
472
|
-
|
|
473
|
-
this.user.guid ===
|
|
498
|
+
tilmeld.currentUser != null &&
|
|
499
|
+
this.user.guid === tilmeld.currentUser.guid
|
|
474
500
|
) {
|
|
475
501
|
// Users can see their group's data.
|
|
476
502
|
this.$privateData = [];
|
|
477
503
|
} else if (
|
|
478
|
-
user != null &&
|
|
479
504
|
tilmeld.config.domainSupport &&
|
|
480
505
|
domain &&
|
|
481
|
-
|
|
506
|
+
tilmeld.gatekeeper(`tilmeld/domain/${domain}/admin`)
|
|
482
507
|
) {
|
|
483
508
|
// Domain admins can see their groups' data.
|
|
484
509
|
this.$privateData = [];
|
|
@@ -914,7 +939,7 @@ export class Group extends AbleObject<GroupData> {
|
|
|
914
939
|
}
|
|
915
940
|
|
|
916
941
|
// Groups should never have 'system/admin', 'tilmeld/admin',
|
|
917
|
-
// 'tilmeld/switch', or
|
|
942
|
+
// 'tilmeld/switch', or system abilities.
|
|
918
943
|
this.abilities = (this.abilities ?? []).filter((ability) => {
|
|
919
944
|
if (
|
|
920
945
|
['system/admin', 'tilmeld/admin', 'tilmeld/switch'].indexOf(ability) !==
|
|
@@ -925,7 +950,7 @@ export class Group extends AbleObject<GroupData> {
|
|
|
925
950
|
if (ability == null) {
|
|
926
951
|
return false;
|
|
927
952
|
}
|
|
928
|
-
if (ability.startsWith('
|
|
953
|
+
if (ability.startsWith('system/')) {
|
|
929
954
|
return false;
|
|
930
955
|
}
|
|
931
956
|
return true;
|
package/src/Tilmeld.ts
CHANGED
|
@@ -9,6 +9,10 @@ import {
|
|
|
9
9
|
TilmeldAccessLevels,
|
|
10
10
|
TilmeldAccessRequest,
|
|
11
11
|
ACProperties,
|
|
12
|
+
entitiesToReferences,
|
|
13
|
+
entityConstructorsToClassNames,
|
|
14
|
+
classNamesToEntityConstructors,
|
|
15
|
+
referencesToEntities,
|
|
12
16
|
} from '@nymphjs/nymph';
|
|
13
17
|
import { Request, Response } from 'express';
|
|
14
18
|
import { xor } from 'lodash-es';
|
|
@@ -165,15 +169,53 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
165
169
|
const currentUserCDate = this.currentUser.cdate;
|
|
166
170
|
const currentUserMDate = this.currentUser.mdate;
|
|
167
171
|
const currentUserTags = this.currentUser.tags;
|
|
168
|
-
const currentUserData =
|
|
172
|
+
const currentUserData = entityConstructorsToClassNames(
|
|
173
|
+
entitiesToReferences(this.currentUser.$getData(false), true),
|
|
174
|
+
);
|
|
169
175
|
const currentUserSData = this.currentUser.$getSData();
|
|
176
|
+
const currentUserOriginalAcValues =
|
|
177
|
+
this.currentUser.$getOriginalAcValues();
|
|
170
178
|
|
|
171
179
|
const user = this.User.factorySync();
|
|
172
180
|
user.guid = currentUserGUID;
|
|
173
181
|
user.cdate = currentUserCDate;
|
|
174
182
|
user.mdate = currentUserMDate;
|
|
175
183
|
user.tags = currentUserTags;
|
|
176
|
-
|
|
184
|
+
// First, put the trusted original AC values in with the server flag.
|
|
185
|
+
Entity.factorySync().$putData.call(
|
|
186
|
+
user,
|
|
187
|
+
{
|
|
188
|
+
...currentUserOriginalAcValues,
|
|
189
|
+
user:
|
|
190
|
+
currentUserOriginalAcValues.user != null
|
|
191
|
+
? this.User.factoryReference([
|
|
192
|
+
'nymph_entity_reference',
|
|
193
|
+
currentUserOriginalAcValues.user,
|
|
194
|
+
this.User.class,
|
|
195
|
+
])
|
|
196
|
+
: undefined,
|
|
197
|
+
group:
|
|
198
|
+
currentUserOriginalAcValues.group != null
|
|
199
|
+
? this.Group.factoryReference([
|
|
200
|
+
'nymph_entity_reference',
|
|
201
|
+
currentUserOriginalAcValues.group,
|
|
202
|
+
this.Group.class,
|
|
203
|
+
])
|
|
204
|
+
: undefined,
|
|
205
|
+
},
|
|
206
|
+
{},
|
|
207
|
+
'server',
|
|
208
|
+
);
|
|
209
|
+
// Now put the real data in, that could potentially have been altered from
|
|
210
|
+
// the client.
|
|
211
|
+
user.$putData(
|
|
212
|
+
classNamesToEntityConstructors(
|
|
213
|
+
this.nymph,
|
|
214
|
+
referencesToEntities(currentUserData, this.nymph, false, false),
|
|
215
|
+
false,
|
|
216
|
+
),
|
|
217
|
+
currentUserSData,
|
|
218
|
+
);
|
|
177
219
|
user.$originalEmail = this.currentUser.$originalEmail;
|
|
178
220
|
user.$originalUsername = this.currentUser.$originalUsername;
|
|
179
221
|
this.currentUser = user;
|
|
@@ -292,7 +334,7 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
292
334
|
if (entity == null) {
|
|
293
335
|
throw new AccessControlError("You can't delete this entity by ID.");
|
|
294
336
|
}
|
|
295
|
-
checkPermissionsDelete(nymph, entity);
|
|
337
|
+
await checkPermissionsDelete(nymph, entity);
|
|
296
338
|
};
|
|
297
339
|
checkPermissionsDeleteByID.skipOnClone = true;
|
|
298
340
|
|
|
@@ -373,7 +415,6 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
373
415
|
!tilmeld.checkPermissions(
|
|
374
416
|
entity,
|
|
375
417
|
TilmeldAccessLevels.FULL_ACCESS,
|
|
376
|
-
undefined,
|
|
377
418
|
originalAc,
|
|
378
419
|
)
|
|
379
420
|
) {
|
|
@@ -740,7 +781,7 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
740
781
|
}
|
|
741
782
|
|
|
742
783
|
/**
|
|
743
|
-
* Check an entity's permissions for
|
|
784
|
+
* Check an entity's permissions for the current user.
|
|
744
785
|
*
|
|
745
786
|
* This will check the AC (Access Control) properties of the entity. These
|
|
746
787
|
* include the following properties:
|
|
@@ -800,37 +841,26 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
800
841
|
*
|
|
801
842
|
* @param entity The entity to check.
|
|
802
843
|
* @param type The lowest level of permission to consider a pass.
|
|
803
|
-
* @param user The user to check permissions for. If null, uses the current user. If false, checks for public access.
|
|
804
844
|
* @param acProperties The acProperties to use instead of getting them from the entity.
|
|
805
845
|
* @returns Whether the current user has at least `type` permission for the entity.
|
|
806
846
|
*/
|
|
807
847
|
public checkPermissions(
|
|
808
848
|
entity: EntityInterface,
|
|
809
849
|
type: TilmeldAccessLevels = TilmeldAccessLevels.READ_ACCESS,
|
|
810
|
-
user?: User | false,
|
|
811
850
|
acProperties?: ACProperties,
|
|
812
851
|
) {
|
|
813
852
|
if (!acProperties) {
|
|
814
853
|
acProperties = entity.$getCurrentAcValues() as ACProperties;
|
|
815
854
|
}
|
|
816
855
|
|
|
817
|
-
let
|
|
818
|
-
let userOrEmpty: User = this.User.factorySync();
|
|
819
|
-
// Calculate the user.
|
|
820
|
-
if (user == null) {
|
|
821
|
-
userOrNull = this.currentUser;
|
|
822
|
-
userOrEmpty = this.User.current(true);
|
|
823
|
-
} else if (user !== false) {
|
|
824
|
-
userOrNull = user;
|
|
825
|
-
userOrEmpty = user;
|
|
826
|
-
}
|
|
856
|
+
let userOrEmpty: User = this.User.current(true);
|
|
827
857
|
|
|
828
858
|
// Users and groups are always readable. Editable by Tilmeld admins.
|
|
829
859
|
if (
|
|
830
860
|
(entity instanceof User || entity instanceof Group) &&
|
|
831
861
|
(type === TilmeldAccessLevels.READ_ACCESS ||
|
|
832
|
-
|
|
833
|
-
|
|
862
|
+
this.gatekeeper('tilmeld/admin') ||
|
|
863
|
+
this.gatekeeper('system/admin'))
|
|
834
864
|
) {
|
|
835
865
|
return true;
|
|
836
866
|
}
|
|
@@ -848,10 +878,7 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
848
878
|
'@',
|
|
849
879
|
2,
|
|
850
880
|
);
|
|
851
|
-
if (
|
|
852
|
-
domain &&
|
|
853
|
-
userOrEmpty.abilities?.includes(`tilmeld/domain/${domain}/admin`)
|
|
854
|
-
) {
|
|
881
|
+
if (domain && this.gatekeeper(`tilmeld/domain/${domain}/admin`)) {
|
|
855
882
|
return true;
|
|
856
883
|
}
|
|
857
884
|
}
|
|
@@ -861,7 +888,7 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
861
888
|
const acGroup = acProperties.acGroup ?? TilmeldAccessLevels.READ_ACCESS;
|
|
862
889
|
const acOther = acProperties.acOther ?? TilmeldAccessLevels.NO_ACCESS;
|
|
863
890
|
|
|
864
|
-
if (
|
|
891
|
+
if (this.currentUser == null) {
|
|
865
892
|
return acOther >= type;
|
|
866
893
|
}
|
|
867
894
|
|
|
@@ -931,7 +958,10 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
931
958
|
}
|
|
932
959
|
|
|
933
960
|
// Check ownership ac properties.
|
|
934
|
-
if (
|
|
961
|
+
if (
|
|
962
|
+
acProperties.user != null &&
|
|
963
|
+
acProperties.user === this.currentUser.guid
|
|
964
|
+
) {
|
|
935
965
|
return acUser >= type;
|
|
936
966
|
}
|
|
937
967
|
if (acProperties.group != null && allGids.includes(acProperties.group)) {
|
|
@@ -1013,10 +1043,26 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
1013
1043
|
* @param user The user.
|
|
1014
1044
|
*/
|
|
1015
1045
|
public async fillSession(user: User) {
|
|
1016
|
-
|
|
1046
|
+
// Clear any currently logged in user.
|
|
1047
|
+
const oldUser = this.currentUser;
|
|
1048
|
+
this.currentUser = null;
|
|
1049
|
+
this.gatekeeperCache = null;
|
|
1050
|
+
if (oldUser) {
|
|
1051
|
+
oldUser.$updateDataProtection();
|
|
1052
|
+
oldUser.$updateGroupDataProtection();
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
// Update data protection on the incoming user.
|
|
1056
|
+
user.$updateDataProtection();
|
|
1057
|
+
user.$updateGroupDataProtection();
|
|
1058
|
+
|
|
1059
|
+
// Get the gatekeeper cache for incoming user.
|
|
1017
1060
|
this.gatekeeperCache = await user.$getGatekeeperCache();
|
|
1018
1061
|
|
|
1019
|
-
// Now
|
|
1062
|
+
// Now we're ready to set the current user.
|
|
1063
|
+
this.currentUser = user;
|
|
1064
|
+
|
|
1065
|
+
// And update the data protection on the user and all the groups.
|
|
1020
1066
|
this.currentUser.$updateDataProtection();
|
|
1021
1067
|
this.currentUser.$updateGroupDataProtection();
|
|
1022
1068
|
}
|
package/src/User.ts
CHANGED
|
@@ -927,19 +927,12 @@ export class User extends AbleObject<UserData> {
|
|
|
927
927
|
if (domain) {
|
|
928
928
|
domain = domain.toLowerCase();
|
|
929
929
|
}
|
|
930
|
-
const
|
|
931
|
-
const isCurrentUser = user != null && user.$is(this);
|
|
932
|
-
// While loading, accessing abilities on the current user will infinitely
|
|
933
|
-
// loop, but if this is the current user, we can use its abilities.
|
|
934
|
-
const abilities =
|
|
935
|
-
(isCurrentUser || user == null ? this.abilities : user?.abilities) ??
|
|
936
|
-
[];
|
|
930
|
+
const isCurrentUser = this.$is(tilmeld.currentUser);
|
|
937
931
|
const isNewUser = input.guid == null;
|
|
938
932
|
const isDomainUser =
|
|
939
933
|
!isCurrentUser &&
|
|
940
|
-
user != null &&
|
|
941
934
|
domain &&
|
|
942
|
-
|
|
935
|
+
tilmeld.gatekeeper(`tilmeld/domain/${domain}/admin`);
|
|
943
936
|
|
|
944
937
|
reloadDataProtection = !!(isNewUser && isDomainUser);
|
|
945
938
|
}
|
|
@@ -1045,14 +1038,21 @@ export class User extends AbleObject<UserData> {
|
|
|
1045
1038
|
sdata?: SerializedEntityData,
|
|
1046
1039
|
source?: 'server',
|
|
1047
1040
|
) {
|
|
1048
|
-
|
|
1041
|
+
let newData = { ...data };
|
|
1042
|
+
let newSdata = sdata && { ...sdata };
|
|
1049
1043
|
// TODO: Fix these being added by the drivers.
|
|
1050
1044
|
// @ts-ignore
|
|
1051
|
-
delete
|
|
1045
|
+
delete newData.acRead;
|
|
1052
1046
|
// @ts-ignore
|
|
1053
|
-
delete
|
|
1047
|
+
delete newData.acWrite;
|
|
1054
1048
|
// @ts-ignore
|
|
1055
|
-
delete
|
|
1049
|
+
delete newData.acFull;
|
|
1050
|
+
if (newSdata) {
|
|
1051
|
+
delete newSdata.acRead;
|
|
1052
|
+
delete newSdata.acWrite;
|
|
1053
|
+
delete newSdata.acFull;
|
|
1054
|
+
}
|
|
1055
|
+
super.$putData(newData, newSdata, source);
|
|
1056
1056
|
if (source === 'server') {
|
|
1057
1057
|
this.$originalEmail = this.email;
|
|
1058
1058
|
this.$originalUsername = this.username;
|
|
@@ -1061,13 +1061,10 @@ export class User extends AbleObject<UserData> {
|
|
|
1061
1061
|
}
|
|
1062
1062
|
|
|
1063
1063
|
/**
|
|
1064
|
-
* Update the data protection arrays for
|
|
1065
|
-
*
|
|
1066
|
-
* @param givenUser User to update protection for. If undefined, will use the currently logged in user.
|
|
1064
|
+
* Update the data protection arrays for the current user.
|
|
1067
1065
|
*/
|
|
1068
|
-
public $updateDataProtection(
|
|
1066
|
+
public $updateDataProtection() {
|
|
1069
1067
|
const tilmeld = enforceTilmeld(this);
|
|
1070
|
-
let user = givenUser ?? tilmeld.User.current();
|
|
1071
1068
|
let [_username, domain] = tilmeld.config.domainSupport
|
|
1072
1069
|
? splitn(this.$originalUsername ?? this.username ?? '', '@', 2)
|
|
1073
1070
|
: [this.$originalUsername ?? this.username, null];
|
|
@@ -1084,18 +1081,13 @@ export class User extends AbleObject<UserData> {
|
|
|
1084
1081
|
this.$privateData.push('username');
|
|
1085
1082
|
}
|
|
1086
1083
|
|
|
1087
|
-
const isCurrentUser =
|
|
1088
|
-
// While loading, accessing abilities on the current user will infinitely
|
|
1089
|
-
// loop, but if this is the current user, we can use its abilities.
|
|
1090
|
-
const abilities =
|
|
1091
|
-
(isCurrentUser || user == null ? this.abilities : user?.abilities) ?? [];
|
|
1084
|
+
const isCurrentUser = this.$is(tilmeld.currentUser);
|
|
1092
1085
|
const isNewUser = this.guid == null;
|
|
1093
1086
|
const isDomainUser =
|
|
1094
1087
|
tilmeld.config.domainSupport &&
|
|
1095
1088
|
!isCurrentUser &&
|
|
1096
|
-
user != null &&
|
|
1097
1089
|
domain &&
|
|
1098
|
-
|
|
1090
|
+
tilmeld.gatekeeper(`tilmeld/domain/${domain}/admin`);
|
|
1099
1091
|
|
|
1100
1092
|
if (isCurrentUser) {
|
|
1101
1093
|
// Users can check to see what abilities they have.
|
|
@@ -1121,12 +1113,18 @@ export class User extends AbleObject<UserData> {
|
|
|
1121
1113
|
}
|
|
1122
1114
|
|
|
1123
1115
|
if (
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
abilities.includes('system/admin'))
|
|
1116
|
+
tilmeld.gatekeeper('tilmeld/admin') ||
|
|
1117
|
+
tilmeld.gatekeeper('system/admin')
|
|
1127
1118
|
) {
|
|
1128
1119
|
// Users who can edit other users can see most of their data.
|
|
1129
|
-
this.$privateData = [
|
|
1120
|
+
this.$privateData = [
|
|
1121
|
+
'newEmailSecret',
|
|
1122
|
+
'cancelEmailSecret',
|
|
1123
|
+
'recoverSecret',
|
|
1124
|
+
'salt',
|
|
1125
|
+
'password',
|
|
1126
|
+
'totpSecret',
|
|
1127
|
+
];
|
|
1130
1128
|
this.$clientEnabledMethods.push('$hasTOTPSecret');
|
|
1131
1129
|
this.$clientEnabledMethods.push('$removeTOTPSecret');
|
|
1132
1130
|
this.$allowlistData = undefined;
|
|
@@ -1229,10 +1227,9 @@ export class User extends AbleObject<UserData> {
|
|
|
1229
1227
|
}
|
|
1230
1228
|
|
|
1231
1229
|
if (
|
|
1232
|
-
user != null &&
|
|
1233
1230
|
!isCurrentUser &&
|
|
1234
|
-
(
|
|
1235
|
-
|
|
1231
|
+
(tilmeld.gatekeeper('tilmeld/switch') ||
|
|
1232
|
+
tilmeld.gatekeeper('system/admin'))
|
|
1236
1233
|
) {
|
|
1237
1234
|
// Users with this ability can switch to other users.
|
|
1238
1235
|
this.$clientEnabledMethods.push('$switchUser');
|
|
@@ -1647,14 +1644,42 @@ export class User extends AbleObject<UserData> {
|
|
|
1647
1644
|
* @param data The input data from the client.
|
|
1648
1645
|
* @returns An object with a boolean 'result' entry and a 'message' entry.
|
|
1649
1646
|
*/
|
|
1650
|
-
public async $revokeCurrentTokens(data
|
|
1647
|
+
public async $revokeCurrentTokens(data?: {
|
|
1651
1648
|
password: string;
|
|
1652
1649
|
}): Promise<{ result: boolean; message: string }> {
|
|
1653
1650
|
const tilmeld = enforceTilmeld(this);
|
|
1651
|
+
|
|
1654
1652
|
if (!tilmeld.gatekeeper()) {
|
|
1655
1653
|
return { result: false, message: 'You must be logged in.' };
|
|
1656
1654
|
}
|
|
1657
|
-
|
|
1655
|
+
|
|
1656
|
+
if (this.guid == null) {
|
|
1657
|
+
return { result: false, message: 'This user has not been saved.' };
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
// Work on real data.
|
|
1661
|
+
await this.$refresh();
|
|
1662
|
+
|
|
1663
|
+
let [_username, domain] = tilmeld.config.domainSupport
|
|
1664
|
+
? splitn(this.$originalUsername ?? this.username ?? '', '@', 2)
|
|
1665
|
+
: [this.$originalUsername ?? this.username, null];
|
|
1666
|
+
// Lowercase the domain part.
|
|
1667
|
+
if (domain) {
|
|
1668
|
+
domain = domain.toLowerCase();
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
const isAdmin = tilmeld.gatekeeper('tilmeld/admin');
|
|
1672
|
+
const isDomainUser =
|
|
1673
|
+
tilmeld.config.domainSupport &&
|
|
1674
|
+
!this.$is(tilmeld.currentUser) &&
|
|
1675
|
+
domain &&
|
|
1676
|
+
tilmeld.gatekeeper(`tilmeld/domain/${domain}/admin`);
|
|
1677
|
+
|
|
1678
|
+
if (
|
|
1679
|
+
!isAdmin &&
|
|
1680
|
+
!isDomainUser &&
|
|
1681
|
+
(data == null || !(await this.$checkPassword(data.password ?? '')))
|
|
1682
|
+
) {
|
|
1658
1683
|
return { result: false, message: 'Incorrect password.' };
|
|
1659
1684
|
}
|
|
1660
1685
|
|
package/src/conf/defaults.ts
CHANGED
|
@@ -233,6 +233,21 @@ export default {
|
|
|
233
233
|
.pattern(/^[0-9]+$/, 'numbers'),
|
|
234
234
|
}
|
|
235
235
|
: {};
|
|
236
|
+
for (let ability of group.abilities ?? []) {
|
|
237
|
+
if (ability.startsWith('system/')) {
|
|
238
|
+
throw new Error('Invalid Group: Groups cannot have system abilities.');
|
|
239
|
+
}
|
|
240
|
+
if (ability === 'tilmeld/admin') {
|
|
241
|
+
throw new Error(
|
|
242
|
+
'Invalid Group: Groups cannot have Tilmeld admin ability.',
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
if (ability === 'tilmeld/switch') {
|
|
246
|
+
throw new Error(
|
|
247
|
+
'Invalid Group: Groups cannot have Tilmeld switch ability.',
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
236
251
|
Joi.attempt(
|
|
237
252
|
group.$getValidatable(),
|
|
238
253
|
Joi.object().keys({
|