@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/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 || Math.random().toString(36).substring(2),
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 || Math.random().toString(36).substring(2),
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 || Math.random().toString(36).substring(2),
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 chars = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
984
- let code = "";
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.hash.encode(code));
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.hash.verify(hashedCodes[i], inputCode.toUpperCase())) {
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
- let otp = "";
1023
- for (let i = 0; i < length; i++) {
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
- const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
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.hash.encode(otp);
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.hash.verify(token.token_hash, inputCode);
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.hash.encode(email);
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.hash.encode(credentials.password);
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.hash.encode(password);
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.hash.encode(password)
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.hash.encode(account.email);
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.hash.encode(email);
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.hash.verify(token, account.email)) {
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.hash.encode(password)
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.hash.encode(account.email);
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.hash.verify(account.password, password)) {
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.hash.encode(password);
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.hash.encode(email);
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.hash.verify(token, confirmation.email)) {
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.hash.encode(email);
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.hash.verify(token, account.email)) {
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.hash.encode(password)
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.hash.verify(account.password, password);
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,