@eaccess/auth 0.1.21 → 1.0.0
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/README.md +90 -41
- package/dist/index.cjs +63 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -4
- package/dist/index.d.ts +6 -4
- package/dist/index.js +62 -52
- package/dist/index.js.map +1 -1
- package/package.json +17 -9
package/dist/index.cjs
CHANGED
|
@@ -75,6 +75,7 @@ __export(index_exports, {
|
|
|
75
75
|
createAuthMiddleware: () => createAuthMiddleware,
|
|
76
76
|
createAuthTables: () => createAuthTables,
|
|
77
77
|
createUser: () => createUser,
|
|
78
|
+
defineRoles: () => defineRoles,
|
|
78
79
|
deleteUserBy: () => deleteUserBy,
|
|
79
80
|
dropAuthTables: () => dropAuthTables,
|
|
80
81
|
forceLogoutForUserBy: () => forceLogoutForUserBy,
|
|
@@ -95,7 +96,7 @@ __export(index_exports, {
|
|
|
95
96
|
module.exports = __toCommonJS(index_exports);
|
|
96
97
|
|
|
97
98
|
// src/auth-manager.ts
|
|
98
|
-
var import_hash4 = require("@prsm/hash");
|
|
99
|
+
var import_hash4 = __toESM(require("@prsm/hash"), 1);
|
|
99
100
|
var import_ms3 = __toESM(require("@prsm/ms"), 1);
|
|
100
101
|
|
|
101
102
|
// src/types.ts
|
|
@@ -811,7 +812,7 @@ var GitHubProvider = class extends BaseOAuthProvider {
|
|
|
811
812
|
client_id: this.config.clientId,
|
|
812
813
|
redirect_uri: this.config.redirectUri,
|
|
813
814
|
scope: scopes?.join(" ") || "user:email",
|
|
814
|
-
state: state ||
|
|
815
|
+
state: state || crypto.randomUUID(),
|
|
815
816
|
response_type: "code"
|
|
816
817
|
});
|
|
817
818
|
return `https://github.com/login/oauth/authorize?${params}`;
|
|
@@ -860,7 +861,7 @@ var GoogleProvider = class extends BaseOAuthProvider {
|
|
|
860
861
|
client_id: this.config.clientId,
|
|
861
862
|
redirect_uri: this.config.redirectUri,
|
|
862
863
|
scope: scopes?.join(" ") || "openid profile email",
|
|
863
|
-
state: state ||
|
|
864
|
+
state: state || crypto.randomUUID(),
|
|
864
865
|
response_type: "code",
|
|
865
866
|
access_type: "offline",
|
|
866
867
|
prompt: "consent"
|
|
@@ -902,7 +903,7 @@ var AzureProvider = class extends BaseOAuthProvider {
|
|
|
902
903
|
client_id: azureConfig.clientId,
|
|
903
904
|
redirect_uri: azureConfig.redirectUri,
|
|
904
905
|
scope: scopes?.join(" ") || "openid profile email User.Read",
|
|
905
|
-
state: state ||
|
|
906
|
+
state: state || crypto.randomUUID(),
|
|
906
907
|
response_type: "code",
|
|
907
908
|
response_mode: "query"
|
|
908
909
|
});
|
|
@@ -961,7 +962,7 @@ var AzureProvider = class extends BaseOAuthProvider {
|
|
|
961
962
|
|
|
962
963
|
// src/two-factor/totp-provider.ts
|
|
963
964
|
var import_totp = __toESM(require("@eaccess/totp"), 1);
|
|
964
|
-
var import_hash = require("@prsm/hash");
|
|
965
|
+
var import_hash = __toESM(require("@prsm/hash"), 1);
|
|
965
966
|
var TotpProvider = class {
|
|
966
967
|
constructor(config) {
|
|
967
968
|
this.config = config;
|
|
@@ -978,23 +979,20 @@ var TotpProvider = class {
|
|
|
978
979
|
return import_totp.default.verifyTotp(secret, code, window);
|
|
979
980
|
}
|
|
980
981
|
generateBackupCodes(count = 10) {
|
|
982
|
+
const chars = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
|
|
981
983
|
const codes = [];
|
|
982
984
|
for (let i = 0; i < count; i++) {
|
|
983
|
-
const
|
|
984
|
-
|
|
985
|
-
for (let j = 0; j < 8; j++) {
|
|
986
|
-
code += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
987
|
-
}
|
|
988
|
-
codes.push(code);
|
|
985
|
+
const bytes = crypto.getRandomValues(new Uint8Array(8));
|
|
986
|
+
codes.push(Array.from(bytes, (b) => chars[b % chars.length]).join(""));
|
|
989
987
|
}
|
|
990
988
|
return codes;
|
|
991
989
|
}
|
|
992
|
-
hashBackupCodes(codes) {
|
|
993
|
-
return codes.map((code) => import_hash.
|
|
990
|
+
async hashBackupCodes(codes) {
|
|
991
|
+
return await Promise.all(codes.map((code) => import_hash.default.encode(code)));
|
|
994
992
|
}
|
|
995
|
-
verifyBackupCode(hashedCodes, inputCode) {
|
|
993
|
+
async verifyBackupCode(hashedCodes, inputCode) {
|
|
996
994
|
for (let i = 0; i < hashedCodes.length; i++) {
|
|
997
|
-
if (import_hash.
|
|
995
|
+
if (await import_hash.default.verify(hashedCodes[i], inputCode.toUpperCase())) {
|
|
998
996
|
return { isValid: true, index: i };
|
|
999
997
|
}
|
|
1000
998
|
}
|
|
@@ -1011,7 +1009,7 @@ var TotpProvider = class {
|
|
|
1011
1009
|
|
|
1012
1010
|
// src/two-factor/otp-provider.ts
|
|
1013
1011
|
var import_ms = __toESM(require("@prsm/ms"), 1);
|
|
1014
|
-
var import_hash2 = require("@prsm/hash");
|
|
1012
|
+
var import_hash2 = __toESM(require("@prsm/hash"), 1);
|
|
1015
1013
|
var OtpProvider = class {
|
|
1016
1014
|
constructor(config) {
|
|
1017
1015
|
this.config = config;
|
|
@@ -1019,24 +1017,16 @@ var OtpProvider = class {
|
|
|
1019
1017
|
}
|
|
1020
1018
|
generateOTP() {
|
|
1021
1019
|
const length = this.config.twoFactor?.codeLength || 6;
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
otp += Math.floor(Math.random() * 10).toString();
|
|
1025
|
-
}
|
|
1026
|
-
return otp;
|
|
1020
|
+
const bytes = crypto.getRandomValues(new Uint8Array(length));
|
|
1021
|
+
return Array.from(bytes, (b) => (b % 10).toString()).join("");
|
|
1027
1022
|
}
|
|
1028
1023
|
generateSelector() {
|
|
1029
|
-
|
|
1030
|
-
let selector = "";
|
|
1031
|
-
for (let i = 0; i < 32; i++) {
|
|
1032
|
-
selector += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
1033
|
-
}
|
|
1034
|
-
return selector;
|
|
1024
|
+
return crypto.randomUUID().replace(/-/g, "");
|
|
1035
1025
|
}
|
|
1036
1026
|
async createAndStoreOTP(accountId, mechanism) {
|
|
1037
1027
|
const otp = this.generateOTP();
|
|
1038
1028
|
const selector = this.generateSelector();
|
|
1039
|
-
const tokenHash = import_hash2.
|
|
1029
|
+
const tokenHash = await import_hash2.default.encode(otp);
|
|
1040
1030
|
const expiryDuration = this.config.twoFactor?.tokenExpiry || "5m";
|
|
1041
1031
|
const expiresAt = new Date(Date.now() + (0, import_ms.default)(expiryDuration));
|
|
1042
1032
|
await this.queries.deleteTwoFactorTokensByAccountAndMechanism(accountId, mechanism);
|
|
@@ -1058,7 +1048,7 @@ var OtpProvider = class {
|
|
|
1058
1048
|
await this.queries.deleteTwoFactorToken(token.id);
|
|
1059
1049
|
return { isValid: false };
|
|
1060
1050
|
}
|
|
1061
|
-
const isValid = import_hash2.
|
|
1051
|
+
const isValid = await import_hash2.default.verify(token.token_hash, inputCode);
|
|
1062
1052
|
if (isValid) {
|
|
1063
1053
|
await this.queries.deleteTwoFactorToken(token.id);
|
|
1064
1054
|
return { isValid: true, token };
|
|
@@ -1105,7 +1095,7 @@ var TwoFactorManager = class {
|
|
|
1105
1095
|
const backupCodesCount = this.config.twoFactor?.backupCodesCount || 10;
|
|
1106
1096
|
backupCodes = this.totpProvider.generateBackupCodes(backupCodesCount);
|
|
1107
1097
|
}
|
|
1108
|
-
const hashedBackupCodes = backupCodes ? this.totpProvider.hashBackupCodes(backupCodes) : void 0;
|
|
1098
|
+
const hashedBackupCodes = backupCodes ? await this.totpProvider.hashBackupCodes(backupCodes) : void 0;
|
|
1109
1099
|
const verified = !requireVerification;
|
|
1110
1100
|
if (existingMethod) {
|
|
1111
1101
|
await this.queries.updateTwoFactorMethod(existingMethod.id, {
|
|
@@ -1203,7 +1193,7 @@ var TwoFactorManager = class {
|
|
|
1203
1193
|
}
|
|
1204
1194
|
const backupCodesCount = this.config.twoFactor?.backupCodesCount || 10;
|
|
1205
1195
|
const backupCodes = this.totpProvider.generateBackupCodes(backupCodesCount);
|
|
1206
|
-
const hashedBackupCodes = this.totpProvider.hashBackupCodes(backupCodes);
|
|
1196
|
+
const hashedBackupCodes = await this.totpProvider.hashBackupCodes(backupCodes);
|
|
1207
1197
|
await this.queries.updateTwoFactorMethod(method.id, {
|
|
1208
1198
|
verified: true,
|
|
1209
1199
|
backup_codes: hashedBackupCodes,
|
|
@@ -1255,7 +1245,7 @@ var TwoFactorManager = class {
|
|
|
1255
1245
|
if (!method || !method.verified || !method.backup_codes) {
|
|
1256
1246
|
throw new TwoFactorNotSetupError();
|
|
1257
1247
|
}
|
|
1258
|
-
const { isValid, index } = this.totpProvider.verifyBackupCode(method.backup_codes, code);
|
|
1248
|
+
const { isValid, index } = await this.totpProvider.verifyBackupCode(method.backup_codes, code);
|
|
1259
1249
|
if (!isValid) {
|
|
1260
1250
|
await this.activityLogger.logActivity(twoFactorState.accountId, AuthActivityAction.TwoFactorFailed, this.req, false, { mechanism: "backup_code", reason: "invalid_code" });
|
|
1261
1251
|
throw new InvalidBackupCodeError();
|
|
@@ -1404,7 +1394,7 @@ var TwoFactorManager = class {
|
|
|
1404
1394
|
}
|
|
1405
1395
|
const backupCodesCount = this.config.twoFactor?.backupCodesCount || 10;
|
|
1406
1396
|
const backupCodes = this.totpProvider.generateBackupCodes(backupCodesCount);
|
|
1407
|
-
const hashedBackupCodes = this.totpProvider.hashBackupCodes(backupCodes);
|
|
1397
|
+
const hashedBackupCodes = await this.totpProvider.hashBackupCodes(backupCodes);
|
|
1408
1398
|
await this.queries.updateTwoFactorMethod(method.id, {
|
|
1409
1399
|
backup_codes: hashedBackupCodes
|
|
1410
1400
|
});
|
|
@@ -1486,7 +1476,7 @@ __export(auth_functions_exports, {
|
|
|
1486
1476
|
setStatusForUserBy: () => setStatusForUserBy,
|
|
1487
1477
|
userExistsByEmail: () => userExistsByEmail
|
|
1488
1478
|
});
|
|
1489
|
-
var import_hash3 = require("@prsm/hash");
|
|
1479
|
+
var import_hash3 = __toESM(require("@prsm/hash"), 1);
|
|
1490
1480
|
var import_ms2 = __toESM(require("@prsm/ms"), 1);
|
|
1491
1481
|
function parseCookies(cookieHeader) {
|
|
1492
1482
|
const cookies = {};
|
|
@@ -1557,7 +1547,7 @@ async function findAccountByIdentifier(queries, identifier) {
|
|
|
1557
1547
|
return null;
|
|
1558
1548
|
}
|
|
1559
1549
|
async function createConfirmationToken(queries, account, email, callback) {
|
|
1560
|
-
const token = import_hash3.
|
|
1550
|
+
const token = await import_hash3.default.encode(email);
|
|
1561
1551
|
const expires = new Date(Date.now() + 1e3 * 60 * 60 * 24 * 7);
|
|
1562
1552
|
await queries.createConfirmation({
|
|
1563
1553
|
accountId: account.id,
|
|
@@ -1578,7 +1568,7 @@ async function createUser(config, credentials, userId, callback) {
|
|
|
1578
1568
|
throw new EmailTakenError();
|
|
1579
1569
|
}
|
|
1580
1570
|
const finalUserId = userId || generateAutoUserId();
|
|
1581
|
-
const hashedPassword = import_hash3.
|
|
1571
|
+
const hashedPassword = await import_hash3.default.encode(credentials.password);
|
|
1582
1572
|
const verified = typeof callback !== "function";
|
|
1583
1573
|
const account = await queries.createAccount({
|
|
1584
1574
|
userId: finalUserId,
|
|
@@ -1602,7 +1592,7 @@ async function register(config, email, password, userId, callback) {
|
|
|
1602
1592
|
throw new EmailTakenError();
|
|
1603
1593
|
}
|
|
1604
1594
|
const finalUserId = userId || generateAutoUserId();
|
|
1605
|
-
const hashedPassword = import_hash3.
|
|
1595
|
+
const hashedPassword = await import_hash3.default.encode(password);
|
|
1606
1596
|
const verified = typeof callback !== "function";
|
|
1607
1597
|
const account = await queries.createAccount({
|
|
1608
1598
|
userId: finalUserId,
|
|
@@ -1659,7 +1649,7 @@ async function changePasswordForUserBy(config, identifier, password) {
|
|
|
1659
1649
|
throw new UserNotFoundError();
|
|
1660
1650
|
}
|
|
1661
1651
|
await queries.updateAccount(account.id, {
|
|
1662
|
-
password: import_hash3.
|
|
1652
|
+
password: await import_hash3.default.encode(password)
|
|
1663
1653
|
});
|
|
1664
1654
|
}
|
|
1665
1655
|
async function setStatusForUserBy(config, identifier, status) {
|
|
@@ -1680,7 +1670,7 @@ async function initiatePasswordResetForUserBy(config, identifier, expiresAfter =
|
|
|
1680
1670
|
throw new EmailNotVerifiedError();
|
|
1681
1671
|
}
|
|
1682
1672
|
const expiry = !expiresAfter ? (0, import_ms2.default)("6h") : (0, import_ms2.default)(expiresAfter);
|
|
1683
|
-
const token = import_hash3.
|
|
1673
|
+
const token = await import_hash3.default.encode(account.email);
|
|
1684
1674
|
const expires = new Date(Date.now() + expiry);
|
|
1685
1675
|
await queries.createResetToken({
|
|
1686
1676
|
accountId: account.id,
|
|
@@ -1707,7 +1697,7 @@ async function resetPassword(config, email, expiresAfter = null, maxOpenRequests
|
|
|
1707
1697
|
if (openRequests >= maxRequests) {
|
|
1708
1698
|
throw new TooManyResetsError();
|
|
1709
1699
|
}
|
|
1710
|
-
const token = import_hash3.
|
|
1700
|
+
const token = await import_hash3.default.encode(email);
|
|
1711
1701
|
const expires = new Date(Date.now() + expiry);
|
|
1712
1702
|
await queries.createResetToken({
|
|
1713
1703
|
accountId: account.id,
|
|
@@ -1735,11 +1725,11 @@ async function confirmResetPassword(config, token, password) {
|
|
|
1735
1725
|
throw new ResetDisabledError();
|
|
1736
1726
|
}
|
|
1737
1727
|
validatePassword(password, config);
|
|
1738
|
-
if (!import_hash3.
|
|
1728
|
+
if (!await import_hash3.default.verify(token, account.email)) {
|
|
1739
1729
|
throw new InvalidTokenError();
|
|
1740
1730
|
}
|
|
1741
1731
|
await queries.updateAccount(account.id, {
|
|
1742
|
-
password: import_hash3.
|
|
1732
|
+
password: await import_hash3.default.encode(password)
|
|
1743
1733
|
});
|
|
1744
1734
|
await queries.deleteResetToken(token);
|
|
1745
1735
|
return { accountId: account.id, email: account.email };
|
|
@@ -1809,7 +1799,7 @@ var AuthManager = class {
|
|
|
1809
1799
|
}
|
|
1810
1800
|
}
|
|
1811
1801
|
getRoleMap() {
|
|
1812
|
-
return createMapFromEnum(AuthRole);
|
|
1802
|
+
return createMapFromEnum(this.config.roles || AuthRole);
|
|
1813
1803
|
}
|
|
1814
1804
|
getStatusMap() {
|
|
1815
1805
|
return createMapFromEnum(AuthStatus);
|
|
@@ -1960,7 +1950,7 @@ var AuthManager = class {
|
|
|
1960
1950
|
});
|
|
1961
1951
|
}
|
|
1962
1952
|
async createRememberDirective(account) {
|
|
1963
|
-
const token = import_hash4.
|
|
1953
|
+
const token = await import_hash4.default.encode(account.email);
|
|
1964
1954
|
const duration = this.config.rememberDuration || "30d";
|
|
1965
1955
|
const expires = new Date(Date.now() + (0, import_ms3.default)(duration));
|
|
1966
1956
|
await this.queries.createRememberToken({
|
|
@@ -1998,7 +1988,7 @@ var AuthManager = class {
|
|
|
1998
1988
|
await this.activityLogger.logActivity(null, AuthActivityAction.FailedLogin, this.req, false, { email, reason: "account_not_found" });
|
|
1999
1989
|
throw new UserNotFoundError();
|
|
2000
1990
|
}
|
|
2001
|
-
if (!account.password || !import_hash4.
|
|
1991
|
+
if (!account.password || !await import_hash4.default.verify(account.password, password)) {
|
|
2002
1992
|
await this.activityLogger.logActivity(account.id, AuthActivityAction.FailedLogin, this.req, false, { email, reason: "invalid_password" });
|
|
2003
1993
|
throw new InvalidPasswordError();
|
|
2004
1994
|
}
|
|
@@ -2111,7 +2101,7 @@ var AuthManager = class {
|
|
|
2111
2101
|
throw new EmailTakenError();
|
|
2112
2102
|
}
|
|
2113
2103
|
const finalUserId = userId || this.generateAutoUserId();
|
|
2114
|
-
const hashedPassword = import_hash4.
|
|
2104
|
+
const hashedPassword = await import_hash4.default.encode(password);
|
|
2115
2105
|
const verified = typeof callback !== "function";
|
|
2116
2106
|
const account = await this.queries.createAccount({
|
|
2117
2107
|
userId: finalUserId,
|
|
@@ -2128,7 +2118,7 @@ var AuthManager = class {
|
|
|
2128
2118
|
return account;
|
|
2129
2119
|
}
|
|
2130
2120
|
async createConfirmationToken(account, email, callback) {
|
|
2131
|
-
const token = import_hash4.
|
|
2121
|
+
const token = await import_hash4.default.encode(email);
|
|
2132
2122
|
const expires = new Date(Date.now() + 1e3 * 60 * 60 * 24 * 7);
|
|
2133
2123
|
await this.queries.createConfirmation({
|
|
2134
2124
|
accountId: account.id,
|
|
@@ -2270,7 +2260,7 @@ var AuthManager = class {
|
|
|
2270
2260
|
if (new Date(confirmation.expires) < /* @__PURE__ */ new Date()) {
|
|
2271
2261
|
throw new ConfirmationExpiredError();
|
|
2272
2262
|
}
|
|
2273
|
-
if (!import_hash4.
|
|
2263
|
+
if (!await import_hash4.default.verify(token, confirmation.email)) {
|
|
2274
2264
|
throw new InvalidTokenError();
|
|
2275
2265
|
}
|
|
2276
2266
|
await this.queries.updateAccount(confirmation.account_id, {
|
|
@@ -2368,7 +2358,7 @@ var AuthManager = class {
|
|
|
2368
2358
|
if (openRequests >= maxRequests) {
|
|
2369
2359
|
throw new TooManyResetsError();
|
|
2370
2360
|
}
|
|
2371
|
-
const token = import_hash4.
|
|
2361
|
+
const token = await import_hash4.default.encode(email);
|
|
2372
2362
|
const expires = new Date(Date.now() + expiry);
|
|
2373
2363
|
await this.queries.createResetToken({
|
|
2374
2364
|
accountId: account.id,
|
|
@@ -2410,11 +2400,11 @@ var AuthManager = class {
|
|
|
2410
2400
|
throw new ResetDisabledError();
|
|
2411
2401
|
}
|
|
2412
2402
|
this.validatePassword(password);
|
|
2413
|
-
if (!import_hash4.
|
|
2403
|
+
if (!await import_hash4.default.verify(token, account.email)) {
|
|
2414
2404
|
throw new InvalidTokenError();
|
|
2415
2405
|
}
|
|
2416
2406
|
await this.queries.updateAccount(account.id, {
|
|
2417
|
-
password: import_hash4.
|
|
2407
|
+
password: await import_hash4.default.encode(password)
|
|
2418
2408
|
});
|
|
2419
2409
|
if (logout) {
|
|
2420
2410
|
await this.forceLogoutForAccountById(account.id);
|
|
@@ -2442,7 +2432,7 @@ var AuthManager = class {
|
|
|
2442
2432
|
if (!account.password) {
|
|
2443
2433
|
return false;
|
|
2444
2434
|
}
|
|
2445
|
-
return import_hash4.
|
|
2435
|
+
return await import_hash4.default.verify(account.password, password);
|
|
2446
2436
|
}
|
|
2447
2437
|
async forceLogoutForAccountById(accountId) {
|
|
2448
2438
|
await this.queries.deleteRememberTokensForAccount(accountId);
|
|
@@ -2774,6 +2764,26 @@ function createAuthContext(config) {
|
|
|
2774
2764
|
}
|
|
2775
2765
|
|
|
2776
2766
|
// src/user-roles.ts
|
|
2767
|
+
var MAX_ROLES = 31;
|
|
2768
|
+
function defineRoles(...names) {
|
|
2769
|
+
if (names.length > MAX_ROLES) {
|
|
2770
|
+
throw new Error(`Cannot define more than ${MAX_ROLES} roles (postgres INTEGER is 32-bit signed)`);
|
|
2771
|
+
}
|
|
2772
|
+
if (names.length === 0) {
|
|
2773
|
+
throw new Error("At least one role name is required");
|
|
2774
|
+
}
|
|
2775
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2776
|
+
const roles = {};
|
|
2777
|
+
for (let i = 0; i < names.length; i++) {
|
|
2778
|
+
const name = names[i];
|
|
2779
|
+
if (seen.has(name)) {
|
|
2780
|
+
throw new Error(`Duplicate role name: ${name}`);
|
|
2781
|
+
}
|
|
2782
|
+
seen.add(name);
|
|
2783
|
+
roles[name] = 1 << i;
|
|
2784
|
+
}
|
|
2785
|
+
return Object.freeze(roles);
|
|
2786
|
+
}
|
|
2777
2787
|
async function findAccountByIdentifier2(queries, identifier) {
|
|
2778
2788
|
let account = null;
|
|
2779
2789
|
if (identifier.accountId !== void 0) {
|
|
@@ -2857,6 +2867,7 @@ async function getUserRoles(config, identifier) {
|
|
|
2857
2867
|
createAuthMiddleware,
|
|
2858
2868
|
createAuthTables,
|
|
2859
2869
|
createUser,
|
|
2870
|
+
defineRoles,
|
|
2860
2871
|
deleteUserBy,
|
|
2861
2872
|
dropAuthTables,
|
|
2862
2873
|
forceLogoutForUserBy,
|