@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 +562 -525
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +219 -57
- package/dist/index.d.ts +219 -57
- package/dist/index.js +568 -526
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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-
|
|
83
|
-
var
|
|
84
|
-
var
|
|
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
|
-
|
|
939
|
-
|
|
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
|
|
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) =>
|
|
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 (
|
|
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
|
|
1265
|
-
var
|
|
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 =
|
|
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,
|
|
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 =
|
|
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 =
|
|
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 || !
|
|
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 =
|
|
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 =
|
|
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 (!
|
|
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 =
|
|
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 (!
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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,
|