@nymphjs/tilmeld 1.0.0-beta.5 → 1.0.0-beta.50

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/dist/Tilmeld.js CHANGED
@@ -10,6 +10,7 @@ const conf_1 = require("./conf");
10
10
  const errors_1 = require("./errors");
11
11
  const Group_1 = __importDefault(require("./Group"));
12
12
  const User_1 = __importDefault(require("./User"));
13
+ const enforceTilmeld_1 = require("./enforceTilmeld");
13
14
  class Tilmeld {
14
15
  constructor(config) {
15
16
  this.nymph = {};
@@ -18,7 +19,8 @@ class Tilmeld {
18
19
  this.Group = Group_1.default;
19
20
  this.request = null;
20
21
  this.response = null;
21
- this.skipAuthenticate = false;
22
+ this.alreadyLoggedOutSwitch = false;
23
+ this.gatekeeperCache = null;
22
24
  this.config = { ...conf_1.ConfigDefaults, ...config };
23
25
  }
24
26
  clone() {
@@ -26,7 +28,7 @@ class Tilmeld {
26
28
  tilmeld.request = this.request;
27
29
  tilmeld.response = this.response;
28
30
  tilmeld.currentUser = this.currentUser;
29
- tilmeld.skipAuthenticate = true;
31
+ tilmeld.gatekeeperCache = this.gatekeeperCache;
30
32
  return tilmeld;
31
33
  }
32
34
  init(nymph) {
@@ -34,41 +36,54 @@ class Tilmeld {
34
36
  if (this.nymph.driver == null) {
35
37
  throw new Error("Tilmeld can't be configured before Nymph.");
36
38
  }
37
- class NymphUser extends User_1.default {
39
+ if (nymph.parent) {
40
+ this.User = this.nymph.getEntityClass(User_1.default);
41
+ this.Group = this.nymph.getEntityClass(Group_1.default);
38
42
  }
39
- NymphUser.nymph = this.nymph;
40
- NymphUser.tilmeld = this;
41
- NymphUser.skipOnClone = true;
42
- this.User = NymphUser;
43
- this.nymph.addEntityClass(NymphUser);
44
- class NymphGroup extends Group_1.default {
43
+ else {
44
+ this.User = this.nymph.addEntityClass(User_1.default);
45
+ this.Group = this.nymph.addEntityClass(Group_1.default);
46
+ }
47
+ if (this.currentUser) {
48
+ const currentUserGUID = this.currentUser.guid;
49
+ const currentUserCDate = this.currentUser.cdate;
50
+ const currentUserMDate = this.currentUser.mdate;
51
+ const currentUserTags = this.currentUser.tags;
52
+ const currentUserData = this.currentUser.$getData();
53
+ const currentUserSData = this.currentUser.$getSData();
54
+ const user = this.User.factorySync();
55
+ user.guid = currentUserGUID;
56
+ user.cdate = currentUserCDate;
57
+ user.mdate = currentUserMDate;
58
+ user.tags = currentUserTags;
59
+ user.$putData(currentUserData, currentUserSData);
60
+ this.currentUser = user;
61
+ this.currentUser.$updateDataProtection();
62
+ this.currentUser.$updateGroupDataProtection();
45
63
  }
46
- NymphGroup.nymph = this.nymph;
47
- NymphGroup.tilmeld = this;
48
- NymphUser.skipOnClone = true;
49
- this.Group = NymphGroup;
50
- this.nymph.addEntityClass(NymphGroup);
51
64
  this.initAccessControl();
52
- if (this.request != null && !this.skipAuthenticate) {
53
- this.authenticate();
54
- }
55
- this.skipAuthenticate = false;
56
65
  }
57
66
  gatekeeper(ability) {
58
- if (this.currentUser == null) {
67
+ if (this.currentUser == null || this.gatekeeperCache == null) {
59
68
  return false;
60
69
  }
61
- return this.currentUser.$gatekeeper(ability);
70
+ if (ability == null) {
71
+ return true;
72
+ }
73
+ return ((ability in this.gatekeeperCache && !!this.gatekeeperCache[ability]) ||
74
+ !!this.currentUser.abilities?.includes('system/admin'));
62
75
  }
63
76
  initAccessControl() {
64
77
  const handleQuery = function (nymph, options, selectors) {
65
- const tilmeld = nymph.tilmeld;
78
+ const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(nymph);
66
79
  if (!options ||
67
80
  !('skipAc' in options) ||
68
81
  !options.skipAc ||
69
82
  options.source === 'client') {
70
83
  if (options?.source === 'client') {
71
- if (!tilmeld.gatekeeper('tilmeld/admin') &&
84
+ if ((!tilmeld.currentUser ||
85
+ (!tilmeld.currentUser.abilities?.includes('tilmeld/admin') &&
86
+ !tilmeld.currentUser.abilities?.includes('system/admin'))) &&
72
87
  ((!tilmeld.config.enableUserSearch &&
73
88
  options.class?.factorySync() instanceof User_1.default) ||
74
89
  (!tilmeld.config.enableGroupSearch &&
@@ -90,7 +105,7 @@ class Tilmeld {
90
105
  };
91
106
  handleQuery.skipOnClone = true;
92
107
  const checkPermissionsDelete = async function (nymph, entity) {
93
- const tilmeld = nymph.tilmeld;
108
+ const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(nymph);
94
109
  if (typeof entity.$tilmeldDeleteSkipAC === 'function' &&
95
110
  entity.$tilmeldDeleteSkipAC()) {
96
111
  return;
@@ -101,14 +116,14 @@ class Tilmeld {
101
116
  };
102
117
  checkPermissionsDelete.skipOnClone = true;
103
118
  const checkPermissionsDeleteByID = async function (nymph, guid, className) {
104
- const entity = nymph.driver.getEntitySync({ class: nymph.getEntityClass(className ?? 'Entity') }, { type: '&', guid: guid });
119
+ const entity = await nymph.getEntity({ class: nymph.getEntityClass(className ?? 'Entity') }, { type: '&', guid: guid });
105
120
  if (entity != null) {
106
121
  checkPermissionsDelete(nymph, entity);
107
122
  }
108
123
  };
109
124
  checkPermissionsDeleteByID.skipOnClone = true;
110
125
  const checkPermissionsSaveAndFilterAcChanges = async function (nymph, entity) {
111
- const tilmeld = nymph.tilmeld;
126
+ const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(nymph);
112
127
  if (!entity) {
113
128
  return;
114
129
  }
@@ -118,28 +133,7 @@ class Tilmeld {
118
133
  }
119
134
  if (entity.guid != null) {
120
135
  const originalAc = entity.$getOriginalAcValues();
121
- const newAc = {
122
- user: entity.user ?? undefined,
123
- group: entity.group ?? undefined,
124
- acUser: entity.acUser ?? undefined,
125
- acGroup: entity.acGroup ?? undefined,
126
- acOther: entity.acOther ?? undefined,
127
- acRead: entity.acRead ?? undefined,
128
- acWrite: entity.acWrite ?? undefined,
129
- acFull: entity.acFull ?? undefined,
130
- };
131
- const setAcProperties = (acValues) => {
132
- for (let name in acValues) {
133
- const value = acValues[name];
134
- if (value == null) {
135
- delete entity[name];
136
- }
137
- else {
138
- entity[name] = value;
139
- }
140
- }
141
- };
142
- setAcProperties(originalAc);
136
+ const newAc = entity.$getCurrentAcValues();
143
137
  function areAcPropertiesChanged(a, b) {
144
138
  for (const name of ['user', 'group']) {
145
139
  const aVal = a[name];
@@ -150,7 +144,7 @@ class Tilmeld {
150
144
  else if (aVal == null || bVal == null) {
151
145
  return true;
152
146
  }
153
- if (!aVal.$is(bVal)) {
147
+ if (aVal !== bVal) {
154
148
  return true;
155
149
  }
156
150
  }
@@ -179,31 +173,29 @@ class Tilmeld {
179
173
  if (aVal.length !== bVal.length) {
180
174
  return true;
181
175
  }
182
- if ((0, lodash_1.xor)(aVal.map((entity) => entity.guid), bVal.map((entity) => entity.guid)).length) {
176
+ if ((0, lodash_1.xor)(aVal, bVal).length) {
183
177
  return true;
184
178
  }
185
179
  }
186
180
  return false;
187
181
  }
188
182
  if (areAcPropertiesChanged(originalAc, newAc)) {
189
- if (!tilmeld.checkPermissions(entity, nymph_1.TilmeldAccessLevels.FULL_ACCESS)) {
183
+ if (!tilmeld.checkPermissions(entity, nymph_1.TilmeldAccessLevels.FULL_ACCESS, undefined, originalAc)) {
190
184
  throw new errors_1.AccessControlError('No permission to change access control properties.');
191
185
  }
192
- if (((originalAc.user && !originalAc.user.$is(newAc.user)) ||
186
+ if ((originalAc.user && originalAc.user !== newAc.user) ||
193
187
  (!originalAc.user &&
194
188
  newAc.user &&
195
- !newAc.user.$is(tilmeld.currentUser))) &&
196
- !tilmeld.gatekeeper('tilmeld/admin')) {
189
+ newAc.user !== tilmeld.currentUser)) {
197
190
  throw new errors_1.AccessControlError('No permission to assign to another user.');
198
191
  }
199
192
  if (newAc.group &&
200
- !newAc.group.$is(originalAc.group) &&
201
- !(newAc.group.$is(tilmeld.currentUser?.group) ||
202
- newAc.group.$inArray(tilmeld.currentUser?.groups ?? [])) &&
203
- !tilmeld.gatekeeper('tilmeld/admin')) {
193
+ newAc.group !== originalAc.group &&
194
+ !(newAc.group =
195
+ tilmeld.currentUser?.$getGid() ||
196
+ (tilmeld.currentUser?.$getGids() ?? []).includes(newAc.group))) {
204
197
  throw new errors_1.AccessControlError('No permission to assign to another group.');
205
198
  }
206
- setAcProperties(newAc);
207
199
  }
208
200
  }
209
201
  if (!tilmeld.checkPermissions(entity, nymph_1.TilmeldAccessLevels.WRITE_ACCESS)) {
@@ -212,7 +204,7 @@ class Tilmeld {
212
204
  };
213
205
  checkPermissionsSaveAndFilterAcChanges.skipOnClone = true;
214
206
  const addAccess = async function (nymph, entity) {
215
- const tilmeld = nymph.tilmeld;
207
+ const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(nymph);
216
208
  const user = tilmeld.currentUser;
217
209
  if (user != null &&
218
210
  entity.guid == null &&
@@ -221,10 +213,11 @@ class Tilmeld {
221
213
  if (entity.user == null) {
222
214
  entity.user = user;
223
215
  }
224
- if (entity.group == null &&
225
- user.group != null &&
226
- user.group.guid != null) {
227
- entity.group = user.group;
216
+ if (entity.group == null) {
217
+ const group = user.group;
218
+ if (group != null && group.guid != null) {
219
+ entity.group = group;
220
+ }
228
221
  }
229
222
  if (entity.acUser == null) {
230
223
  entity.acUser = nymph_1.TilmeldAccessLevels.FULL_ACCESS;
@@ -306,10 +299,6 @@ class Tilmeld {
306
299
  }
307
300
  addAccessControlSelectors(options, selectors) {
308
301
  const user = this.currentUser;
309
- if (user != null &&
310
- (user.abilities?.indexOf('system/admin') ?? -1) !== -1) {
311
- return;
312
- }
313
302
  if (options == null) {
314
303
  throw new Error('No options in argument.');
315
304
  }
@@ -344,27 +333,19 @@ class Tilmeld {
344
333
  ];
345
334
  const groupRefs = [];
346
335
  const acRefs = [];
347
- if (user.group != null && user.group.guid != null) {
348
- groupRefs.push(['group', user.group.guid]);
349
- acRefs.push(['acRead', user.group.guid]);
350
- acRefs.push(['acWrite', user.group.guid]);
351
- acRefs.push(['acFull', user.group.guid]);
352
- }
353
- for (let curSecondaryGroup of user.groups ?? []) {
354
- if (curSecondaryGroup != null && curSecondaryGroup.guid != null) {
355
- groupRefs.push(['group', curSecondaryGroup.guid]);
356
- acRefs.push(['acRead', curSecondaryGroup.guid]);
357
- acRefs.push(['acWrite', curSecondaryGroup.guid]);
358
- acRefs.push(['acFull', curSecondaryGroup.guid]);
359
- }
336
+ const gid = user.$getGid();
337
+ if (gid != null) {
338
+ groupRefs.push(['group', gid]);
339
+ acRefs.push(['acRead', gid]);
340
+ acRefs.push(['acWrite', gid]);
341
+ acRefs.push(['acFull', gid]);
360
342
  }
361
- for (let curDescendantGroup of user.$getDescendantGroupsSync()) {
362
- if (curDescendantGroup != null && curDescendantGroup.guid != null) {
363
- groupRefs.push(['group', curDescendantGroup.guid]);
364
- acRefs.push(['acRead', curDescendantGroup.guid]);
365
- acRefs.push(['acWrite', curDescendantGroup.guid]);
366
- acRefs.push(['acFull', curDescendantGroup.guid]);
367
- }
343
+ const gids = user.$getGids();
344
+ for (let curGid of gids ?? []) {
345
+ groupRefs.push(['group', curGid]);
346
+ acRefs.push(['acRead', curGid]);
347
+ acRefs.push(['acWrite', curGid]);
348
+ acRefs.push(['acFull', curGid]);
368
349
  }
369
350
  if (groupRefs.length) {
370
351
  subSelectors.push({
@@ -397,9 +378,9 @@ class Tilmeld {
397
378
  selectors.push(selector);
398
379
  }
399
380
  }
400
- checkPermissions(entity, type = nymph_1.TilmeldAccessLevels.READ_ACCESS, user) {
401
- if (typeof entity !== 'object' || typeof entity.$is !== 'function') {
402
- return false;
381
+ checkPermissions(entity, type = nymph_1.TilmeldAccessLevels.READ_ACCESS, user, acProperties) {
382
+ if (!acProperties) {
383
+ acProperties = entity.$getCurrentAcValues();
403
384
  }
404
385
  let userOrNull = null;
405
386
  let userOrEmpty = this.User.factorySync();
@@ -411,75 +392,64 @@ class Tilmeld {
411
392
  userOrNull = user;
412
393
  userOrEmpty = user;
413
394
  }
414
- if (userOrEmpty.$gatekeeper('system/admin')) {
415
- return true;
416
- }
417
395
  if ((entity instanceof User_1.default || entity instanceof Group_1.default) &&
418
396
  (type === nymph_1.TilmeldAccessLevels.READ_ACCESS ||
419
- userOrEmpty.$gatekeeper('tilmeld/admin'))) {
420
- return true;
421
- }
422
- if (entity.user == null && entity.group == null) {
397
+ userOrEmpty.abilities?.includes('tilmeld/admin') ||
398
+ userOrEmpty.abilities?.includes('system/admin'))) {
423
399
  return true;
424
400
  }
425
- const acUser = entity.acUser ?? nymph_1.TilmeldAccessLevels.FULL_ACCESS;
426
- const acGroup = entity.acGroup ?? nymph_1.TilmeldAccessLevels.READ_ACCESS;
427
- const acOther = entity.acOther ?? nymph_1.TilmeldAccessLevels.NO_ACCESS;
428
- if (userOrNull === null) {
401
+ const acUser = acProperties.acUser ?? nymph_1.TilmeldAccessLevels.FULL_ACCESS;
402
+ const acGroup = acProperties.acGroup ?? nymph_1.TilmeldAccessLevels.READ_ACCESS;
403
+ const acOther = acProperties.acOther ?? nymph_1.TilmeldAccessLevels.NO_ACCESS;
404
+ if (userOrNull == null) {
429
405
  return acOther >= type;
430
406
  }
431
407
  if (userOrEmpty.$is(entity)) {
432
408
  return true;
433
409
  }
434
- if (userOrEmpty.group != null &&
435
- typeof userOrEmpty.group.$is === 'function' &&
436
- userOrEmpty.group.$is(entity) &&
410
+ const gid = userOrEmpty.$getGid();
411
+ if (gid != null &&
412
+ entity.guid === gid &&
437
413
  type === nymph_1.TilmeldAccessLevels.READ_ACCESS) {
438
414
  return true;
439
415
  }
440
- let allGroups = userOrEmpty.group == null ? [] : [userOrEmpty.group];
441
- allGroups = allGroups.concat(userOrEmpty.groups ?? []);
442
- allGroups = allGroups.concat(userOrEmpty.$getDescendantGroupsSync());
416
+ let allGids = gid == null ? [] : [gid];
417
+ allGids = allGids.concat(userOrEmpty.$getGids() ?? []);
443
418
  const checks = [
444
419
  {
445
420
  type: nymph_1.TilmeldAccessLevels.FULL_ACCESS,
446
- array: [...(entity.acFull ?? [])],
421
+ array: [...(acProperties.acFull ?? [])],
447
422
  },
448
423
  {
449
424
  type: nymph_1.TilmeldAccessLevels.WRITE_ACCESS,
450
- array: [...(entity.acWrite ?? [])],
425
+ array: [...(acProperties.acWrite ?? [])],
451
426
  },
452
427
  {
453
428
  type: nymph_1.TilmeldAccessLevels.READ_ACCESS,
454
- array: [...(entity.acRead ?? [])],
429
+ array: [...(acProperties.acRead ?? [])],
455
430
  },
456
431
  ];
457
432
  for (let curCheck of checks) {
458
433
  if (type <= curCheck.type) {
459
- if (userOrEmpty.$inArray(curCheck.array)) {
434
+ if (curCheck.array.includes(userOrEmpty.guid)) {
460
435
  return true;
461
436
  }
462
- for (let curGroup of allGroups) {
463
- if (typeof curGroup.$inArray === 'function' &&
464
- curGroup.$inArray(curCheck.array)) {
437
+ for (let curGid of allGids) {
438
+ if (curCheck.array.includes(curGid)) {
465
439
  return true;
466
440
  }
467
441
  }
468
442
  }
469
443
  }
470
- if (entity.user != null &&
471
- typeof entity.user.$is === 'function' &&
472
- entity.user.$is(userOrNull)) {
444
+ if (acProperties.user != null && acProperties.user === userOrNull.guid) {
473
445
  return acUser >= type;
474
446
  }
475
- if (entity.group != null &&
476
- typeof entity.group.$inArray === 'function' &&
477
- entity.group.$inArray(allGroups)) {
447
+ if (acProperties.group != null && allGids.includes(acProperties.group)) {
478
448
  return acGroup >= type;
479
449
  }
480
450
  return acOther >= type;
481
451
  }
482
- checkClientUIDPermissions(name, type = nymph_1.TilmeldAccessLevels.READ_ACCESS, user) {
452
+ async checkClientUIDPermissions(name, type = nymph_1.TilmeldAccessLevels.READ_ACCESS, user) {
483
453
  let userOrEmpty = this.User.factorySync();
484
454
  if (user == null) {
485
455
  userOrEmpty = this.User.current(true);
@@ -487,52 +457,42 @@ class Tilmeld {
487
457
  else if (user !== false) {
488
458
  userOrEmpty = user;
489
459
  }
490
- if (userOrEmpty.$gatekeeper('system/admin')) {
460
+ if (userOrEmpty.abilities?.includes('system/admin')) {
491
461
  return true;
492
462
  }
493
463
  if (type === nymph_1.TilmeldAccessLevels.FULL_ACCESS) {
494
464
  return (this.config.clientSetabledUIDs.indexOf(name) !== -1 ||
495
- userOrEmpty.$gatekeeper(`uid/set/${name}`));
465
+ (await userOrEmpty.$gatekeeper(`uid/set/${name}`)));
496
466
  }
497
467
  else if (type === nymph_1.TilmeldAccessLevels.WRITE_ACCESS) {
498
468
  return (this.config.clientEnabledUIDs.indexOf(name) !== -1 ||
499
469
  this.config.clientSetabledUIDs.indexOf(name) !== -1 ||
500
- userOrEmpty.$gatekeeper(`uid/new/${name}`) ||
501
- userOrEmpty.$gatekeeper(`uid/set/${name}`));
470
+ (await userOrEmpty.$gatekeeper(`uid/new/${name}`)) ||
471
+ (await userOrEmpty.$gatekeeper(`uid/set/${name}`)));
502
472
  }
503
473
  else if (type === nymph_1.TilmeldAccessLevels.READ_ACCESS) {
504
474
  return (this.config.clientReadableUIDs.indexOf(name) !== -1 ||
505
475
  this.config.clientEnabledUIDs.indexOf(name) !== -1 ||
506
476
  this.config.clientSetabledUIDs.indexOf(name) !== -1 ||
507
- userOrEmpty.$gatekeeper(`uid/get/${name}`) ||
508
- userOrEmpty.$gatekeeper(`uid/new/${name}`) ||
509
- userOrEmpty.$gatekeeper(`uid/set/${name}`));
477
+ (await userOrEmpty.$gatekeeper(`uid/get/${name}`)) ||
478
+ (await userOrEmpty.$gatekeeper(`uid/new/${name}`)) ||
479
+ (await userOrEmpty.$gatekeeper(`uid/set/${name}`)));
510
480
  }
511
481
  return false;
512
482
  }
513
- fillSession(user) {
514
- const _group = user.group;
515
- const _groups = user.groups;
483
+ async fillSession(user) {
516
484
  this.currentUser = user;
485
+ this.gatekeeperCache = await user.$getGatekeeperCache();
517
486
  this.currentUser.$updateDataProtection();
518
- if (this.currentUser.group != null) {
519
- this.currentUser.group.$updateDataProtection();
520
- }
521
- for (let group of this.currentUser.groups ?? []) {
522
- group.$updateDataProtection();
523
- }
487
+ this.currentUser.$updateGroupDataProtection();
524
488
  }
525
489
  clearSession() {
526
490
  const user = this.currentUser;
527
491
  this.currentUser = null;
492
+ this.gatekeeperCache = null;
528
493
  if (user) {
529
494
  user.$updateDataProtection();
530
- if (user.group != null) {
531
- user.group.$updateDataProtection();
532
- }
533
- for (let group of user.groups ?? []) {
534
- group.$updateDataProtection();
535
- }
495
+ user.$updateGroupDataProtection();
536
496
  }
537
497
  }
538
498
  async extractToken(token) {
@@ -545,89 +505,190 @@ class Tilmeld {
545
505
  type: '&',
546
506
  guid: guid,
547
507
  });
548
- if (!user || !user.guid || !user.enabled) {
508
+ if (!user || !user.guid) {
549
509
  return null;
550
510
  }
551
511
  return user;
552
512
  }
553
- authenticate(skipXsrfToken = false) {
513
+ async authenticate(skipXsrfToken = false) {
554
514
  if (this.request == null) {
555
515
  return false;
556
516
  }
517
+ if (this.response &&
518
+ this.response.locals.user &&
519
+ this.response.locals.user instanceof this.User) {
520
+ const user = this.response.locals.user;
521
+ await this.fillSession(user);
522
+ return true;
523
+ }
557
524
  const cookies = this.request.cookies ?? {};
558
525
  let fromAuthHeader = false;
559
526
  let authToken;
527
+ let switchToken;
560
528
  if (this.request.header('x-tilmeldauth') != null) {
561
529
  fromAuthHeader = true;
562
530
  authToken = this.request.header('x-tilmeldauth');
531
+ switchToken =
532
+ this.request.header('x-tilmeldswitch') ||
533
+ 'TILMELDSWITCH' in cookies
534
+ ? cookies.TILMELDSWITCH
535
+ : null;
563
536
  }
564
537
  else if ('TILMELDAUTH' in cookies) {
565
538
  fromAuthHeader = false;
566
539
  authToken = cookies.TILMELDAUTH;
540
+ switchToken = 'TILMELDSWITCH' in cookies ? cookies.TILMELDSWITCH : null;
567
541
  }
568
542
  else {
569
543
  return false;
570
544
  }
571
- let extract;
545
+ let authExtract;
546
+ let switchExtract;
572
547
  if (skipXsrfToken ||
573
548
  this.request.originalUrl.startsWith(this.config.setupPath)) {
574
- extract = this.config.jwtExtract(this.config, authToken);
549
+ authExtract = this.config.jwtExtract(this.config, authToken);
550
+ switchExtract = switchToken
551
+ ? this.config.jwtExtract(this.config, switchToken)
552
+ : null;
575
553
  }
576
554
  else {
577
555
  const xsrfToken = this.request.header('x-xsrf-token');
578
556
  if (xsrfToken == null && !fromAuthHeader) {
579
557
  return false;
580
558
  }
581
- extract = this.config.jwtExtract(this.config, authToken, xsrfToken);
559
+ authExtract = this.config.jwtExtract(this.config, authToken, xsrfToken);
560
+ switchExtract = switchToken
561
+ ? this.config.jwtExtract(this.config, switchToken)
562
+ : null;
582
563
  }
583
- if (extract == null) {
584
- this.logout();
564
+ if (authExtract == null) {
565
+ await this.logout();
585
566
  return false;
586
567
  }
587
- const { guid, expire } = extract;
588
- const user = this.User.factorySync(guid);
589
- if (user.guid == null || !user.enabled) {
590
- this.logout();
568
+ const { guid, issued, expire } = authExtract;
569
+ const { guid: switchGuid, expire: switchExpire } = switchExtract || {
570
+ guid: null,
571
+ expire: null,
572
+ };
573
+ const user = await this.User.factory(guid);
574
+ if (user.guid == null ||
575
+ !user.enabled ||
576
+ expire.getTime() <= Date.now() ||
577
+ issued.getTime() > Date.now() ||
578
+ (user.revokeTokenDate != null && issued.getTime() <= user.revokeTokenDate)) {
579
+ await this.logout();
591
580
  return false;
592
581
  }
593
- if (expire.valueOf() < Date.now() + this.config.jwtRenew * 1000) {
594
- this.login(user, fromAuthHeader);
582
+ if (switchGuid && switchExpire && switchExpire.getTime() > Date.now()) {
583
+ const switchUser = await this.User.factory(switchGuid);
584
+ if (switchUser.guid == null) {
585
+ await this.logoutSwitch();
586
+ }
587
+ else {
588
+ await this.fillSession(switchUser);
589
+ if (this.response) {
590
+ this.response.locals.user = switchUser;
591
+ }
592
+ return true;
593
+ }
594
+ }
595
+ if (expire.getTime() < Date.now() + this.config.jwtRenew * 1000) {
596
+ await this.login(user, fromAuthHeader);
595
597
  }
596
598
  else {
597
- this.fillSession(user);
599
+ await this.fillSession(user);
600
+ }
601
+ if (this.response) {
602
+ this.response.locals.user = user;
598
603
  }
599
604
  return true;
600
605
  }
601
- login(user, sendAuthHeader) {
606
+ async login(user, sendAuthHeader, sendCookie = true) {
602
607
  if (user.guid != null && user.enabled) {
603
- if (this.response && !this.response.headersSent) {
604
- const token = this.config.jwtBuilder(this.config, user);
605
- const appUrl = new url_1.URL(this.config.appUrl);
606
- this.response.cookie('TILMELDAUTH', token, {
607
- domain: this.config.cookieDomain,
608
- path: this.config.cookiePath,
609
- maxAge: this.config.jwtExpire * 1000,
610
- secure: appUrl.protocol === 'https',
611
- httpOnly: false,
612
- sameSite: appUrl.protocol === 'https' ? 'lax' : 'strict',
613
- });
614
- if (sendAuthHeader) {
615
- this.response.set('X-TILMELDAUTH', token);
608
+ if (this.response) {
609
+ if (!this.response.headersSent) {
610
+ const token = this.config.jwtBuilder(this.config, user);
611
+ if (sendCookie) {
612
+ const appUrl = new url_1.URL(this.config.appUrl);
613
+ this.response.cookie('TILMELDAUTH', token, {
614
+ domain: this.config.cookieDomain,
615
+ path: this.config.cookiePath,
616
+ maxAge: this.config.jwtExpire * 1000,
617
+ secure: appUrl.protocol === 'https:',
618
+ httpOnly: false,
619
+ sameSite: appUrl.protocol === 'https:' ? 'lax' : 'strict',
620
+ });
621
+ }
622
+ if (sendAuthHeader) {
623
+ this.response.set('X-TILMELDAUTH', token);
624
+ }
625
+ }
626
+ this.response.locals.user = user;
627
+ }
628
+ await this.fillSession(user);
629
+ return true;
630
+ }
631
+ return false;
632
+ }
633
+ async loginSwitch(user, sendAuthHeader, sendCookie = true) {
634
+ if (user.guid != null) {
635
+ if (this.response) {
636
+ if (!this.response.headersSent) {
637
+ const token = this.config.jwtBuilder(this.config, user, true);
638
+ if (sendCookie) {
639
+ const appUrl = new url_1.URL(this.config.appUrl);
640
+ this.response.cookie('TILMELDSWITCH', token, {
641
+ domain: this.config.cookieDomain,
642
+ path: this.config.cookiePath,
643
+ maxAge: this.config.jwtSwitchExpire * 1000,
644
+ secure: appUrl.protocol === 'https:',
645
+ httpOnly: false,
646
+ sameSite: appUrl.protocol === 'https:' ? 'lax' : 'strict',
647
+ });
648
+ }
649
+ if (sendAuthHeader) {
650
+ this.response.set('X-TILMELDSWITCH', token);
651
+ }
616
652
  }
653
+ this.response.locals.user = user;
617
654
  }
618
- this.fillSession(user);
655
+ await this.fillSession(user);
619
656
  return true;
620
657
  }
621
658
  return false;
622
659
  }
623
- logout() {
660
+ async logout(clearCookie = true) {
661
+ if (this.request && !this.alreadyLoggedOutSwitch) {
662
+ const cookies = this.request.cookies ?? {};
663
+ if ('TILMELDSWITCH' in cookies) {
664
+ this.alreadyLoggedOutSwitch = true;
665
+ return await this.logoutSwitch(clearCookie);
666
+ }
667
+ }
624
668
  this.clearSession();
625
- if (this.response && !this.response.headersSent) {
626
- this.response.clearCookie('TILMELDAUTH', {
627
- domain: this.config.cookieDomain,
628
- path: this.config.cookiePath,
629
- });
630
- this.response.set('X-TILMELDAUTH', '');
669
+ if (this.response) {
670
+ if (clearCookie && !this.response.headersSent) {
671
+ this.response.clearCookie('TILMELDAUTH', {
672
+ domain: this.config.cookieDomain,
673
+ path: this.config.cookiePath,
674
+ });
675
+ this.response.set('X-TILMELDAUTH', '');
676
+ }
677
+ this.response.locals.user = null;
678
+ }
679
+ }
680
+ async logoutSwitch(clearCookie = true) {
681
+ this.clearSession();
682
+ if (this.response) {
683
+ if (clearCookie && !this.response.headersSent) {
684
+ this.response.clearCookie('TILMELDSWITCH', {
685
+ domain: this.config.cookieDomain,
686
+ path: this.config.cookiePath,
687
+ });
688
+ this.response.set('X-TILMELDSWITCH', '');
689
+ }
690
+ this.response.locals.user = null;
691
+ await this.authenticate();
631
692
  }
632
693
  }
633
694
  }