@eaccess/auth 0.1.2 → 0.1.4

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.js CHANGED
@@ -1,6 +1,74 @@
1
- // src/auth-admin-manager.ts
2
- import { hash as hash2 } from "@prsm/hash";
3
- import ms from "@prsm/ms";
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
7
+ // src/auth-manager.ts
8
+ import { hash as hash4 } from "@prsm/hash";
9
+ import ms3 from "@prsm/ms";
10
+
11
+ // src/types.ts
12
+ import "express-session";
13
+ var TwoFactorMechanism = /* @__PURE__ */ ((TwoFactorMechanism2) => {
14
+ TwoFactorMechanism2[TwoFactorMechanism2["TOTP"] = 1] = "TOTP";
15
+ TwoFactorMechanism2[TwoFactorMechanism2["EMAIL"] = 2] = "EMAIL";
16
+ TwoFactorMechanism2[TwoFactorMechanism2["SMS"] = 3] = "SMS";
17
+ return TwoFactorMechanism2;
18
+ })(TwoFactorMechanism || {});
19
+ var AuthStatus = {
20
+ Normal: 0,
21
+ Archived: 1,
22
+ Banned: 2,
23
+ Locked: 3,
24
+ PendingReview: 4,
25
+ Suspended: 5
26
+ };
27
+ var AuthRole = {
28
+ Admin: 1,
29
+ Author: 2,
30
+ Collaborator: 4,
31
+ Consultant: 8,
32
+ Consumer: 16,
33
+ Contributor: 32,
34
+ Coordinator: 64,
35
+ Creator: 128,
36
+ Developer: 256,
37
+ Director: 512,
38
+ Editor: 1024,
39
+ Employee: 2048,
40
+ Maintainer: 4096,
41
+ Manager: 8192,
42
+ Moderator: 16384,
43
+ Publisher: 32768,
44
+ Reviewer: 65536,
45
+ Subscriber: 131072,
46
+ SuperAdmin: 262144,
47
+ SuperEditor: 524288,
48
+ SuperModerator: 1048576,
49
+ Translator: 2097152
50
+ };
51
+ var AuthActivityAction = {
52
+ Login: "login",
53
+ Logout: "logout",
54
+ FailedLogin: "failed_login",
55
+ Register: "register",
56
+ EmailConfirmed: "email_confirmed",
57
+ PasswordResetRequested: "password_reset_requested",
58
+ PasswordResetCompleted: "password_reset_completed",
59
+ PasswordChanged: "password_changed",
60
+ EmailChanged: "email_changed",
61
+ RoleChanged: "role_changed",
62
+ StatusChanged: "status_changed",
63
+ ForceLogout: "force_logout",
64
+ OAuthConnected: "oauth_connected",
65
+ RememberTokenCreated: "remember_token_created",
66
+ TwoFactorSetup: "two_factor_setup",
67
+ TwoFactorVerified: "two_factor_verified",
68
+ TwoFactorFailed: "two_factor_failed",
69
+ TwoFactorDisabled: "two_factor_disabled",
70
+ BackupCodeUsed: "backup_code_used"
71
+ };
4
72
 
5
73
  // src/queries.ts
6
74
  var AuthQueries = class {
@@ -264,6 +332,158 @@ var AuthQueries = class {
264
332
  }
265
333
  };
266
334
 
335
+ // src/activity-logger.ts
336
+ import Bowser from "bowser";
337
+ var ActivityLogger = class {
338
+ constructor(config) {
339
+ this.config = config;
340
+ this.enabled = config.activityLog?.enabled !== false;
341
+ this.maxEntries = config.activityLog?.maxEntries || 1e4;
342
+ this.allowedActions = config.activityLog?.actions || null;
343
+ this.tablePrefix = config.tablePrefix || "user_";
344
+ }
345
+ get activityTable() {
346
+ return `${this.tablePrefix}activity_log`;
347
+ }
348
+ parseUserAgent(userAgent) {
349
+ if (!userAgent) {
350
+ return { browser: null, os: null, device: null };
351
+ }
352
+ try {
353
+ const browser = Bowser.getParser(userAgent);
354
+ const result = browser.getResult();
355
+ return {
356
+ browser: result.browser.name || null,
357
+ os: result.os.name || null,
358
+ device: result.platform.type || "desktop"
359
+ };
360
+ } catch (error) {
361
+ return this.parseUserAgentSimple(userAgent);
362
+ }
363
+ }
364
+ parseUserAgentSimple(userAgent) {
365
+ let browser = null;
366
+ if (userAgent.includes("Chrome")) browser = "Chrome";
367
+ else if (userAgent.includes("Firefox")) browser = "Firefox";
368
+ else if (userAgent.includes("Safari")) browser = "Safari";
369
+ else if (userAgent.includes("Edge")) browser = "Edge";
370
+ let os = null;
371
+ if (userAgent.includes("Windows")) os = "Windows";
372
+ else if (userAgent.includes("Mac OS")) os = "macOS";
373
+ else if (userAgent.includes("Linux")) os = "Linux";
374
+ else if (userAgent.includes("Android")) os = "Android";
375
+ else if (userAgent.includes("iOS")) os = "iOS";
376
+ let device = "desktop";
377
+ if (userAgent.includes("Mobile")) device = "mobile";
378
+ else if (userAgent.includes("Tablet")) device = "tablet";
379
+ return { browser, os, device };
380
+ }
381
+ getIpAddress(req) {
382
+ return req.ip || req.connection?.remoteAddress || req.socket?.remoteAddress || req.connection?.socket?.remoteAddress || null;
383
+ }
384
+ async logActivity(accountId, action, req, success = true, metadata = {}) {
385
+ if (!this.enabled) return;
386
+ if (this.allowedActions && !this.allowedActions.includes(action)) {
387
+ return;
388
+ }
389
+ const userAgent = (typeof req.get === "function" ? req.get("User-Agent") : req.headers?.["user-agent"]) || null;
390
+ const ip = this.getIpAddress(req);
391
+ const parsed = this.parseUserAgent(userAgent);
392
+ try {
393
+ await this.config.db.query(
394
+ `
395
+ INSERT INTO ${this.activityTable}
396
+ (account_id, action, ip_address, user_agent, browser, os, device, success, metadata)
397
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
398
+ `,
399
+ [accountId, action, ip, userAgent, parsed.browser, parsed.os, parsed.device, success, Object.keys(metadata).length > 0 ? JSON.stringify(metadata) : null]
400
+ );
401
+ if (Math.random() < 0.01) {
402
+ await this.cleanup();
403
+ }
404
+ } catch (error) {
405
+ console.error("ActivityLogger: Failed to log activity:", error);
406
+ }
407
+ }
408
+ async cleanup() {
409
+ if (!this.enabled) return;
410
+ try {
411
+ await this.config.db.query(
412
+ `
413
+ DELETE FROM ${this.activityTable}
414
+ WHERE id NOT IN (
415
+ SELECT id FROM ${this.activityTable}
416
+ ORDER BY created_at DESC
417
+ LIMIT $1
418
+ )
419
+ `,
420
+ [this.maxEntries]
421
+ );
422
+ } catch (error) {
423
+ console.error("ActivityLogger: Failed to cleanup old entries:", error);
424
+ }
425
+ }
426
+ async getRecentActivity(limit = 100, accountId) {
427
+ if (!this.enabled) return [];
428
+ try {
429
+ let sql = `
430
+ SELECT
431
+ al.*,
432
+ a.email
433
+ FROM ${this.activityTable} al
434
+ LEFT JOIN ${this.tablePrefix}accounts a ON al.account_id = a.id
435
+ `;
436
+ const params = [];
437
+ if (accountId !== void 0) {
438
+ sql += " WHERE al.account_id = $1";
439
+ params.push(accountId);
440
+ }
441
+ sql += ` ORDER BY al.created_at DESC LIMIT $${params.length + 1}`;
442
+ params.push(Math.min(limit, 1e3));
443
+ const result = await this.config.db.query(sql, params);
444
+ return result.rows.map((row) => ({
445
+ ...row,
446
+ metadata: row.metadata ? JSON.parse(row.metadata) : null
447
+ }));
448
+ } catch (error) {
449
+ console.error("ActivityLogger: Failed to get recent activity:", error);
450
+ return [];
451
+ }
452
+ }
453
+ async getActivityStats() {
454
+ if (!this.enabled) {
455
+ return {
456
+ totalEntries: 0,
457
+ uniqueUsers: 0,
458
+ recentLogins: 0,
459
+ failedAttempts: 0
460
+ };
461
+ }
462
+ try {
463
+ const [total, unique, recent, failed] = await Promise.all([
464
+ this.config.db.query(`SELECT COUNT(*) as count FROM ${this.activityTable}`),
465
+ this.config.db.query(`SELECT COUNT(DISTINCT account_id) as count FROM ${this.activityTable} WHERE account_id IS NOT NULL`),
466
+ this.config.db.query(`SELECT COUNT(*) as count FROM ${this.activityTable} WHERE action = 'login' AND created_at > NOW() - INTERVAL '24 hours'`),
467
+ this.config.db.query(`SELECT COUNT(*) as count FROM ${this.activityTable} WHERE success = false AND created_at > NOW() - INTERVAL '24 hours'`)
468
+ ]);
469
+ return {
470
+ totalEntries: parseInt(total.rows[0]?.count || "0"),
471
+ uniqueUsers: parseInt(unique.rows[0]?.count || "0"),
472
+ recentLogins: parseInt(recent.rows[0]?.count || "0"),
473
+ failedAttempts: parseInt(failed.rows[0]?.count || "0")
474
+ };
475
+ } catch (error) {
476
+ console.error("ActivityLogger: Failed to get activity stats:", error);
477
+ return {
478
+ totalEntries: 0,
479
+ uniqueUsers: 0,
480
+ recentLogins: 0,
481
+ failedAttempts: 0
482
+ };
483
+ }
484
+ }
485
+ };
486
+
267
487
  // src/errors.ts
268
488
  var AuthError = class extends Error {
269
489
  constructor(message) {
@@ -378,515 +598,23 @@ var TwoFactorSetupIncompleteError = class extends AuthError {
378
598
  }
379
599
  };
380
600
 
381
- // src/create-user.ts
382
- import { hash } from "@prsm/hash";
383
-
384
601
  // src/util.ts
385
602
  var isValidEmail = (email) => {
386
603
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
387
604
  return emailRegex.test(email);
388
605
  };
389
- var validateEmail = (email) => {
390
- if (typeof email !== "string") {
391
- throw new InvalidEmailError();
392
- }
393
- if (!email.trim()) {
394
- throw new InvalidEmailError();
395
- }
396
- if (!isValidEmail(email)) {
397
- throw new InvalidEmailError();
398
- }
399
- };
400
- var createMapFromEnum = (enumObj) => Object.fromEntries(Object.entries(enumObj).map(([key, value]) => [value, key]));
401
-
402
- // src/types.ts
403
- import "express-session";
404
- var TwoFactorMechanism = /* @__PURE__ */ ((TwoFactorMechanism2) => {
405
- TwoFactorMechanism2[TwoFactorMechanism2["TOTP"] = 1] = "TOTP";
406
- TwoFactorMechanism2[TwoFactorMechanism2["EMAIL"] = 2] = "EMAIL";
407
- TwoFactorMechanism2[TwoFactorMechanism2["SMS"] = 3] = "SMS";
408
- return TwoFactorMechanism2;
409
- })(TwoFactorMechanism || {});
410
- var AuthStatus = {
411
- Normal: 0,
412
- Archived: 1,
413
- Banned: 2,
414
- Locked: 3,
415
- PendingReview: 4,
416
- Suspended: 5
417
- };
418
- var AuthRole = {
419
- Admin: 1,
420
- Author: 2,
421
- Collaborator: 4,
422
- Consultant: 8,
423
- Consumer: 16,
424
- Contributor: 32,
425
- Coordinator: 64,
426
- Creator: 128,
427
- Developer: 256,
428
- Director: 512,
429
- Editor: 1024,
430
- Employee: 2048,
431
- Maintainer: 4096,
432
- Manager: 8192,
433
- Moderator: 16384,
434
- Publisher: 32768,
435
- Reviewer: 65536,
436
- Subscriber: 131072,
437
- SuperAdmin: 262144,
438
- SuperEditor: 524288,
439
- SuperModerator: 1048576,
440
- Translator: 2097152
441
- };
442
- var AuthActivityAction = {
443
- Login: "login",
444
- Logout: "logout",
445
- FailedLogin: "failed_login",
446
- Register: "register",
447
- EmailConfirmed: "email_confirmed",
448
- PasswordResetRequested: "password_reset_requested",
449
- PasswordResetCompleted: "password_reset_completed",
450
- PasswordChanged: "password_changed",
451
- EmailChanged: "email_changed",
452
- RoleChanged: "role_changed",
453
- StatusChanged: "status_changed",
454
- ForceLogout: "force_logout",
455
- OAuthConnected: "oauth_connected",
456
- RememberTokenCreated: "remember_token_created",
457
- TwoFactorSetup: "two_factor_setup",
458
- TwoFactorVerified: "two_factor_verified",
459
- TwoFactorFailed: "two_factor_failed",
460
- TwoFactorDisabled: "two_factor_disabled",
461
- BackupCodeUsed: "backup_code_used"
462
- };
463
-
464
- // src/create-user.ts
465
- function validatePassword(password, config) {
466
- const minLength = config.minPasswordLength || 8;
467
- const maxLength = config.maxPasswordLength || 64;
468
- if (typeof password !== "string") {
469
- throw new InvalidPasswordError();
470
- }
471
- if (password.length < minLength) {
472
- throw new InvalidPasswordError();
473
- }
474
- if (password.length > maxLength) {
475
- throw new InvalidPasswordError();
476
- }
477
- }
478
- function generateAutoUserId() {
479
- return crypto.randomUUID();
480
- }
481
- async function createConfirmationToken(queries, account, email, callback) {
482
- const token = hash.encode(email);
483
- const expires = new Date(Date.now() + 1e3 * 60 * 60 * 24 * 7);
484
- await queries.createConfirmation({
485
- accountId: account.id,
486
- token,
487
- email,
488
- expires
489
- });
490
- if (callback) {
491
- callback(token);
492
- }
493
- }
494
- async function createUser(config, credentials, userId, callback) {
495
- validateEmail(credentials.email);
496
- validatePassword(credentials.password, config);
497
- const queries = new AuthQueries(config);
498
- const existing = await queries.findAccountByEmail(credentials.email);
499
- if (existing) {
500
- throw new EmailTakenError();
501
- }
502
- const finalUserId = userId || generateAutoUserId();
503
- const hashedPassword = hash.encode(credentials.password);
504
- const verified = typeof callback !== "function";
505
- const account = await queries.createAccount({
506
- userId: finalUserId,
507
- email: credentials.email,
508
- password: hashedPassword,
509
- verified,
510
- status: AuthStatus.Normal,
511
- rolemask: 0
512
- });
513
- if (!verified && callback) {
514
- await createConfirmationToken(queries, account, credentials.email, callback);
515
- }
516
- return account;
517
- }
518
-
519
- // src/auth-admin-manager.ts
520
- var AuthAdminManager = class {
521
- constructor(req, res, config, auth) {
522
- this.req = req;
523
- this.res = res;
524
- this.config = config;
525
- this.queries = new AuthQueries(config);
526
- this.auth = auth;
527
- }
528
- validatePassword(password) {
529
- const minLength = this.config.minPasswordLength || 8;
530
- const maxLength = this.config.maxPasswordLength || 64;
531
- if (typeof password !== "string") {
532
- throw new InvalidPasswordError();
533
- }
534
- if (password.length < minLength) {
535
- throw new InvalidPasswordError();
536
- }
537
- if (password.length > maxLength) {
538
- throw new InvalidPasswordError();
539
- }
540
- }
541
- async findAccountByIdentifier(identifier) {
542
- if (identifier.accountId !== void 0) {
543
- return await this.queries.findAccountById(identifier.accountId);
544
- } else if (identifier.email !== void 0) {
545
- return await this.queries.findAccountByEmail(identifier.email);
546
- } else if (identifier.userId !== void 0) {
547
- return await this.queries.findAccountByUserId(identifier.userId);
548
- }
549
- return null;
550
- }
551
- async createConfirmationToken(account, email, callback) {
552
- const token = hash2.encode(email);
553
- const expires = new Date(Date.now() + 1e3 * 60 * 60 * 24 * 7);
554
- await this.queries.createConfirmation({
555
- accountId: account.id,
556
- token,
557
- email,
558
- expires
559
- });
560
- if (callback) {
561
- callback(token);
562
- }
563
- }
564
- /**
565
- * Create a new user account (admin function).
566
- *
567
- * @param credentials - Email and password for new account
568
- * @param userId - Optional user ID to link this auth account to. If not provided, a UUID will be generated automatically.
569
- * @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.
570
- * @returns The created account record
571
- * @throws {EmailTakenError} Email is already registered
572
- * @throws {InvalidPasswordError} Password doesn't meet length requirements
573
- */
574
- async createUser(credentials, userId, callback) {
575
- return createUser(this.config, credentials, userId, callback);
576
- }
577
- /**
578
- * Log in as another user (admin function).
579
- * Creates a new session as the target user without requiring their password.
580
- *
581
- * @param identifier - Find user by accountId, email, or userId
582
- * @throws {UserNotFoundError} No account matches the identifier
583
- */
584
- async loginAsUserBy(identifier) {
585
- const account = await this.findAccountByIdentifier(identifier);
586
- if (!account) {
587
- throw new UserNotFoundError();
588
- }
589
- await this.auth.onLoginSuccessful(account, false);
590
- }
591
- /**
592
- * Delete a user account and all associated data (admin function).
593
- * Removes account, confirmations, remember tokens, and reset tokens.
594
- *
595
- * @param identifier - Find user by accountId, email, or userId
596
- * @throws {UserNotFoundError} No account matches the identifier
597
- */
598
- async deleteUserBy(identifier) {
599
- const account = await this.findAccountByIdentifier(identifier);
600
- if (!account) {
601
- throw new UserNotFoundError();
602
- }
603
- await this.queries.deleteAccount(account.id);
604
- }
605
- /**
606
- * Add a role to a user's account (admin function).
607
- * Uses bitwise OR to add role to existing rolemask.
608
- *
609
- * @param identifier - Find user by accountId, email, or userId
610
- * @param role - Role bitmask to add (e.g., AuthRole.Admin)
611
- * @throws {UserNotFoundError} No account matches the identifier
612
- */
613
- async addRoleForUserBy(identifier, role) {
614
- const account = await this.findAccountByIdentifier(identifier);
615
- if (!account) {
616
- throw new UserNotFoundError();
617
- }
618
- const rolemask = account.rolemask | role;
619
- await this.queries.updateAccount(account.id, { rolemask });
620
- }
621
- /**
622
- * Remove a role from a user's account (admin function).
623
- * Uses bitwise operations to remove role from rolemask.
624
- *
625
- * @param identifier - Find user by accountId, email, or userId
626
- * @param role - Role bitmask to remove (e.g., AuthRole.Admin)
627
- * @throws {UserNotFoundError} No account matches the identifier
628
- */
629
- async removeRoleForUserBy(identifier, role) {
630
- const account = await this.findAccountByIdentifier(identifier);
631
- if (!account) {
632
- throw new UserNotFoundError();
633
- }
634
- const rolemask = account.rolemask & ~role;
635
- await this.queries.updateAccount(account.id, { rolemask });
636
- }
637
- /**
638
- * Check if a user has a specific role (admin function).
639
- *
640
- * @param identifier - Find user by accountId, email, or userId
641
- * @param role - Role bitmask to check (e.g., AuthRole.Admin)
642
- * @returns true if user has the role, false otherwise
643
- * @throws {UserNotFoundError} No account matches the identifier
644
- */
645
- async hasRoleForUserBy(identifier, role) {
646
- const account = await this.findAccountByIdentifier(identifier);
647
- if (!account) {
648
- throw new UserNotFoundError();
649
- }
650
- return (account.rolemask & role) === role;
651
- }
652
- /**
653
- * Change a user's password (admin function).
654
- * Does not require knowing the current password.
655
- *
656
- * @param identifier - Find user by accountId, email, or userId
657
- * @param password - New password (will be hashed)
658
- * @throws {UserNotFoundError} No account matches the identifier
659
- * @throws {InvalidPasswordError} New password doesn't meet requirements
660
- */
661
- async changePasswordForUserBy(identifier, password) {
662
- this.validatePassword(password);
663
- const account = await this.findAccountByIdentifier(identifier);
664
- if (!account) {
665
- throw new UserNotFoundError();
666
- }
667
- await this.queries.updateAccount(account.id, {
668
- password: hash2.encode(password)
669
- });
670
- }
671
- /**
672
- * Change a user's account status (admin function).
673
- *
674
- * @param identifier - Find user by accountId, email, or userId
675
- * @param status - New status (0=Normal, 1=Archived, 2=Banned, 3=Locked, etc.)
676
- * @throws {UserNotFoundError} No account matches the identifier
677
- */
678
- async setStatusForUserBy(identifier, status) {
679
- const account = await this.findAccountByIdentifier(identifier);
680
- if (!account) {
681
- throw new UserNotFoundError();
682
- }
683
- await this.queries.updateAccount(account.id, { status });
684
- }
685
- /**
686
- * Initiate password reset for a user (admin function).
687
- * Creates a reset token without rate limiting.
688
- *
689
- * @param identifier - Find user by accountId, email, or userId
690
- * @param expiresAfter - Token expiration (default: 6h). Accepts ms format like '1h', '30m'
691
- * @param callback - Called with reset token. Create a URL like /reset/{token} and call confirmResetPassword() in that handler
692
- * @throws {UserNotFoundError} No account matches the identifier
693
- * @throws {EmailNotVerifiedError} Account exists but email is not verified
694
- */
695
- async initiatePasswordResetForUserBy(identifier, expiresAfter = null, callback) {
696
- const account = await this.findAccountByIdentifier(identifier);
697
- if (!account) {
698
- throw new UserNotFoundError();
699
- }
700
- if (!account.verified) {
701
- throw new EmailNotVerifiedError();
702
- }
703
- const expiry = !expiresAfter ? ms("6h") : ms(expiresAfter);
704
- const token = hash2.encode(account.email);
705
- const expires = new Date(Date.now() + expiry);
706
- await this.queries.createResetToken({
707
- accountId: account.id,
708
- token,
709
- expires
710
- });
711
- if (callback) {
712
- callback(token);
713
- }
714
- }
715
- /**
716
- * Force logout all sessions for a specific user (admin function).
717
- * Increments force_logout counter and deletes all remember tokens.
718
- * If target user is currently logged in, marks their session for logout.
719
- *
720
- * @param identifier - Find user by accountId, email, or userId
721
- * @throws {UserNotFoundError} No account matches the identifier
722
- */
723
- async forceLogoutForUserBy(identifier) {
724
- const account = await this.findAccountByIdentifier(identifier);
725
- if (!account) {
726
- throw new UserNotFoundError();
727
- }
728
- await this.queries.incrementForceLogout(account.id);
729
- if (this.auth.getId() === account.id) {
730
- this.req.session.auth.shouldForceLogout = true;
731
- }
732
- }
733
- };
734
-
735
- // src/auth-manager.ts
736
- import { hash as hash5 } from "@prsm/hash";
737
- import ms3 from "@prsm/ms";
738
-
739
- // src/activity-logger.ts
740
- import Bowser from "bowser";
741
- var ActivityLogger = class {
742
- constructor(config) {
743
- this.config = config;
744
- this.enabled = config.activityLog?.enabled !== false;
745
- this.maxEntries = config.activityLog?.maxEntries || 1e4;
746
- this.allowedActions = config.activityLog?.actions || null;
747
- this.tablePrefix = config.tablePrefix || "user_";
748
- }
749
- get activityTable() {
750
- return `${this.tablePrefix}activity_log`;
751
- }
752
- parseUserAgent(userAgent) {
753
- if (!userAgent) {
754
- return { browser: null, os: null, device: null };
755
- }
756
- try {
757
- const browser = Bowser.getParser(userAgent);
758
- const result = browser.getResult();
759
- return {
760
- browser: result.browser.name || null,
761
- os: result.os.name || null,
762
- device: result.platform.type || "desktop"
763
- };
764
- } catch (error) {
765
- return this.parseUserAgentSimple(userAgent);
766
- }
767
- }
768
- parseUserAgentSimple(userAgent) {
769
- let browser = null;
770
- if (userAgent.includes("Chrome")) browser = "Chrome";
771
- else if (userAgent.includes("Firefox")) browser = "Firefox";
772
- else if (userAgent.includes("Safari")) browser = "Safari";
773
- else if (userAgent.includes("Edge")) browser = "Edge";
774
- let os = null;
775
- if (userAgent.includes("Windows")) os = "Windows";
776
- else if (userAgent.includes("Mac OS")) os = "macOS";
777
- else if (userAgent.includes("Linux")) os = "Linux";
778
- else if (userAgent.includes("Android")) os = "Android";
779
- else if (userAgent.includes("iOS")) os = "iOS";
780
- let device = "desktop";
781
- if (userAgent.includes("Mobile")) device = "mobile";
782
- else if (userAgent.includes("Tablet")) device = "tablet";
783
- return { browser, os, device };
784
- }
785
- getIpAddress(req) {
786
- return req.ip || req.connection?.remoteAddress || req.socket?.remoteAddress || req.connection?.socket?.remoteAddress || null;
787
- }
788
- async logActivity(accountId, action, req, success = true, metadata = {}) {
789
- if (!this.enabled) return;
790
- if (this.allowedActions && !this.allowedActions.includes(action)) {
791
- return;
792
- }
793
- const userAgent = (typeof req.get === "function" ? req.get("User-Agent") : req.headers?.["user-agent"]) || null;
794
- const ip = this.getIpAddress(req);
795
- const parsed = this.parseUserAgent(userAgent);
796
- try {
797
- await this.config.db.query(
798
- `
799
- INSERT INTO ${this.activityTable}
800
- (account_id, action, ip_address, user_agent, browser, os, device, success, metadata)
801
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
802
- `,
803
- [accountId, action, ip, userAgent, parsed.browser, parsed.os, parsed.device, success, Object.keys(metadata).length > 0 ? JSON.stringify(metadata) : null]
804
- );
805
- if (Math.random() < 0.01) {
806
- await this.cleanup();
807
- }
808
- } catch (error) {
809
- console.error("ActivityLogger: Failed to log activity:", error);
810
- }
811
- }
812
- async cleanup() {
813
- if (!this.enabled) return;
814
- try {
815
- await this.config.db.query(
816
- `
817
- DELETE FROM ${this.activityTable}
818
- WHERE id NOT IN (
819
- SELECT id FROM ${this.activityTable}
820
- ORDER BY created_at DESC
821
- LIMIT $1
822
- )
823
- `,
824
- [this.maxEntries]
825
- );
826
- } catch (error) {
827
- console.error("ActivityLogger: Failed to cleanup old entries:", error);
828
- }
606
+ var validateEmail = (email) => {
607
+ if (typeof email !== "string") {
608
+ throw new InvalidEmailError();
829
609
  }
830
- async getRecentActivity(limit = 100, accountId) {
831
- if (!this.enabled) return [];
832
- try {
833
- let sql = `
834
- SELECT
835
- al.*,
836
- a.email
837
- FROM ${this.activityTable} al
838
- LEFT JOIN ${this.tablePrefix}accounts a ON al.account_id = a.id
839
- `;
840
- const params = [];
841
- if (accountId !== void 0) {
842
- sql += " WHERE al.account_id = $1";
843
- params.push(accountId);
844
- }
845
- sql += ` ORDER BY al.created_at DESC LIMIT $${params.length + 1}`;
846
- params.push(Math.min(limit, 1e3));
847
- const result = await this.config.db.query(sql, params);
848
- return result.rows.map((row) => ({
849
- ...row,
850
- metadata: row.metadata ? JSON.parse(row.metadata) : null
851
- }));
852
- } catch (error) {
853
- console.error("ActivityLogger: Failed to get recent activity:", error);
854
- return [];
855
- }
610
+ if (!email.trim()) {
611
+ throw new InvalidEmailError();
856
612
  }
857
- async getActivityStats() {
858
- if (!this.enabled) {
859
- return {
860
- totalEntries: 0,
861
- uniqueUsers: 0,
862
- recentLogins: 0,
863
- failedAttempts: 0
864
- };
865
- }
866
- try {
867
- const [total, unique, recent, failed] = await Promise.all([
868
- this.config.db.query(`SELECT COUNT(*) as count FROM ${this.activityTable}`),
869
- this.config.db.query(`SELECT COUNT(DISTINCT account_id) as count FROM ${this.activityTable} WHERE account_id IS NOT NULL`),
870
- this.config.db.query(`SELECT COUNT(*) as count FROM ${this.activityTable} WHERE action = 'login' AND created_at > NOW() - INTERVAL '24 hours'`),
871
- this.config.db.query(`SELECT COUNT(*) as count FROM ${this.activityTable} WHERE success = false AND created_at > NOW() - INTERVAL '24 hours'`)
872
- ]);
873
- return {
874
- totalEntries: parseInt(total.rows[0]?.count || "0"),
875
- uniqueUsers: parseInt(unique.rows[0]?.count || "0"),
876
- recentLogins: parseInt(recent.rows[0]?.count || "0"),
877
- failedAttempts: parseInt(failed.rows[0]?.count || "0")
878
- };
879
- } catch (error) {
880
- console.error("ActivityLogger: Failed to get activity stats:", error);
881
- return {
882
- totalEntries: 0,
883
- uniqueUsers: 0,
884
- recentLogins: 0,
885
- failedAttempts: 0
886
- };
887
- }
613
+ if (!isValidEmail(email)) {
614
+ throw new InvalidEmailError();
888
615
  }
889
616
  };
617
+ var createMapFromEnum = (enumObj) => Object.fromEntries(Object.entries(enumObj).map(([key, value]) => [value, key]));
890
618
 
891
619
  // src/providers/base-provider.ts
892
620
  var BaseOAuthProvider = class {
@@ -1131,7 +859,7 @@ var AzureProvider = class extends BaseOAuthProvider {
1131
859
 
1132
860
  // src/two-factor/totp-provider.ts
1133
861
  import Otp from "@eaccess/totp";
1134
- import { hash as hash3 } from "@prsm/hash";
862
+ import { hash } from "@prsm/hash";
1135
863
  var TotpProvider = class {
1136
864
  constructor(config) {
1137
865
  this.config = config;
@@ -1160,11 +888,11 @@ var TotpProvider = class {
1160
888
  return codes;
1161
889
  }
1162
890
  hashBackupCodes(codes) {
1163
- return codes.map((code) => hash3.encode(code));
891
+ return codes.map((code) => hash.encode(code));
1164
892
  }
1165
893
  verifyBackupCode(hashedCodes, inputCode) {
1166
894
  for (let i = 0; i < hashedCodes.length; i++) {
1167
- if (hash3.verify(hashedCodes[i], inputCode.toUpperCase())) {
895
+ if (hash.verify(hashedCodes[i], inputCode.toUpperCase())) {
1168
896
  return { isValid: true, index: i };
1169
897
  }
1170
898
  }
@@ -1180,8 +908,8 @@ var TotpProvider = class {
1180
908
  };
1181
909
 
1182
910
  // src/two-factor/otp-provider.ts
1183
- import ms2 from "@prsm/ms";
1184
- import { hash as hash4 } from "@prsm/hash";
911
+ import ms from "@prsm/ms";
912
+ import { hash as hash2 } from "@prsm/hash";
1185
913
  var OtpProvider = class {
1186
914
  constructor(config) {
1187
915
  this.config = config;
@@ -1206,9 +934,9 @@ var OtpProvider = class {
1206
934
  async createAndStoreOTP(accountId, mechanism) {
1207
935
  const otp = this.generateOTP();
1208
936
  const selector = this.generateSelector();
1209
- const tokenHash = hash4.encode(otp);
937
+ const tokenHash = hash2.encode(otp);
1210
938
  const expiryDuration = this.config.twoFactor?.tokenExpiry || "5m";
1211
- const expiresAt = new Date(Date.now() + ms2(expiryDuration));
939
+ const expiresAt = new Date(Date.now() + ms(expiryDuration));
1212
940
  await this.queries.deleteTwoFactorTokensByAccountAndMechanism(accountId, mechanism);
1213
941
  await this.queries.createTwoFactorToken({
1214
942
  accountId,
@@ -1228,7 +956,7 @@ var OtpProvider = class {
1228
956
  await this.queries.deleteTwoFactorToken(token.id);
1229
957
  return { isValid: false };
1230
958
  }
1231
- const isValid = hash4.verify(token.token_hash, inputCode);
959
+ const isValid = hash2.verify(token.token_hash, inputCode);
1232
960
  if (isValid) {
1233
961
  await this.queries.deleteTwoFactorToken(token.id);
1234
962
  return { isValid: true, token };
@@ -1626,6 +1354,248 @@ var TwoFactorManager = class {
1626
1354
  }
1627
1355
  };
1628
1356
 
1357
+ // src/auth-functions.ts
1358
+ var auth_functions_exports = {};
1359
+ __export(auth_functions_exports, {
1360
+ addRoleForUserBy: () => addRoleForUserBy,
1361
+ changePasswordForUserBy: () => changePasswordForUserBy,
1362
+ confirmResetPassword: () => confirmResetPassword,
1363
+ createUser: () => createUser,
1364
+ deleteUserBy: () => deleteUserBy,
1365
+ forceLogoutForUserBy: () => forceLogoutForUserBy,
1366
+ hasRoleForUserBy: () => hasRoleForUserBy,
1367
+ initiatePasswordResetForUserBy: () => initiatePasswordResetForUserBy,
1368
+ register: () => register,
1369
+ removeRoleForUserBy: () => removeRoleForUserBy,
1370
+ resetPassword: () => resetPassword,
1371
+ setStatusForUserBy: () => setStatusForUserBy
1372
+ });
1373
+ import { hash as hash3 } from "@prsm/hash";
1374
+ import ms2 from "@prsm/ms";
1375
+ function validatePassword(password, config) {
1376
+ const minLength = config.minPasswordLength || 8;
1377
+ const maxLength = config.maxPasswordLength || 64;
1378
+ if (typeof password !== "string") {
1379
+ throw new InvalidPasswordError();
1380
+ }
1381
+ if (password.length < minLength) {
1382
+ throw new InvalidPasswordError();
1383
+ }
1384
+ if (password.length > maxLength) {
1385
+ throw new InvalidPasswordError();
1386
+ }
1387
+ }
1388
+ function generateAutoUserId() {
1389
+ return crypto.randomUUID();
1390
+ }
1391
+ async function findAccountByIdentifier(queries, identifier) {
1392
+ if (identifier.accountId !== void 0) {
1393
+ return await queries.findAccountById(identifier.accountId);
1394
+ } else if (identifier.email !== void 0) {
1395
+ return await queries.findAccountByEmail(identifier.email);
1396
+ } else if (identifier.userId !== void 0) {
1397
+ return await queries.findAccountByUserId(identifier.userId);
1398
+ }
1399
+ return null;
1400
+ }
1401
+ async function createConfirmationToken(queries, account, email, callback) {
1402
+ const token = hash3.encode(email);
1403
+ const expires = new Date(Date.now() + 1e3 * 60 * 60 * 24 * 7);
1404
+ await queries.createConfirmation({
1405
+ accountId: account.id,
1406
+ token,
1407
+ email,
1408
+ expires
1409
+ });
1410
+ if (callback) {
1411
+ callback(token);
1412
+ }
1413
+ }
1414
+ async function createUser(config, credentials, userId, callback) {
1415
+ validateEmail(credentials.email);
1416
+ validatePassword(credentials.password, config);
1417
+ const queries = new AuthQueries(config);
1418
+ const existing = await queries.findAccountByEmail(credentials.email);
1419
+ if (existing) {
1420
+ throw new EmailTakenError();
1421
+ }
1422
+ const finalUserId = userId || generateAutoUserId();
1423
+ const hashedPassword = hash3.encode(credentials.password);
1424
+ const verified = typeof callback !== "function";
1425
+ const account = await queries.createAccount({
1426
+ userId: finalUserId,
1427
+ email: credentials.email,
1428
+ password: hashedPassword,
1429
+ verified,
1430
+ status: AuthStatus.Normal,
1431
+ rolemask: 0
1432
+ });
1433
+ if (!verified && callback) {
1434
+ await createConfirmationToken(queries, account, credentials.email, callback);
1435
+ }
1436
+ return account;
1437
+ }
1438
+ async function register(config, email, password, userId, callback) {
1439
+ validateEmail(email);
1440
+ validatePassword(password, config);
1441
+ const queries = new AuthQueries(config);
1442
+ const existing = await queries.findAccountByEmail(email);
1443
+ if (existing) {
1444
+ throw new EmailTakenError();
1445
+ }
1446
+ const finalUserId = userId || generateAutoUserId();
1447
+ const hashedPassword = hash3.encode(password);
1448
+ const verified = typeof callback !== "function";
1449
+ const account = await queries.createAccount({
1450
+ userId: finalUserId,
1451
+ email,
1452
+ password: hashedPassword,
1453
+ verified,
1454
+ status: AuthStatus.Normal,
1455
+ rolemask: 0
1456
+ });
1457
+ if (!verified && callback) {
1458
+ await createConfirmationToken(queries, account, email, callback);
1459
+ }
1460
+ return account;
1461
+ }
1462
+ async function deleteUserBy(config, identifier) {
1463
+ const queries = new AuthQueries(config);
1464
+ const account = await findAccountByIdentifier(queries, identifier);
1465
+ if (!account) {
1466
+ throw new UserNotFoundError();
1467
+ }
1468
+ await queries.deleteAccount(account.id);
1469
+ }
1470
+ async function addRoleForUserBy(config, identifier, role) {
1471
+ const queries = new AuthQueries(config);
1472
+ const account = await findAccountByIdentifier(queries, identifier);
1473
+ if (!account) {
1474
+ throw new UserNotFoundError();
1475
+ }
1476
+ const rolemask = account.rolemask | role;
1477
+ await queries.updateAccount(account.id, { rolemask });
1478
+ }
1479
+ async function removeRoleForUserBy(config, identifier, role) {
1480
+ const queries = new AuthQueries(config);
1481
+ const account = await findAccountByIdentifier(queries, identifier);
1482
+ if (!account) {
1483
+ throw new UserNotFoundError();
1484
+ }
1485
+ const rolemask = account.rolemask & ~role;
1486
+ await queries.updateAccount(account.id, { rolemask });
1487
+ }
1488
+ async function hasRoleForUserBy(config, identifier, role) {
1489
+ const queries = new AuthQueries(config);
1490
+ const account = await findAccountByIdentifier(queries, identifier);
1491
+ if (!account) {
1492
+ throw new UserNotFoundError();
1493
+ }
1494
+ return (account.rolemask & role) === role;
1495
+ }
1496
+ async function changePasswordForUserBy(config, identifier, password) {
1497
+ validatePassword(password, config);
1498
+ const queries = new AuthQueries(config);
1499
+ const account = await findAccountByIdentifier(queries, identifier);
1500
+ if (!account) {
1501
+ throw new UserNotFoundError();
1502
+ }
1503
+ await queries.updateAccount(account.id, {
1504
+ password: hash3.encode(password)
1505
+ });
1506
+ }
1507
+ async function setStatusForUserBy(config, identifier, status) {
1508
+ const queries = new AuthQueries(config);
1509
+ const account = await findAccountByIdentifier(queries, identifier);
1510
+ if (!account) {
1511
+ throw new UserNotFoundError();
1512
+ }
1513
+ await queries.updateAccount(account.id, { status });
1514
+ }
1515
+ async function initiatePasswordResetForUserBy(config, identifier, expiresAfter = null, callback) {
1516
+ const queries = new AuthQueries(config);
1517
+ const account = await findAccountByIdentifier(queries, identifier);
1518
+ if (!account) {
1519
+ throw new UserNotFoundError();
1520
+ }
1521
+ if (!account.verified) {
1522
+ throw new EmailNotVerifiedError();
1523
+ }
1524
+ const expiry = !expiresAfter ? ms2("6h") : ms2(expiresAfter);
1525
+ const token = hash3.encode(account.email);
1526
+ const expires = new Date(Date.now() + expiry);
1527
+ await queries.createResetToken({
1528
+ accountId: account.id,
1529
+ token,
1530
+ expires
1531
+ });
1532
+ if (callback) {
1533
+ callback(token);
1534
+ }
1535
+ }
1536
+ async function resetPassword(config, email, expiresAfter = null, maxOpenRequests = null, callback) {
1537
+ validateEmail(email);
1538
+ const expiry = !expiresAfter ? ms2("6h") : ms2(expiresAfter);
1539
+ const maxRequests = maxOpenRequests === null ? 2 : Math.max(1, maxOpenRequests);
1540
+ const queries = new AuthQueries(config);
1541
+ const account = await queries.findAccountByEmail(email);
1542
+ if (!account || !account.verified) {
1543
+ throw new EmailNotVerifiedError();
1544
+ }
1545
+ if (!account.resettable) {
1546
+ throw new ResetDisabledError();
1547
+ }
1548
+ const openRequests = await queries.countActiveResetTokensForAccount(account.id);
1549
+ if (openRequests >= maxRequests) {
1550
+ throw new TooManyResetsError();
1551
+ }
1552
+ const token = hash3.encode(email);
1553
+ const expires = new Date(Date.now() + expiry);
1554
+ await queries.createResetToken({
1555
+ accountId: account.id,
1556
+ token,
1557
+ expires
1558
+ });
1559
+ if (callback) {
1560
+ callback(token);
1561
+ }
1562
+ }
1563
+ async function confirmResetPassword(config, token, password) {
1564
+ const queries = new AuthQueries(config);
1565
+ const reset = await queries.findResetToken(token);
1566
+ if (!reset) {
1567
+ throw new ResetNotFoundError();
1568
+ }
1569
+ if (new Date(reset.expires) < /* @__PURE__ */ new Date()) {
1570
+ throw new ResetExpiredError();
1571
+ }
1572
+ const account = await queries.findAccountById(reset.account_id);
1573
+ if (!account) {
1574
+ throw new UserNotFoundError();
1575
+ }
1576
+ if (!account.resettable) {
1577
+ throw new ResetDisabledError();
1578
+ }
1579
+ validatePassword(password, config);
1580
+ if (!hash3.verify(token, account.email)) {
1581
+ throw new InvalidTokenError();
1582
+ }
1583
+ await queries.updateAccount(account.id, {
1584
+ password: hash3.encode(password)
1585
+ });
1586
+ await queries.deleteResetToken(token);
1587
+ return { accountId: account.id, email: account.email };
1588
+ }
1589
+ async function forceLogoutForUserBy(config, identifier) {
1590
+ const queries = new AuthQueries(config);
1591
+ const account = await findAccountByIdentifier(queries, identifier);
1592
+ if (!account) {
1593
+ throw new UserNotFoundError();
1594
+ }
1595
+ await queries.incrementForceLogout(account.id);
1596
+ return { accountId: account.id };
1597
+ }
1598
+
1629
1599
  // src/auth-manager.ts
1630
1600
  var AuthManager = class {
1631
1601
  constructor(req, res, config) {
@@ -1817,7 +1787,7 @@ var AuthManager = class {
1817
1787
  });
1818
1788
  }
1819
1789
  async createRememberDirective(account) {
1820
- const token = hash5.encode(account.email);
1790
+ const token = hash4.encode(account.email);
1821
1791
  const duration = this.config.rememberDuration || "30d";
1822
1792
  const expires = new Date(Date.now() + ms3(duration));
1823
1793
  await this.queries.createRememberToken({
@@ -1855,7 +1825,7 @@ var AuthManager = class {
1855
1825
  await this.activityLogger.logActivity(null, AuthActivityAction.FailedLogin, this.req, false, { email, reason: "account_not_found" });
1856
1826
  throw new UserNotFoundError();
1857
1827
  }
1858
- if (!account.password || !hash5.verify(account.password, password)) {
1828
+ if (!account.password || !hash4.verify(account.password, password)) {
1859
1829
  await this.activityLogger.logActivity(account.id, AuthActivityAction.FailedLogin, this.req, false, { email, reason: "invalid_password" });
1860
1830
  throw new InvalidPasswordError();
1861
1831
  }
@@ -1967,7 +1937,7 @@ var AuthManager = class {
1967
1937
  throw new EmailTakenError();
1968
1938
  }
1969
1939
  const finalUserId = userId || this.generateAutoUserId();
1970
- const hashedPassword = hash5.encode(password);
1940
+ const hashedPassword = hash4.encode(password);
1971
1941
  const verified = typeof callback !== "function";
1972
1942
  const account = await this.queries.createAccount({
1973
1943
  userId: finalUserId,
@@ -1984,7 +1954,7 @@ var AuthManager = class {
1984
1954
  return account;
1985
1955
  }
1986
1956
  async createConfirmationToken(account, email, callback) {
1987
- const token = hash5.encode(email);
1957
+ const token = hash4.encode(email);
1988
1958
  const expires = new Date(Date.now() + 1e3 * 60 * 60 * 24 * 7);
1989
1959
  await this.queries.createConfirmation({
1990
1960
  accountId: account.id,
@@ -2118,7 +2088,7 @@ var AuthManager = class {
2118
2088
  if (new Date(confirmation.expires) < /* @__PURE__ */ new Date()) {
2119
2089
  throw new ConfirmationExpiredError();
2120
2090
  }
2121
- if (!hash5.verify(token, confirmation.email)) {
2091
+ if (!hash4.verify(token, confirmation.email)) {
2122
2092
  throw new InvalidTokenError();
2123
2093
  }
2124
2094
  await this.queries.updateAccount(confirmation.account_id, {
@@ -2215,7 +2185,7 @@ var AuthManager = class {
2215
2185
  if (openRequests >= maxRequests) {
2216
2186
  throw new TooManyResetsError();
2217
2187
  }
2218
- const token = hash5.encode(email);
2188
+ const token = hash4.encode(email);
2219
2189
  const expires = new Date(Date.now() + expiry);
2220
2190
  await this.queries.createResetToken({
2221
2191
  accountId: account.id,
@@ -2257,11 +2227,11 @@ var AuthManager = class {
2257
2227
  throw new ResetDisabledError();
2258
2228
  }
2259
2229
  this.validatePassword(password);
2260
- if (!hash5.verify(token, account.email)) {
2230
+ if (!hash4.verify(token, account.email)) {
2261
2231
  throw new InvalidTokenError();
2262
2232
  }
2263
2233
  await this.queries.updateAccount(account.id, {
2264
- password: hash5.encode(password)
2234
+ password: hash4.encode(password)
2265
2235
  });
2266
2236
  if (logout) {
2267
2237
  await this.forceLogoutForAccountById(account.id);
@@ -2289,7 +2259,7 @@ var AuthManager = class {
2289
2259
  if (!account.password) {
2290
2260
  return false;
2291
2261
  }
2292
- return hash5.verify(account.password, password);
2262
+ return hash4.verify(account.password, password);
2293
2263
  }
2294
2264
  async forceLogoutForAccountById(accountId) {
2295
2265
  await this.queries.deleteRememberTokensForAccount(accountId);
@@ -2327,6 +2297,61 @@ var AuthManager = class {
2327
2297
  await this.logoutEverywhereElse();
2328
2298
  await this.logout();
2329
2299
  }
2300
+ async findAccountByIdentifier(identifier) {
2301
+ if (identifier.accountId !== void 0) {
2302
+ return await this.queries.findAccountById(identifier.accountId);
2303
+ } else if (identifier.email !== void 0) {
2304
+ return await this.queries.findAccountByEmail(identifier.email);
2305
+ } else if (identifier.userId !== void 0) {
2306
+ return await this.queries.findAccountByUserId(identifier.userId);
2307
+ }
2308
+ return null;
2309
+ }
2310
+ // Admin/standalone functions (delegated to auth-functions.js)
2311
+ async createUser(credentials, userId, callback) {
2312
+ return createUser(this.config, credentials, userId, callback);
2313
+ }
2314
+ async deleteUserBy(identifier) {
2315
+ return deleteUserBy(this.config, identifier);
2316
+ }
2317
+ async addRoleForUserBy(identifier, role) {
2318
+ return addRoleForUserBy(this.config, identifier, role);
2319
+ }
2320
+ async removeRoleForUserBy(identifier, role) {
2321
+ return removeRoleForUserBy(this.config, identifier, role);
2322
+ }
2323
+ async hasRoleForUserBy(identifier, role) {
2324
+ return hasRoleForUserBy(this.config, identifier, role);
2325
+ }
2326
+ async changePasswordForUserBy(identifier, password) {
2327
+ return changePasswordForUserBy(this.config, identifier, password);
2328
+ }
2329
+ async setStatusForUserBy(identifier, status) {
2330
+ return setStatusForUserBy(this.config, identifier, status);
2331
+ }
2332
+ async initiatePasswordResetForUserBy(identifier, expiresAfter, callback) {
2333
+ return initiatePasswordResetForUserBy(this.config, identifier, expiresAfter, callback);
2334
+ }
2335
+ async forceLogoutForUserBy(identifier) {
2336
+ const result = await forceLogoutForUserBy(this.config, identifier);
2337
+ if (this.getId() === result.accountId) {
2338
+ this.req.session.auth.shouldForceLogout = true;
2339
+ }
2340
+ }
2341
+ /**
2342
+ * Log in as another user (admin function).
2343
+ * Creates a new session as the target user without requiring their password.
2344
+ *
2345
+ * @param identifier - Find user by accountId, email, or userId
2346
+ * @throws {UserNotFoundError} No account matches the identifier
2347
+ */
2348
+ async loginAsUserBy(identifier) {
2349
+ const account = await this.findAccountByIdentifier(identifier);
2350
+ if (!account) {
2351
+ throw new UserNotFoundError();
2352
+ }
2353
+ await this.onLoginSuccessful(account, false);
2354
+ }
2330
2355
  };
2331
2356
 
2332
2357
  // src/middleware.ts
@@ -2334,9 +2359,7 @@ function createAuthMiddleware(config) {
2334
2359
  return async (req, res, next) => {
2335
2360
  try {
2336
2361
  const authManager = new AuthManager(req, res, config);
2337
- const authAdminManager = new AuthAdminManager(req, res, config, authManager);
2338
2362
  req.auth = authManager;
2339
- req.authAdmin = authAdminManager;
2340
2363
  await authManager.resyncSession();
2341
2364
  await authManager.processRememberDirective();
2342
2365
  next();
@@ -2544,6 +2567,62 @@ async function getAuthTableStats(config) {
2544
2567
  expiredTwoFactorTokens: parseInt(expiredTwoFactorTokensResult.rows[0]?.count || "0")
2545
2568
  };
2546
2569
  }
2570
+
2571
+ // src/auth-context.ts
2572
+ function createAuthContext(config) {
2573
+ return {
2574
+ createUser: (credentials, userId, callback) => createUser(config, credentials, userId, callback),
2575
+ register: (email, password, userId, callback) => register(config, email, password, userId, callback),
2576
+ deleteUserBy: (identifier) => deleteUserBy(config, identifier),
2577
+ addRoleForUserBy: (identifier, role) => addRoleForUserBy(config, identifier, role),
2578
+ removeRoleForUserBy: (identifier, role) => removeRoleForUserBy(config, identifier, role),
2579
+ hasRoleForUserBy: (identifier, role) => hasRoleForUserBy(config, identifier, role),
2580
+ changePasswordForUserBy: (identifier, password) => changePasswordForUserBy(config, identifier, password),
2581
+ setStatusForUserBy: (identifier, status) => setStatusForUserBy(config, identifier, status),
2582
+ initiatePasswordResetForUserBy: (identifier, expiresAfter, callback) => initiatePasswordResetForUserBy(config, identifier, expiresAfter, callback),
2583
+ resetPassword: (email, expiresAfter, maxOpenRequests, callback) => resetPassword(config, email, expiresAfter, maxOpenRequests, callback),
2584
+ confirmResetPassword: (token, password) => confirmResetPassword(config, token, password),
2585
+ forceLogoutForUserBy: (identifier) => forceLogoutForUserBy(config, identifier)
2586
+ };
2587
+ }
2588
+
2589
+ // src/user-roles.ts
2590
+ async function findAccountByIdentifier2(queries, identifier) {
2591
+ let account = null;
2592
+ if (identifier.accountId !== void 0) {
2593
+ account = await queries.findAccountById(identifier.accountId);
2594
+ } else if (identifier.email !== void 0) {
2595
+ account = await queries.findAccountByEmail(identifier.email);
2596
+ } else if (identifier.userId !== void 0) {
2597
+ account = await queries.findAccountByUserId(identifier.userId);
2598
+ }
2599
+ if (!account) {
2600
+ throw new UserNotFoundError();
2601
+ }
2602
+ return account;
2603
+ }
2604
+ async function addRoleToUser(config, identifier, role) {
2605
+ const queries = new AuthQueries(config);
2606
+ const account = await findAccountByIdentifier2(queries, identifier);
2607
+ const rolemask = account.rolemask | role;
2608
+ await queries.updateAccount(account.id, { rolemask });
2609
+ }
2610
+ async function removeRoleFromUser(config, identifier, role) {
2611
+ const queries = new AuthQueries(config);
2612
+ const account = await findAccountByIdentifier2(queries, identifier);
2613
+ const rolemask = account.rolemask & ~role;
2614
+ await queries.updateAccount(account.id, { rolemask });
2615
+ }
2616
+ async function setUserRoles(config, identifier, rolemask) {
2617
+ const queries = new AuthQueries(config);
2618
+ const account = await findAccountByIdentifier2(queries, identifier);
2619
+ await queries.updateAccount(account.id, { rolemask });
2620
+ }
2621
+ async function getUserRoles(config, identifier) {
2622
+ const queries = new AuthQueries(config);
2623
+ const account = await findAccountByIdentifier2(queries, identifier);
2624
+ return account.rolemask;
2625
+ }
2547
2626
  export {
2548
2627
  ActivityLogger,
2549
2628
  AuthActivityAction,
@@ -2579,13 +2658,18 @@ export {
2579
2658
  UserInactiveError,
2580
2659
  UserNotFoundError,
2581
2660
  UserNotLoggedInError,
2661
+ addRoleToUser,
2662
+ auth_functions_exports as authFunctions,
2582
2663
  cleanupExpiredTokens,
2664
+ createAuthContext,
2583
2665
  createAuthMiddleware,
2584
2666
  createAuthTables,
2585
- createUser,
2586
2667
  dropAuthTables,
2587
2668
  getAuthTableStats,
2669
+ getUserRoles,
2588
2670
  isValidEmail,
2671
+ removeRoleFromUser,
2672
+ setUserRoles,
2589
2673
  validateEmail
2590
2674
  };
2591
2675
  //# sourceMappingURL=index.js.map