@eaccess/auth 0.1.3 → 0.1.5

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
@@ -65,10 +65,11 @@ __export(index_exports, {
65
65
  UserNotFoundError: () => UserNotFoundError,
66
66
  UserNotLoggedInError: () => UserNotLoggedInError,
67
67
  addRoleToUser: () => addRoleToUser,
68
+ authFunctions: () => auth_functions_exports,
68
69
  cleanupExpiredTokens: () => cleanupExpiredTokens,
70
+ createAuthContext: () => createAuthContext,
69
71
  createAuthMiddleware: () => createAuthMiddleware,
70
72
  createAuthTables: () => createAuthTables,
71
- createUser: () => createUser,
72
73
  dropAuthTables: () => dropAuthTables,
73
74
  getAuthTableStats: () => getAuthTableStats,
74
75
  getUserRoles: () => getUserRoles,
@@ -79,9 +80,71 @@ __export(index_exports, {
79
80
  });
80
81
  module.exports = __toCommonJS(index_exports);
81
82
 
82
- // src/auth-admin-manager.ts
83
- var import_hash2 = require("@prsm/hash");
84
- var import_ms = __toESM(require("@prsm/ms"), 1);
83
+ // src/auth-manager.ts
84
+ var import_hash4 = require("@prsm/hash");
85
+ var import_ms3 = __toESM(require("@prsm/ms"), 1);
86
+
87
+ // src/types.ts
88
+ var import_express_session = require("express-session");
89
+ var TwoFactorMechanism = /* @__PURE__ */ ((TwoFactorMechanism2) => {
90
+ TwoFactorMechanism2[TwoFactorMechanism2["TOTP"] = 1] = "TOTP";
91
+ TwoFactorMechanism2[TwoFactorMechanism2["EMAIL"] = 2] = "EMAIL";
92
+ TwoFactorMechanism2[TwoFactorMechanism2["SMS"] = 3] = "SMS";
93
+ return TwoFactorMechanism2;
94
+ })(TwoFactorMechanism || {});
95
+ var AuthStatus = {
96
+ Normal: 0,
97
+ Archived: 1,
98
+ Banned: 2,
99
+ Locked: 3,
100
+ PendingReview: 4,
101
+ Suspended: 5
102
+ };
103
+ var AuthRole = {
104
+ Admin: 1,
105
+ Author: 2,
106
+ Collaborator: 4,
107
+ Consultant: 8,
108
+ Consumer: 16,
109
+ Contributor: 32,
110
+ Coordinator: 64,
111
+ Creator: 128,
112
+ Developer: 256,
113
+ Director: 512,
114
+ Editor: 1024,
115
+ Employee: 2048,
116
+ Maintainer: 4096,
117
+ Manager: 8192,
118
+ Moderator: 16384,
119
+ Publisher: 32768,
120
+ Reviewer: 65536,
121
+ Subscriber: 131072,
122
+ SuperAdmin: 262144,
123
+ SuperEditor: 524288,
124
+ SuperModerator: 1048576,
125
+ Translator: 2097152
126
+ };
127
+ var AuthActivityAction = {
128
+ Login: "login",
129
+ Logout: "logout",
130
+ FailedLogin: "failed_login",
131
+ Register: "register",
132
+ EmailConfirmed: "email_confirmed",
133
+ PasswordResetRequested: "password_reset_requested",
134
+ PasswordResetCompleted: "password_reset_completed",
135
+ PasswordChanged: "password_changed",
136
+ EmailChanged: "email_changed",
137
+ RoleChanged: "role_changed",
138
+ StatusChanged: "status_changed",
139
+ ForceLogout: "force_logout",
140
+ OAuthConnected: "oauth_connected",
141
+ RememberTokenCreated: "remember_token_created",
142
+ TwoFactorSetup: "two_factor_setup",
143
+ TwoFactorVerified: "two_factor_verified",
144
+ TwoFactorFailed: "two_factor_failed",
145
+ TwoFactorDisabled: "two_factor_disabled",
146
+ BackupCodeUsed: "backup_code_used"
147
+ };
85
148
 
86
149
  // src/queries.ts
87
150
  var AuthQueries = class {
@@ -345,6 +408,158 @@ var AuthQueries = class {
345
408
  }
346
409
  };
347
410
 
411
+ // src/activity-logger.ts
412
+ var import_bowser = __toESM(require("bowser"), 1);
413
+ var ActivityLogger = class {
414
+ constructor(config) {
415
+ this.config = config;
416
+ this.enabled = config.activityLog?.enabled !== false;
417
+ this.maxEntries = config.activityLog?.maxEntries || 1e4;
418
+ this.allowedActions = config.activityLog?.actions || null;
419
+ this.tablePrefix = config.tablePrefix || "user_";
420
+ }
421
+ get activityTable() {
422
+ return `${this.tablePrefix}activity_log`;
423
+ }
424
+ parseUserAgent(userAgent) {
425
+ if (!userAgent) {
426
+ return { browser: null, os: null, device: null };
427
+ }
428
+ try {
429
+ const browser = import_bowser.default.getParser(userAgent);
430
+ const result = browser.getResult();
431
+ return {
432
+ browser: result.browser.name || null,
433
+ os: result.os.name || null,
434
+ device: result.platform.type || "desktop"
435
+ };
436
+ } catch (error) {
437
+ return this.parseUserAgentSimple(userAgent);
438
+ }
439
+ }
440
+ parseUserAgentSimple(userAgent) {
441
+ let browser = null;
442
+ if (userAgent.includes("Chrome")) browser = "Chrome";
443
+ else if (userAgent.includes("Firefox")) browser = "Firefox";
444
+ else if (userAgent.includes("Safari")) browser = "Safari";
445
+ else if (userAgent.includes("Edge")) browser = "Edge";
446
+ let os = null;
447
+ if (userAgent.includes("Windows")) os = "Windows";
448
+ else if (userAgent.includes("Mac OS")) os = "macOS";
449
+ else if (userAgent.includes("Linux")) os = "Linux";
450
+ else if (userAgent.includes("Android")) os = "Android";
451
+ else if (userAgent.includes("iOS")) os = "iOS";
452
+ let device = "desktop";
453
+ if (userAgent.includes("Mobile")) device = "mobile";
454
+ else if (userAgent.includes("Tablet")) device = "tablet";
455
+ return { browser, os, device };
456
+ }
457
+ getIpAddress(req) {
458
+ return req.ip || req.connection?.remoteAddress || req.socket?.remoteAddress || req.connection?.socket?.remoteAddress || null;
459
+ }
460
+ async logActivity(accountId, action, req, success = true, metadata = {}) {
461
+ if (!this.enabled) return;
462
+ if (this.allowedActions && !this.allowedActions.includes(action)) {
463
+ return;
464
+ }
465
+ const userAgent = (typeof req.get === "function" ? req.get("User-Agent") : req.headers?.["user-agent"]) || null;
466
+ const ip = this.getIpAddress(req);
467
+ const parsed = this.parseUserAgent(userAgent);
468
+ try {
469
+ await this.config.db.query(
470
+ `
471
+ INSERT INTO ${this.activityTable}
472
+ (account_id, action, ip_address, user_agent, browser, os, device, success, metadata)
473
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
474
+ `,
475
+ [accountId, action, ip, userAgent, parsed.browser, parsed.os, parsed.device, success, Object.keys(metadata).length > 0 ? JSON.stringify(metadata) : null]
476
+ );
477
+ if (Math.random() < 0.01) {
478
+ await this.cleanup();
479
+ }
480
+ } catch (error) {
481
+ console.error("ActivityLogger: Failed to log activity:", error);
482
+ }
483
+ }
484
+ async cleanup() {
485
+ if (!this.enabled) return;
486
+ try {
487
+ await this.config.db.query(
488
+ `
489
+ DELETE FROM ${this.activityTable}
490
+ WHERE id NOT IN (
491
+ SELECT id FROM ${this.activityTable}
492
+ ORDER BY created_at DESC
493
+ LIMIT $1
494
+ )
495
+ `,
496
+ [this.maxEntries]
497
+ );
498
+ } catch (error) {
499
+ console.error("ActivityLogger: Failed to cleanup old entries:", error);
500
+ }
501
+ }
502
+ async getRecentActivity(limit = 100, accountId) {
503
+ if (!this.enabled) return [];
504
+ try {
505
+ let sql = `
506
+ SELECT
507
+ al.*,
508
+ a.email
509
+ FROM ${this.activityTable} al
510
+ LEFT JOIN ${this.tablePrefix}accounts a ON al.account_id = a.id
511
+ `;
512
+ const params = [];
513
+ if (accountId !== void 0) {
514
+ sql += " WHERE al.account_id = $1";
515
+ params.push(accountId);
516
+ }
517
+ sql += ` ORDER BY al.created_at DESC LIMIT $${params.length + 1}`;
518
+ params.push(Math.min(limit, 1e3));
519
+ const result = await this.config.db.query(sql, params);
520
+ return result.rows.map((row) => ({
521
+ ...row,
522
+ metadata: row.metadata ? JSON.parse(row.metadata) : null
523
+ }));
524
+ } catch (error) {
525
+ console.error("ActivityLogger: Failed to get recent activity:", error);
526
+ return [];
527
+ }
528
+ }
529
+ async getActivityStats() {
530
+ if (!this.enabled) {
531
+ return {
532
+ totalEntries: 0,
533
+ uniqueUsers: 0,
534
+ recentLogins: 0,
535
+ failedAttempts: 0
536
+ };
537
+ }
538
+ try {
539
+ const [total, unique, recent, failed] = await Promise.all([
540
+ this.config.db.query(`SELECT COUNT(*) as count FROM ${this.activityTable}`),
541
+ this.config.db.query(`SELECT COUNT(DISTINCT account_id) as count FROM ${this.activityTable} WHERE account_id IS NOT NULL`),
542
+ this.config.db.query(`SELECT COUNT(*) as count FROM ${this.activityTable} WHERE action = 'login' AND created_at > NOW() - INTERVAL '24 hours'`),
543
+ this.config.db.query(`SELECT COUNT(*) as count FROM ${this.activityTable} WHERE success = false AND created_at > NOW() - INTERVAL '24 hours'`)
544
+ ]);
545
+ return {
546
+ totalEntries: parseInt(total.rows[0]?.count || "0"),
547
+ uniqueUsers: parseInt(unique.rows[0]?.count || "0"),
548
+ recentLogins: parseInt(recent.rows[0]?.count || "0"),
549
+ failedAttempts: parseInt(failed.rows[0]?.count || "0")
550
+ };
551
+ } catch (error) {
552
+ console.error("ActivityLogger: Failed to get activity stats:", error);
553
+ return {
554
+ totalEntries: 0,
555
+ uniqueUsers: 0,
556
+ recentLogins: 0,
557
+ failedAttempts: 0
558
+ };
559
+ }
560
+ }
561
+ };
562
+
348
563
  // src/errors.ts
349
564
  var AuthError = class extends Error {
350
565
  constructor(message) {
@@ -459,9 +674,6 @@ var TwoFactorSetupIncompleteError = class extends AuthError {
459
674
  }
460
675
  };
461
676
 
462
- // src/create-user.ts
463
- var import_hash = require("@prsm/hash");
464
-
465
677
  // src/util.ts
466
678
  var isValidEmail = (email) => {
467
679
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
@@ -472,502 +684,13 @@ var validateEmail = (email) => {
472
684
  throw new InvalidEmailError();
473
685
  }
474
686
  if (!email.trim()) {
475
- throw new InvalidEmailError();
476
- }
477
- if (!isValidEmail(email)) {
478
- throw new InvalidEmailError();
479
- }
480
- };
481
- var createMapFromEnum = (enumObj) => Object.fromEntries(Object.entries(enumObj).map(([key, value]) => [value, key]));
482
-
483
- // src/types.ts
484
- var import_express_session = require("express-session");
485
- var TwoFactorMechanism = /* @__PURE__ */ ((TwoFactorMechanism2) => {
486
- TwoFactorMechanism2[TwoFactorMechanism2["TOTP"] = 1] = "TOTP";
487
- TwoFactorMechanism2[TwoFactorMechanism2["EMAIL"] = 2] = "EMAIL";
488
- TwoFactorMechanism2[TwoFactorMechanism2["SMS"] = 3] = "SMS";
489
- return TwoFactorMechanism2;
490
- })(TwoFactorMechanism || {});
491
- var AuthStatus = {
492
- Normal: 0,
493
- Archived: 1,
494
- Banned: 2,
495
- Locked: 3,
496
- PendingReview: 4,
497
- Suspended: 5
498
- };
499
- var AuthRole = {
500
- Admin: 1,
501
- Author: 2,
502
- Collaborator: 4,
503
- Consultant: 8,
504
- Consumer: 16,
505
- Contributor: 32,
506
- Coordinator: 64,
507
- Creator: 128,
508
- Developer: 256,
509
- Director: 512,
510
- Editor: 1024,
511
- Employee: 2048,
512
- Maintainer: 4096,
513
- Manager: 8192,
514
- Moderator: 16384,
515
- Publisher: 32768,
516
- Reviewer: 65536,
517
- Subscriber: 131072,
518
- SuperAdmin: 262144,
519
- SuperEditor: 524288,
520
- SuperModerator: 1048576,
521
- Translator: 2097152
522
- };
523
- var AuthActivityAction = {
524
- Login: "login",
525
- Logout: "logout",
526
- FailedLogin: "failed_login",
527
- Register: "register",
528
- EmailConfirmed: "email_confirmed",
529
- PasswordResetRequested: "password_reset_requested",
530
- PasswordResetCompleted: "password_reset_completed",
531
- PasswordChanged: "password_changed",
532
- EmailChanged: "email_changed",
533
- RoleChanged: "role_changed",
534
- StatusChanged: "status_changed",
535
- ForceLogout: "force_logout",
536
- OAuthConnected: "oauth_connected",
537
- RememberTokenCreated: "remember_token_created",
538
- TwoFactorSetup: "two_factor_setup",
539
- TwoFactorVerified: "two_factor_verified",
540
- TwoFactorFailed: "two_factor_failed",
541
- TwoFactorDisabled: "two_factor_disabled",
542
- BackupCodeUsed: "backup_code_used"
543
- };
544
-
545
- // src/create-user.ts
546
- function validatePassword(password, config) {
547
- const minLength = config.minPasswordLength || 8;
548
- const maxLength = config.maxPasswordLength || 64;
549
- if (typeof password !== "string") {
550
- throw new InvalidPasswordError();
551
- }
552
- if (password.length < minLength) {
553
- throw new InvalidPasswordError();
554
- }
555
- if (password.length > maxLength) {
556
- throw new InvalidPasswordError();
557
- }
558
- }
559
- function generateAutoUserId() {
560
- return crypto.randomUUID();
561
- }
562
- async function createConfirmationToken(queries, account, email, callback) {
563
- const token = import_hash.hash.encode(email);
564
- const expires = new Date(Date.now() + 1e3 * 60 * 60 * 24 * 7);
565
- await queries.createConfirmation({
566
- accountId: account.id,
567
- token,
568
- email,
569
- expires
570
- });
571
- if (callback) {
572
- callback(token);
573
- }
574
- }
575
- async function createUser(config, credentials, userId, callback) {
576
- validateEmail(credentials.email);
577
- validatePassword(credentials.password, config);
578
- const queries = new AuthQueries(config);
579
- const existing = await queries.findAccountByEmail(credentials.email);
580
- if (existing) {
581
- throw new EmailTakenError();
582
- }
583
- const finalUserId = userId || generateAutoUserId();
584
- const hashedPassword = import_hash.hash.encode(credentials.password);
585
- const verified = typeof callback !== "function";
586
- const account = await queries.createAccount({
587
- userId: finalUserId,
588
- email: credentials.email,
589
- password: hashedPassword,
590
- verified,
591
- status: AuthStatus.Normal,
592
- rolemask: 0
593
- });
594
- if (!verified && callback) {
595
- await createConfirmationToken(queries, account, credentials.email, callback);
596
- }
597
- return account;
598
- }
599
-
600
- // src/auth-admin-manager.ts
601
- var AuthAdminManager = class {
602
- constructor(req, res, config, auth) {
603
- this.req = req;
604
- this.res = res;
605
- this.config = config;
606
- this.queries = new AuthQueries(config);
607
- this.auth = auth;
608
- }
609
- validatePassword(password) {
610
- const minLength = this.config.minPasswordLength || 8;
611
- const maxLength = this.config.maxPasswordLength || 64;
612
- if (typeof password !== "string") {
613
- throw new InvalidPasswordError();
614
- }
615
- if (password.length < minLength) {
616
- throw new InvalidPasswordError();
617
- }
618
- if (password.length > maxLength) {
619
- throw new InvalidPasswordError();
620
- }
621
- }
622
- async findAccountByIdentifier(identifier) {
623
- if (identifier.accountId !== void 0) {
624
- return await this.queries.findAccountById(identifier.accountId);
625
- } else if (identifier.email !== void 0) {
626
- return await this.queries.findAccountByEmail(identifier.email);
627
- } else if (identifier.userId !== void 0) {
628
- return await this.queries.findAccountByUserId(identifier.userId);
629
- }
630
- return null;
631
- }
632
- async createConfirmationToken(account, email, callback) {
633
- const token = import_hash2.hash.encode(email);
634
- const expires = new Date(Date.now() + 1e3 * 60 * 60 * 24 * 7);
635
- await this.queries.createConfirmation({
636
- accountId: account.id,
637
- token,
638
- email,
639
- expires
640
- });
641
- if (callback) {
642
- callback(token);
643
- }
644
- }
645
- /**
646
- * Create a new user account (admin function).
647
- *
648
- * @param credentials - Email and password for new account
649
- * @param userId - Optional user ID to link this auth account to. If not provided, a UUID will be generated automatically.
650
- * @param callback - If provided, account is created unverified and callback receives confirmation token. Create a URL like /confirm/{token} and call confirmEmail() in that handler. If omitted, account is immediately verified.
651
- * @returns The created account record
652
- * @throws {EmailTakenError} Email is already registered
653
- * @throws {InvalidPasswordError} Password doesn't meet length requirements
654
- */
655
- async createUser(credentials, userId, callback) {
656
- return createUser(this.config, credentials, userId, callback);
657
- }
658
- /**
659
- * Log in as another user (admin function).
660
- * Creates a new session as the target user without requiring their password.
661
- *
662
- * @param identifier - Find user by accountId, email, or userId
663
- * @throws {UserNotFoundError} No account matches the identifier
664
- */
665
- async loginAsUserBy(identifier) {
666
- const account = await this.findAccountByIdentifier(identifier);
667
- if (!account) {
668
- throw new UserNotFoundError();
669
- }
670
- await this.auth.onLoginSuccessful(account, false);
671
- }
672
- /**
673
- * Delete a user account and all associated data (admin function).
674
- * Removes account, confirmations, remember tokens, and reset tokens.
675
- *
676
- * @param identifier - Find user by accountId, email, or userId
677
- * @throws {UserNotFoundError} No account matches the identifier
678
- */
679
- async deleteUserBy(identifier) {
680
- const account = await this.findAccountByIdentifier(identifier);
681
- if (!account) {
682
- throw new UserNotFoundError();
683
- }
684
- await this.queries.deleteAccount(account.id);
685
- }
686
- /**
687
- * Add a role to a user's account (admin function).
688
- * Uses bitwise OR to add role to existing rolemask.
689
- *
690
- * @param identifier - Find user by accountId, email, or userId
691
- * @param role - Role bitmask to add (e.g., AuthRole.Admin)
692
- * @throws {UserNotFoundError} No account matches the identifier
693
- */
694
- async addRoleForUserBy(identifier, role) {
695
- const account = await this.findAccountByIdentifier(identifier);
696
- if (!account) {
697
- throw new UserNotFoundError();
698
- }
699
- const rolemask = account.rolemask | role;
700
- await this.queries.updateAccount(account.id, { rolemask });
701
- }
702
- /**
703
- * Remove a role from a user's account (admin function).
704
- * Uses bitwise operations to remove role from rolemask.
705
- *
706
- * @param identifier - Find user by accountId, email, or userId
707
- * @param role - Role bitmask to remove (e.g., AuthRole.Admin)
708
- * @throws {UserNotFoundError} No account matches the identifier
709
- */
710
- async removeRoleForUserBy(identifier, role) {
711
- const account = await this.findAccountByIdentifier(identifier);
712
- if (!account) {
713
- throw new UserNotFoundError();
714
- }
715
- const rolemask = account.rolemask & ~role;
716
- await this.queries.updateAccount(account.id, { rolemask });
717
- }
718
- /**
719
- * Check if a user has a specific role (admin function).
720
- *
721
- * @param identifier - Find user by accountId, email, or userId
722
- * @param role - Role bitmask to check (e.g., AuthRole.Admin)
723
- * @returns true if user has the role, false otherwise
724
- * @throws {UserNotFoundError} No account matches the identifier
725
- */
726
- async hasRoleForUserBy(identifier, role) {
727
- const account = await this.findAccountByIdentifier(identifier);
728
- if (!account) {
729
- throw new UserNotFoundError();
730
- }
731
- return (account.rolemask & role) === role;
732
- }
733
- /**
734
- * Change a user's password (admin function).
735
- * Does not require knowing the current password.
736
- *
737
- * @param identifier - Find user by accountId, email, or userId
738
- * @param password - New password (will be hashed)
739
- * @throws {UserNotFoundError} No account matches the identifier
740
- * @throws {InvalidPasswordError} New password doesn't meet requirements
741
- */
742
- async changePasswordForUserBy(identifier, password) {
743
- this.validatePassword(password);
744
- const account = await this.findAccountByIdentifier(identifier);
745
- if (!account) {
746
- throw new UserNotFoundError();
747
- }
748
- await this.queries.updateAccount(account.id, {
749
- password: import_hash2.hash.encode(password)
750
- });
751
- }
752
- /**
753
- * Change a user's account status (admin function).
754
- *
755
- * @param identifier - Find user by accountId, email, or userId
756
- * @param status - New status (0=Normal, 1=Archived, 2=Banned, 3=Locked, etc.)
757
- * @throws {UserNotFoundError} No account matches the identifier
758
- */
759
- async setStatusForUserBy(identifier, status) {
760
- const account = await this.findAccountByIdentifier(identifier);
761
- if (!account) {
762
- throw new UserNotFoundError();
763
- }
764
- await this.queries.updateAccount(account.id, { status });
765
- }
766
- /**
767
- * Initiate password reset for a user (admin function).
768
- * Creates a reset token without rate limiting.
769
- *
770
- * @param identifier - Find user by accountId, email, or userId
771
- * @param expiresAfter - Token expiration (default: 6h). Accepts ms format like '1h', '30m'
772
- * @param callback - Called with reset token. Create a URL like /reset/{token} and call confirmResetPassword() in that handler
773
- * @throws {UserNotFoundError} No account matches the identifier
774
- * @throws {EmailNotVerifiedError} Account exists but email is not verified
775
- */
776
- async initiatePasswordResetForUserBy(identifier, expiresAfter = null, callback) {
777
- const account = await this.findAccountByIdentifier(identifier);
778
- if (!account) {
779
- throw new UserNotFoundError();
780
- }
781
- if (!account.verified) {
782
- throw new EmailNotVerifiedError();
783
- }
784
- const expiry = !expiresAfter ? (0, import_ms.default)("6h") : (0, import_ms.default)(expiresAfter);
785
- const token = import_hash2.hash.encode(account.email);
786
- const expires = new Date(Date.now() + expiry);
787
- await this.queries.createResetToken({
788
- accountId: account.id,
789
- token,
790
- expires
791
- });
792
- if (callback) {
793
- callback(token);
794
- }
795
- }
796
- /**
797
- * Force logout all sessions for a specific user (admin function).
798
- * Increments force_logout counter and deletes all remember tokens.
799
- * If target user is currently logged in, marks their session for logout.
800
- *
801
- * @param identifier - Find user by accountId, email, or userId
802
- * @throws {UserNotFoundError} No account matches the identifier
803
- */
804
- async forceLogoutForUserBy(identifier) {
805
- const account = await this.findAccountByIdentifier(identifier);
806
- if (!account) {
807
- throw new UserNotFoundError();
808
- }
809
- await this.queries.incrementForceLogout(account.id);
810
- if (this.auth.getId() === account.id) {
811
- this.req.session.auth.shouldForceLogout = true;
812
- }
813
- }
814
- };
815
-
816
- // src/auth-manager.ts
817
- var import_hash5 = require("@prsm/hash");
818
- var import_ms3 = __toESM(require("@prsm/ms"), 1);
819
-
820
- // src/activity-logger.ts
821
- var import_bowser = __toESM(require("bowser"), 1);
822
- var ActivityLogger = class {
823
- constructor(config) {
824
- this.config = config;
825
- this.enabled = config.activityLog?.enabled !== false;
826
- this.maxEntries = config.activityLog?.maxEntries || 1e4;
827
- this.allowedActions = config.activityLog?.actions || null;
828
- this.tablePrefix = config.tablePrefix || "user_";
829
- }
830
- get activityTable() {
831
- return `${this.tablePrefix}activity_log`;
832
- }
833
- parseUserAgent(userAgent) {
834
- if (!userAgent) {
835
- return { browser: null, os: null, device: null };
836
- }
837
- try {
838
- const browser = import_bowser.default.getParser(userAgent);
839
- const result = browser.getResult();
840
- return {
841
- browser: result.browser.name || null,
842
- os: result.os.name || null,
843
- device: result.platform.type || "desktop"
844
- };
845
- } catch (error) {
846
- return this.parseUserAgentSimple(userAgent);
847
- }
848
- }
849
- parseUserAgentSimple(userAgent) {
850
- let browser = null;
851
- if (userAgent.includes("Chrome")) browser = "Chrome";
852
- else if (userAgent.includes("Firefox")) browser = "Firefox";
853
- else if (userAgent.includes("Safari")) browser = "Safari";
854
- else if (userAgent.includes("Edge")) browser = "Edge";
855
- let os = null;
856
- if (userAgent.includes("Windows")) os = "Windows";
857
- else if (userAgent.includes("Mac OS")) os = "macOS";
858
- else if (userAgent.includes("Linux")) os = "Linux";
859
- else if (userAgent.includes("Android")) os = "Android";
860
- else if (userAgent.includes("iOS")) os = "iOS";
861
- let device = "desktop";
862
- if (userAgent.includes("Mobile")) device = "mobile";
863
- else if (userAgent.includes("Tablet")) device = "tablet";
864
- return { browser, os, device };
865
- }
866
- getIpAddress(req) {
867
- return req.ip || req.connection?.remoteAddress || req.socket?.remoteAddress || req.connection?.socket?.remoteAddress || null;
868
- }
869
- async logActivity(accountId, action, req, success = true, metadata = {}) {
870
- if (!this.enabled) return;
871
- if (this.allowedActions && !this.allowedActions.includes(action)) {
872
- return;
873
- }
874
- const userAgent = (typeof req.get === "function" ? req.get("User-Agent") : req.headers?.["user-agent"]) || null;
875
- const ip = this.getIpAddress(req);
876
- const parsed = this.parseUserAgent(userAgent);
877
- try {
878
- await this.config.db.query(
879
- `
880
- INSERT INTO ${this.activityTable}
881
- (account_id, action, ip_address, user_agent, browser, os, device, success, metadata)
882
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
883
- `,
884
- [accountId, action, ip, userAgent, parsed.browser, parsed.os, parsed.device, success, Object.keys(metadata).length > 0 ? JSON.stringify(metadata) : null]
885
- );
886
- if (Math.random() < 0.01) {
887
- await this.cleanup();
888
- }
889
- } catch (error) {
890
- console.error("ActivityLogger: Failed to log activity:", error);
891
- }
892
- }
893
- async cleanup() {
894
- if (!this.enabled) return;
895
- try {
896
- await this.config.db.query(
897
- `
898
- DELETE FROM ${this.activityTable}
899
- WHERE id NOT IN (
900
- SELECT id FROM ${this.activityTable}
901
- ORDER BY created_at DESC
902
- LIMIT $1
903
- )
904
- `,
905
- [this.maxEntries]
906
- );
907
- } catch (error) {
908
- console.error("ActivityLogger: Failed to cleanup old entries:", error);
909
- }
910
- }
911
- async getRecentActivity(limit = 100, accountId) {
912
- if (!this.enabled) return [];
913
- try {
914
- let sql = `
915
- SELECT
916
- al.*,
917
- a.email
918
- FROM ${this.activityTable} al
919
- LEFT JOIN ${this.tablePrefix}accounts a ON al.account_id = a.id
920
- `;
921
- const params = [];
922
- if (accountId !== void 0) {
923
- sql += " WHERE al.account_id = $1";
924
- params.push(accountId);
925
- }
926
- sql += ` ORDER BY al.created_at DESC LIMIT $${params.length + 1}`;
927
- params.push(Math.min(limit, 1e3));
928
- const result = await this.config.db.query(sql, params);
929
- return result.rows.map((row) => ({
930
- ...row,
931
- metadata: row.metadata ? JSON.parse(row.metadata) : null
932
- }));
933
- } catch (error) {
934
- console.error("ActivityLogger: Failed to get recent activity:", error);
935
- return [];
936
- }
687
+ throw new InvalidEmailError();
937
688
  }
938
- async getActivityStats() {
939
- if (!this.enabled) {
940
- return {
941
- totalEntries: 0,
942
- uniqueUsers: 0,
943
- recentLogins: 0,
944
- failedAttempts: 0
945
- };
946
- }
947
- try {
948
- const [total, unique, recent, failed] = await Promise.all([
949
- this.config.db.query(`SELECT COUNT(*) as count FROM ${this.activityTable}`),
950
- this.config.db.query(`SELECT COUNT(DISTINCT account_id) as count FROM ${this.activityTable} WHERE account_id IS NOT NULL`),
951
- this.config.db.query(`SELECT COUNT(*) as count FROM ${this.activityTable} WHERE action = 'login' AND created_at > NOW() - INTERVAL '24 hours'`),
952
- this.config.db.query(`SELECT COUNT(*) as count FROM ${this.activityTable} WHERE success = false AND created_at > NOW() - INTERVAL '24 hours'`)
953
- ]);
954
- return {
955
- totalEntries: parseInt(total.rows[0]?.count || "0"),
956
- uniqueUsers: parseInt(unique.rows[0]?.count || "0"),
957
- recentLogins: parseInt(recent.rows[0]?.count || "0"),
958
- failedAttempts: parseInt(failed.rows[0]?.count || "0")
959
- };
960
- } catch (error) {
961
- console.error("ActivityLogger: Failed to get activity stats:", error);
962
- return {
963
- totalEntries: 0,
964
- uniqueUsers: 0,
965
- recentLogins: 0,
966
- failedAttempts: 0
967
- };
968
- }
689
+ if (!isValidEmail(email)) {
690
+ throw new InvalidEmailError();
969
691
  }
970
692
  };
693
+ var createMapFromEnum = (enumObj) => Object.fromEntries(Object.entries(enumObj).map(([key, value]) => [value, key]));
971
694
 
972
695
  // src/providers/base-provider.ts
973
696
  var BaseOAuthProvider = class {
@@ -1212,7 +935,7 @@ var AzureProvider = class extends BaseOAuthProvider {
1212
935
 
1213
936
  // src/two-factor/totp-provider.ts
1214
937
  var import_totp = __toESM(require("@eaccess/totp"), 1);
1215
- var import_hash3 = require("@prsm/hash");
938
+ var import_hash = require("@prsm/hash");
1216
939
  var TotpProvider = class {
1217
940
  constructor(config) {
1218
941
  this.config = config;
@@ -1241,11 +964,11 @@ var TotpProvider = class {
1241
964
  return codes;
1242
965
  }
1243
966
  hashBackupCodes(codes) {
1244
- return codes.map((code) => import_hash3.hash.encode(code));
967
+ return codes.map((code) => import_hash.hash.encode(code));
1245
968
  }
1246
969
  verifyBackupCode(hashedCodes, inputCode) {
1247
970
  for (let i = 0; i < hashedCodes.length; i++) {
1248
- if (import_hash3.hash.verify(hashedCodes[i], inputCode.toUpperCase())) {
971
+ if (import_hash.hash.verify(hashedCodes[i], inputCode.toUpperCase())) {
1249
972
  return { isValid: true, index: i };
1250
973
  }
1251
974
  }
@@ -1261,8 +984,8 @@ var TotpProvider = class {
1261
984
  };
1262
985
 
1263
986
  // src/two-factor/otp-provider.ts
1264
- var import_ms2 = __toESM(require("@prsm/ms"), 1);
1265
- var import_hash4 = require("@prsm/hash");
987
+ var import_ms = __toESM(require("@prsm/ms"), 1);
988
+ var import_hash2 = require("@prsm/hash");
1266
989
  var OtpProvider = class {
1267
990
  constructor(config) {
1268
991
  this.config = config;
@@ -1287,9 +1010,9 @@ var OtpProvider = class {
1287
1010
  async createAndStoreOTP(accountId, mechanism) {
1288
1011
  const otp = this.generateOTP();
1289
1012
  const selector = this.generateSelector();
1290
- const tokenHash = import_hash4.hash.encode(otp);
1013
+ const tokenHash = import_hash2.hash.encode(otp);
1291
1014
  const expiryDuration = this.config.twoFactor?.tokenExpiry || "5m";
1292
- const expiresAt = new Date(Date.now() + (0, import_ms2.default)(expiryDuration));
1015
+ const expiresAt = new Date(Date.now() + (0, import_ms.default)(expiryDuration));
1293
1016
  await this.queries.deleteTwoFactorTokensByAccountAndMechanism(accountId, mechanism);
1294
1017
  await this.queries.createTwoFactorToken({
1295
1018
  accountId,
@@ -1309,7 +1032,7 @@ var OtpProvider = class {
1309
1032
  await this.queries.deleteTwoFactorToken(token.id);
1310
1033
  return { isValid: false };
1311
1034
  }
1312
- const isValid = import_hash4.hash.verify(token.token_hash, inputCode);
1035
+ const isValid = import_hash2.hash.verify(token.token_hash, inputCode);
1313
1036
  if (isValid) {
1314
1037
  await this.queries.deleteTwoFactorToken(token.id);
1315
1038
  return { isValid: true, token };
@@ -1707,6 +1430,248 @@ var TwoFactorManager = class {
1707
1430
  }
1708
1431
  };
1709
1432
 
1433
+ // src/auth-functions.ts
1434
+ var auth_functions_exports = {};
1435
+ __export(auth_functions_exports, {
1436
+ addRoleForUserBy: () => addRoleForUserBy,
1437
+ changePasswordForUserBy: () => changePasswordForUserBy,
1438
+ confirmResetPassword: () => confirmResetPassword,
1439
+ createUser: () => createUser,
1440
+ deleteUserBy: () => deleteUserBy,
1441
+ forceLogoutForUserBy: () => forceLogoutForUserBy,
1442
+ hasRoleForUserBy: () => hasRoleForUserBy,
1443
+ initiatePasswordResetForUserBy: () => initiatePasswordResetForUserBy,
1444
+ register: () => register,
1445
+ removeRoleForUserBy: () => removeRoleForUserBy,
1446
+ resetPassword: () => resetPassword,
1447
+ setStatusForUserBy: () => setStatusForUserBy
1448
+ });
1449
+ var import_hash3 = require("@prsm/hash");
1450
+ var import_ms2 = __toESM(require("@prsm/ms"), 1);
1451
+ function validatePassword(password, config) {
1452
+ const minLength = config.minPasswordLength || 8;
1453
+ const maxLength = config.maxPasswordLength || 64;
1454
+ if (typeof password !== "string") {
1455
+ throw new InvalidPasswordError();
1456
+ }
1457
+ if (password.length < minLength) {
1458
+ throw new InvalidPasswordError();
1459
+ }
1460
+ if (password.length > maxLength) {
1461
+ throw new InvalidPasswordError();
1462
+ }
1463
+ }
1464
+ function generateAutoUserId() {
1465
+ return crypto.randomUUID();
1466
+ }
1467
+ async function findAccountByIdentifier(queries, identifier) {
1468
+ if (identifier.accountId !== void 0) {
1469
+ return await queries.findAccountById(identifier.accountId);
1470
+ } else if (identifier.email !== void 0) {
1471
+ return await queries.findAccountByEmail(identifier.email);
1472
+ } else if (identifier.userId !== void 0) {
1473
+ return await queries.findAccountByUserId(identifier.userId);
1474
+ }
1475
+ return null;
1476
+ }
1477
+ async function createConfirmationToken(queries, account, email, callback) {
1478
+ const token = import_hash3.hash.encode(email);
1479
+ const expires = new Date(Date.now() + 1e3 * 60 * 60 * 24 * 7);
1480
+ await queries.createConfirmation({
1481
+ accountId: account.id,
1482
+ token,
1483
+ email,
1484
+ expires
1485
+ });
1486
+ if (callback) {
1487
+ callback(token);
1488
+ }
1489
+ }
1490
+ async function createUser(config, credentials, userId, callback) {
1491
+ validateEmail(credentials.email);
1492
+ validatePassword(credentials.password, config);
1493
+ const queries = new AuthQueries(config);
1494
+ const existing = await queries.findAccountByEmail(credentials.email);
1495
+ if (existing) {
1496
+ throw new EmailTakenError();
1497
+ }
1498
+ const finalUserId = userId || generateAutoUserId();
1499
+ const hashedPassword = import_hash3.hash.encode(credentials.password);
1500
+ const verified = typeof callback !== "function";
1501
+ const account = await queries.createAccount({
1502
+ userId: finalUserId,
1503
+ email: credentials.email,
1504
+ password: hashedPassword,
1505
+ verified,
1506
+ status: AuthStatus.Normal,
1507
+ rolemask: 0
1508
+ });
1509
+ if (!verified && callback) {
1510
+ await createConfirmationToken(queries, account, credentials.email, callback);
1511
+ }
1512
+ return account;
1513
+ }
1514
+ async function register(config, email, password, userId, callback) {
1515
+ validateEmail(email);
1516
+ validatePassword(password, config);
1517
+ const queries = new AuthQueries(config);
1518
+ const existing = await queries.findAccountByEmail(email);
1519
+ if (existing) {
1520
+ throw new EmailTakenError();
1521
+ }
1522
+ const finalUserId = userId || generateAutoUserId();
1523
+ const hashedPassword = import_hash3.hash.encode(password);
1524
+ const verified = typeof callback !== "function";
1525
+ const account = await queries.createAccount({
1526
+ userId: finalUserId,
1527
+ email,
1528
+ password: hashedPassword,
1529
+ verified,
1530
+ status: AuthStatus.Normal,
1531
+ rolemask: 0
1532
+ });
1533
+ if (!verified && callback) {
1534
+ await createConfirmationToken(queries, account, email, callback);
1535
+ }
1536
+ return account;
1537
+ }
1538
+ async function deleteUserBy(config, identifier) {
1539
+ const queries = new AuthQueries(config);
1540
+ const account = await findAccountByIdentifier(queries, identifier);
1541
+ if (!account) {
1542
+ throw new UserNotFoundError();
1543
+ }
1544
+ await queries.deleteAccount(account.id);
1545
+ }
1546
+ async function addRoleForUserBy(config, identifier, role) {
1547
+ const queries = new AuthQueries(config);
1548
+ const account = await findAccountByIdentifier(queries, identifier);
1549
+ if (!account) {
1550
+ throw new UserNotFoundError();
1551
+ }
1552
+ const rolemask = account.rolemask | role;
1553
+ await queries.updateAccount(account.id, { rolemask });
1554
+ }
1555
+ async function removeRoleForUserBy(config, identifier, role) {
1556
+ const queries = new AuthQueries(config);
1557
+ const account = await findAccountByIdentifier(queries, identifier);
1558
+ if (!account) {
1559
+ throw new UserNotFoundError();
1560
+ }
1561
+ const rolemask = account.rolemask & ~role;
1562
+ await queries.updateAccount(account.id, { rolemask });
1563
+ }
1564
+ async function hasRoleForUserBy(config, identifier, role) {
1565
+ const queries = new AuthQueries(config);
1566
+ const account = await findAccountByIdentifier(queries, identifier);
1567
+ if (!account) {
1568
+ throw new UserNotFoundError();
1569
+ }
1570
+ return (account.rolemask & role) === role;
1571
+ }
1572
+ async function changePasswordForUserBy(config, identifier, password) {
1573
+ validatePassword(password, config);
1574
+ const queries = new AuthQueries(config);
1575
+ const account = await findAccountByIdentifier(queries, identifier);
1576
+ if (!account) {
1577
+ throw new UserNotFoundError();
1578
+ }
1579
+ await queries.updateAccount(account.id, {
1580
+ password: import_hash3.hash.encode(password)
1581
+ });
1582
+ }
1583
+ async function setStatusForUserBy(config, identifier, status) {
1584
+ const queries = new AuthQueries(config);
1585
+ const account = await findAccountByIdentifier(queries, identifier);
1586
+ if (!account) {
1587
+ throw new UserNotFoundError();
1588
+ }
1589
+ await queries.updateAccount(account.id, { status });
1590
+ }
1591
+ async function initiatePasswordResetForUserBy(config, identifier, expiresAfter = null, callback) {
1592
+ const queries = new AuthQueries(config);
1593
+ const account = await findAccountByIdentifier(queries, identifier);
1594
+ if (!account) {
1595
+ throw new UserNotFoundError();
1596
+ }
1597
+ if (!account.verified) {
1598
+ throw new EmailNotVerifiedError();
1599
+ }
1600
+ const expiry = !expiresAfter ? (0, import_ms2.default)("6h") : (0, import_ms2.default)(expiresAfter);
1601
+ const token = import_hash3.hash.encode(account.email);
1602
+ const expires = new Date(Date.now() + expiry);
1603
+ await queries.createResetToken({
1604
+ accountId: account.id,
1605
+ token,
1606
+ expires
1607
+ });
1608
+ if (callback) {
1609
+ callback(token);
1610
+ }
1611
+ }
1612
+ async function resetPassword(config, email, expiresAfter = null, maxOpenRequests = null, callback) {
1613
+ validateEmail(email);
1614
+ const expiry = !expiresAfter ? (0, import_ms2.default)("6h") : (0, import_ms2.default)(expiresAfter);
1615
+ const maxRequests = maxOpenRequests === null ? 2 : Math.max(1, maxOpenRequests);
1616
+ const queries = new AuthQueries(config);
1617
+ const account = await queries.findAccountByEmail(email);
1618
+ if (!account || !account.verified) {
1619
+ throw new EmailNotVerifiedError();
1620
+ }
1621
+ if (!account.resettable) {
1622
+ throw new ResetDisabledError();
1623
+ }
1624
+ const openRequests = await queries.countActiveResetTokensForAccount(account.id);
1625
+ if (openRequests >= maxRequests) {
1626
+ throw new TooManyResetsError();
1627
+ }
1628
+ const token = import_hash3.hash.encode(email);
1629
+ const expires = new Date(Date.now() + expiry);
1630
+ await queries.createResetToken({
1631
+ accountId: account.id,
1632
+ token,
1633
+ expires
1634
+ });
1635
+ if (callback) {
1636
+ callback(token);
1637
+ }
1638
+ }
1639
+ async function confirmResetPassword(config, token, password) {
1640
+ const queries = new AuthQueries(config);
1641
+ const reset = await queries.findResetToken(token);
1642
+ if (!reset) {
1643
+ throw new ResetNotFoundError();
1644
+ }
1645
+ if (new Date(reset.expires) < /* @__PURE__ */ new Date()) {
1646
+ throw new ResetExpiredError();
1647
+ }
1648
+ const account = await queries.findAccountById(reset.account_id);
1649
+ if (!account) {
1650
+ throw new UserNotFoundError();
1651
+ }
1652
+ if (!account.resettable) {
1653
+ throw new ResetDisabledError();
1654
+ }
1655
+ validatePassword(password, config);
1656
+ if (!import_hash3.hash.verify(token, account.email)) {
1657
+ throw new InvalidTokenError();
1658
+ }
1659
+ await queries.updateAccount(account.id, {
1660
+ password: import_hash3.hash.encode(password)
1661
+ });
1662
+ await queries.deleteResetToken(token);
1663
+ return { accountId: account.id, email: account.email };
1664
+ }
1665
+ async function forceLogoutForUserBy(config, identifier) {
1666
+ const queries = new AuthQueries(config);
1667
+ const account = await findAccountByIdentifier(queries, identifier);
1668
+ if (!account) {
1669
+ throw new UserNotFoundError();
1670
+ }
1671
+ await queries.incrementForceLogout(account.id);
1672
+ return { accountId: account.id };
1673
+ }
1674
+
1710
1675
  // src/auth-manager.ts
1711
1676
  var AuthManager = class {
1712
1677
  constructor(req, res, config) {
@@ -1898,7 +1863,7 @@ var AuthManager = class {
1898
1863
  });
1899
1864
  }
1900
1865
  async createRememberDirective(account) {
1901
- const token = import_hash5.hash.encode(account.email);
1866
+ const token = import_hash4.hash.encode(account.email);
1902
1867
  const duration = this.config.rememberDuration || "30d";
1903
1868
  const expires = new Date(Date.now() + (0, import_ms3.default)(duration));
1904
1869
  await this.queries.createRememberToken({
@@ -1936,7 +1901,7 @@ var AuthManager = class {
1936
1901
  await this.activityLogger.logActivity(null, AuthActivityAction.FailedLogin, this.req, false, { email, reason: "account_not_found" });
1937
1902
  throw new UserNotFoundError();
1938
1903
  }
1939
- if (!account.password || !import_hash5.hash.verify(account.password, password)) {
1904
+ if (!account.password || !import_hash4.hash.verify(account.password, password)) {
1940
1905
  await this.activityLogger.logActivity(account.id, AuthActivityAction.FailedLogin, this.req, false, { email, reason: "invalid_password" });
1941
1906
  throw new InvalidPasswordError();
1942
1907
  }
@@ -2048,7 +2013,7 @@ var AuthManager = class {
2048
2013
  throw new EmailTakenError();
2049
2014
  }
2050
2015
  const finalUserId = userId || this.generateAutoUserId();
2051
- const hashedPassword = import_hash5.hash.encode(password);
2016
+ const hashedPassword = import_hash4.hash.encode(password);
2052
2017
  const verified = typeof callback !== "function";
2053
2018
  const account = await this.queries.createAccount({
2054
2019
  userId: finalUserId,
@@ -2065,7 +2030,7 @@ var AuthManager = class {
2065
2030
  return account;
2066
2031
  }
2067
2032
  async createConfirmationToken(account, email, callback) {
2068
- const token = import_hash5.hash.encode(email);
2033
+ const token = import_hash4.hash.encode(email);
2069
2034
  const expires = new Date(Date.now() + 1e3 * 60 * 60 * 24 * 7);
2070
2035
  await this.queries.createConfirmation({
2071
2036
  accountId: account.id,
@@ -2199,7 +2164,7 @@ var AuthManager = class {
2199
2164
  if (new Date(confirmation.expires) < /* @__PURE__ */ new Date()) {
2200
2165
  throw new ConfirmationExpiredError();
2201
2166
  }
2202
- if (!import_hash5.hash.verify(token, confirmation.email)) {
2167
+ if (!import_hash4.hash.verify(token, confirmation.email)) {
2203
2168
  throw new InvalidTokenError();
2204
2169
  }
2205
2170
  await this.queries.updateAccount(confirmation.account_id, {
@@ -2296,7 +2261,7 @@ var AuthManager = class {
2296
2261
  if (openRequests >= maxRequests) {
2297
2262
  throw new TooManyResetsError();
2298
2263
  }
2299
- const token = import_hash5.hash.encode(email);
2264
+ const token = import_hash4.hash.encode(email);
2300
2265
  const expires = new Date(Date.now() + expiry);
2301
2266
  await this.queries.createResetToken({
2302
2267
  accountId: account.id,
@@ -2338,11 +2303,11 @@ var AuthManager = class {
2338
2303
  throw new ResetDisabledError();
2339
2304
  }
2340
2305
  this.validatePassword(password);
2341
- if (!import_hash5.hash.verify(token, account.email)) {
2306
+ if (!import_hash4.hash.verify(token, account.email)) {
2342
2307
  throw new InvalidTokenError();
2343
2308
  }
2344
2309
  await this.queries.updateAccount(account.id, {
2345
- password: import_hash5.hash.encode(password)
2310
+ password: import_hash4.hash.encode(password)
2346
2311
  });
2347
2312
  if (logout) {
2348
2313
  await this.forceLogoutForAccountById(account.id);
@@ -2370,7 +2335,7 @@ var AuthManager = class {
2370
2335
  if (!account.password) {
2371
2336
  return false;
2372
2337
  }
2373
- return import_hash5.hash.verify(account.password, password);
2338
+ return import_hash4.hash.verify(account.password, password);
2374
2339
  }
2375
2340
  async forceLogoutForAccountById(accountId) {
2376
2341
  await this.queries.deleteRememberTokensForAccount(accountId);
@@ -2408,6 +2373,61 @@ var AuthManager = class {
2408
2373
  await this.logoutEverywhereElse();
2409
2374
  await this.logout();
2410
2375
  }
2376
+ async findAccountByIdentifier(identifier) {
2377
+ if (identifier.accountId !== void 0) {
2378
+ return await this.queries.findAccountById(identifier.accountId);
2379
+ } else if (identifier.email !== void 0) {
2380
+ return await this.queries.findAccountByEmail(identifier.email);
2381
+ } else if (identifier.userId !== void 0) {
2382
+ return await this.queries.findAccountByUserId(identifier.userId);
2383
+ }
2384
+ return null;
2385
+ }
2386
+ // admin/standalone functions (delegated to auth-functions.js due to lack of need for request context)
2387
+ async createUser(credentials, userId, callback) {
2388
+ return createUser(this.config, credentials, userId, callback);
2389
+ }
2390
+ async deleteUserBy(identifier) {
2391
+ return deleteUserBy(this.config, identifier);
2392
+ }
2393
+ async addRoleForUserBy(identifier, role) {
2394
+ return addRoleForUserBy(this.config, identifier, role);
2395
+ }
2396
+ async removeRoleForUserBy(identifier, role) {
2397
+ return removeRoleForUserBy(this.config, identifier, role);
2398
+ }
2399
+ async hasRoleForUserBy(identifier, role) {
2400
+ return hasRoleForUserBy(this.config, identifier, role);
2401
+ }
2402
+ async changePasswordForUserBy(identifier, password) {
2403
+ return changePasswordForUserBy(this.config, identifier, password);
2404
+ }
2405
+ async setStatusForUserBy(identifier, status) {
2406
+ return setStatusForUserBy(this.config, identifier, status);
2407
+ }
2408
+ async initiatePasswordResetForUserBy(identifier, expiresAfter, callback) {
2409
+ return initiatePasswordResetForUserBy(this.config, identifier, expiresAfter, callback);
2410
+ }
2411
+ async forceLogoutForUserBy(identifier) {
2412
+ const result = await forceLogoutForUserBy(this.config, identifier);
2413
+ if (this.getId() === result.accountId) {
2414
+ this.req.session.auth.shouldForceLogout = true;
2415
+ }
2416
+ }
2417
+ /**
2418
+ * Log in as another user (admin function).
2419
+ * Creates a new session as the target user without requiring their password.
2420
+ *
2421
+ * @param identifier - Find user by accountId, email, or userId
2422
+ * @throws {UserNotFoundError} No account matches the identifier
2423
+ */
2424
+ async loginAsUserBy(identifier) {
2425
+ const account = await this.findAccountByIdentifier(identifier);
2426
+ if (!account) {
2427
+ throw new UserNotFoundError();
2428
+ }
2429
+ await this.onLoginSuccessful(account, false);
2430
+ }
2411
2431
  };
2412
2432
 
2413
2433
  // src/middleware.ts
@@ -2415,9 +2435,7 @@ function createAuthMiddleware(config) {
2415
2435
  return async (req, res, next) => {
2416
2436
  try {
2417
2437
  const authManager = new AuthManager(req, res, config);
2418
- const authAdminManager = new AuthAdminManager(req, res, config, authManager);
2419
2438
  req.auth = authManager;
2420
- req.authAdmin = authAdminManager;
2421
2439
  await authManager.resyncSession();
2422
2440
  await authManager.processRememberDirective();
2423
2441
  next();
@@ -2626,8 +2644,26 @@ async function getAuthTableStats(config) {
2626
2644
  };
2627
2645
  }
2628
2646
 
2647
+ // src/auth-context.ts
2648
+ function createAuthContext(config) {
2649
+ return {
2650
+ createUser: (credentials, userId, callback) => createUser(config, credentials, userId, callback),
2651
+ register: (email, password, userId, callback) => register(config, email, password, userId, callback),
2652
+ deleteUserBy: (identifier) => deleteUserBy(config, identifier),
2653
+ addRoleForUserBy: (identifier, role) => addRoleForUserBy(config, identifier, role),
2654
+ removeRoleForUserBy: (identifier, role) => removeRoleForUserBy(config, identifier, role),
2655
+ hasRoleForUserBy: (identifier, role) => hasRoleForUserBy(config, identifier, role),
2656
+ changePasswordForUserBy: (identifier, password) => changePasswordForUserBy(config, identifier, password),
2657
+ setStatusForUserBy: (identifier, status) => setStatusForUserBy(config, identifier, status),
2658
+ initiatePasswordResetForUserBy: (identifier, expiresAfter, callback) => initiatePasswordResetForUserBy(config, identifier, expiresAfter, callback),
2659
+ resetPassword: (email, expiresAfter, maxOpenRequests, callback) => resetPassword(config, email, expiresAfter, maxOpenRequests, callback),
2660
+ confirmResetPassword: (token, password) => confirmResetPassword(config, token, password),
2661
+ forceLogoutForUserBy: (identifier) => forceLogoutForUserBy(config, identifier)
2662
+ };
2663
+ }
2664
+
2629
2665
  // src/user-roles.ts
2630
- async function findAccountByIdentifier(queries, identifier) {
2666
+ async function findAccountByIdentifier2(queries, identifier) {
2631
2667
  let account = null;
2632
2668
  if (identifier.accountId !== void 0) {
2633
2669
  account = await queries.findAccountById(identifier.accountId);
@@ -2643,24 +2679,24 @@ async function findAccountByIdentifier(queries, identifier) {
2643
2679
  }
2644
2680
  async function addRoleToUser(config, identifier, role) {
2645
2681
  const queries = new AuthQueries(config);
2646
- const account = await findAccountByIdentifier(queries, identifier);
2682
+ const account = await findAccountByIdentifier2(queries, identifier);
2647
2683
  const rolemask = account.rolemask | role;
2648
2684
  await queries.updateAccount(account.id, { rolemask });
2649
2685
  }
2650
2686
  async function removeRoleFromUser(config, identifier, role) {
2651
2687
  const queries = new AuthQueries(config);
2652
- const account = await findAccountByIdentifier(queries, identifier);
2688
+ const account = await findAccountByIdentifier2(queries, identifier);
2653
2689
  const rolemask = account.rolemask & ~role;
2654
2690
  await queries.updateAccount(account.id, { rolemask });
2655
2691
  }
2656
2692
  async function setUserRoles(config, identifier, rolemask) {
2657
2693
  const queries = new AuthQueries(config);
2658
- const account = await findAccountByIdentifier(queries, identifier);
2694
+ const account = await findAccountByIdentifier2(queries, identifier);
2659
2695
  await queries.updateAccount(account.id, { rolemask });
2660
2696
  }
2661
2697
  async function getUserRoles(config, identifier) {
2662
2698
  const queries = new AuthQueries(config);
2663
- const account = await findAccountByIdentifier(queries, identifier);
2699
+ const account = await findAccountByIdentifier2(queries, identifier);
2664
2700
  return account.rolemask;
2665
2701
  }
2666
2702
  // Annotate the CommonJS export names for ESM import in node:
@@ -2700,10 +2736,11 @@ async function getUserRoles(config, identifier) {
2700
2736
  UserNotFoundError,
2701
2737
  UserNotLoggedInError,
2702
2738
  addRoleToUser,
2739
+ authFunctions,
2703
2740
  cleanupExpiredTokens,
2741
+ createAuthContext,
2704
2742
  createAuthMiddleware,
2705
2743
  createAuthTables,
2706
- createUser,
2707
2744
  dropAuthTables,
2708
2745
  getAuthTableStats,
2709
2746
  getUserRoles,