@nymphjs/tilmeld 1.0.0-beta.45 → 1.0.0-beta.47
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 +15 -0
- package/README.md +1 -1
- package/dist/Group.js +18 -4
- package/dist/Group.js.map +1 -1
- package/dist/Tilmeld.js +4 -4
- package/dist/Tilmeld.js.map +1 -1
- package/dist/User.d.ts +1 -1
- package/dist/User.js +50 -26
- package/dist/User.js.map +1 -1
- package/dist/conf/d.d.ts +1 -0
- package/dist/conf/defaults.js +1 -0
- package/dist/conf/defaults.js.map +1 -1
- package/package.json +24 -24
- package/src/AbleObject.ts +1 -1
- package/src/Group.test.ts +1 -1
- package/src/Group.ts +49 -37
- package/src/Tilmeld.ts +26 -26
- package/src/User.test.ts +1 -1
- package/src/User.ts +99 -78
- package/src/conf/d.ts +9 -5
- package/src/conf/defaults.ts +8 -7
- package/src/tilmeldJoiProps.ts +9 -9
package/src/User.ts
CHANGED
|
@@ -40,7 +40,7 @@ export type EventType =
|
|
|
40
40
|
*/
|
|
41
41
|
export type TilmeldCheckUsernameCallback = (
|
|
42
42
|
user: User & UserData,
|
|
43
|
-
data: { username: string }
|
|
43
|
+
data: { username: string },
|
|
44
44
|
) => Promise<{ result: boolean; message?: string }>;
|
|
45
45
|
/**
|
|
46
46
|
* Theses are run before the user data checks, so the only checks before are
|
|
@@ -48,11 +48,11 @@ export type TilmeldCheckUsernameCallback = (
|
|
|
48
48
|
*/
|
|
49
49
|
export type TilmeldBeforeRegisterCallback = (
|
|
50
50
|
user: User & UserData,
|
|
51
|
-
data: { password: string; additionalData?: { [k: string]: any } }
|
|
51
|
+
data: { password: string; additionalData?: { [k: string]: any } },
|
|
52
52
|
) => Promise<void>;
|
|
53
53
|
export type TilmeldAfterRegisterCallback = (
|
|
54
54
|
user: User & UserData,
|
|
55
|
-
result: { loggedin: boolean; message: string }
|
|
55
|
+
result: { loggedin: boolean; message: string },
|
|
56
56
|
) => Promise<void>;
|
|
57
57
|
/**
|
|
58
58
|
* These are run after the authentication checks, but before the login action.
|
|
@@ -63,20 +63,20 @@ export type TilmeldBeforeLoginCallback = (
|
|
|
63
63
|
username: string;
|
|
64
64
|
password: string;
|
|
65
65
|
additionalData?: { [k: string]: any };
|
|
66
|
-
}
|
|
66
|
+
},
|
|
67
67
|
) => Promise<void>;
|
|
68
68
|
/**
|
|
69
69
|
* This is run before the transaction is committed, and you can perform
|
|
70
70
|
* additional functions on the transaction, which is available in `user.$nymph`.
|
|
71
71
|
*/
|
|
72
72
|
export type TilmeldAfterLoginCallback = (
|
|
73
|
-
user: User & UserData
|
|
73
|
+
user: User & UserData,
|
|
74
74
|
) => Promise<void>;
|
|
75
75
|
export type TilmeldBeforeLogoutCallback = (
|
|
76
|
-
user: User & UserData
|
|
76
|
+
user: User & UserData,
|
|
77
77
|
) => Promise<void>;
|
|
78
78
|
export type TilmeldAfterLogoutCallback = (
|
|
79
|
-
user: User & UserData
|
|
79
|
+
user: User & UserData,
|
|
80
80
|
) => Promise<void>;
|
|
81
81
|
|
|
82
82
|
export type UserData = {
|
|
@@ -303,7 +303,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
303
303
|
{
|
|
304
304
|
type: '&',
|
|
305
305
|
ilike: ['username', username.replace(/([\\%_])/g, (s) => `\\${s}`)],
|
|
306
|
-
}
|
|
306
|
+
},
|
|
307
307
|
);
|
|
308
308
|
if (entity != null) {
|
|
309
309
|
return entity;
|
|
@@ -329,10 +329,10 @@ export default class User extends AbleObject<UserData> {
|
|
|
329
329
|
|
|
330
330
|
public static current(returnObjectIfNotExist: true): User & UserData;
|
|
331
331
|
public static current(
|
|
332
|
-
returnObjectIfNotExist?: false
|
|
332
|
+
returnObjectIfNotExist?: false,
|
|
333
333
|
): (User & UserData) | null;
|
|
334
334
|
public static current(
|
|
335
|
-
returnObjectIfNotExist?: boolean
|
|
335
|
+
returnObjectIfNotExist?: boolean,
|
|
336
336
|
): (User & UserData) | null {
|
|
337
337
|
const tilmeld = enforceTilmeld(this);
|
|
338
338
|
if (tilmeld.currentUser == null) {
|
|
@@ -370,7 +370,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
370
370
|
{
|
|
371
371
|
type: '&',
|
|
372
372
|
ilike: ['email', data.account.replace(/([\\%_])/g, (s) => `\\${s}`)],
|
|
373
|
-
}
|
|
373
|
+
},
|
|
374
374
|
);
|
|
375
375
|
|
|
376
376
|
if (getUser == null) {
|
|
@@ -466,7 +466,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
466
466
|
data.secret !== user.recoverSecret ||
|
|
467
467
|
strtotime(
|
|
468
468
|
'+' + tilmeld.config.pwRecoveryTimeLimit,
|
|
469
|
-
Math.floor((user.recoverSecretDate ?? 0) / 1000)
|
|
469
|
+
Math.floor((user.recoverSecretDate ?? 0) / 1000),
|
|
470
470
|
) *
|
|
471
471
|
1000 <
|
|
472
472
|
Date.now()
|
|
@@ -745,7 +745,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
745
745
|
await Promise.all(this.$data.groups?.map((e) => e.$wake()) || []);
|
|
746
746
|
for (let curGroup of this.$data.groups ?? []) {
|
|
747
747
|
this.$descendantGroups = this.$descendantGroups?.concat(
|
|
748
|
-
await curGroup.$getDescendants()
|
|
748
|
+
await curGroup.$getDescendants(),
|
|
749
749
|
);
|
|
750
750
|
}
|
|
751
751
|
}
|
|
@@ -764,7 +764,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
764
764
|
!tilmeld.currentUser.abilities?.includes('system/admin'))
|
|
765
765
|
) {
|
|
766
766
|
throw new BadDataError(
|
|
767
|
-
"You don't have the authority to grant or revoke system/admin."
|
|
767
|
+
"You don't have the authority to grant or revoke system/admin.",
|
|
768
768
|
);
|
|
769
769
|
}
|
|
770
770
|
|
|
@@ -776,7 +776,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
776
776
|
!tilmeld.currentUser.abilities?.includes('system/admin'))
|
|
777
777
|
) {
|
|
778
778
|
throw new BadDataError(
|
|
779
|
-
"You don't have the authority to grant or revoke tilmeld/admin."
|
|
779
|
+
"You don't have the authority to grant or revoke tilmeld/admin.",
|
|
780
780
|
);
|
|
781
781
|
}
|
|
782
782
|
|
|
@@ -788,7 +788,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
788
788
|
!tilmeld.currentUser.abilities?.includes('system/admin'))
|
|
789
789
|
) {
|
|
790
790
|
throw new BadDataError(
|
|
791
|
-
"You don't have the authority to grant or revoke tilmeld/switch."
|
|
791
|
+
"You don't have the authority to grant or revoke tilmeld/switch.",
|
|
792
792
|
);
|
|
793
793
|
}
|
|
794
794
|
|
|
@@ -808,7 +808,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
808
808
|
!tilmeld.currentUser.abilities?.includes('system/admin'))
|
|
809
809
|
) {
|
|
810
810
|
throw new BadDataError(
|
|
811
|
-
"You don't have the authority to grant or revoke system/admin."
|
|
811
|
+
"You don't have the authority to grant or revoke system/admin.",
|
|
812
812
|
);
|
|
813
813
|
}
|
|
814
814
|
|
|
@@ -820,7 +820,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
820
820
|
!tilmeld.currentUser.abilities?.includes('system/admin'))
|
|
821
821
|
) {
|
|
822
822
|
throw new BadDataError(
|
|
823
|
-
"You don't have the authority to grant or revoke tilmeld/admin."
|
|
823
|
+
"You don't have the authority to grant or revoke tilmeld/admin.",
|
|
824
824
|
);
|
|
825
825
|
}
|
|
826
826
|
|
|
@@ -832,7 +832,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
832
832
|
!tilmeld.currentUser.abilities?.includes('system/admin'))
|
|
833
833
|
) {
|
|
834
834
|
throw new BadDataError(
|
|
835
|
-
"You don't have the authority to grant or revoke tilmeld/switch."
|
|
835
|
+
"You don't have the authority to grant or revoke tilmeld/switch.",
|
|
836
836
|
);
|
|
837
837
|
}
|
|
838
838
|
|
|
@@ -891,6 +891,8 @@ export default class User extends AbleObject<UserData> {
|
|
|
891
891
|
) {
|
|
892
892
|
// Users who can edit other users can see most of their data.
|
|
893
893
|
this.$privateData = ['password', 'salt', 'totpSecret'];
|
|
894
|
+
this.$clientEnabledMethods.push('$hasTOTPSecret');
|
|
895
|
+
this.$clientEnabledMethods.push('$removeTOTPSecret');
|
|
894
896
|
this.$allowlistData = undefined;
|
|
895
897
|
} else if (isCurrentUser || isNewUser) {
|
|
896
898
|
// Users can see their own data, and edit some of it.
|
|
@@ -1013,7 +1015,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
1013
1015
|
}
|
|
1014
1016
|
}
|
|
1015
1017
|
return Object.fromEntries(
|
|
1016
|
-
abilities.map((ability) => [ability, true as true])
|
|
1018
|
+
abilities.map((ability) => [ability, true as true]),
|
|
1017
1019
|
);
|
|
1018
1020
|
}
|
|
1019
1021
|
|
|
@@ -1042,7 +1044,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
1042
1044
|
|
|
1043
1045
|
if (this.$data.secret != null) {
|
|
1044
1046
|
const link = `${verifyUrl}?action=verify&id=${encodeURIComponent(
|
|
1045
|
-
this.guid
|
|
1047
|
+
this.guid,
|
|
1046
1048
|
)}&secret=${encodeURIComponent(this.$data.secret)}`;
|
|
1047
1049
|
success =
|
|
1048
1050
|
success &&
|
|
@@ -1060,13 +1062,13 @@ export default class User extends AbleObject<UserData> {
|
|
|
1060
1062
|
verifyLink: link,
|
|
1061
1063
|
},
|
|
1062
1064
|
},
|
|
1063
|
-
this
|
|
1065
|
+
this,
|
|
1064
1066
|
));
|
|
1065
1067
|
}
|
|
1066
1068
|
|
|
1067
1069
|
if (this.$data.newEmailSecret != null) {
|
|
1068
1070
|
const link = `${verifyUrl}?action=verifychange&id=${encodeURIComponent(
|
|
1069
|
-
this.guid
|
|
1071
|
+
this.guid,
|
|
1070
1072
|
)}&secret=${encodeURIComponent(this.$data.newEmailSecret)}`;
|
|
1071
1073
|
success =
|
|
1072
1074
|
success &&
|
|
@@ -1086,13 +1088,13 @@ export default class User extends AbleObject<UserData> {
|
|
|
1086
1088
|
newEmail: this.$data.newEmailAddress,
|
|
1087
1089
|
},
|
|
1088
1090
|
},
|
|
1089
|
-
this
|
|
1091
|
+
this,
|
|
1090
1092
|
));
|
|
1091
1093
|
}
|
|
1092
1094
|
|
|
1093
1095
|
if (this.$data.cancelEmailSecret != null) {
|
|
1094
1096
|
const link = `${verifyUrl}?action=cancelchange&id=${encodeURIComponent(
|
|
1095
|
-
this.guid
|
|
1097
|
+
this.guid,
|
|
1096
1098
|
)}&secret=${encodeURIComponent(this.$data.cancelEmailSecret)}`;
|
|
1097
1099
|
success =
|
|
1098
1100
|
success &&
|
|
@@ -1112,7 +1114,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
1112
1114
|
newEmail: this.$data.newEmailAddress ?? this.$data.email,
|
|
1113
1115
|
},
|
|
1114
1116
|
},
|
|
1115
|
-
this
|
|
1117
|
+
this,
|
|
1116
1118
|
));
|
|
1117
1119
|
}
|
|
1118
1120
|
|
|
@@ -1284,7 +1286,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
1284
1286
|
default:
|
|
1285
1287
|
this.$data.salt = nanoid();
|
|
1286
1288
|
this.$data.password = sha256(password + this.$data.salt).toString(
|
|
1287
|
-
Base64
|
|
1289
|
+
Base64,
|
|
1288
1290
|
);
|
|
1289
1291
|
break;
|
|
1290
1292
|
}
|
|
@@ -1447,39 +1449,46 @@ export default class User extends AbleObject<UserData> {
|
|
|
1447
1449
|
* @param data The input data from the client.
|
|
1448
1450
|
* @returns An object with a boolean 'result' entry and a 'message' entry.
|
|
1449
1451
|
*/
|
|
1450
|
-
public async $removeTOTPSecret(data
|
|
1452
|
+
public async $removeTOTPSecret(data?: {
|
|
1451
1453
|
password: string;
|
|
1452
1454
|
code: string;
|
|
1453
1455
|
}): Promise<{ result: boolean; message: string }> {
|
|
1454
|
-
|
|
1455
|
-
return { result: false, message: 'Incorrect password.' };
|
|
1456
|
-
}
|
|
1457
|
-
|
|
1458
|
-
if (this.$data.totpSecret == null) {
|
|
1459
|
-
return { result: false, message: "You don't have a 2FA secret." };
|
|
1460
|
-
}
|
|
1456
|
+
const tilmeld = enforceTilmeld(this);
|
|
1461
1457
|
|
|
1462
|
-
if (
|
|
1463
|
-
data.
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
) {
|
|
1467
|
-
return { result: false, message: '2FA code is invalid.' };
|
|
1468
|
-
}
|
|
1458
|
+
if (data) {
|
|
1459
|
+
if (!this.$checkPassword(data.password ?? '')) {
|
|
1460
|
+
return { result: false, message: 'Incorrect password.' };
|
|
1461
|
+
}
|
|
1469
1462
|
|
|
1470
|
-
|
|
1463
|
+
if (
|
|
1464
|
+
data.code == null ||
|
|
1465
|
+
typeof data.code !== 'string' ||
|
|
1466
|
+
data.code.length !== 6
|
|
1467
|
+
) {
|
|
1468
|
+
return { result: false, message: '2FA code is invalid.' };
|
|
1469
|
+
}
|
|
1471
1470
|
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
algorithm: 'SHA1',
|
|
1476
|
-
digits: 6,
|
|
1477
|
-
period: 30,
|
|
1478
|
-
secret: this.$data.totpSecret,
|
|
1479
|
-
});
|
|
1471
|
+
if (this.$data.totpSecret == null) {
|
|
1472
|
+
return { result: false, message: "You don't have a 2FA secret." };
|
|
1473
|
+
}
|
|
1480
1474
|
|
|
1481
|
-
|
|
1482
|
-
|
|
1475
|
+
const totp = new TOTP({
|
|
1476
|
+
issuer: tilmeld.config.appName,
|
|
1477
|
+
label: this.$data.username,
|
|
1478
|
+
algorithm: 'SHA1',
|
|
1479
|
+
digits: 6,
|
|
1480
|
+
period: 30,
|
|
1481
|
+
secret: this.$data.totpSecret,
|
|
1482
|
+
});
|
|
1483
|
+
|
|
1484
|
+
if (totp.validate({ token: data.code, window: 2 }) == null) {
|
|
1485
|
+
return { result: false, message: '2FA code is incorrect.' };
|
|
1486
|
+
}
|
|
1487
|
+
} else if (!tilmeld.gatekeeper('tilmeld/admin')) {
|
|
1488
|
+
return {
|
|
1489
|
+
result: false,
|
|
1490
|
+
message: 'You must provide your password and 2FA code.',
|
|
1491
|
+
};
|
|
1483
1492
|
}
|
|
1484
1493
|
|
|
1485
1494
|
delete this.$data.totpSecret;
|
|
@@ -1487,7 +1496,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
1487
1496
|
if (await this.$save()) {
|
|
1488
1497
|
return {
|
|
1489
1498
|
result: true,
|
|
1490
|
-
message: '
|
|
1499
|
+
message: 'Two factor secret has been removed.',
|
|
1491
1500
|
};
|
|
1492
1501
|
} else {
|
|
1493
1502
|
return { result: false, message: "Couldn't remove two factor secret." };
|
|
@@ -1505,10 +1514,16 @@ export default class User extends AbleObject<UserData> {
|
|
|
1505
1514
|
if (this.$data.username == null || !this.$data.username.length) {
|
|
1506
1515
|
return { result: false, message: 'Please specify a username.' };
|
|
1507
1516
|
}
|
|
1508
|
-
if (
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1517
|
+
if (this.$data.username.length < tilmeld.config.minUsernameLength) {
|
|
1518
|
+
return {
|
|
1519
|
+
result: false,
|
|
1520
|
+
message:
|
|
1521
|
+
'Usernames must be at least ' +
|
|
1522
|
+
tilmeld.config.minUsernameLength +
|
|
1523
|
+
' characters.',
|
|
1524
|
+
};
|
|
1525
|
+
}
|
|
1526
|
+
if (this.$data.username.length > tilmeld.config.maxUsernameLength) {
|
|
1512
1527
|
return {
|
|
1513
1528
|
result: false,
|
|
1514
1529
|
message:
|
|
@@ -1521,7 +1536,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
1521
1536
|
if (
|
|
1522
1537
|
difference(
|
|
1523
1538
|
this.$data.username.split(''),
|
|
1524
|
-
tilmeld.config.validChars.split('')
|
|
1539
|
+
tilmeld.config.validChars.split(''),
|
|
1525
1540
|
).length
|
|
1526
1541
|
) {
|
|
1527
1542
|
return {
|
|
@@ -1548,7 +1563,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
1548
1563
|
}
|
|
1549
1564
|
const test = await this.$nymph.getEntity(
|
|
1550
1565
|
{ class: tilmeld.User, skipAc: true },
|
|
1551
|
-
selector
|
|
1566
|
+
selector,
|
|
1552
1567
|
);
|
|
1553
1568
|
if (test != null) {
|
|
1554
1569
|
return { result: false, message: 'That username is taken.' };
|
|
@@ -1576,10 +1591,16 @@ export default class User extends AbleObject<UserData> {
|
|
|
1576
1591
|
if (this.$data.username == null || !this.$data.username.length) {
|
|
1577
1592
|
return { result: false, message: 'Please specify an email.' };
|
|
1578
1593
|
}
|
|
1579
|
-
if (
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1594
|
+
if (this.$data.username.length < tilmeld.config.minUsernameLength) {
|
|
1595
|
+
return {
|
|
1596
|
+
result: false,
|
|
1597
|
+
message:
|
|
1598
|
+
'Emails must be at least ' +
|
|
1599
|
+
tilmeld.config.minUsernameLength +
|
|
1600
|
+
' characters.',
|
|
1601
|
+
};
|
|
1602
|
+
}
|
|
1603
|
+
if (this.$data.username.length > tilmeld.config.maxUsernameLength) {
|
|
1583
1604
|
return {
|
|
1584
1605
|
result: false,
|
|
1585
1606
|
message:
|
|
@@ -1622,7 +1643,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
1622
1643
|
}
|
|
1623
1644
|
const test = await this.$nymph.getEntity(
|
|
1624
1645
|
{ class: tilmeld.User, skipAc: true },
|
|
1625
|
-
selector
|
|
1646
|
+
selector,
|
|
1626
1647
|
);
|
|
1627
1648
|
if (test != null) {
|
|
1628
1649
|
return {
|
|
@@ -1666,7 +1687,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
1666
1687
|
}
|
|
1667
1688
|
const test = await this.$nymph.getEntity(
|
|
1668
1689
|
{ class: tilmeld.User, skipAc: true },
|
|
1669
|
-
selector
|
|
1690
|
+
selector,
|
|
1670
1691
|
);
|
|
1671
1692
|
if (test != null) {
|
|
1672
1693
|
return { result: false, message: 'Phone number is in use.' };
|
|
@@ -1762,7 +1783,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
1762
1783
|
{
|
|
1763
1784
|
type: '&',
|
|
1764
1785
|
equal: ['defaultPrimary', true],
|
|
1765
|
-
}
|
|
1786
|
+
},
|
|
1766
1787
|
);
|
|
1767
1788
|
if (parent != null) {
|
|
1768
1789
|
generatedPrimaryGroup.parent = parent;
|
|
@@ -1784,7 +1805,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
1784
1805
|
{
|
|
1785
1806
|
type: '&',
|
|
1786
1807
|
equal: ['defaultPrimary', true],
|
|
1787
|
-
}
|
|
1808
|
+
},
|
|
1788
1809
|
);
|
|
1789
1810
|
if (group != null) {
|
|
1790
1811
|
this.$data.group = group;
|
|
@@ -1799,7 +1820,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
1799
1820
|
{
|
|
1800
1821
|
type: '&',
|
|
1801
1822
|
equal: ['unverifiedSecondary', true],
|
|
1802
|
-
}
|
|
1823
|
+
},
|
|
1803
1824
|
);
|
|
1804
1825
|
} else {
|
|
1805
1826
|
// Add the default secondaries.
|
|
@@ -1808,7 +1829,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
1808
1829
|
{
|
|
1809
1830
|
type: '&',
|
|
1810
1831
|
equal: ['defaultSecondary', true],
|
|
1811
|
-
}
|
|
1832
|
+
},
|
|
1812
1833
|
);
|
|
1813
1834
|
}
|
|
1814
1835
|
|
|
@@ -1858,7 +1879,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
1858
1879
|
userPhone: this.$data.phone,
|
|
1859
1880
|
},
|
|
1860
1881
|
},
|
|
1861
|
-
this
|
|
1882
|
+
this,
|
|
1862
1883
|
);
|
|
1863
1884
|
}
|
|
1864
1885
|
|
|
@@ -1961,7 +1982,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
1961
1982
|
this.$data.abilities?.includes('system/admin')
|
|
1962
1983
|
) {
|
|
1963
1984
|
throw new BadDataError(
|
|
1964
|
-
"You don't have the authority to modify system admins."
|
|
1985
|
+
"You don't have the authority to modify system admins.",
|
|
1965
1986
|
);
|
|
1966
1987
|
}
|
|
1967
1988
|
|
|
@@ -2079,10 +2100,10 @@ export default class User extends AbleObject<UserData> {
|
|
|
2079
2100
|
new Date(
|
|
2080
2101
|
strtotime(
|
|
2081
2102
|
'+' + tilmeld.config.emailRateLimit,
|
|
2082
|
-
Math.floor(this.$data.emailChangeDate / 1000)
|
|
2083
|
-
) * 1000
|
|
2103
|
+
Math.floor(this.$data.emailChangeDate / 1000),
|
|
2104
|
+
) * 1000,
|
|
2084
2105
|
).toString() +
|
|
2085
|
-
' to change your email address again.'
|
|
2106
|
+
' to change your email address again.',
|
|
2086
2107
|
);
|
|
2087
2108
|
} else {
|
|
2088
2109
|
if (
|
|
@@ -2237,7 +2258,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
2237
2258
|
this.$data.abilities?.includes('system/admin')
|
|
2238
2259
|
) {
|
|
2239
2260
|
throw new BadDataError(
|
|
2240
|
-
"You don't have the authority to delete system admins."
|
|
2261
|
+
"You don't have the authority to delete system admins.",
|
|
2241
2262
|
);
|
|
2242
2263
|
}
|
|
2243
2264
|
if (tilmeld.User.current(true).$is(this)) {
|
|
@@ -2262,7 +2283,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
2262
2283
|
? TilmeldBeforeLogoutCallback
|
|
2263
2284
|
: T extends 'afterLogout'
|
|
2264
2285
|
? TilmeldAfterLogoutCallback
|
|
2265
|
-
: never
|
|
2286
|
+
: never,
|
|
2266
2287
|
) {
|
|
2267
2288
|
const prop = (event + 'Callbacks') as T extends 'checkUsername'
|
|
2268
2289
|
? 'checkUsernameCallbacks'
|
|
@@ -2303,7 +2324,7 @@ export default class User extends AbleObject<UserData> {
|
|
|
2303
2324
|
? TilmeldBeforeLogoutCallback
|
|
2304
2325
|
: T extends 'afterLogout'
|
|
2305
2326
|
? TilmeldAfterLogoutCallback
|
|
2306
|
-
: never
|
|
2327
|
+
: never,
|
|
2307
2328
|
) {
|
|
2308
2329
|
const prop = (event + 'Callbacks') as T extends 'checkUsername'
|
|
2309
2330
|
? 'checkUsernameCallbacks'
|
package/src/conf/d.ts
CHANGED
|
@@ -206,7 +206,11 @@ export interface Config {
|
|
|
206
206
|
*/
|
|
207
207
|
validEmailRegexNotice: string;
|
|
208
208
|
/**
|
|
209
|
-
* The
|
|
209
|
+
* The minimum length for usernames.
|
|
210
|
+
*/
|
|
211
|
+
minUsernameLength: number;
|
|
212
|
+
/**
|
|
213
|
+
* The maximum length for usernames. `Infinity` for unlimited.
|
|
210
214
|
*/
|
|
211
215
|
maxUsernameLength: number;
|
|
212
216
|
/**
|
|
@@ -233,7 +237,7 @@ export interface Config {
|
|
|
233
237
|
jwtBuilder: (
|
|
234
238
|
config: Config,
|
|
235
239
|
user: User & UserData,
|
|
236
|
-
switchToken?: boolean
|
|
240
|
+
switchToken?: boolean,
|
|
237
241
|
) => string;
|
|
238
242
|
/**
|
|
239
243
|
* Function to verify that a JWT was signed with the secret key, validate its
|
|
@@ -247,7 +251,7 @@ export interface Config {
|
|
|
247
251
|
jwtExtract: (
|
|
248
252
|
config: Config,
|
|
249
253
|
token: string,
|
|
250
|
-
xsrfToken?: string
|
|
254
|
+
xsrfToken?: string,
|
|
251
255
|
) => { guid: string; issued: Date; expire: Date } | null;
|
|
252
256
|
/**
|
|
253
257
|
* The absolute path to the email template directory. Used by the default
|
|
@@ -264,7 +268,7 @@ export interface Config {
|
|
|
264
268
|
configEmail: (
|
|
265
269
|
tilmeld: Tilmeld,
|
|
266
270
|
options: EmailOptions,
|
|
267
|
-
user: User & UserData
|
|
271
|
+
user: User & UserData,
|
|
268
272
|
) => Promise<EmailConfig>;
|
|
269
273
|
/**
|
|
270
274
|
* Send an email to a user. Uses `email-templates` by default.
|
|
@@ -294,7 +298,7 @@ export interface Config {
|
|
|
294
298
|
sendEmail: (
|
|
295
299
|
tilmeld: Tilmeld,
|
|
296
300
|
options: EmailOptions,
|
|
297
|
-
user: User & UserData
|
|
301
|
+
user: User & UserData,
|
|
298
302
|
) => Promise<boolean>;
|
|
299
303
|
/**
|
|
300
304
|
* The address you'd like to receive a notification of registered users, if
|
package/src/conf/defaults.ts
CHANGED
|
@@ -49,6 +49,7 @@ export default {
|
|
|
49
49
|
validEmailRegex:
|
|
50
50
|
/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,
|
|
51
51
|
validEmailRegexNotice: 'Email must be a correctly formatted address.',
|
|
52
|
+
minUsernameLength: 1,
|
|
52
53
|
maxUsernameLength: 128,
|
|
53
54
|
jwtSecret: '',
|
|
54
55
|
jwtExpire: 60 * 60 * 24 * 7 * 8, // 8 weeks(ish)
|
|
@@ -68,7 +69,7 @@ export default {
|
|
|
68
69
|
xsrfToken: 'TILMELDXSRF-' + nanoid(),
|
|
69
70
|
},
|
|
70
71
|
secret,
|
|
71
|
-
{ expiresIn: switchToken ? config.jwtSwitchExpire : config.jwtExpire }
|
|
72
|
+
{ expiresIn: switchToken ? config.jwtSwitchExpire : config.jwtExpire },
|
|
72
73
|
);
|
|
73
74
|
},
|
|
74
75
|
jwtExtract: (config, token, xsrfToken?) => {
|
|
@@ -128,14 +129,14 @@ export default {
|
|
|
128
129
|
},
|
|
129
130
|
sendEmail: async (tilmeld, options, user) => {
|
|
130
131
|
const email = new Email(
|
|
131
|
-
await tilmeld.config.configEmail(tilmeld, options, user)
|
|
132
|
+
await tilmeld.config.configEmail(tilmeld, options, user),
|
|
132
133
|
);
|
|
133
134
|
try {
|
|
134
135
|
const result = await email.send({
|
|
135
136
|
...options,
|
|
136
137
|
template: path.join(
|
|
137
138
|
tilmeld.config.emailTemplateDir,
|
|
138
|
-
options.template ?? '.'
|
|
139
|
+
options.template ?? '.',
|
|
139
140
|
),
|
|
140
141
|
locals: {
|
|
141
142
|
// System
|
|
@@ -205,13 +206,13 @@ export default {
|
|
|
205
206
|
name: 'control characters',
|
|
206
207
|
invert: true,
|
|
207
208
|
})
|
|
208
|
-
.max(256)
|
|
209
|
+
.max(256),
|
|
209
210
|
),
|
|
210
211
|
defaultPrimary: Joi.boolean(),
|
|
211
212
|
defaultSecondary: Joi.boolean(),
|
|
212
213
|
unverifiedSecondary: Joi.boolean(),
|
|
213
214
|
}),
|
|
214
|
-
'Invalid Group: '
|
|
215
|
+
'Invalid Group: ',
|
|
215
216
|
);
|
|
216
217
|
},
|
|
217
218
|
validatorUser: (user) => {
|
|
@@ -274,7 +275,7 @@ export default {
|
|
|
274
275
|
name: 'control characters',
|
|
275
276
|
invert: true,
|
|
276
277
|
})
|
|
277
|
-
.max(256)
|
|
278
|
+
.max(256),
|
|
278
279
|
),
|
|
279
280
|
inheritAbilities: Joi.boolean(),
|
|
280
281
|
secret: Joi.string()
|
|
@@ -322,7 +323,7 @@ export default {
|
|
|
322
323
|
.max(40)
|
|
323
324
|
.pattern(/^[A-Z234567]+$/, 'base32 encoded unpadded'),
|
|
324
325
|
}),
|
|
325
|
-
'Invalid User: '
|
|
326
|
+
'Invalid User: ',
|
|
326
327
|
);
|
|
327
328
|
},
|
|
328
329
|
} as Config;
|
package/src/tilmeldJoiProps.ts
CHANGED
|
@@ -11,36 +11,36 @@ export default {
|
|
|
11
11
|
TilmeldAccessLevels.NO_ACCESS,
|
|
12
12
|
TilmeldAccessLevels.READ_ACCESS,
|
|
13
13
|
TilmeldAccessLevels.WRITE_ACCESS,
|
|
14
|
-
TilmeldAccessLevels.FULL_ACCESS
|
|
14
|
+
TilmeldAccessLevels.FULL_ACCESS,
|
|
15
15
|
),
|
|
16
16
|
acGroup: Joi.number().valid(
|
|
17
17
|
TilmeldAccessLevels.NO_ACCESS,
|
|
18
18
|
TilmeldAccessLevels.READ_ACCESS,
|
|
19
19
|
TilmeldAccessLevels.WRITE_ACCESS,
|
|
20
|
-
TilmeldAccessLevels.FULL_ACCESS
|
|
20
|
+
TilmeldAccessLevels.FULL_ACCESS,
|
|
21
21
|
),
|
|
22
22
|
acOther: Joi.number().valid(
|
|
23
23
|
TilmeldAccessLevels.NO_ACCESS,
|
|
24
24
|
TilmeldAccessLevels.READ_ACCESS,
|
|
25
25
|
TilmeldAccessLevels.WRITE_ACCESS,
|
|
26
|
-
TilmeldAccessLevels.FULL_ACCESS
|
|
26
|
+
TilmeldAccessLevels.FULL_ACCESS,
|
|
27
27
|
),
|
|
28
28
|
acRead: Joi.array().items(
|
|
29
29
|
Joi.alternatives().try(
|
|
30
30
|
Joi.object().instance(User),
|
|
31
|
-
Joi.object().instance(Group)
|
|
32
|
-
)
|
|
31
|
+
Joi.object().instance(Group),
|
|
32
|
+
),
|
|
33
33
|
),
|
|
34
34
|
acWrite: Joi.array().items(
|
|
35
35
|
Joi.alternatives().try(
|
|
36
36
|
Joi.object().instance(User),
|
|
37
|
-
Joi.object().instance(Group)
|
|
38
|
-
)
|
|
37
|
+
Joi.object().instance(Group),
|
|
38
|
+
),
|
|
39
39
|
),
|
|
40
40
|
acFull: Joi.array().items(
|
|
41
41
|
Joi.alternatives().try(
|
|
42
42
|
Joi.object().instance(User),
|
|
43
|
-
Joi.object().instance(Group)
|
|
44
|
-
)
|
|
43
|
+
Joi.object().instance(Group),
|
|
44
|
+
),
|
|
45
45
|
),
|
|
46
46
|
};
|