@nymphjs/tilmeld 1.0.0-beta.40 → 1.0.0-beta.41

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/src/Tilmeld.ts CHANGED
@@ -5,6 +5,7 @@ import {
5
5
  Options,
6
6
  TilmeldInterface,
7
7
  TilmeldAccessLevels,
8
+ ACProperties,
8
9
  } from '@nymphjs/nymph';
9
10
  import { URL } from 'url';
10
11
  import { Request, Response } from 'express';
@@ -69,11 +70,6 @@ export default class Tilmeld implements TilmeldInterface {
69
70
  public request: Request | null = null;
70
71
  public response: Response | null = null;
71
72
 
72
- /**
73
- * Skip the authenticate step of initialization.
74
- */
75
- private skipAuthenticate = false;
76
-
77
73
  /**
78
74
  * Used to avoid infinite loop.
79
75
  */
@@ -98,7 +94,6 @@ export default class Tilmeld implements TilmeldInterface {
98
94
  tilmeld.request = this.request;
99
95
  tilmeld.response = this.response;
100
96
  tilmeld.currentUser = this.currentUser;
101
- tilmeld.skipAuthenticate = true;
102
97
 
103
98
  return tilmeld;
104
99
  }
@@ -148,10 +143,6 @@ export default class Tilmeld implements TilmeldInterface {
148
143
 
149
144
  // Set up access control hooks when Nymph is called.
150
145
  this.initAccessControl();
151
- if (this.request != null && !this.skipAuthenticate) {
152
- this.authenticate();
153
- }
154
- this.skipAuthenticate = false;
155
146
  }
156
147
 
157
148
  /**
@@ -163,11 +154,11 @@ export default class Tilmeld implements TilmeldInterface {
163
154
  * @param ability The ability.
164
155
  * @returns Whether the user has the given ability.
165
156
  */
166
- public gatekeeper(ability?: string): boolean {
157
+ public async gatekeeper(ability?: string): Promise<boolean> {
167
158
  if (this.currentUser == null) {
168
159
  return false;
169
160
  }
170
- return this.currentUser.$gatekeeper(ability);
161
+ return await this.currentUser.$gatekeeper(ability);
171
162
  }
172
163
 
173
164
  private initAccessControl() {
@@ -186,7 +177,9 @@ export default class Tilmeld implements TilmeldInterface {
186
177
  ) {
187
178
  if (options?.source === 'client') {
188
179
  if (
189
- !tilmeld.gatekeeper('tilmeld/admin') && // The user is not an admin.
180
+ (!tilmeld.currentUser ||
181
+ (!tilmeld.currentUser.abilities?.includes('tilmeld/admin') &&
182
+ !tilmeld.currentUser.abilities?.includes('system/admin'))) && // The user is not an admin.
190
183
  ((!tilmeld.config.enableUserSearch &&
191
184
  options.class?.factorySync() instanceof User) || // The use is searching for a user and searching is disabled.
192
185
  (!tilmeld.config.enableGroupSearch &&
@@ -237,7 +230,7 @@ export default class Tilmeld implements TilmeldInterface {
237
230
  guid: string,
238
231
  className?: string
239
232
  ) {
240
- const entity = nymph.driver.getEntitySync(
233
+ const entity = await nymph.getEntity(
241
234
  { class: nymph.getEntityClass(className ?? 'Entity') },
242
235
  { type: '&', guid: guid }
243
236
  );
@@ -269,35 +262,9 @@ export default class Tilmeld implements TilmeldInterface {
269
262
  // allowing a change to ac properties.
270
263
 
271
264
  const originalAc = entity.$getOriginalAcValues();
272
- const newAc: AccessControlData = {
273
- user: entity.user ?? undefined,
274
- group: entity.group ?? undefined,
275
- acUser: entity.acUser ?? undefined,
276
- acGroup: entity.acGroup ?? undefined,
277
- acOther: entity.acOther ?? undefined,
278
- acRead: entity.acRead ?? undefined,
279
- acWrite: entity.acWrite ?? undefined,
280
- acFull: entity.acFull ?? undefined,
281
- };
265
+ const newAc = entity.$getCurrentAcValues();
282
266
 
283
- const setAcProperties = (acValues: { [k: string]: any }) => {
284
- for (let name in acValues) {
285
- const value = acValues[name];
286
- if (value == null) {
287
- delete entity[name];
288
- } else {
289
- entity[name] = value;
290
- }
291
- }
292
- };
293
-
294
- // Restore original AC properties and check permissions.
295
- setAcProperties(originalAc);
296
-
297
- function areAcPropertiesChanged(
298
- a: AccessControlData,
299
- b: AccessControlData
300
- ) {
267
+ function areAcPropertiesChanged(a: ACProperties, b: ACProperties) {
301
268
  for (const name of ['user', 'group'] as ('user' | 'group')[]) {
302
269
  const aVal = a[name];
303
270
  const bVal = b[name];
@@ -306,7 +273,7 @@ export default class Tilmeld implements TilmeldInterface {
306
273
  } else if (aVal == null || bVal == null) {
307
274
  return true;
308
275
  }
309
- if (!aVal.$is(bVal)) {
276
+ if (aVal !== bVal) {
310
277
  return true;
311
278
  }
312
279
  }
@@ -341,12 +308,7 @@ export default class Tilmeld implements TilmeldInterface {
341
308
  if (aVal.length !== bVal.length) {
342
309
  return true;
343
310
  }
344
- if (
345
- xor(
346
- aVal.map((entity) => entity.guid),
347
- bVal.map((entity) => entity.guid)
348
- ).length
349
- ) {
311
+ if (xor(aVal, bVal).length) {
350
312
  return true;
351
313
  }
352
314
  }
@@ -355,7 +317,12 @@ export default class Tilmeld implements TilmeldInterface {
355
317
 
356
318
  if (areAcPropertiesChanged(originalAc, newAc)) {
357
319
  if (
358
- !tilmeld.checkPermissions(entity, TilmeldAccessLevels.FULL_ACCESS)
320
+ !tilmeld.checkPermissions(
321
+ entity,
322
+ TilmeldAccessLevels.FULL_ACCESS,
323
+ undefined,
324
+ originalAc
325
+ )
359
326
  ) {
360
327
  // Only allow changes to AC properties if the user has full access.
361
328
  throw new AccessControlError(
@@ -364,10 +331,10 @@ export default class Tilmeld implements TilmeldInterface {
364
331
  }
365
332
 
366
333
  if (
367
- (originalAc.user && !originalAc.user.$is(newAc.user)) ||
334
+ (originalAc.user && originalAc.user !== newAc.user) ||
368
335
  (!originalAc.user &&
369
336
  newAc.user &&
370
- !newAc.user.$is(tilmeld.currentUser))
337
+ newAc.user !== tilmeld.currentUser)
371
338
  ) {
372
339
  throw new AccessControlError(
373
340
  'No permission to assign to another user.'
@@ -376,18 +343,15 @@ export default class Tilmeld implements TilmeldInterface {
376
343
 
377
344
  if (
378
345
  newAc.group &&
379
- !newAc.group.$is(originalAc.group) &&
380
- !(
381
- newAc.group.$is(tilmeld.currentUser?.group) ||
382
- newAc.group.$inArray(tilmeld.currentUser?.groups ?? [])
383
- )
346
+ newAc.group !== originalAc.group &&
347
+ !(newAc.group =
348
+ tilmeld.currentUser?.$getGid() ||
349
+ (tilmeld.currentUser?.$getGids() ?? []).includes(newAc.group))
384
350
  ) {
385
351
  throw new AccessControlError(
386
352
  'No permission to assign to another group.'
387
353
  );
388
354
  }
389
-
390
- setAcProperties(newAc);
391
355
  }
392
356
  }
393
357
 
@@ -429,12 +393,11 @@ export default class Tilmeld implements TilmeldInterface {
429
393
  if (entity.user == null) {
430
394
  entity.user = user;
431
395
  }
432
- if (
433
- entity.group == null &&
434
- user.group != null &&
435
- user.group.guid != null
436
- ) {
437
- entity.group = user.group;
396
+ if (entity.group == null) {
397
+ const group = user.group;
398
+ if (group != null && group.guid != null) {
399
+ entity.group = group;
400
+ }
438
401
  }
439
402
  if (entity.acUser == null) {
440
403
  entity.acUser = TilmeldAccessLevels.FULL_ACCESS;
@@ -589,33 +552,23 @@ export default class Tilmeld implements TilmeldInterface {
589
552
  ];
590
553
  const groupRefs: FormattedSelector['ref'] = [];
591
554
  const acRefs: FormattedSelector['ref'] = [];
592
- if (user.group != null && user.group.guid != null) {
555
+ const gid = user.$getGid();
556
+ if (gid != null) {
593
557
  // It belongs to the user's primary group.
594
- groupRefs.push(['group', user.group.guid]);
558
+ groupRefs.push(['group', gid]);
595
559
  // User's primary group is listed in acRead, acWrite, or acFull.
596
- acRefs.push(['acRead', user.group.guid]);
597
- acRefs.push(['acWrite', user.group.guid]);
598
- acRefs.push(['acFull', user.group.guid]);
560
+ acRefs.push(['acRead', gid]);
561
+ acRefs.push(['acWrite', gid]);
562
+ acRefs.push(['acFull', gid]);
599
563
  }
600
- for (let curSecondaryGroup of user.groups ?? []) {
601
- if (curSecondaryGroup != null && curSecondaryGroup.guid != null) {
602
- // It belongs to the user's secondary group.
603
- groupRefs.push(['group', curSecondaryGroup.guid]);
604
- // User's secondary group is listed in acRead, acWrite, or acFull.
605
- acRefs.push(['acRead', curSecondaryGroup.guid]);
606
- acRefs.push(['acWrite', curSecondaryGroup.guid]);
607
- acRefs.push(['acFull', curSecondaryGroup.guid]);
608
- }
609
- }
610
- for (let curDescendantGroup of user.$getDescendantGroupsSync()) {
611
- if (curDescendantGroup != null && curDescendantGroup.guid != null) {
612
- // It belongs to the user's secondary group.
613
- groupRefs.push(['group', curDescendantGroup.guid]);
614
- // User's secondary group is listed in acRead, acWrite, or acFull.
615
- acRefs.push(['acRead', curDescendantGroup.guid]);
616
- acRefs.push(['acWrite', curDescendantGroup.guid]);
617
- acRefs.push(['acFull', curDescendantGroup.guid]);
618
- }
564
+ const gids = user.$getGids();
565
+ for (let curGid of gids ?? []) {
566
+ // It belongs to the user's secondary group.
567
+ groupRefs.push(['group', curGid]);
568
+ // User's secondary group is listed in acRead, acWrite, or acFull.
569
+ acRefs.push(['acRead', curGid]);
570
+ acRefs.push(['acWrite', curGid]);
571
+ acRefs.push(['acFull', curGid]);
619
572
  }
620
573
  // All the group refs.
621
574
  if (groupRefs.length) {
@@ -714,16 +667,17 @@ export default class Tilmeld implements TilmeldInterface {
714
667
  * @param entity The entity to check.
715
668
  * @param type The lowest level of permission to consider a pass.
716
669
  * @param user The user to check permissions for. If null, uses the current user. If false, checks for public access.
670
+ * @param acProperties The acProperties to use instead of getting them from the entity.
717
671
  * @returns Whether the current user has at least `type` permission for the entity.
718
672
  */
719
673
  public checkPermissions(
720
- entity: EntityInterface & AccessControlData,
674
+ entity: EntityInterface,
721
675
  type: TilmeldAccessLevels = TilmeldAccessLevels.READ_ACCESS,
722
- user?: (User & UserData) | false
676
+ user?: (User & UserData) | false,
677
+ acProperties?: ACProperties
723
678
  ) {
724
- // Only works for entities.
725
- if (typeof entity !== 'object' || typeof entity.$is !== 'function') {
726
- return false;
679
+ if (!acProperties) {
680
+ acProperties = entity.$getCurrentAcValues() as ACProperties;
727
681
  }
728
682
 
729
683
  let userOrNull: (User & UserData) | null = null;
@@ -748,9 +702,9 @@ export default class Tilmeld implements TilmeldInterface {
748
702
  }
749
703
 
750
704
  // Load access control, since we need it now...
751
- const acUser = entity.acUser ?? TilmeldAccessLevels.FULL_ACCESS;
752
- const acGroup = entity.acGroup ?? TilmeldAccessLevels.READ_ACCESS;
753
- const acOther = entity.acOther ?? TilmeldAccessLevels.NO_ACCESS;
705
+ const acUser = acProperties.acUser ?? TilmeldAccessLevels.FULL_ACCESS;
706
+ const acGroup = acProperties.acGroup ?? TilmeldAccessLevels.READ_ACCESS;
707
+ const acOther = acProperties.acOther ?? TilmeldAccessLevels.NO_ACCESS;
754
708
 
755
709
  if (userOrNull == null) {
756
710
  return acOther >= type;
@@ -762,45 +716,41 @@ export default class Tilmeld implements TilmeldInterface {
762
716
  }
763
717
 
764
718
  // Check if the entity is the user's group. Always readable.
719
+ const gid = userOrEmpty.$getGid();
765
720
  if (
766
- userOrEmpty.group != null &&
767
- typeof userOrEmpty.group.$is === 'function' &&
768
- userOrEmpty.group.$is(entity) &&
721
+ gid != null &&
722
+ entity.guid === gid &&
769
723
  type === TilmeldAccessLevels.READ_ACCESS
770
724
  ) {
771
725
  return true;
772
726
  }
773
727
 
774
728
  // Calculate all the groups the user belongs to.
775
- let allGroups = userOrEmpty.group == null ? [] : [userOrEmpty.group];
776
- allGroups = allGroups.concat(userOrEmpty.groups ?? []);
777
- allGroups = allGroups.concat(userOrEmpty.$getDescendantGroupsSync());
729
+ let allGids = gid == null ? [] : [gid];
730
+ allGids = allGids.concat(userOrEmpty.$getGids() ?? []);
778
731
 
779
732
  // Check access ac properties.
780
733
  const checks = [
781
734
  {
782
735
  type: TilmeldAccessLevels.FULL_ACCESS,
783
- array: [...(entity.acFull ?? [])],
736
+ array: [...(acProperties.acFull ?? [])],
784
737
  },
785
738
  {
786
739
  type: TilmeldAccessLevels.WRITE_ACCESS,
787
- array: [...(entity.acWrite ?? [])],
740
+ array: [...(acProperties.acWrite ?? [])],
788
741
  },
789
742
  {
790
743
  type: TilmeldAccessLevels.READ_ACCESS,
791
- array: [...(entity.acRead ?? [])],
744
+ array: [...(acProperties.acRead ?? [])],
792
745
  },
793
746
  ];
794
747
  for (let curCheck of checks) {
795
748
  if (type <= curCheck.type) {
796
- if (userOrEmpty.$inArray(curCheck.array)) {
749
+ if (curCheck.array.includes(userOrEmpty.guid)) {
797
750
  return true;
798
751
  }
799
- for (let curGroup of allGroups) {
800
- if (
801
- typeof curGroup.$inArray === 'function' &&
802
- curGroup.$inArray(curCheck.array)
803
- ) {
752
+ for (let curGid of allGids) {
753
+ if (curCheck.array.includes(curGid)) {
804
754
  return true;
805
755
  }
806
756
  }
@@ -808,18 +758,10 @@ export default class Tilmeld implements TilmeldInterface {
808
758
  }
809
759
 
810
760
  // Check ownership ac properties.
811
- if (
812
- entity.user != null &&
813
- typeof entity.user.$is === 'function' &&
814
- entity.user.$is(userOrNull)
815
- ) {
761
+ if (acProperties.user != null && acProperties.user === userOrNull.guid) {
816
762
  return acUser >= type;
817
763
  }
818
- if (
819
- entity.group != null &&
820
- typeof entity.group.$inArray === 'function' &&
821
- entity.group.$inArray(allGroups)
822
- ) {
764
+ if (acProperties.group != null && allGids.includes(acProperties.group)) {
823
765
  return acGroup >= type;
824
766
  }
825
767
  return acOther >= type;
@@ -849,7 +791,7 @@ export default class Tilmeld implements TilmeldInterface {
849
791
  * @param user The user to check permissions for. If null, uses the current user. If false, checks for public access.
850
792
  * @returns Whether the current user has at least `type` permission for the UID.
851
793
  */
852
- public checkClientUIDPermissions(
794
+ public async checkClientUIDPermissions(
853
795
  name: string,
854
796
  type: TilmeldAccessLevels = TilmeldAccessLevels.READ_ACCESS,
855
797
  user?: (User & UserData) | false
@@ -869,23 +811,23 @@ export default class Tilmeld implements TilmeldInterface {
869
811
  if (type === TilmeldAccessLevels.FULL_ACCESS) {
870
812
  return (
871
813
  this.config.clientSetabledUIDs.indexOf(name) !== -1 ||
872
- userOrEmpty.$gatekeeper(`uid/set/${name}`)
814
+ (await userOrEmpty.$gatekeeper(`uid/set/${name}`))
873
815
  );
874
816
  } else if (type === TilmeldAccessLevels.WRITE_ACCESS) {
875
817
  return (
876
818
  this.config.clientEnabledUIDs.indexOf(name) !== -1 ||
877
819
  this.config.clientSetabledUIDs.indexOf(name) !== -1 ||
878
- userOrEmpty.$gatekeeper(`uid/new/${name}`) ||
879
- userOrEmpty.$gatekeeper(`uid/set/${name}`)
820
+ (await userOrEmpty.$gatekeeper(`uid/new/${name}`)) ||
821
+ (await userOrEmpty.$gatekeeper(`uid/set/${name}`))
880
822
  );
881
823
  } else if (type === TilmeldAccessLevels.READ_ACCESS) {
882
824
  return (
883
825
  this.config.clientReadableUIDs.indexOf(name) !== -1 ||
884
826
  this.config.clientEnabledUIDs.indexOf(name) !== -1 ||
885
827
  this.config.clientSetabledUIDs.indexOf(name) !== -1 ||
886
- userOrEmpty.$gatekeeper(`uid/get/${name}`) ||
887
- userOrEmpty.$gatekeeper(`uid/new/${name}`) ||
888
- userOrEmpty.$gatekeeper(`uid/set/${name}`)
828
+ (await userOrEmpty.$gatekeeper(`uid/get/${name}`)) ||
829
+ (await userOrEmpty.$gatekeeper(`uid/new/${name}`)) ||
830
+ (await userOrEmpty.$gatekeeper(`uid/set/${name}`))
889
831
  );
890
832
  }
891
833
 
@@ -898,19 +840,10 @@ export default class Tilmeld implements TilmeldInterface {
898
840
  * @param user The user.
899
841
  */
900
842
  public fillSession(user: User & UserData) {
901
- // Read groups right now, since gatekeeper needs them, so
902
- // $udpateDataProtection will fail to read them (since it runs gatekeeper).
903
- const _group = user.group;
904
- const _groups = user.groups;
905
843
  this.currentUser = user;
906
844
  // Now update the data protection on the user and all the groups.
907
845
  this.currentUser.$updateDataProtection();
908
- if (this.currentUser.group != null) {
909
- this.currentUser.group.$updateDataProtection();
910
- }
911
- for (let group of this.currentUser.groups ?? []) {
912
- group.$updateDataProtection();
913
- }
846
+ this.currentUser.$updateGroupDataProtection();
914
847
  }
915
848
 
916
849
  /**
@@ -921,12 +854,7 @@ export default class Tilmeld implements TilmeldInterface {
921
854
  this.currentUser = null;
922
855
  if (user) {
923
856
  user.$updateDataProtection();
924
- if (user.group != null) {
925
- user.group.$updateDataProtection();
926
- }
927
- for (let group of user.groups ?? []) {
928
- group.$updateDataProtection();
929
- }
857
+ user.$updateGroupDataProtection();
930
858
  }
931
859
  }
932
860
 
@@ -973,7 +901,7 @@ export default class Tilmeld implements TilmeldInterface {
973
901
  * @param skipXsrfToken Skip the XSRF token check.
974
902
  * @returns True if a user was authenticated, false on any failure.
975
903
  */
976
- public authenticate(skipXsrfToken = false) {
904
+ public async authenticate(skipXsrfToken = false) {
977
905
  if (this.request == null) {
978
906
  return false;
979
907
  }
@@ -1039,7 +967,7 @@ export default class Tilmeld implements TilmeldInterface {
1039
967
  }
1040
968
 
1041
969
  if (authExtract == null) {
1042
- this.logout();
970
+ await this.logout();
1043
971
  return false;
1044
972
  }
1045
973
  const { guid, issued, expire } = authExtract;
@@ -1048,7 +976,7 @@ export default class Tilmeld implements TilmeldInterface {
1048
976
  expire: null,
1049
977
  };
1050
978
 
1051
- const user = this.User.factorySync(guid);
979
+ const user = await this.User.factory(guid);
1052
980
  if (
1053
981
  user.guid == null ||
1054
982
  !user.enabled ||
@@ -1056,15 +984,15 @@ export default class Tilmeld implements TilmeldInterface {
1056
984
  issued.getTime() > Date.now() ||
1057
985
  (user.revokeTokenDate != null && issued.getTime() <= user.revokeTokenDate)
1058
986
  ) {
1059
- this.logout();
987
+ await this.logout();
1060
988
  return false;
1061
989
  }
1062
990
 
1063
991
  if (switchGuid && switchExpire && switchExpire.getTime() > Date.now()) {
1064
992
  // Load the switch user.
1065
- const switchUser = this.User.factorySync(switchGuid);
993
+ const switchUser = await this.User.factory(switchGuid);
1066
994
  if (switchUser.guid == null) {
1067
- this.logoutSwitch();
995
+ await this.logoutSwitch();
1068
996
  } else {
1069
997
  this.fillSession(switchUser);
1070
998
 
@@ -1186,13 +1114,13 @@ export default class Tilmeld implements TilmeldInterface {
1186
1114
  *
1187
1115
  * @param clearCookie Clear the auth cookie. (Also send a header.)
1188
1116
  */
1189
- public logout(clearCookie = true) {
1117
+ public async logout(clearCookie = true) {
1190
1118
  if (this.request && !this.alreadyLoggedOutSwitch) {
1191
1119
  const cookies = this.request.cookies ?? {};
1192
1120
 
1193
1121
  if ('TILMELDSWITCH' in cookies) {
1194
1122
  this.alreadyLoggedOutSwitch = true;
1195
- return this.logoutSwitch(clearCookie);
1123
+ return await this.logoutSwitch(clearCookie);
1196
1124
  }
1197
1125
  }
1198
1126
 
@@ -1214,7 +1142,7 @@ export default class Tilmeld implements TilmeldInterface {
1214
1142
  *
1215
1143
  * @param clearCookie Clear the auth cookie. (Also send a header.)
1216
1144
  */
1217
- public logoutSwitch(clearCookie = true) {
1145
+ public async logoutSwitch(clearCookie = true) {
1218
1146
  this.clearSession();
1219
1147
  if (this.response) {
1220
1148
  if (clearCookie && !this.response.headersSent) {
@@ -1226,7 +1154,7 @@ export default class Tilmeld implements TilmeldInterface {
1226
1154
  }
1227
1155
  this.response.locals.user = null;
1228
1156
 
1229
- this.authenticate();
1157
+ await this.authenticate();
1230
1158
  }
1231
1159
  }
1232
1160