@nymphjs/tilmeld 1.0.0-beta.4 → 1.0.0-beta.40
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 +182 -0
- package/README.md +13 -0
- package/dist/Group.d.ts +0 -2
- package/dist/Group.js +57 -28
- package/dist/Group.js.map +1 -1
- package/dist/Tilmeld.d.ts +5 -2
- package/dist/Tilmeld.js +164 -63
- package/dist/Tilmeld.js.map +1 -1
- package/dist/User.d.ts +56 -5
- package/dist/User.js +331 -66
- package/dist/User.js.map +1 -1
- package/dist/conf/d.d.ts +3 -1
- package/dist/conf/defaults.js +15 -4
- package/dist/conf/defaults.js.map +1 -1
- package/dist/enforceTilmeld.d.ts +3 -0
- package/dist/enforceTilmeld.js +22 -0
- package/dist/enforceTilmeld.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +23 -20
- package/src/Group.ts +80 -32
- package/src/Tilmeld.ts +241 -78
- package/src/User.ts +508 -74
- package/src/conf/d.ts +16 -7
- package/src/conf/defaults.ts +17 -4
- package/src/enforceTilmeld.ts +20 -0
- package/src/index.ts +2 -0
- package/typedoc.json +4 -0
package/src/Tilmeld.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { AccessControlError } from './errors';
|
|
|
15
15
|
import Group from './Group';
|
|
16
16
|
import User, { UserData } from './User';
|
|
17
17
|
import { AccessControlData } from './Tilmeld.types';
|
|
18
|
+
import { enforceTilmeld } from './enforceTilmeld';
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* A user and group system for Nymph.js.
|
|
@@ -73,6 +74,11 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
73
74
|
*/
|
|
74
75
|
private skipAuthenticate = false;
|
|
75
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Used to avoid infinite loop.
|
|
79
|
+
*/
|
|
80
|
+
private alreadyLoggedOutSwitch = false;
|
|
81
|
+
|
|
76
82
|
/**
|
|
77
83
|
* Create a new instance of Tilmeld.
|
|
78
84
|
*
|
|
@@ -84,6 +90,7 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
84
90
|
|
|
85
91
|
/**
|
|
86
92
|
* This is used internally by Nymph. Don't call it yourself.
|
|
93
|
+
*
|
|
87
94
|
* @returns A clone of this instance.
|
|
88
95
|
*/
|
|
89
96
|
public clone() {
|
|
@@ -106,25 +113,40 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
106
113
|
public init(nymph: Nymph) {
|
|
107
114
|
this.nymph = nymph;
|
|
108
115
|
|
|
109
|
-
// Set up access control hooks when Nymph is called.
|
|
110
116
|
if (this.nymph.driver == null) {
|
|
111
117
|
throw new Error("Tilmeld can't be configured before Nymph.");
|
|
112
118
|
}
|
|
113
119
|
|
|
114
120
|
// Configure the classes.
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
this.
|
|
121
|
+
if (nymph.parent) {
|
|
122
|
+
// This is a cloned Nymph, it should have classes already.
|
|
123
|
+
this.User = this.nymph.getEntityClass(User);
|
|
124
|
+
this.Group = this.nymph.getEntityClass(Group);
|
|
125
|
+
} else {
|
|
126
|
+
// This is a new Nymph, add the classes.
|
|
127
|
+
this.User = this.nymph.addEntityClass(User);
|
|
128
|
+
this.Group = this.nymph.addEntityClass(Group);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Clone the current user so its Nymph instance is correct.
|
|
132
|
+
if (this.currentUser) {
|
|
133
|
+
const currentUserGUID = this.currentUser.guid;
|
|
134
|
+
const currentUserCDate = this.currentUser.cdate;
|
|
135
|
+
const currentUserMDate = this.currentUser.mdate;
|
|
136
|
+
const currentUserTags = this.currentUser.tags;
|
|
137
|
+
const currentUserData = this.currentUser.$getData();
|
|
138
|
+
const currentUserSData = this.currentUser.$getSData();
|
|
139
|
+
|
|
140
|
+
const user = this.User.factorySync();
|
|
141
|
+
user.guid = currentUserGUID;
|
|
142
|
+
user.cdate = currentUserCDate;
|
|
143
|
+
user.mdate = currentUserMDate;
|
|
144
|
+
user.tags = currentUserTags;
|
|
145
|
+
user.$putData(currentUserData, currentUserSData);
|
|
146
|
+
this.fillSession(user);
|
|
147
|
+
}
|
|
127
148
|
|
|
149
|
+
// Set up access control hooks when Nymph is called.
|
|
128
150
|
this.initAccessControl();
|
|
129
151
|
if (this.request != null && !this.skipAuthenticate) {
|
|
130
152
|
this.authenticate();
|
|
@@ -155,7 +177,7 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
155
177
|
options: Options,
|
|
156
178
|
selectors: FormattedSelector[]
|
|
157
179
|
) {
|
|
158
|
-
const tilmeld = nymph
|
|
180
|
+
const tilmeld = enforceTilmeld(nymph);
|
|
159
181
|
if (
|
|
160
182
|
!options ||
|
|
161
183
|
!('skipAc' in options) ||
|
|
@@ -195,7 +217,7 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
195
217
|
nymph: Nymph,
|
|
196
218
|
entity: EntityInterface
|
|
197
219
|
) {
|
|
198
|
-
const tilmeld = nymph
|
|
220
|
+
const tilmeld = enforceTilmeld(nymph);
|
|
199
221
|
if (
|
|
200
222
|
typeof entity.$tilmeldDeleteSkipAC === 'function' &&
|
|
201
223
|
entity.$tilmeldDeleteSkipAC()
|
|
@@ -231,7 +253,7 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
231
253
|
nymph: Nymph,
|
|
232
254
|
entity: EntityInterface & AccessControlData
|
|
233
255
|
) {
|
|
234
|
-
const tilmeld = nymph
|
|
256
|
+
const tilmeld = enforceTilmeld(nymph);
|
|
235
257
|
if (!entity) {
|
|
236
258
|
return;
|
|
237
259
|
}
|
|
@@ -342,11 +364,10 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
342
364
|
}
|
|
343
365
|
|
|
344
366
|
if (
|
|
345
|
-
(
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
!tilmeld.gatekeeper('tilmeld/admin')
|
|
367
|
+
(originalAc.user && !originalAc.user.$is(newAc.user)) ||
|
|
368
|
+
(!originalAc.user &&
|
|
369
|
+
newAc.user &&
|
|
370
|
+
!newAc.user.$is(tilmeld.currentUser))
|
|
350
371
|
) {
|
|
351
372
|
throw new AccessControlError(
|
|
352
373
|
'No permission to assign to another user.'
|
|
@@ -359,8 +380,7 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
359
380
|
!(
|
|
360
381
|
newAc.group.$is(tilmeld.currentUser?.group) ||
|
|
361
382
|
newAc.group.$inArray(tilmeld.currentUser?.groups ?? [])
|
|
362
|
-
)
|
|
363
|
-
!tilmeld.gatekeeper('tilmeld/admin')
|
|
383
|
+
)
|
|
364
384
|
) {
|
|
365
385
|
throw new AccessControlError(
|
|
366
386
|
'No permission to assign to another group.'
|
|
@@ -398,7 +418,7 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
398
418
|
nymph: Nymph,
|
|
399
419
|
entity: EntityInterface & AccessControlData
|
|
400
420
|
) {
|
|
401
|
-
const tilmeld = nymph
|
|
421
|
+
const tilmeld = enforceTilmeld(nymph);
|
|
402
422
|
const user = tilmeld.currentUser;
|
|
403
423
|
if (
|
|
404
424
|
user != null &&
|
|
@@ -530,14 +550,6 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
530
550
|
) {
|
|
531
551
|
const user = this.currentUser;
|
|
532
552
|
|
|
533
|
-
if (
|
|
534
|
-
user != null &&
|
|
535
|
-
(user.abilities?.indexOf('system/admin') ?? -1) !== -1
|
|
536
|
-
) {
|
|
537
|
-
// The user is a system admin, so they can see everything.
|
|
538
|
-
return;
|
|
539
|
-
}
|
|
540
|
-
|
|
541
553
|
if (options == null) {
|
|
542
554
|
throw new Error('No options in argument.');
|
|
543
555
|
} else if (
|
|
@@ -669,7 +681,7 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
669
681
|
* - FULL_ACCESS, the user has read, write, and delete access to the entity,
|
|
670
682
|
* as well as being able to manage its access controls and ownership.
|
|
671
683
|
*
|
|
672
|
-
* These properties
|
|
684
|
+
* These properties default to:
|
|
673
685
|
*
|
|
674
686
|
* - acUser = TilmeldAccessLevels.FULL_ACCESS
|
|
675
687
|
* - acGroup = TilmeldAccessLevels.READ_ACCESS
|
|
@@ -684,9 +696,7 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
684
696
|
* The following conditions will result in different checks, which determine
|
|
685
697
|
* whether the check passes:
|
|
686
698
|
*
|
|
687
|
-
* - The user has the "system/admin" ability. (Always true.)
|
|
688
699
|
* - It is a user or group. (True for READ_ACCESS or Tilmeld admins.)
|
|
689
|
-
* - The entity has no "user" and no "group". (Always true.)
|
|
690
700
|
* - No user is logged in. (Check other AC.)
|
|
691
701
|
* - The entity is the user. (Always true.)
|
|
692
702
|
* - It is the user's primary group. (True for READ_ACCESS.)
|
|
@@ -727,30 +737,22 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
727
737
|
userOrEmpty = user;
|
|
728
738
|
}
|
|
729
739
|
|
|
730
|
-
if (userOrEmpty.$gatekeeper('system/admin')) {
|
|
731
|
-
return true;
|
|
732
|
-
}
|
|
733
|
-
|
|
734
740
|
// Users and groups are always readable. Editable by Tilmeld admins.
|
|
735
741
|
if (
|
|
736
742
|
(entity instanceof User || entity instanceof Group) &&
|
|
737
743
|
(type === TilmeldAccessLevels.READ_ACCESS ||
|
|
738
|
-
userOrEmpty
|
|
744
|
+
userOrEmpty.abilities?.includes('tilmeld/admin') ||
|
|
745
|
+
userOrEmpty.abilities?.includes('system/admin'))
|
|
739
746
|
) {
|
|
740
747
|
return true;
|
|
741
748
|
}
|
|
742
749
|
|
|
743
|
-
// Entities with no owners are always editable.
|
|
744
|
-
if (entity.user == null && entity.group == null) {
|
|
745
|
-
return true;
|
|
746
|
-
}
|
|
747
|
-
|
|
748
750
|
// Load access control, since we need it now...
|
|
749
751
|
const acUser = entity.acUser ?? TilmeldAccessLevels.FULL_ACCESS;
|
|
750
752
|
const acGroup = entity.acGroup ?? TilmeldAccessLevels.READ_ACCESS;
|
|
751
753
|
const acOther = entity.acOther ?? TilmeldAccessLevels.NO_ACCESS;
|
|
752
754
|
|
|
753
|
-
if (userOrNull
|
|
755
|
+
if (userOrNull == null) {
|
|
754
756
|
return acOther >= type;
|
|
755
757
|
}
|
|
756
758
|
|
|
@@ -860,7 +862,7 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
860
862
|
userOrEmpty = user;
|
|
861
863
|
}
|
|
862
864
|
|
|
863
|
-
if (userOrEmpty
|
|
865
|
+
if (userOrEmpty.abilities?.includes('system/admin')) {
|
|
864
866
|
return true;
|
|
865
867
|
}
|
|
866
868
|
|
|
@@ -948,7 +950,7 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
948
950
|
guid: guid,
|
|
949
951
|
}
|
|
950
952
|
);
|
|
951
|
-
if (!user || !user.guid
|
|
953
|
+
if (!user || !user.guid) {
|
|
952
954
|
return null;
|
|
953
955
|
}
|
|
954
956
|
|
|
@@ -956,7 +958,17 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
956
958
|
}
|
|
957
959
|
|
|
958
960
|
/**
|
|
959
|
-
* Check for
|
|
961
|
+
* Check for TILMELDAUTH and TILMELDSWITCH tokens, and, if set, authenticate
|
|
962
|
+
* from it/them.
|
|
963
|
+
*
|
|
964
|
+
* You can also call this function after setting `response.locals.user` to the
|
|
965
|
+
* user you want to authenticate. You *should* check for `user.enabled` before
|
|
966
|
+
* setting this variable, unless you explicitly want to log in as a disabled
|
|
967
|
+
* user. (The user must be an instance of the User class for this Tilmeld
|
|
968
|
+
* instance.)
|
|
969
|
+
*
|
|
970
|
+
* This function will set `response.locals.user` to the logged in user on
|
|
971
|
+
* successful authentication.
|
|
960
972
|
*
|
|
961
973
|
* @param skipXsrfToken Skip the XSRF token check.
|
|
962
974
|
* @returns True if a user was authenticated, false on any failure.
|
|
@@ -966,30 +978,52 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
966
978
|
return false;
|
|
967
979
|
}
|
|
968
980
|
|
|
981
|
+
if (
|
|
982
|
+
this.response &&
|
|
983
|
+
this.response.locals.user &&
|
|
984
|
+
this.response.locals.user instanceof this.User
|
|
985
|
+
) {
|
|
986
|
+
// The user has already been authenticated through some other means.
|
|
987
|
+
const user = this.response.locals.user;
|
|
988
|
+
this.fillSession(user);
|
|
989
|
+
return true;
|
|
990
|
+
}
|
|
991
|
+
|
|
969
992
|
const cookies = this.request.cookies ?? {};
|
|
970
993
|
|
|
971
994
|
// If a client does't support cookies, they can use the X-TILMELDAUTH header
|
|
972
995
|
// to provide the auth token.
|
|
973
996
|
let fromAuthHeader = false;
|
|
974
997
|
let authToken: string;
|
|
998
|
+
let switchToken: string | null;
|
|
975
999
|
if (this.request.header('x-tilmeldauth') != null) {
|
|
976
1000
|
fromAuthHeader = true;
|
|
977
1001
|
authToken = this.request.header('x-tilmeldauth') as string;
|
|
1002
|
+
switchToken =
|
|
1003
|
+
(this.request.header('x-tilmeldswitch') as string) ||
|
|
1004
|
+
'TILMELDSWITCH' in cookies
|
|
1005
|
+
? cookies.TILMELDSWITCH
|
|
1006
|
+
: null;
|
|
978
1007
|
} else if ('TILMELDAUTH' in cookies) {
|
|
979
1008
|
fromAuthHeader = false;
|
|
980
1009
|
authToken = cookies.TILMELDAUTH;
|
|
1010
|
+
switchToken = 'TILMELDSWITCH' in cookies ? cookies.TILMELDSWITCH : null;
|
|
981
1011
|
} else {
|
|
982
1012
|
return false;
|
|
983
1013
|
}
|
|
984
1014
|
|
|
985
|
-
let
|
|
1015
|
+
let authExtract: { guid: string; issued: Date; expire: Date } | null;
|
|
1016
|
+
let switchExtract: { guid: string; expire: Date } | null;
|
|
986
1017
|
if (
|
|
987
1018
|
skipXsrfToken ||
|
|
988
1019
|
this.request.originalUrl.startsWith(this.config.setupPath)
|
|
989
1020
|
) {
|
|
990
1021
|
// The request is for the setup app, or we were told to skip the XSRF
|
|
991
1022
|
// check, so don't check for the XSRF token.
|
|
992
|
-
|
|
1023
|
+
authExtract = this.config.jwtExtract(this.config, authToken);
|
|
1024
|
+
switchExtract = switchToken
|
|
1025
|
+
? this.config.jwtExtract(this.config, switchToken)
|
|
1026
|
+
: null;
|
|
993
1027
|
} else {
|
|
994
1028
|
// The request is for something else, so check for a valid XSRF token,
|
|
995
1029
|
// unless the auth token is provided by a header (instead of a cookie).
|
|
@@ -998,28 +1032,62 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
998
1032
|
return false;
|
|
999
1033
|
}
|
|
1000
1034
|
|
|
1001
|
-
|
|
1035
|
+
authExtract = this.config.jwtExtract(this.config, authToken, xsrfToken);
|
|
1036
|
+
switchExtract = switchToken
|
|
1037
|
+
? this.config.jwtExtract(this.config, switchToken)
|
|
1038
|
+
: null;
|
|
1002
1039
|
}
|
|
1003
1040
|
|
|
1004
|
-
if (
|
|
1041
|
+
if (authExtract == null) {
|
|
1005
1042
|
this.logout();
|
|
1006
1043
|
return false;
|
|
1007
1044
|
}
|
|
1008
|
-
const { guid, expire } =
|
|
1045
|
+
const { guid, issued, expire } = authExtract;
|
|
1046
|
+
const { guid: switchGuid, expire: switchExpire } = switchExtract || {
|
|
1047
|
+
guid: null,
|
|
1048
|
+
expire: null,
|
|
1049
|
+
};
|
|
1009
1050
|
|
|
1010
1051
|
const user = this.User.factorySync(guid);
|
|
1011
|
-
if (
|
|
1052
|
+
if (
|
|
1053
|
+
user.guid == null ||
|
|
1054
|
+
!user.enabled ||
|
|
1055
|
+
expire.getTime() <= Date.now() ||
|
|
1056
|
+
issued.getTime() > Date.now() ||
|
|
1057
|
+
(user.revokeTokenDate != null && issued.getTime() <= user.revokeTokenDate)
|
|
1058
|
+
) {
|
|
1012
1059
|
this.logout();
|
|
1013
1060
|
return false;
|
|
1014
1061
|
}
|
|
1015
1062
|
|
|
1016
|
-
if (
|
|
1063
|
+
if (switchGuid && switchExpire && switchExpire.getTime() > Date.now()) {
|
|
1064
|
+
// Load the switch user.
|
|
1065
|
+
const switchUser = this.User.factorySync(switchGuid);
|
|
1066
|
+
if (switchUser.guid == null) {
|
|
1067
|
+
this.logoutSwitch();
|
|
1068
|
+
} else {
|
|
1069
|
+
this.fillSession(switchUser);
|
|
1070
|
+
|
|
1071
|
+
if (this.response) {
|
|
1072
|
+
this.response.locals.user = switchUser;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
return true;
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
if (expire.getTime() < Date.now() + this.config.jwtRenew * 1000) {
|
|
1017
1080
|
// If the user is less than renew time from needing a new token, give them
|
|
1018
1081
|
// a new one.
|
|
1019
1082
|
this.login(user, fromAuthHeader);
|
|
1020
1083
|
} else {
|
|
1021
1084
|
this.fillSession(user);
|
|
1022
1085
|
}
|
|
1086
|
+
|
|
1087
|
+
if (this.response) {
|
|
1088
|
+
this.response.locals.user = user;
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1023
1091
|
return true;
|
|
1024
1092
|
}
|
|
1025
1093
|
|
|
@@ -1027,26 +1095,86 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
1027
1095
|
* Logs the given user into the system.
|
|
1028
1096
|
*
|
|
1029
1097
|
* @param user The user.
|
|
1030
|
-
* @param sendAuthHeader
|
|
1098
|
+
* @param sendAuthHeader Send the auth token as a custom header.
|
|
1099
|
+
* @param sendCookie Send the auth token as a cookie.
|
|
1031
1100
|
* @returns True on success, false on failure.
|
|
1032
1101
|
*/
|
|
1033
|
-
public login(
|
|
1102
|
+
public login(
|
|
1103
|
+
user: User & UserData,
|
|
1104
|
+
sendAuthHeader: boolean,
|
|
1105
|
+
sendCookie = true
|
|
1106
|
+
) {
|
|
1034
1107
|
if (user.guid != null && user.enabled) {
|
|
1035
|
-
if (this.response
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1108
|
+
if (this.response) {
|
|
1109
|
+
if (!this.response.headersSent) {
|
|
1110
|
+
const token = this.config.jwtBuilder(this.config, user);
|
|
1111
|
+
|
|
1112
|
+
if (sendCookie) {
|
|
1113
|
+
const appUrl = new URL(this.config.appUrl);
|
|
1114
|
+
this.response.cookie('TILMELDAUTH', token, {
|
|
1115
|
+
domain: this.config.cookieDomain,
|
|
1116
|
+
path: this.config.cookiePath,
|
|
1117
|
+
maxAge: this.config.jwtExpire * 1000,
|
|
1118
|
+
secure: appUrl.protocol === 'https',
|
|
1119
|
+
httpOnly: false, // Allow JS access (for CSRF protection).
|
|
1120
|
+
sameSite: appUrl.protocol === 'https' ? 'lax' : 'strict',
|
|
1121
|
+
});
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
if (sendAuthHeader) {
|
|
1125
|
+
this.response.set('X-TILMELDAUTH', token);
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
this.response.locals.user = user;
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
this.fillSession(user);
|
|
1133
|
+
return true;
|
|
1134
|
+
}
|
|
1135
|
+
return false;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
/**
|
|
1139
|
+
* Adds a switch auth token for the given user.
|
|
1140
|
+
*
|
|
1141
|
+
* This effectively logs the current user in to the system as the given user.
|
|
1142
|
+
*
|
|
1143
|
+
* @param user The user.
|
|
1144
|
+
* @param sendAuthHeader Send the auth token as a custom header.
|
|
1145
|
+
* @param sendCookie Send the auth token as a cookie.
|
|
1146
|
+
* @returns True on success, false on failure.
|
|
1147
|
+
*/
|
|
1148
|
+
public loginSwitch(
|
|
1149
|
+
user: User & UserData,
|
|
1150
|
+
sendAuthHeader: boolean,
|
|
1151
|
+
sendCookie = true
|
|
1152
|
+
) {
|
|
1153
|
+
if (user.guid != null) {
|
|
1154
|
+
if (this.response) {
|
|
1155
|
+
if (!this.response.headersSent) {
|
|
1156
|
+
const token = this.config.jwtBuilder(this.config, user, true);
|
|
1157
|
+
|
|
1158
|
+
if (sendCookie) {
|
|
1159
|
+
const appUrl = new URL(this.config.appUrl);
|
|
1160
|
+
this.response.cookie('TILMELDSWITCH', token, {
|
|
1161
|
+
domain: this.config.cookieDomain,
|
|
1162
|
+
path: this.config.cookiePath,
|
|
1163
|
+
maxAge: this.config.jwtSwitchExpire * 1000,
|
|
1164
|
+
secure: appUrl.protocol === 'https',
|
|
1165
|
+
httpOnly: false, // Allow JS access (for PubSub auth token).
|
|
1166
|
+
sameSite: appUrl.protocol === 'https' ? 'lax' : 'strict',
|
|
1167
|
+
});
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
if (sendAuthHeader) {
|
|
1171
|
+
this.response.set('X-TILMELDSWITCH', token);
|
|
1172
|
+
}
|
|
1048
1173
|
}
|
|
1174
|
+
|
|
1175
|
+
this.response.locals.user = user;
|
|
1049
1176
|
}
|
|
1177
|
+
|
|
1050
1178
|
this.fillSession(user);
|
|
1051
1179
|
return true;
|
|
1052
1180
|
}
|
|
@@ -1055,15 +1183,50 @@ export default class Tilmeld implements TilmeldInterface {
|
|
|
1055
1183
|
|
|
1056
1184
|
/**
|
|
1057
1185
|
* Logs the current user out of the system.
|
|
1186
|
+
*
|
|
1187
|
+
* @param clearCookie Clear the auth cookie. (Also send a header.)
|
|
1058
1188
|
*/
|
|
1059
|
-
public logout() {
|
|
1189
|
+
public logout(clearCookie = true) {
|
|
1190
|
+
if (this.request && !this.alreadyLoggedOutSwitch) {
|
|
1191
|
+
const cookies = this.request.cookies ?? {};
|
|
1192
|
+
|
|
1193
|
+
if ('TILMELDSWITCH' in cookies) {
|
|
1194
|
+
this.alreadyLoggedOutSwitch = true;
|
|
1195
|
+
return this.logoutSwitch(clearCookie);
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1060
1199
|
this.clearSession();
|
|
1061
|
-
if (this.response
|
|
1062
|
-
this.response.
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1200
|
+
if (this.response) {
|
|
1201
|
+
if (clearCookie && !this.response.headersSent) {
|
|
1202
|
+
this.response.clearCookie('TILMELDAUTH', {
|
|
1203
|
+
domain: this.config.cookieDomain,
|
|
1204
|
+
path: this.config.cookiePath,
|
|
1205
|
+
});
|
|
1206
|
+
this.response.set('X-TILMELDAUTH', '');
|
|
1207
|
+
}
|
|
1208
|
+
this.response.locals.user = null;
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
/**
|
|
1213
|
+
* Clears the switch user out of the system.
|
|
1214
|
+
*
|
|
1215
|
+
* @param clearCookie Clear the auth cookie. (Also send a header.)
|
|
1216
|
+
*/
|
|
1217
|
+
public logoutSwitch(clearCookie = true) {
|
|
1218
|
+
this.clearSession();
|
|
1219
|
+
if (this.response) {
|
|
1220
|
+
if (clearCookie && !this.response.headersSent) {
|
|
1221
|
+
this.response.clearCookie('TILMELDSWITCH', {
|
|
1222
|
+
domain: this.config.cookieDomain,
|
|
1223
|
+
path: this.config.cookiePath,
|
|
1224
|
+
});
|
|
1225
|
+
this.response.set('X-TILMELDSWITCH', '');
|
|
1226
|
+
}
|
|
1227
|
+
this.response.locals.user = null;
|
|
1228
|
+
|
|
1229
|
+
this.authenticate();
|
|
1067
1230
|
}
|
|
1068
1231
|
}
|
|
1069
1232
|
|