@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/CHANGELOG.md +238 -0
- package/README.md +14 -1
- package/dist/AbleObject.js.map +1 -1
- package/dist/Group.d.ts +4 -7
- package/dist/Group.js +124 -86
- package/dist/Group.js.map +1 -1
- package/dist/Tilmeld.d.ts +12 -9
- package/dist/Tilmeld.js +240 -179
- package/dist/Tilmeld.js.map +1 -1
- package/dist/User.d.ts +69 -13
- package/dist/User.js +492 -169
- package/dist/User.js.map +1 -1
- package/dist/conf/d.d.ts +4 -1
- package/dist/conf/defaults.js +22 -8
- 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 +29 -26
- package/src/AbleObject.ts +1 -1
- package/src/Group.test.ts +1 -1
- package/src/Group.ts +180 -130
- package/src/Tilmeld.ts +355 -244
- package/src/User.test.ts +1 -1
- package/src/User.ts +717 -230
- package/src/conf/d.ts +24 -11
- package/src/conf/defaults.ts +30 -14
- package/src/enforceTilmeld.ts +20 -0
- package/src/index.ts +2 -0
- package/src/tilmeldJoiProps.ts +9 -9
- package/typedoc.json +4 -0
package/dist/User.js
CHANGED
|
@@ -3,12 +3,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const guid_1 = require("@nymphjs/guid");
|
|
6
7
|
const strtotime_1 = __importDefault(require("locutus/php/datetime/strtotime"));
|
|
7
8
|
const enc_base64_1 = __importDefault(require("crypto-js/enc-base64"));
|
|
8
9
|
const sha256_1 = __importDefault(require("crypto-js/sha256"));
|
|
9
10
|
const md5_1 = __importDefault(require("crypto-js/md5"));
|
|
10
11
|
const lodash_1 = require("lodash");
|
|
11
|
-
const
|
|
12
|
+
const otpauth_1 = require("otpauth");
|
|
13
|
+
const qrcode_1 = require("qrcode");
|
|
14
|
+
const enforceTilmeld_1 = require("./enforceTilmeld");
|
|
12
15
|
const AbleObject_1 = __importDefault(require("./AbleObject"));
|
|
13
16
|
const errors_1 = require("./errors");
|
|
14
17
|
class User extends AbleObject_1.default {
|
|
@@ -30,32 +33,32 @@ class User extends AbleObject_1.default {
|
|
|
30
33
|
}
|
|
31
34
|
return entity;
|
|
32
35
|
}
|
|
33
|
-
static factorySync(
|
|
34
|
-
return super.factorySync(
|
|
36
|
+
static factorySync() {
|
|
37
|
+
return super.factorySync();
|
|
35
38
|
}
|
|
36
|
-
constructor(
|
|
37
|
-
super(
|
|
39
|
+
constructor() {
|
|
40
|
+
super();
|
|
38
41
|
this.$clientEnabledMethods = [...User.DEFAULT_CLIENT_ENABLED_METHODS];
|
|
39
42
|
this.$privateData = [...User.DEFAULT_PRIVATE_DATA];
|
|
40
43
|
this.$allowlistData = [...User.DEFAULT_ALLOWLIST_DATA];
|
|
41
44
|
this.$allowlistTags = [];
|
|
42
45
|
this.$skipAcWhenSaving = false;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
this.$updateDataProtection();
|
|
49
|
-
}
|
|
46
|
+
this.$data.enabled = true;
|
|
47
|
+
this.$data.abilities = [];
|
|
48
|
+
this.$data.groups = [];
|
|
49
|
+
this.$data.inheritAbilities = true;
|
|
50
|
+
this.$updateDataProtection();
|
|
50
51
|
}
|
|
51
52
|
static current(returnObjectIfNotExist) {
|
|
52
|
-
|
|
53
|
+
const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
54
|
+
if (tilmeld.currentUser == null) {
|
|
53
55
|
return returnObjectIfNotExist ? this.factorySync() : null;
|
|
54
56
|
}
|
|
55
|
-
return
|
|
57
|
+
return tilmeld.currentUser;
|
|
56
58
|
}
|
|
57
59
|
static async sendRecovery(data) {
|
|
58
|
-
|
|
60
|
+
const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
61
|
+
if (!tilmeld.config.pwRecovery) {
|
|
59
62
|
return {
|
|
60
63
|
result: false,
|
|
61
64
|
message: 'Account recovery is not allowed.',
|
|
@@ -63,9 +66,8 @@ class User extends AbleObject_1.default {
|
|
|
63
66
|
}
|
|
64
67
|
let user;
|
|
65
68
|
const options = {};
|
|
66
|
-
if (!
|
|
67
|
-
|
|
68
|
-
const getUser = await this.nymph.getEntity({ class: this.tilmeld.User, skipAc: true }, {
|
|
69
|
+
if (!tilmeld.config.emailUsernames && data.recoveryType === 'username') {
|
|
70
|
+
const getUser = await this.nymph.getEntity({ class: tilmeld.User, skipAc: true }, {
|
|
69
71
|
type: '&',
|
|
70
72
|
ilike: ['email', data.account.replace(/([\\%_])/g, (s) => `\\${s}`)],
|
|
71
73
|
});
|
|
@@ -86,7 +88,7 @@ class User extends AbleObject_1.default {
|
|
|
86
88
|
options.locals = {};
|
|
87
89
|
}
|
|
88
90
|
else if (data.recoveryType === 'password') {
|
|
89
|
-
const getUser = await
|
|
91
|
+
const getUser = await tilmeld.User.factoryUsername(data.account);
|
|
90
92
|
if (getUser.guid == null) {
|
|
91
93
|
return {
|
|
92
94
|
result: false,
|
|
@@ -108,13 +110,13 @@ class User extends AbleObject_1.default {
|
|
|
108
110
|
};
|
|
109
111
|
options.locals = {
|
|
110
112
|
recoverCode: getUser.recoverSecret,
|
|
111
|
-
timeLimit:
|
|
113
|
+
timeLimit: tilmeld.config.pwRecoveryTimeLimit,
|
|
112
114
|
};
|
|
113
115
|
}
|
|
114
116
|
else {
|
|
115
117
|
return { result: false, message: 'Invalid recovery type.' };
|
|
116
118
|
}
|
|
117
|
-
if (await
|
|
119
|
+
if (await tilmeld.config.sendEmail(tilmeld, options, user)) {
|
|
118
120
|
return {
|
|
119
121
|
result: true,
|
|
120
122
|
message: "We've sent an email to your registered address. Please " +
|
|
@@ -126,17 +128,18 @@ class User extends AbleObject_1.default {
|
|
|
126
128
|
}
|
|
127
129
|
}
|
|
128
130
|
static async recover(data) {
|
|
129
|
-
|
|
131
|
+
const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
132
|
+
if (!tilmeld.config.pwRecovery) {
|
|
130
133
|
return {
|
|
131
134
|
result: false,
|
|
132
135
|
message: 'Account recovery is not allowed.',
|
|
133
136
|
};
|
|
134
137
|
}
|
|
135
|
-
const user = await
|
|
138
|
+
const user = await tilmeld.User.factoryUsername(data.username);
|
|
136
139
|
if (user.guid == null ||
|
|
137
140
|
user.recoverSecret == null ||
|
|
138
141
|
data.secret !== user.recoverSecret ||
|
|
139
|
-
(0, strtotime_1.default)('+' +
|
|
142
|
+
(0, strtotime_1.default)('+' + tilmeld.config.pwRecoveryTimeLimit, Math.floor((user.recoverSecretDate ?? 0) / 1000)) *
|
|
140
143
|
1000 <
|
|
141
144
|
Date.now()) {
|
|
142
145
|
return {
|
|
@@ -161,22 +164,24 @@ class User extends AbleObject_1.default {
|
|
|
161
164
|
}
|
|
162
165
|
}
|
|
163
166
|
static getClientConfig() {
|
|
167
|
+
const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
164
168
|
return {
|
|
165
|
-
regFields:
|
|
166
|
-
userFields:
|
|
167
|
-
emailUsernames:
|
|
168
|
-
allowRegistration:
|
|
169
|
-
allowUsernameChange:
|
|
170
|
-
pwRecovery:
|
|
171
|
-
verifyEmail:
|
|
172
|
-
unverifiedAccess:
|
|
169
|
+
regFields: tilmeld.config.regFields,
|
|
170
|
+
userFields: tilmeld.config.userFields,
|
|
171
|
+
emailUsernames: tilmeld.config.emailUsernames,
|
|
172
|
+
allowRegistration: tilmeld.config.allowRegistration,
|
|
173
|
+
allowUsernameChange: tilmeld.config.allowUsernameChange,
|
|
174
|
+
pwRecovery: tilmeld.config.pwRecovery,
|
|
175
|
+
verifyEmail: tilmeld.config.verifyEmail,
|
|
176
|
+
unverifiedAccess: tilmeld.config.unverifiedAccess,
|
|
173
177
|
};
|
|
174
178
|
}
|
|
175
179
|
static async loginUser(data) {
|
|
180
|
+
const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
176
181
|
if (!('username' in data) || !data.username.length) {
|
|
177
182
|
return { result: false, message: 'Incorrect login/password.' };
|
|
178
183
|
}
|
|
179
|
-
const user = await
|
|
184
|
+
const user = await tilmeld.User.factoryUsername(data.username);
|
|
180
185
|
const result = await user.$login(data);
|
|
181
186
|
if (result.result) {
|
|
182
187
|
user.$updateDataProtection();
|
|
@@ -185,19 +190,33 @@ class User extends AbleObject_1.default {
|
|
|
185
190
|
return result;
|
|
186
191
|
}
|
|
187
192
|
async $login(data) {
|
|
188
|
-
const tilmeld = this
|
|
193
|
+
const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
189
194
|
if (this.guid == null) {
|
|
190
195
|
return { result: false, message: 'Incorrect login/password.' };
|
|
191
196
|
}
|
|
192
197
|
if (!this.$data.enabled) {
|
|
193
198
|
return { result: false, message: 'This user is disabled.' };
|
|
194
199
|
}
|
|
195
|
-
if (this.$gatekeeper()) {
|
|
200
|
+
if (await this.$gatekeeper()) {
|
|
196
201
|
return { result: true, message: 'You are already logged in.' };
|
|
197
202
|
}
|
|
198
203
|
if (!this.$checkPassword(data.password)) {
|
|
199
204
|
return { result: false, message: 'Incorrect login/password.' };
|
|
200
205
|
}
|
|
206
|
+
if (this.$data.totpSecret != null) {
|
|
207
|
+
if (data.code == null ||
|
|
208
|
+
typeof data.code !== 'string' ||
|
|
209
|
+
data.code.length !== 6) {
|
|
210
|
+
return {
|
|
211
|
+
result: false,
|
|
212
|
+
needTOTP: true,
|
|
213
|
+
message: 'You need to provide a 2FA code.',
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
if (!this.$checkTOTPCode(data.code)) {
|
|
217
|
+
return { result: false, message: 'Incorrect 2FA code.' };
|
|
218
|
+
}
|
|
219
|
+
}
|
|
201
220
|
try {
|
|
202
221
|
for (let callback of this.constructor
|
|
203
222
|
.beforeLoginCallbacks) {
|
|
@@ -212,7 +231,62 @@ class User extends AbleObject_1.default {
|
|
|
212
231
|
message: e.message,
|
|
213
232
|
};
|
|
214
233
|
}
|
|
215
|
-
if (!tilmeld.login(this, true)) {
|
|
234
|
+
if (!(await tilmeld.login(this, true))) {
|
|
235
|
+
return { result: false, message: 'Incorrect login/password.' };
|
|
236
|
+
}
|
|
237
|
+
for (let callback of this.constructor
|
|
238
|
+
.afterLoginCallbacks) {
|
|
239
|
+
if (callback) {
|
|
240
|
+
await callback(this);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return { result: true, message: 'You are logged in.' };
|
|
244
|
+
}
|
|
245
|
+
async $switchUser(data) {
|
|
246
|
+
const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
247
|
+
if (this.guid == null) {
|
|
248
|
+
return { result: false, message: 'Incorrect login/password.' };
|
|
249
|
+
}
|
|
250
|
+
let user = tilmeld.User.current();
|
|
251
|
+
if (!user || user.guid == null) {
|
|
252
|
+
return { result: false, message: "You're not logged in." };
|
|
253
|
+
}
|
|
254
|
+
const isCurrentUser = user != null && user.$is(this);
|
|
255
|
+
if (isCurrentUser) {
|
|
256
|
+
return { result: false, message: "You can't switch to yourself." };
|
|
257
|
+
}
|
|
258
|
+
const toAbilities = this.$data.abilities || [];
|
|
259
|
+
const fromAbilities = user.abilities || [];
|
|
260
|
+
if (fromAbilities.indexOf('tilmeld/switch') === -1 &&
|
|
261
|
+
fromAbilities.indexOf('system/admin') === -1) {
|
|
262
|
+
return {
|
|
263
|
+
result: false,
|
|
264
|
+
message: "You don't have permission to switch users.",
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
if (toAbilities.indexOf('system/admin') !== -1 ||
|
|
268
|
+
toAbilities.indexOf('tilmeld/admin') !== -1) {
|
|
269
|
+
return { result: false, message: "You can't switch to an admin." };
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
for (let callback of this.constructor
|
|
273
|
+
.beforeLoginCallbacks) {
|
|
274
|
+
if (callback) {
|
|
275
|
+
await callback(this, {
|
|
276
|
+
username: this.$data.username || '',
|
|
277
|
+
password: '',
|
|
278
|
+
...(data || {}),
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
catch (e) {
|
|
284
|
+
return {
|
|
285
|
+
result: false,
|
|
286
|
+
message: e.message,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
if (!(await tilmeld.loginSwitch(this, true))) {
|
|
216
290
|
return { result: false, message: 'Incorrect login/password.' };
|
|
217
291
|
}
|
|
218
292
|
for (let callback of this.constructor
|
|
@@ -224,7 +298,7 @@ class User extends AbleObject_1.default {
|
|
|
224
298
|
return { result: true, message: 'You are logged in.' };
|
|
225
299
|
}
|
|
226
300
|
async $logout() {
|
|
227
|
-
const tilmeld = this
|
|
301
|
+
const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
228
302
|
try {
|
|
229
303
|
for (let callback of this.constructor
|
|
230
304
|
.beforeLogoutCallbacks) {
|
|
@@ -239,7 +313,7 @@ class User extends AbleObject_1.default {
|
|
|
239
313
|
message: e.message,
|
|
240
314
|
};
|
|
241
315
|
}
|
|
242
|
-
tilmeld.logout();
|
|
316
|
+
await tilmeld.logout();
|
|
243
317
|
for (let callback of this.constructor
|
|
244
318
|
.afterLogoutCallbacks) {
|
|
245
319
|
if (callback) {
|
|
@@ -259,52 +333,84 @@ class User extends AbleObject_1.default {
|
|
|
259
333
|
(0, md5_1.default)(this.$data.email.trim().toLowerCase()).toString() +
|
|
260
334
|
'?d=identicon&s=40');
|
|
261
335
|
}
|
|
336
|
+
$getGid() {
|
|
337
|
+
if (this.$data.group) {
|
|
338
|
+
return this.$data.group.guid;
|
|
339
|
+
}
|
|
340
|
+
return null;
|
|
341
|
+
}
|
|
342
|
+
$getGids() {
|
|
343
|
+
if (this.$data.groups) {
|
|
344
|
+
return this.$data.groups
|
|
345
|
+
.map((group) => group.guid)
|
|
346
|
+
.filter((guid) => guid != null);
|
|
347
|
+
}
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
262
350
|
async $getDescendantGroups() {
|
|
263
351
|
if (this.$descendantGroups == null) {
|
|
264
352
|
this.$descendantGroups = [];
|
|
265
353
|
if (this.$data.group != null) {
|
|
354
|
+
await this.$data.group.$wake();
|
|
266
355
|
this.$descendantGroups = await this.$data.group.$getDescendants();
|
|
267
356
|
}
|
|
357
|
+
await Promise.all(this.$data.groups?.map((e) => e.$wake()) || []);
|
|
268
358
|
for (let curGroup of this.$data.groups ?? []) {
|
|
269
359
|
this.$descendantGroups = this.$descendantGroups?.concat(await curGroup.$getDescendants());
|
|
270
360
|
}
|
|
271
361
|
}
|
|
272
362
|
return this.$descendantGroups;
|
|
273
363
|
}
|
|
274
|
-
$getDescendantGroupsSync() {
|
|
275
|
-
if (this.$descendantGroups == null) {
|
|
276
|
-
this.$descendantGroups = [];
|
|
277
|
-
if (this.$data.group != null) {
|
|
278
|
-
this.$descendantGroups = this.$data.group.$getDescendantsSync();
|
|
279
|
-
}
|
|
280
|
-
for (let curGroup of this.$data.groups ?? []) {
|
|
281
|
-
this.$descendantGroups = this.$descendantGroups?.concat(curGroup.$getDescendantsSync());
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
return this.$descendantGroups;
|
|
285
|
-
}
|
|
286
364
|
$jsonAcceptData(input, allowConflict = false) {
|
|
287
|
-
const tilmeld = this
|
|
288
|
-
this.$
|
|
365
|
+
const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
366
|
+
this.$check();
|
|
367
|
+
if ('abilities' in input.data &&
|
|
368
|
+
input.data.abilities?.includes('system/admin') !==
|
|
369
|
+
this.$data.abilities?.includes('system/admin') &&
|
|
370
|
+
(!tilmeld.currentUser ||
|
|
371
|
+
!tilmeld.currentUser.abilities?.includes('system/admin'))) {
|
|
372
|
+
throw new errors_1.BadDataError("You don't have the authority to grant or revoke system/admin.");
|
|
373
|
+
}
|
|
374
|
+
if ('abilities' in input.data &&
|
|
375
|
+
input.data.abilities?.includes('tilmeld/admin') !==
|
|
376
|
+
this.$data.abilities?.includes('tilmeld/admin') &&
|
|
377
|
+
(!tilmeld.currentUser ||
|
|
378
|
+
!tilmeld.currentUser.abilities?.includes('system/admin'))) {
|
|
379
|
+
throw new errors_1.BadDataError("You don't have the authority to grant or revoke tilmeld/admin.");
|
|
380
|
+
}
|
|
289
381
|
if ('abilities' in input.data &&
|
|
290
|
-
input.data.abilities
|
|
291
|
-
|
|
292
|
-
tilmeld.
|
|
293
|
-
|
|
294
|
-
throw new errors_1.BadDataError("You don't have the authority to
|
|
382
|
+
input.data.abilities?.includes('tilmeld/switch') !==
|
|
383
|
+
this.$data.abilities?.includes('tilmeld/switch') &&
|
|
384
|
+
(!tilmeld.currentUser ||
|
|
385
|
+
!tilmeld.currentUser.abilities?.includes('system/admin'))) {
|
|
386
|
+
throw new errors_1.BadDataError("You don't have the authority to grant or revoke tilmeld/switch.");
|
|
295
387
|
}
|
|
296
388
|
this.$originalEmail = this.$data.email;
|
|
297
389
|
super.$jsonAcceptData(input, allowConflict);
|
|
298
390
|
}
|
|
299
391
|
$jsonAcceptPatch(patch, allowConflict = false) {
|
|
300
|
-
const tilmeld = this
|
|
301
|
-
this.$
|
|
392
|
+
const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
393
|
+
this.$check();
|
|
394
|
+
if ('abilities' in patch.set &&
|
|
395
|
+
patch.set.abilities?.includes('system/admin') !==
|
|
396
|
+
this.$data.abilities?.includes('system/admin') &&
|
|
397
|
+
(!tilmeld.currentUser ||
|
|
398
|
+
!tilmeld.currentUser.abilities?.includes('system/admin'))) {
|
|
399
|
+
throw new errors_1.BadDataError("You don't have the authority to grant or revoke system/admin.");
|
|
400
|
+
}
|
|
401
|
+
if ('abilities' in patch.set &&
|
|
402
|
+
patch.set.abilities?.includes('tilmeld/admin') !==
|
|
403
|
+
this.$data.abilities?.includes('tilmeld/admin') &&
|
|
404
|
+
(!tilmeld.currentUser ||
|
|
405
|
+
!tilmeld.currentUser.abilities?.includes('system/admin'))) {
|
|
406
|
+
throw new errors_1.BadDataError("You don't have the authority to grant or revoke tilmeld/admin.");
|
|
407
|
+
}
|
|
302
408
|
if ('abilities' in patch.set &&
|
|
303
|
-
patch.set.abilities
|
|
304
|
-
|
|
305
|
-
tilmeld.
|
|
306
|
-
|
|
307
|
-
throw new errors_1.BadDataError("You don't have the authority to
|
|
409
|
+
patch.set.abilities?.includes('tilmeld/switch') !==
|
|
410
|
+
this.$data.abilities?.includes('tilmeld/switch') &&
|
|
411
|
+
(!tilmeld.currentUser ||
|
|
412
|
+
!tilmeld.currentUser.abilities?.includes('system/admin'))) {
|
|
413
|
+
throw new errors_1.BadDataError("You don't have the authority to grant or revoke tilmeld/switch.");
|
|
308
414
|
}
|
|
309
415
|
this.$originalEmail = this.$data.email;
|
|
310
416
|
super.$jsonAcceptPatch(patch, allowConflict);
|
|
@@ -314,7 +420,7 @@ class User extends AbleObject_1.default {
|
|
|
314
420
|
this.$updateDataProtection();
|
|
315
421
|
}
|
|
316
422
|
$updateDataProtection(givenUser) {
|
|
317
|
-
const tilmeld = this
|
|
423
|
+
const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
318
424
|
let user = givenUser ?? tilmeld.User.current();
|
|
319
425
|
this.$clientEnabledMethods = [...User.DEFAULT_CLIENT_ENABLED_METHODS];
|
|
320
426
|
this.$privateData = [...User.DEFAULT_PRIVATE_DATA];
|
|
@@ -330,13 +436,20 @@ class User extends AbleObject_1.default {
|
|
|
330
436
|
if (isCurrentUser) {
|
|
331
437
|
this.$clientEnabledMethods.push('$gatekeeper');
|
|
332
438
|
this.$clientEnabledMethods.push('$changePassword');
|
|
439
|
+
this.$clientEnabledMethods.push('$revokeCurrentTokens');
|
|
333
440
|
this.$clientEnabledMethods.push('$logout');
|
|
334
441
|
this.$clientEnabledMethods.push('$sendEmailVerification');
|
|
442
|
+
this.$clientEnabledMethods.push('$hasTOTPSecret');
|
|
443
|
+
this.$clientEnabledMethods.push('$getNewTOTPSecret');
|
|
444
|
+
this.$clientEnabledMethods.push('$saveTOTPSecret');
|
|
445
|
+
this.$clientEnabledMethods.push('$removeTOTPSecret');
|
|
335
446
|
}
|
|
336
447
|
if (user != null &&
|
|
337
448
|
(abilities.indexOf('tilmeld/admin') !== -1 ||
|
|
338
449
|
abilities.indexOf('system/admin') !== -1)) {
|
|
339
|
-
this.$privateData = ['password', 'salt'];
|
|
450
|
+
this.$privateData = ['password', 'salt', 'totpSecret'];
|
|
451
|
+
this.$clientEnabledMethods.push('$hasTOTPSecret');
|
|
452
|
+
this.$clientEnabledMethods.push('$removeTOTPSecret');
|
|
340
453
|
this.$allowlistData = undefined;
|
|
341
454
|
}
|
|
342
455
|
else if (isCurrentUser || isNewUser) {
|
|
@@ -357,41 +470,66 @@ class User extends AbleObject_1.default {
|
|
|
357
470
|
this.$allowlistData.push('phone');
|
|
358
471
|
}
|
|
359
472
|
this.$privateData = [
|
|
473
|
+
'enabled',
|
|
360
474
|
'secret',
|
|
475
|
+
'emailChangeDate',
|
|
361
476
|
'newEmailSecret',
|
|
362
|
-
'cancelEmailAddress',
|
|
363
477
|
'cancelEmailSecret',
|
|
364
|
-
'
|
|
478
|
+
'cancelEmailAddress',
|
|
365
479
|
'recoverSecret',
|
|
366
480
|
'recoverSecretDate',
|
|
367
|
-
'password',
|
|
368
481
|
'salt',
|
|
482
|
+
'password',
|
|
483
|
+
'passwordTemp',
|
|
484
|
+
'totpSecret',
|
|
369
485
|
];
|
|
370
486
|
}
|
|
487
|
+
if (user != null &&
|
|
488
|
+
!isCurrentUser &&
|
|
489
|
+
(abilities.indexOf('tilmeld/switch') !== -1 ||
|
|
490
|
+
abilities.indexOf('system/admin') !== -1)) {
|
|
491
|
+
this.$clientEnabledMethods.push('$switchUser');
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
$updateGroupDataProtection() {
|
|
495
|
+
if (this.$data.group != null && !this.$data.group.$asleep()) {
|
|
496
|
+
this.$data.group.$updateDataProtection();
|
|
497
|
+
}
|
|
498
|
+
for (let group of this.$data.groups ?? []) {
|
|
499
|
+
if (!group.$asleep()) {
|
|
500
|
+
group.$updateDataProtection();
|
|
501
|
+
}
|
|
502
|
+
}
|
|
371
503
|
}
|
|
372
|
-
$gatekeeper(ability) {
|
|
373
|
-
|
|
504
|
+
async $gatekeeper(ability) {
|
|
505
|
+
await this.$wake();
|
|
506
|
+
const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
374
507
|
if (ability == null) {
|
|
375
508
|
return tilmeld.User.current()?.$is(this) ?? false;
|
|
376
509
|
}
|
|
377
510
|
if (this.$gatekeeperCache == null) {
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
511
|
+
this.$gatekeeperCache = await this.$getGatekeeperCache();
|
|
512
|
+
}
|
|
513
|
+
return ((ability in this.$gatekeeperCache && !!this.$gatekeeperCache[ability]) ||
|
|
514
|
+
!!this.$data.abilities?.includes('system/admin'));
|
|
515
|
+
}
|
|
516
|
+
async $getGatekeeperCache() {
|
|
517
|
+
await this.$wake();
|
|
518
|
+
let abilities = this.$data.abilities ?? [];
|
|
519
|
+
if (this.$data.inheritAbilities) {
|
|
520
|
+
await Promise.all(this.$data.groups?.map((e) => e.$wake()) || []);
|
|
521
|
+
for (let curGroup of this.$data.groups ?? []) {
|
|
522
|
+
if (curGroup.enabled) {
|
|
523
|
+
abilities = abilities.concat(curGroup.abilities ?? []);
|
|
389
524
|
}
|
|
390
525
|
}
|
|
391
|
-
this.$
|
|
526
|
+
await this.$data.group?.$wake();
|
|
527
|
+
const group = this.$data.group;
|
|
528
|
+
if (group != null && group.cdate != null && group.enabled) {
|
|
529
|
+
abilities = abilities.concat(group.abilities ?? []);
|
|
530
|
+
}
|
|
392
531
|
}
|
|
393
|
-
return ((ability
|
|
394
|
-
!!this.$gatekeeperCache['system/admin']);
|
|
532
|
+
return Object.fromEntries(abilities.map((ability) => [ability, true]));
|
|
395
533
|
}
|
|
396
534
|
$clearCache() {
|
|
397
535
|
const ret = super.$clearCache();
|
|
@@ -400,7 +538,7 @@ class User extends AbleObject_1.default {
|
|
|
400
538
|
return ret;
|
|
401
539
|
}
|
|
402
540
|
async $sendEmailVerification() {
|
|
403
|
-
const tilmeld = this
|
|
541
|
+
const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
404
542
|
if (this.guid == null) {
|
|
405
543
|
return false;
|
|
406
544
|
}
|
|
@@ -463,18 +601,21 @@ class User extends AbleObject_1.default {
|
|
|
463
601
|
}
|
|
464
602
|
return success;
|
|
465
603
|
}
|
|
466
|
-
$addGroup(group) {
|
|
467
|
-
|
|
468
|
-
|
|
604
|
+
async $addGroup(group) {
|
|
605
|
+
await Promise.all(this.$data.groups?.map((e) => e.$wake()) || []);
|
|
606
|
+
let groups = this.$data.groups;
|
|
607
|
+
if (groups == null) {
|
|
608
|
+
groups = [];
|
|
469
609
|
}
|
|
470
|
-
if (!group.$inArray(
|
|
471
|
-
|
|
472
|
-
|
|
610
|
+
if (!group.$inArray(groups)) {
|
|
611
|
+
groups.push(group);
|
|
612
|
+
this.$data.groups = groups;
|
|
613
|
+
return groups;
|
|
473
614
|
}
|
|
474
615
|
return true;
|
|
475
616
|
}
|
|
476
617
|
$checkPassword(password) {
|
|
477
|
-
const tilmeld = this
|
|
618
|
+
const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
478
619
|
switch (tilmeld.config.pwMethod) {
|
|
479
620
|
case 'plain':
|
|
480
621
|
return this.$data.password === password;
|
|
@@ -486,10 +627,12 @@ class User extends AbleObject_1.default {
|
|
|
486
627
|
(0, sha256_1.default)(password + this.$data.salt).toString(enc_base64_1.default));
|
|
487
628
|
}
|
|
488
629
|
}
|
|
489
|
-
$delGroup(group) {
|
|
490
|
-
|
|
630
|
+
async $delGroup(group) {
|
|
631
|
+
await Promise.all(this.$data.groups?.map((e) => e.$wake()) || []);
|
|
632
|
+
let groups = this.$data.groups || [];
|
|
633
|
+
if (this.$data.groups != null && group.$inArray(groups)) {
|
|
491
634
|
const newGroups = [];
|
|
492
|
-
for (let curGroup of
|
|
635
|
+
for (let curGroup of groups) {
|
|
493
636
|
if (!group.$is(curGroup)) {
|
|
494
637
|
newGroups.push(curGroup);
|
|
495
638
|
}
|
|
@@ -499,7 +642,7 @@ class User extends AbleObject_1.default {
|
|
|
499
642
|
}
|
|
500
643
|
return true;
|
|
501
644
|
}
|
|
502
|
-
$inGroup(group) {
|
|
645
|
+
async $inGroup(group) {
|
|
503
646
|
if (typeof group === 'string') {
|
|
504
647
|
if (this.$data.group?.guid === group) {
|
|
505
648
|
return true;
|
|
@@ -513,13 +656,16 @@ class User extends AbleObject_1.default {
|
|
|
513
656
|
}
|
|
514
657
|
return (group.$is(this.$data.group) || group.$inArray(this.$data.groups ?? []));
|
|
515
658
|
}
|
|
516
|
-
$isDescendant(group) {
|
|
517
|
-
|
|
518
|
-
|
|
659
|
+
async $isDescendant(group) {
|
|
660
|
+
await this.$data.group?.$wake();
|
|
661
|
+
if (this.$data.group != null &&
|
|
662
|
+
this.$data.group?.cdate != null &&
|
|
663
|
+
(await this.$data.group?.$isDescendant(group))) {
|
|
519
664
|
return true;
|
|
520
665
|
}
|
|
666
|
+
await Promise.all(this.$data.groups?.map((e) => e.$wake()) || []);
|
|
521
667
|
for (let curGroup of this.$data.groups ?? []) {
|
|
522
|
-
if (curGroup.$isDescendant(group)) {
|
|
668
|
+
if (await curGroup.$isDescendant(group)) {
|
|
523
669
|
return true;
|
|
524
670
|
}
|
|
525
671
|
}
|
|
@@ -533,7 +679,14 @@ class User extends AbleObject_1.default {
|
|
|
533
679
|
return { result: false, message: 'Incorrect password.' };
|
|
534
680
|
}
|
|
535
681
|
this.$data.passwordTemp = data.newPassword;
|
|
682
|
+
if (data.revokeCurrentTokens) {
|
|
683
|
+
this.$data.revokeTokenDate = Date.now();
|
|
684
|
+
}
|
|
536
685
|
if (await this.$save()) {
|
|
686
|
+
if (data.revokeCurrentTokens) {
|
|
687
|
+
const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
688
|
+
await tilmeld.login(this, true);
|
|
689
|
+
}
|
|
537
690
|
return { result: true, message: 'Your password has been changed.' };
|
|
538
691
|
}
|
|
539
692
|
else {
|
|
@@ -541,7 +694,7 @@ class User extends AbleObject_1.default {
|
|
|
541
694
|
}
|
|
542
695
|
}
|
|
543
696
|
$password(password) {
|
|
544
|
-
const tilmeld = this
|
|
697
|
+
const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
545
698
|
switch (tilmeld.config.pwMethod) {
|
|
546
699
|
case 'plain':
|
|
547
700
|
delete this.$data.salt;
|
|
@@ -559,14 +712,158 @@ class User extends AbleObject_1.default {
|
|
|
559
712
|
}
|
|
560
713
|
return this.$data.password;
|
|
561
714
|
}
|
|
715
|
+
async $revokeCurrentTokens(data) {
|
|
716
|
+
if (!this.$checkPassword(data.password ?? '')) {
|
|
717
|
+
return { result: false, message: 'Incorrect password.' };
|
|
718
|
+
}
|
|
719
|
+
this.$data.revokeTokenDate = Date.now();
|
|
720
|
+
if (await this.$save()) {
|
|
721
|
+
const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
722
|
+
await tilmeld.login(this, true);
|
|
723
|
+
return {
|
|
724
|
+
result: true,
|
|
725
|
+
message: 'You have logged out of all other sessions.',
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
else {
|
|
729
|
+
return { result: false, message: "Couldn't save revocation date." };
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
async $hasTOTPSecret() {
|
|
733
|
+
return this.$data.totpSecret != null;
|
|
734
|
+
}
|
|
735
|
+
$checkTOTPCode(code) {
|
|
736
|
+
if (this.$data.totpSecret == null) {
|
|
737
|
+
return false;
|
|
738
|
+
}
|
|
739
|
+
const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
740
|
+
const totp = new otpauth_1.TOTP({
|
|
741
|
+
issuer: tilmeld.config.appName,
|
|
742
|
+
label: this.$data.username,
|
|
743
|
+
algorithm: 'SHA1',
|
|
744
|
+
digits: 6,
|
|
745
|
+
period: 30,
|
|
746
|
+
secret: this.$data.totpSecret,
|
|
747
|
+
});
|
|
748
|
+
return totp.validate({ token: code, window: 2 }) != null;
|
|
749
|
+
}
|
|
750
|
+
async $getNewTOTPSecret() {
|
|
751
|
+
const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
752
|
+
if (this.$data.totpSecret != null) {
|
|
753
|
+
throw new errors_1.BadDataError('You already have a 2FA secret.');
|
|
754
|
+
}
|
|
755
|
+
const secret = new otpauth_1.Secret();
|
|
756
|
+
const totp = new otpauth_1.TOTP({
|
|
757
|
+
issuer: tilmeld.config.appName,
|
|
758
|
+
label: this.$data.username,
|
|
759
|
+
algorithm: 'SHA1',
|
|
760
|
+
digits: 6,
|
|
761
|
+
period: 30,
|
|
762
|
+
secret,
|
|
763
|
+
});
|
|
764
|
+
const uri = totp.toString();
|
|
765
|
+
const qrcode = await (0, qrcode_1.toDataURL)(uri);
|
|
766
|
+
return {
|
|
767
|
+
uri,
|
|
768
|
+
qrcode,
|
|
769
|
+
secret: secret.base32,
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
async $saveTOTPSecret(data) {
|
|
773
|
+
if (!this.$checkPassword(data.password ?? '')) {
|
|
774
|
+
return { result: false, message: 'Incorrect password.' };
|
|
775
|
+
}
|
|
776
|
+
if (this.$data.totpSecret != null) {
|
|
777
|
+
return { result: false, message: 'You already have a 2FA secret.' };
|
|
778
|
+
}
|
|
779
|
+
if (data.secret == null ||
|
|
780
|
+
typeof data.secret !== 'string' ||
|
|
781
|
+
data.secret === '') {
|
|
782
|
+
return { result: false, message: '2FA secret is invalid.' };
|
|
783
|
+
}
|
|
784
|
+
if (data.code == null ||
|
|
785
|
+
typeof data.code !== 'string' ||
|
|
786
|
+
data.code.length !== 6) {
|
|
787
|
+
return { result: false, message: '2FA code is invalid.' };
|
|
788
|
+
}
|
|
789
|
+
const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
790
|
+
const totp = new otpauth_1.TOTP({
|
|
791
|
+
issuer: tilmeld.config.appName,
|
|
792
|
+
label: this.$data.username,
|
|
793
|
+
algorithm: 'SHA1',
|
|
794
|
+
digits: 6,
|
|
795
|
+
period: 30,
|
|
796
|
+
secret: data.secret,
|
|
797
|
+
});
|
|
798
|
+
if (totp.validate({ token: data.code, window: 2 }) == null) {
|
|
799
|
+
return { result: false, message: '2FA code is incorrect.' };
|
|
800
|
+
}
|
|
801
|
+
this.$data.totpSecret = data.secret;
|
|
802
|
+
if (await this.$save()) {
|
|
803
|
+
return { result: true, message: 'Your two factor secret is now set.' };
|
|
804
|
+
}
|
|
805
|
+
else {
|
|
806
|
+
return { result: false, message: "Couldn't save two factor secret." };
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
async $removeTOTPSecret(data) {
|
|
810
|
+
const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
811
|
+
if (data) {
|
|
812
|
+
if (!this.$checkPassword(data.password ?? '')) {
|
|
813
|
+
return { result: false, message: 'Incorrect password.' };
|
|
814
|
+
}
|
|
815
|
+
if (data.code == null ||
|
|
816
|
+
typeof data.code !== 'string' ||
|
|
817
|
+
data.code.length !== 6) {
|
|
818
|
+
return { result: false, message: '2FA code is invalid.' };
|
|
819
|
+
}
|
|
820
|
+
if (this.$data.totpSecret == null) {
|
|
821
|
+
return { result: false, message: "You don't have a 2FA secret." };
|
|
822
|
+
}
|
|
823
|
+
const totp = new otpauth_1.TOTP({
|
|
824
|
+
issuer: tilmeld.config.appName,
|
|
825
|
+
label: this.$data.username,
|
|
826
|
+
algorithm: 'SHA1',
|
|
827
|
+
digits: 6,
|
|
828
|
+
period: 30,
|
|
829
|
+
secret: this.$data.totpSecret,
|
|
830
|
+
});
|
|
831
|
+
if (totp.validate({ token: data.code, window: 2 }) == null) {
|
|
832
|
+
return { result: false, message: '2FA code is incorrect.' };
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
else if (!tilmeld.gatekeeper('tilmeld/admin')) {
|
|
836
|
+
return {
|
|
837
|
+
result: false,
|
|
838
|
+
message: 'You must provide your password and 2FA code.',
|
|
839
|
+
};
|
|
840
|
+
}
|
|
841
|
+
delete this.$data.totpSecret;
|
|
842
|
+
if (await this.$save()) {
|
|
843
|
+
return {
|
|
844
|
+
result: true,
|
|
845
|
+
message: 'Two factor secret has been removed.',
|
|
846
|
+
};
|
|
847
|
+
}
|
|
848
|
+
else {
|
|
849
|
+
return { result: false, message: "Couldn't remove two factor secret." };
|
|
850
|
+
}
|
|
851
|
+
}
|
|
562
852
|
async $checkUsername() {
|
|
563
|
-
const tilmeld = this
|
|
853
|
+
const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
564
854
|
if (!tilmeld.config.emailUsernames) {
|
|
565
855
|
if (this.$data.username == null || !this.$data.username.length) {
|
|
566
856
|
return { result: false, message: 'Please specify a username.' };
|
|
567
857
|
}
|
|
568
|
-
if (tilmeld.config.
|
|
569
|
-
|
|
858
|
+
if (this.$data.username.length < tilmeld.config.minUsernameLength) {
|
|
859
|
+
return {
|
|
860
|
+
result: false,
|
|
861
|
+
message: 'Usernames must be at least ' +
|
|
862
|
+
tilmeld.config.minUsernameLength +
|
|
863
|
+
' characters.',
|
|
864
|
+
};
|
|
865
|
+
}
|
|
866
|
+
if (this.$data.username.length > tilmeld.config.maxUsernameLength) {
|
|
570
867
|
return {
|
|
571
868
|
result: false,
|
|
572
869
|
message: 'Usernames must not exceed ' +
|
|
@@ -600,6 +897,17 @@ class User extends AbleObject_1.default {
|
|
|
600
897
|
if (test != null) {
|
|
601
898
|
return { result: false, message: 'That username is taken.' };
|
|
602
899
|
}
|
|
900
|
+
for (let callback of this.constructor
|
|
901
|
+
.checkUsernameCallbacks) {
|
|
902
|
+
if (callback) {
|
|
903
|
+
const result = await callback(this, {
|
|
904
|
+
username: this.$data.username,
|
|
905
|
+
});
|
|
906
|
+
if (!result.result) {
|
|
907
|
+
return { message: 'Username is not available.', ...result };
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
}
|
|
603
911
|
return {
|
|
604
912
|
result: true,
|
|
605
913
|
message: this.guid != null ? 'Username is valid.' : 'Username is available!',
|
|
@@ -610,8 +918,15 @@ class User extends AbleObject_1.default {
|
|
|
610
918
|
if (this.$data.username == null || !this.$data.username.length) {
|
|
611
919
|
return { result: false, message: 'Please specify an email.' };
|
|
612
920
|
}
|
|
613
|
-
if (tilmeld.config.
|
|
614
|
-
|
|
921
|
+
if (this.$data.username.length < tilmeld.config.minUsernameLength) {
|
|
922
|
+
return {
|
|
923
|
+
result: false,
|
|
924
|
+
message: 'Emails must be at least ' +
|
|
925
|
+
tilmeld.config.minUsernameLength +
|
|
926
|
+
' characters.',
|
|
927
|
+
};
|
|
928
|
+
}
|
|
929
|
+
if (this.$data.username.length > tilmeld.config.maxUsernameLength) {
|
|
615
930
|
return {
|
|
616
931
|
result: false,
|
|
617
932
|
message: 'Emails must not exceed ' +
|
|
@@ -623,7 +938,7 @@ class User extends AbleObject_1.default {
|
|
|
623
938
|
}
|
|
624
939
|
}
|
|
625
940
|
async $checkEmail() {
|
|
626
|
-
const tilmeld = this
|
|
941
|
+
const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
627
942
|
if (this.$data.email == null || !this.$data.email.length) {
|
|
628
943
|
if (tilmeld.config.verifyEmail) {
|
|
629
944
|
return { result: false, message: 'Please specify an email.' };
|
|
@@ -658,7 +973,7 @@ class User extends AbleObject_1.default {
|
|
|
658
973
|
};
|
|
659
974
|
}
|
|
660
975
|
async $checkPhone() {
|
|
661
|
-
const tilmeld = this
|
|
976
|
+
const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
662
977
|
if (this.$data.phone == null || !this.$data.phone.length) {
|
|
663
978
|
return { result: false, message: 'Please specify a phone number.' };
|
|
664
979
|
}
|
|
@@ -686,7 +1001,7 @@ class User extends AbleObject_1.default {
|
|
|
686
1001
|
};
|
|
687
1002
|
}
|
|
688
1003
|
async $register(data) {
|
|
689
|
-
let tilmeld = this
|
|
1004
|
+
let tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
690
1005
|
if (!tilmeld.config.allowRegistration) {
|
|
691
1006
|
return {
|
|
692
1007
|
result: false,
|
|
@@ -701,21 +1016,6 @@ class User extends AbleObject_1.default {
|
|
|
701
1016
|
message: 'This is already a registered user.',
|
|
702
1017
|
};
|
|
703
1018
|
}
|
|
704
|
-
try {
|
|
705
|
-
for (let callback of this.constructor
|
|
706
|
-
.beforeRegisterCallbacks) {
|
|
707
|
-
if (callback) {
|
|
708
|
-
await callback(this, data);
|
|
709
|
-
}
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
catch (e) {
|
|
713
|
-
return {
|
|
714
|
-
result: false,
|
|
715
|
-
loggedin: false,
|
|
716
|
-
message: e.message,
|
|
717
|
-
};
|
|
718
|
-
}
|
|
719
1019
|
if (!('password' in data) || !data.password.length) {
|
|
720
1020
|
return {
|
|
721
1021
|
result: false,
|
|
@@ -744,8 +1044,27 @@ class User extends AbleObject_1.default {
|
|
|
744
1044
|
const nymph = this.$nymph;
|
|
745
1045
|
const tnymph = await this.$nymph.startTransaction(transaction);
|
|
746
1046
|
this.$nymph = tnymph;
|
|
747
|
-
tilmeld = this
|
|
1047
|
+
tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
1048
|
+
let message = '';
|
|
1049
|
+
let loggedin = false;
|
|
748
1050
|
try {
|
|
1051
|
+
try {
|
|
1052
|
+
for (let callback of this.constructor
|
|
1053
|
+
.beforeRegisterCallbacks) {
|
|
1054
|
+
if (callback) {
|
|
1055
|
+
await callback(this, data);
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
catch (e) {
|
|
1060
|
+
await tnymph.rollback(transaction);
|
|
1061
|
+
this.$nymph = nymph;
|
|
1062
|
+
return {
|
|
1063
|
+
result: false,
|
|
1064
|
+
loggedin: false,
|
|
1065
|
+
message: e.message,
|
|
1066
|
+
};
|
|
1067
|
+
}
|
|
749
1068
|
let generatedPrimaryGroup = null;
|
|
750
1069
|
if (tilmeld.config.generatePrimary) {
|
|
751
1070
|
generatedPrimaryGroup = await tilmeld.Group.factory();
|
|
@@ -831,8 +1150,6 @@ class User extends AbleObject_1.default {
|
|
|
831
1150
|
},
|
|
832
1151
|
}, this);
|
|
833
1152
|
}
|
|
834
|
-
let message = '';
|
|
835
|
-
let loggedin = false;
|
|
836
1153
|
if (generatedPrimaryGroup != null) {
|
|
837
1154
|
generatedPrimaryGroup.user = this;
|
|
838
1155
|
if (!(await generatedPrimaryGroup.$saveSkipAC())) {
|
|
@@ -855,7 +1172,7 @@ class User extends AbleObject_1.default {
|
|
|
855
1172
|
else if (tilmeld.config.verifyEmail &&
|
|
856
1173
|
tilmeld.config.unverifiedAccess &&
|
|
857
1174
|
!madeAdmin) {
|
|
858
|
-
if (!tilmeld.login(this, true)) {
|
|
1175
|
+
if (!(await tilmeld.login(this, true))) {
|
|
859
1176
|
throw new Error('An error occurred trying to log you in.');
|
|
860
1177
|
}
|
|
861
1178
|
message +=
|
|
@@ -865,7 +1182,7 @@ class User extends AbleObject_1.default {
|
|
|
865
1182
|
loggedin = true;
|
|
866
1183
|
}
|
|
867
1184
|
else {
|
|
868
|
-
if (!tilmeld.login(this, true)) {
|
|
1185
|
+
if (!(await tilmeld.login(this, true))) {
|
|
869
1186
|
throw new Error('An error occurred trying to log you in.');
|
|
870
1187
|
}
|
|
871
1188
|
message += "You're now registered and logged in!";
|
|
@@ -880,19 +1197,6 @@ class User extends AbleObject_1.default {
|
|
|
880
1197
|
});
|
|
881
1198
|
}
|
|
882
1199
|
}
|
|
883
|
-
try {
|
|
884
|
-
await tnymph.commit(transaction);
|
|
885
|
-
this.$nymph = nymph;
|
|
886
|
-
this.$nymph.tilmeld?.fillSession(this);
|
|
887
|
-
}
|
|
888
|
-
catch (e) {
|
|
889
|
-
throw e;
|
|
890
|
-
}
|
|
891
|
-
return {
|
|
892
|
-
result: true,
|
|
893
|
-
loggedin,
|
|
894
|
-
message,
|
|
895
|
-
};
|
|
896
1200
|
}
|
|
897
1201
|
else {
|
|
898
1202
|
await tnymph.rollback(transaction);
|
|
@@ -909,15 +1213,28 @@ class User extends AbleObject_1.default {
|
|
|
909
1213
|
this.$nymph = nymph;
|
|
910
1214
|
throw e;
|
|
911
1215
|
}
|
|
1216
|
+
try {
|
|
1217
|
+
await tnymph.commit(transaction);
|
|
1218
|
+
this.$nymph = nymph;
|
|
1219
|
+
await this.$nymph.tilmeld?.fillSession(this);
|
|
1220
|
+
}
|
|
1221
|
+
catch (e) {
|
|
1222
|
+
throw e;
|
|
1223
|
+
}
|
|
1224
|
+
return {
|
|
1225
|
+
result: true,
|
|
1226
|
+
loggedin,
|
|
1227
|
+
message,
|
|
1228
|
+
};
|
|
912
1229
|
}
|
|
913
1230
|
async $save() {
|
|
914
|
-
let tilmeld = this
|
|
1231
|
+
let tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
915
1232
|
if (this.$data.username == null || !this.$data.username.trim().length) {
|
|
916
1233
|
return false;
|
|
917
1234
|
}
|
|
918
1235
|
if (tilmeld.gatekeeper('tilmeld/admin') &&
|
|
919
1236
|
!tilmeld.gatekeeper('system/admin') &&
|
|
920
|
-
this.$
|
|
1237
|
+
this.$data.abilities?.includes('system/admin')) {
|
|
921
1238
|
throw new errors_1.BadDataError("You don't have the authority to modify system admins.");
|
|
922
1239
|
}
|
|
923
1240
|
let sendVerification = false;
|
|
@@ -1064,17 +1381,18 @@ class User extends AbleObject_1.default {
|
|
|
1064
1381
|
const nymph = this.$nymph;
|
|
1065
1382
|
const tnymph = await this.$nymph.startTransaction(transaction);
|
|
1066
1383
|
this.$nymph = tnymph;
|
|
1067
|
-
tilmeld = this
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1384
|
+
tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
1385
|
+
const group = this.$data.group;
|
|
1386
|
+
await group?.$wake();
|
|
1387
|
+
if (group != null && group.user != null && this.$is(group.user)) {
|
|
1071
1388
|
try {
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
await
|
|
1389
|
+
group.groupname = this.$data.username;
|
|
1390
|
+
group.avatar = this.$data.avatar;
|
|
1391
|
+
group.email = this.$data.email;
|
|
1392
|
+
group.name = this.$data.name;
|
|
1393
|
+
group.phone = this.$data.phone;
|
|
1394
|
+
await group.$saveSkipAC();
|
|
1395
|
+
this.$data.group = group;
|
|
1078
1396
|
}
|
|
1079
1397
|
catch (e) {
|
|
1080
1398
|
await tnymph.rollback(transaction);
|
|
@@ -1108,8 +1426,9 @@ class User extends AbleObject_1.default {
|
|
|
1108
1426
|
this.$descendantGroups = undefined;
|
|
1109
1427
|
this.$gatekeeperCache = undefined;
|
|
1110
1428
|
await tnymph.commit(transaction);
|
|
1111
|
-
|
|
1112
|
-
|
|
1429
|
+
const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(nymph);
|
|
1430
|
+
if (tilmeld.User.current(true).$is(this)) {
|
|
1431
|
+
await tilmeld.fillSession(this);
|
|
1113
1432
|
}
|
|
1114
1433
|
}
|
|
1115
1434
|
else {
|
|
@@ -1130,12 +1449,12 @@ class User extends AbleObject_1.default {
|
|
|
1130
1449
|
return false;
|
|
1131
1450
|
}
|
|
1132
1451
|
async $delete() {
|
|
1133
|
-
const tilmeld = this
|
|
1452
|
+
const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
|
|
1134
1453
|
if (!tilmeld.gatekeeper('tilmeld/admin')) {
|
|
1135
1454
|
throw new errors_1.BadDataError("You don't have the authority to delete users.");
|
|
1136
1455
|
}
|
|
1137
1456
|
if (!tilmeld.gatekeeper('system/admin') &&
|
|
1138
|
-
this.$
|
|
1457
|
+
this.$data.abilities?.includes('system/admin')) {
|
|
1139
1458
|
throw new errors_1.BadDataError("You don't have the authority to delete system admins.");
|
|
1140
1459
|
}
|
|
1141
1460
|
if (tilmeld.User.current(true).$is(this)) {
|
|
@@ -1163,9 +1482,9 @@ class User extends AbleObject_1.default {
|
|
|
1163
1482
|
return true;
|
|
1164
1483
|
}
|
|
1165
1484
|
}
|
|
1166
|
-
exports.default = User;
|
|
1167
1485
|
User.ETYPE = 'tilmeld_user';
|
|
1168
1486
|
User.class = 'User';
|
|
1487
|
+
User.checkUsernameCallbacks = [];
|
|
1169
1488
|
User.beforeRegisterCallbacks = [];
|
|
1170
1489
|
User.afterRegisterCallbacks = [];
|
|
1171
1490
|
User.beforeLoginCallbacks = [];
|
|
@@ -1180,23 +1499,26 @@ User.DEFAULT_CLIENT_ENABLED_METHODS = [
|
|
|
1180
1499
|
'$register',
|
|
1181
1500
|
];
|
|
1182
1501
|
User.DEFAULT_PRIVATE_DATA = [
|
|
1502
|
+
'abilities',
|
|
1183
1503
|
'email',
|
|
1184
|
-
'originalEmail',
|
|
1185
1504
|
'phone',
|
|
1186
1505
|
'group',
|
|
1187
1506
|
'groups',
|
|
1188
|
-
'abilities',
|
|
1189
1507
|
'inheritAbilities',
|
|
1190
|
-
'
|
|
1191
|
-
'recoverSecretDate',
|
|
1192
|
-
'password',
|
|
1193
|
-
'salt',
|
|
1508
|
+
'enabled',
|
|
1194
1509
|
'secret',
|
|
1195
|
-
'
|
|
1510
|
+
'emailChangeDate',
|
|
1196
1511
|
'newEmailSecret',
|
|
1197
|
-
'
|
|
1512
|
+
'newEmailAddress',
|
|
1198
1513
|
'cancelEmailSecret',
|
|
1199
|
-
'
|
|
1514
|
+
'cancelEmailAddress',
|
|
1515
|
+
'recoverSecret',
|
|
1516
|
+
'recoverSecretDate',
|
|
1517
|
+
'salt',
|
|
1518
|
+
'password',
|
|
1519
|
+
'passwordTemp',
|
|
1520
|
+
'revokeTokenDate',
|
|
1521
|
+
'totpSecret',
|
|
1200
1522
|
];
|
|
1201
1523
|
User.DEFAULT_ALLOWLIST_DATA = [];
|
|
1202
1524
|
User.clientEnabledStaticMethods = [
|
|
@@ -1207,4 +1529,5 @@ User.clientEnabledStaticMethods = [
|
|
|
1207
1529
|
'getClientConfig',
|
|
1208
1530
|
];
|
|
1209
1531
|
User.searchRestrictedData = [...User.DEFAULT_PRIVATE_DATA];
|
|
1532
|
+
exports.default = User;
|
|
1210
1533
|
//# sourceMappingURL=User.js.map
|