@plyaz/auth 1.0.0 → 1.0.2
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/commits.txt +3 -3
- package/dist/common/index.cjs +3 -1
- package/dist/common/index.cjs.map +1 -1
- package/dist/common/index.mjs +3 -1
- package/dist/common/index.mjs.map +1 -1
- package/dist/index.cjs +424 -154
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +421 -152
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
- package/release_message.txt +28 -0
- package/src/adapters/auth-adapter-factory.ts +4 -3
- package/src/adapters/auth-adapter.mapper.ts +2 -2
- package/src/adapters/base-auth.adapter.ts +17 -9
- package/src/adapters/clerk/clerk.adapter.ts +9 -12
- package/src/adapters/custom/custom.adapter.ts +19 -10
- package/src/adapters/index.ts +0 -1
- package/src/adapters/next-auth/authOptions.ts +20 -16
- package/src/adapters/next-auth/next-auth.adapter.ts +13 -15
- package/src/api/client.ts +4 -6
- package/src/audit/audit.logger.ts +19 -10
- package/src/client/components/ProtectedRoute.tsx +15 -11
- package/src/client/hooks/useAuth.ts +23 -21
- package/src/client/hooks/useConnectedAccounts.ts +57 -45
- package/src/client/hooks/usePermissions.ts +1 -1
- package/src/client/hooks/useRBAC.ts +6 -6
- package/src/client/hooks/useSession.ts +5 -5
- package/src/client/providers/AuthProvider.tsx +23 -17
- package/src/client/store/auth.store.ts +71 -62
- package/src/client/utils/storage.ts +45 -18
- package/src/common/constants/oauth-providers.ts +10 -7
- package/src/common/errors/auth.errors.ts +4 -4
- package/src/common/errors/specific-auth-errors.ts +5 -9
- package/src/common/regex/index.ts +6 -4
- package/src/common/types/auth.types.ts +47 -38
- package/src/common/types/index.ts +12 -6
- package/src/common/utils/index.ts +15 -11
- package/src/core/blacklist/token.blacklist.ts +13 -7
- package/src/core/index.ts +2 -2
- package/src/core/jwt/jwt.manager.ts +47 -22
- package/src/core/session/session.manager.ts +17 -14
- package/src/db/repositories/connected-account.repository.ts +120 -78
- package/src/db/repositories/role.repository.ts +41 -26
- package/src/db/repositories/session.repository.ts +9 -10
- package/src/db/repositories/user.repository.ts +105 -91
- package/src/flows/index.ts +2 -2
- package/src/flows/sign-in.flow.ts +28 -14
- package/src/flows/sign-up.flow.ts +31 -20
- package/src/index.ts +36 -37
- package/src/libs/clerk.helper.ts +6 -7
- package/src/libs/supabase.helper.ts +79 -61
- package/src/libs/supabaseClient.ts +3 -3
- package/src/providers/base/auth-provider.interface.ts +13 -11
- package/src/providers/base/index.ts +1 -1
- package/src/providers/index.ts +1 -1
- package/src/providers/oauth/facebook.provider.ts +63 -39
- package/src/providers/oauth/github.provider.ts +14 -10
- package/src/providers/oauth/google.provider.ts +39 -28
- package/src/providers/oauth/index.ts +1 -1
- package/src/rbac/dynamic-roles.ts +88 -54
- package/src/rbac/index.ts +4 -4
- package/src/rbac/permission-checker.ts +147 -75
- package/src/rbac/role-hierarchy.ts +8 -8
- package/src/rbac/role.manager.ts +11 -8
- package/src/security/csrf/csrf.protection.ts +9 -7
- package/src/security/index.ts +2 -2
- package/src/security/rate-limiting/auth/auth.controller.ts +2 -4
- package/src/security/rate-limiting/auth/rate-limiting.interface.ts +26 -6
- package/src/security/rate-limiting/auth.module.ts +1 -2
- package/src/server/auth.module.ts +55 -52
- package/src/server/decorators/auth.decorator.ts +9 -11
- package/src/server/decorators/auth.decorators.ts +8 -9
- package/src/server/decorators/current-user.decorator.ts +6 -6
- package/src/server/decorators/permission.decorator.ts +17 -9
- package/src/server/guards/auth.guard.ts +21 -16
- package/src/server/guards/custom-throttler.guard.ts +4 -9
- package/src/server/guards/permissions.guard.ts +32 -23
- package/src/server/guards/roles.guard.ts +14 -12
- package/src/server/middleware/auth.middleware.ts +4 -4
- package/src/server/middleware/session.middleware.ts +4 -4
- package/src/server/services/account.service.ts +96 -48
- package/src/server/services/auth.service.ts +57 -28
- package/src/server/services/brute-force.service.ts +24 -19
- package/src/server/services/index.ts +1 -1
- package/src/server/services/rate-limiter.service.ts +9 -4
- package/src/server/services/session.service.ts +84 -48
- package/src/server/services/token.service.ts +71 -51
- package/src/session/cookie-store.ts +47 -34
- package/src/session/enhanced-session-manager.ts +69 -48
- package/src/session/index.ts +5 -5
- package/src/session/memory-store.ts +37 -30
- package/src/session/redis-store.ts +105 -72
- package/src/strategies/oauth.strategy.ts +10 -9
- package/src/strategies/traditional-auth.strategy.ts +41 -29
- package/src/tokens/index.ts +4 -4
- package/src/tokens/refresh-token-manager.ts +70 -55
- package/src/tokens/token-validator.ts +109 -53
- package/vitest.setup.d.ts +2 -2
- package/vitest.setup.ts +1 -1
package/dist/index.mjs
CHANGED
|
@@ -85,7 +85,9 @@ function maskSensitiveData(data, sensitiveFields = ["password", "token", "secret
|
|
|
85
85
|
if (typeof data !== "object" || data === null) {
|
|
86
86
|
return data;
|
|
87
87
|
}
|
|
88
|
-
const masked = {
|
|
88
|
+
const masked = {
|
|
89
|
+
...data
|
|
90
|
+
};
|
|
89
91
|
const four = 4;
|
|
90
92
|
for (const field of sensitiveFields) {
|
|
91
93
|
if (field in masked) {
|
|
@@ -119,15 +121,26 @@ var JwtManager = class {
|
|
|
119
121
|
return sign(payload, this.config.privateKey, signOptions);
|
|
120
122
|
}
|
|
121
123
|
generateTokens(user, accessTokenExpiry = "1h", refreshTokenExpiry = "7d") {
|
|
122
|
-
const accessToken = this.generateToken(
|
|
123
|
-
|
|
124
|
+
const accessToken = this.generateToken(
|
|
125
|
+
{ sub: user.id, type: "access" },
|
|
126
|
+
accessTokenExpiry
|
|
127
|
+
);
|
|
128
|
+
const refreshToken = this.generateToken(
|
|
129
|
+
{ sub: user.id, type: "refresh" },
|
|
130
|
+
refreshTokenExpiry
|
|
131
|
+
);
|
|
124
132
|
let expiresIn;
|
|
125
133
|
if (typeof accessTokenExpiry === "string") {
|
|
126
134
|
const match = accessTokenExpiry.match(/^(\d+)([smhd])$/);
|
|
127
135
|
if (match) {
|
|
128
136
|
const value = globalThis.parseInt(match[1], NUMERIX.TEN);
|
|
129
137
|
const unit = match[2];
|
|
130
|
-
const multipliers = {
|
|
138
|
+
const multipliers = {
|
|
139
|
+
s: 1,
|
|
140
|
+
m: 60,
|
|
141
|
+
h: 3600,
|
|
142
|
+
d: 86400
|
|
143
|
+
};
|
|
131
144
|
expiresIn = value * multipliers[unit];
|
|
132
145
|
} else {
|
|
133
146
|
expiresIn = NUMERIX.THIRTY_SIX_HUNDERD;
|
|
@@ -163,10 +176,13 @@ var JwtManager = class {
|
|
|
163
176
|
issuer: this.config.issuer,
|
|
164
177
|
audience: this.config.audience
|
|
165
178
|
});
|
|
166
|
-
if (typeof decoded === "string")
|
|
179
|
+
if (typeof decoded === "string")
|
|
180
|
+
throw new Error(`Invalid ${tokenType} token payload`);
|
|
167
181
|
const payload = decoded;
|
|
168
182
|
if (payload.type !== tokenType) {
|
|
169
|
-
throw new Error(
|
|
183
|
+
throw new Error(
|
|
184
|
+
`Invalid token type. Expected ${tokenType}, got ${payload.type}`
|
|
185
|
+
);
|
|
170
186
|
}
|
|
171
187
|
return payload;
|
|
172
188
|
}
|
|
@@ -318,17 +334,44 @@ var PermissionChecker = class {
|
|
|
318
334
|
}
|
|
319
335
|
}
|
|
320
336
|
const userPermissions = await this.getUserPermissions(userId);
|
|
321
|
-
const directResult = this.checkDirectPermission(
|
|
337
|
+
const directResult = this.checkDirectPermission(
|
|
338
|
+
userPermissions,
|
|
339
|
+
resource,
|
|
340
|
+
action,
|
|
341
|
+
context
|
|
342
|
+
);
|
|
322
343
|
if (directResult.granted) {
|
|
323
|
-
return this.cacheAndReturn(
|
|
344
|
+
return this.cacheAndReturn(
|
|
345
|
+
userId,
|
|
346
|
+
resource,
|
|
347
|
+
action,
|
|
348
|
+
context,
|
|
349
|
+
directResult
|
|
350
|
+
);
|
|
324
351
|
}
|
|
325
|
-
const roleResult = await this.checkRoleBasedPermission(
|
|
352
|
+
const roleResult = await this.checkRoleBasedPermission(
|
|
353
|
+
userId,
|
|
354
|
+
resource,
|
|
355
|
+
action,
|
|
356
|
+
context
|
|
357
|
+
);
|
|
326
358
|
if (roleResult.granted) {
|
|
327
359
|
return this.cacheAndReturn(userId, resource, action, context, roleResult);
|
|
328
360
|
}
|
|
329
|
-
const wildcardResult = this.checkWildcardPermission(
|
|
361
|
+
const wildcardResult = this.checkWildcardPermission(
|
|
362
|
+
userPermissions,
|
|
363
|
+
resource,
|
|
364
|
+
action,
|
|
365
|
+
context
|
|
366
|
+
);
|
|
330
367
|
if (wildcardResult.granted) {
|
|
331
|
-
return this.cacheAndReturn(
|
|
368
|
+
return this.cacheAndReturn(
|
|
369
|
+
userId,
|
|
370
|
+
resource,
|
|
371
|
+
action,
|
|
372
|
+
context,
|
|
373
|
+
wildcardResult
|
|
374
|
+
);
|
|
332
375
|
}
|
|
333
376
|
const deniedResult = {
|
|
334
377
|
granted: false,
|
|
@@ -432,7 +475,10 @@ var PermissionChecker = class {
|
|
|
432
475
|
for (const permission of permissions) {
|
|
433
476
|
if (permission.resource === resource && permission.action === action) {
|
|
434
477
|
if (permission.conditions && Object.keys(permission.conditions).length > 0) {
|
|
435
|
-
const conditionsMet = this.evaluateConditions(
|
|
478
|
+
const conditionsMet = this.evaluateConditions(
|
|
479
|
+
permission.conditions,
|
|
480
|
+
context
|
|
481
|
+
);
|
|
436
482
|
if (conditionsMet) {
|
|
437
483
|
return {
|
|
438
484
|
granted: true,
|
|
@@ -471,7 +517,12 @@ var PermissionChecker = class {
|
|
|
471
517
|
const userRoles = await this.getUserRoles(userId);
|
|
472
518
|
for (const role of userRoles) {
|
|
473
519
|
const rolePermissions = await this.getRolePermissions(role.id);
|
|
474
|
-
const result = this.checkDirectPermission(
|
|
520
|
+
const result = this.checkDirectPermission(
|
|
521
|
+
rolePermissions,
|
|
522
|
+
resource,
|
|
523
|
+
action,
|
|
524
|
+
context
|
|
525
|
+
);
|
|
475
526
|
if (result.granted) {
|
|
476
527
|
return {
|
|
477
528
|
...result,
|
|
@@ -499,7 +550,10 @@ var PermissionChecker = class {
|
|
|
499
550
|
const actionMatch = permission.action === "*" || permission.action === action;
|
|
500
551
|
if (resourceMatch && actionMatch) {
|
|
501
552
|
if (permission.conditions && Object.keys(permission.conditions).length > 0) {
|
|
502
|
-
const conditionsMet = this.evaluateConditions(
|
|
553
|
+
const conditionsMet = this.evaluateConditions(
|
|
554
|
+
permission.conditions,
|
|
555
|
+
context
|
|
556
|
+
);
|
|
503
557
|
if (conditionsMet) {
|
|
504
558
|
return {
|
|
505
559
|
granted: true,
|
|
@@ -1256,7 +1310,11 @@ var DynamicRoles = class {
|
|
|
1256
1310
|
for (const [conditionType, conditionValue] of Object.entries(conditions)) {
|
|
1257
1311
|
const evaluator = this.conditionEvaluators.get(conditionType);
|
|
1258
1312
|
if (evaluator) {
|
|
1259
|
-
const result = await evaluator(
|
|
1313
|
+
const result = await evaluator(
|
|
1314
|
+
userId,
|
|
1315
|
+
{ [conditionType]: conditionValue },
|
|
1316
|
+
context
|
|
1317
|
+
);
|
|
1260
1318
|
if (!result) {
|
|
1261
1319
|
return false;
|
|
1262
1320
|
}
|
|
@@ -1276,7 +1334,9 @@ var DynamicRoles = class {
|
|
|
1276
1334
|
async enforceAssignmentLimits(userId) {
|
|
1277
1335
|
const userAssignments = this.getUserAssignments(userId, false);
|
|
1278
1336
|
if (userAssignments.length >= this.config.maxAssignmentsPerUser) {
|
|
1279
|
-
throw new Error(
|
|
1337
|
+
throw new Error(
|
|
1338
|
+
`Maximum assignments per user exceeded: ${this.config.maxAssignmentsPerUser}`
|
|
1339
|
+
);
|
|
1280
1340
|
}
|
|
1281
1341
|
}
|
|
1282
1342
|
/**
|
|
@@ -1292,9 +1352,12 @@ var DynamicRoles = class {
|
|
|
1292
1352
|
* @private
|
|
1293
1353
|
*/
|
|
1294
1354
|
startCleanupTimer() {
|
|
1295
|
-
this.cleanupTimer = globalThis.setInterval(
|
|
1296
|
-
|
|
1297
|
-
|
|
1355
|
+
this.cleanupTimer = globalThis.setInterval(
|
|
1356
|
+
async () => {
|
|
1357
|
+
await this.cleanupExpiredAssignments();
|
|
1358
|
+
},
|
|
1359
|
+
NUMERIX.FIVE * NUMERIX.SIXTY * NUMERIX.THOUSAND
|
|
1360
|
+
);
|
|
1298
1361
|
}
|
|
1299
1362
|
/**
|
|
1300
1363
|
* Emit role assigned event
|
|
@@ -1392,10 +1455,17 @@ var AuthService = class {
|
|
|
1392
1455
|
}
|
|
1393
1456
|
async signIn(email, password, deviceInfo) {
|
|
1394
1457
|
const user = await this.traditionalAuth.authenticate(email, password);
|
|
1395
|
-
const session = await this.sessionManager.createSession(
|
|
1458
|
+
const session = await this.sessionManager.createSession(
|
|
1459
|
+
user.id,
|
|
1460
|
+
deviceInfo
|
|
1461
|
+
);
|
|
1396
1462
|
const tokens = this.jwtManager.generateTokens(user);
|
|
1397
1463
|
await this.userRepo.updateLastLogin(user.id);
|
|
1398
|
-
return {
|
|
1464
|
+
return {
|
|
1465
|
+
user,
|
|
1466
|
+
tokens: { ...tokens, refreshToken: tokens.refreshToken ?? "" },
|
|
1467
|
+
session
|
|
1468
|
+
};
|
|
1399
1469
|
}
|
|
1400
1470
|
async signUp(userData, password) {
|
|
1401
1471
|
const passwordHash = await this.traditionalAuth.hashPassword(password);
|
|
@@ -1427,11 +1497,22 @@ var AuthService = class {
|
|
|
1427
1497
|
return this.userRepo.findById(userId);
|
|
1428
1498
|
}
|
|
1429
1499
|
async oauthSignIn(profile, accessToken, refreshToken, deviceInfo) {
|
|
1430
|
-
const user = await this.oauthAuth.authenticate(
|
|
1431
|
-
|
|
1500
|
+
const user = await this.oauthAuth.authenticate(
|
|
1501
|
+
profile,
|
|
1502
|
+
accessToken,
|
|
1503
|
+
refreshToken
|
|
1504
|
+
);
|
|
1505
|
+
const session = await this.sessionManager.createSession(
|
|
1506
|
+
user.id,
|
|
1507
|
+
deviceInfo ?? {}
|
|
1508
|
+
);
|
|
1432
1509
|
const tokens = this.jwtManager.generateTokens(user);
|
|
1433
1510
|
await this.userRepo.updateLastLogin(user.id);
|
|
1434
|
-
return {
|
|
1511
|
+
return {
|
|
1512
|
+
user,
|
|
1513
|
+
tokens: { ...tokens, refreshToken: tokens.refreshToken ?? "" },
|
|
1514
|
+
session
|
|
1515
|
+
};
|
|
1435
1516
|
}
|
|
1436
1517
|
};
|
|
1437
1518
|
_init3 = __decoratorStart();
|
|
@@ -1456,8 +1537,13 @@ var _SessionService = class _SessionService {
|
|
|
1456
1537
|
async createSession(userContext, sessionData = {}) {
|
|
1457
1538
|
this.logger.debug(`Creating session for user: ${userContext.userId}`);
|
|
1458
1539
|
try {
|
|
1459
|
-
const session = await this.sessionManager.createSession(
|
|
1460
|
-
|
|
1540
|
+
const session = await this.sessionManager.createSession(
|
|
1541
|
+
userContext,
|
|
1542
|
+
sessionData
|
|
1543
|
+
);
|
|
1544
|
+
this.logger.log(
|
|
1545
|
+
`Session created: ${session.id} for user: ${userContext.userId}`
|
|
1546
|
+
);
|
|
1461
1547
|
this.emitEvent(AUTH_EVENTS.SESSION_CREATED, {
|
|
1462
1548
|
userId: userContext.userId,
|
|
1463
1549
|
sessionId: session.id,
|
|
@@ -1465,7 +1551,10 @@ var _SessionService = class _SessionService {
|
|
|
1465
1551
|
});
|
|
1466
1552
|
return session;
|
|
1467
1553
|
} catch (error) {
|
|
1468
|
-
this.logger.error(
|
|
1554
|
+
this.logger.error(
|
|
1555
|
+
`Failed to create session for user: ${userContext.userId}`,
|
|
1556
|
+
error
|
|
1557
|
+
);
|
|
1469
1558
|
throw error;
|
|
1470
1559
|
}
|
|
1471
1560
|
}
|
|
@@ -1569,7 +1658,10 @@ var _SessionService = class _SessionService {
|
|
|
1569
1658
|
timestamp: /* @__PURE__ */ new Date()
|
|
1570
1659
|
});
|
|
1571
1660
|
} catch (error) {
|
|
1572
|
-
this.logger.error(
|
|
1661
|
+
this.logger.error(
|
|
1662
|
+
`Failed to invalidate all sessions for user: ${userId}`,
|
|
1663
|
+
error
|
|
1664
|
+
);
|
|
1573
1665
|
throw error;
|
|
1574
1666
|
}
|
|
1575
1667
|
}
|
|
@@ -1583,7 +1675,10 @@ var _SessionService = class _SessionService {
|
|
|
1583
1675
|
try {
|
|
1584
1676
|
return await this.sessionManager.detectConcurrentSessions(userId);
|
|
1585
1677
|
} catch (error) {
|
|
1586
|
-
this.logger.error(
|
|
1678
|
+
this.logger.error(
|
|
1679
|
+
`Failed to detect concurrent sessions for user: ${userId}`,
|
|
1680
|
+
error
|
|
1681
|
+
);
|
|
1587
1682
|
throw error;
|
|
1588
1683
|
}
|
|
1589
1684
|
}
|
|
@@ -1597,7 +1692,10 @@ var _SessionService = class _SessionService {
|
|
|
1597
1692
|
try {
|
|
1598
1693
|
return await this.sessionManager.generateCsrfToken(sessionId);
|
|
1599
1694
|
} catch (error) {
|
|
1600
|
-
this.logger.error(
|
|
1695
|
+
this.logger.error(
|
|
1696
|
+
`Failed to generate CSRF token for session: ${sessionId}`,
|
|
1697
|
+
error
|
|
1698
|
+
);
|
|
1601
1699
|
throw error;
|
|
1602
1700
|
}
|
|
1603
1701
|
}
|
|
@@ -1610,13 +1708,19 @@ var _SessionService = class _SessionService {
|
|
|
1610
1708
|
async validateCsrfToken(sessionId, token) {
|
|
1611
1709
|
this.logger.debug(`Validating CSRF token for session: ${sessionId}`);
|
|
1612
1710
|
try {
|
|
1613
|
-
const isValid = await this.sessionManager.validateCsrfToken(
|
|
1711
|
+
const isValid = await this.sessionManager.validateCsrfToken(
|
|
1712
|
+
sessionId,
|
|
1713
|
+
token
|
|
1714
|
+
);
|
|
1614
1715
|
if (!isValid) {
|
|
1615
1716
|
this.logger.warn(`Invalid CSRF token for session: ${sessionId}`);
|
|
1616
1717
|
}
|
|
1617
1718
|
return isValid;
|
|
1618
1719
|
} catch (error) {
|
|
1619
|
-
this.logger.error(
|
|
1720
|
+
this.logger.error(
|
|
1721
|
+
`Failed to validate CSRF token for session: ${sessionId}`,
|
|
1722
|
+
error
|
|
1723
|
+
);
|
|
1620
1724
|
return false;
|
|
1621
1725
|
}
|
|
1622
1726
|
}
|
|
@@ -1629,7 +1733,10 @@ var _SessionService = class _SessionService {
|
|
|
1629
1733
|
try {
|
|
1630
1734
|
return await this.sessionManager.shouldRefreshSession(sessionId);
|
|
1631
1735
|
} catch (error) {
|
|
1632
|
-
this.logger.error(
|
|
1736
|
+
this.logger.error(
|
|
1737
|
+
`Failed to check if session needs refresh: ${sessionId}`,
|
|
1738
|
+
error
|
|
1739
|
+
);
|
|
1633
1740
|
return false;
|
|
1634
1741
|
}
|
|
1635
1742
|
}
|
|
@@ -1681,7 +1788,9 @@ var _TokenService = class _TokenService {
|
|
|
1681
1788
|
try {
|
|
1682
1789
|
const result = await this.tokenValidator.validateAccessToken(token);
|
|
1683
1790
|
if (!result.valid) {
|
|
1684
|
-
this.logger.warn(
|
|
1791
|
+
this.logger.warn(
|
|
1792
|
+
`Access token validation failed: ${result.error?.message}`
|
|
1793
|
+
);
|
|
1685
1794
|
}
|
|
1686
1795
|
return result;
|
|
1687
1796
|
} catch (error) {
|
|
@@ -1705,7 +1814,9 @@ var _TokenService = class _TokenService {
|
|
|
1705
1814
|
try {
|
|
1706
1815
|
const result = await this.tokenValidator.validateRefreshToken(token);
|
|
1707
1816
|
if (!result.valid) {
|
|
1708
|
-
this.logger.warn(
|
|
1817
|
+
this.logger.warn(
|
|
1818
|
+
`Refresh token validation failed: ${result.error?.message}`
|
|
1819
|
+
);
|
|
1709
1820
|
}
|
|
1710
1821
|
return result;
|
|
1711
1822
|
} catch (error) {
|
|
@@ -1739,7 +1850,10 @@ var _TokenService = class _TokenService {
|
|
|
1739
1850
|
this.logger.log(`Token pair generated for user: ${userId}`);
|
|
1740
1851
|
return tokenPair;
|
|
1741
1852
|
} catch (error) {
|
|
1742
|
-
this.logger.error(
|
|
1853
|
+
this.logger.error(
|
|
1854
|
+
`Failed to generate token pair for user: ${userId}`,
|
|
1855
|
+
error
|
|
1856
|
+
);
|
|
1743
1857
|
throw error;
|
|
1744
1858
|
}
|
|
1745
1859
|
}
|
|
@@ -1789,7 +1903,10 @@ var _TokenService = class _TokenService {
|
|
|
1789
1903
|
await this.refreshTokenManager.revokeAllUserTokens(userId);
|
|
1790
1904
|
this.logger.log(`All tokens revoked for user: ${userId}`);
|
|
1791
1905
|
} catch (error) {
|
|
1792
|
-
this.logger.error(
|
|
1906
|
+
this.logger.error(
|
|
1907
|
+
`Failed to revoke all tokens for user: ${userId}`,
|
|
1908
|
+
error
|
|
1909
|
+
);
|
|
1793
1910
|
throw error;
|
|
1794
1911
|
}
|
|
1795
1912
|
}
|
|
@@ -1803,7 +1920,10 @@ var _TokenService = class _TokenService {
|
|
|
1803
1920
|
await this.refreshTokenManager.revokeSessionTokens(sessionId);
|
|
1804
1921
|
this.logger.log(`Tokens revoked for session: ${sessionId}`);
|
|
1805
1922
|
} catch (error) {
|
|
1806
|
-
this.logger.error(
|
|
1923
|
+
this.logger.error(
|
|
1924
|
+
`Failed to revoke tokens for session: ${sessionId}`,
|
|
1925
|
+
error
|
|
1926
|
+
);
|
|
1807
1927
|
throw error;
|
|
1808
1928
|
}
|
|
1809
1929
|
}
|
|
@@ -1899,7 +2019,10 @@ var _AccountService = class _AccountService {
|
|
|
1899
2019
|
});
|
|
1900
2020
|
return connectedAccount;
|
|
1901
2021
|
} catch (error) {
|
|
1902
|
-
this.logger.error(
|
|
2022
|
+
this.logger.error(
|
|
2023
|
+
`Failed to link ${provider} account for user: ${userId}`,
|
|
2024
|
+
error
|
|
2025
|
+
);
|
|
1903
2026
|
throw error;
|
|
1904
2027
|
}
|
|
1905
2028
|
}
|
|
@@ -1927,7 +2050,10 @@ var _AccountService = class _AccountService {
|
|
|
1927
2050
|
timestamp: /* @__PURE__ */ new Date()
|
|
1928
2051
|
});
|
|
1929
2052
|
} catch (error) {
|
|
1930
|
-
this.logger.error(
|
|
2053
|
+
this.logger.error(
|
|
2054
|
+
`Failed to unlink account ${accountId} for user: ${userId}`,
|
|
2055
|
+
error
|
|
2056
|
+
);
|
|
1931
2057
|
throw error;
|
|
1932
2058
|
}
|
|
1933
2059
|
}
|
|
@@ -1951,16 +2077,23 @@ var _AccountService = class _AccountService {
|
|
|
1951
2077
|
* @param accountId - Account identifier to set as primary
|
|
1952
2078
|
*/
|
|
1953
2079
|
async setPrimary(userId, accountId) {
|
|
1954
|
-
this.logger.debug(
|
|
2080
|
+
this.logger.debug(
|
|
2081
|
+
`Setting primary account ${accountId} for user: ${userId}`
|
|
2082
|
+
);
|
|
1955
2083
|
try {
|
|
1956
2084
|
const account = await this.accountRepository.findById(accountId);
|
|
1957
2085
|
if (account?.userId !== userId) {
|
|
1958
2086
|
throw new Error("Account not found or does not belong to user");
|
|
1959
2087
|
}
|
|
1960
2088
|
await this.accountRepository.setPrimary(userId, accountId);
|
|
1961
|
-
this.logger.log(
|
|
2089
|
+
this.logger.log(
|
|
2090
|
+
`Primary account set to ${accountId} for user: ${userId}`
|
|
2091
|
+
);
|
|
1962
2092
|
} catch (error) {
|
|
1963
|
-
this.logger.error(
|
|
2093
|
+
this.logger.error(
|
|
2094
|
+
`Failed to set primary account ${accountId} for user: ${userId}`,
|
|
2095
|
+
error
|
|
2096
|
+
);
|
|
1964
2097
|
throw error;
|
|
1965
2098
|
}
|
|
1966
2099
|
}
|
|
@@ -1974,7 +2107,10 @@ var _AccountService = class _AccountService {
|
|
|
1974
2107
|
try {
|
|
1975
2108
|
return await this.accountRepository.findPrimary(userId);
|
|
1976
2109
|
} catch (error) {
|
|
1977
|
-
this.logger.error(
|
|
2110
|
+
this.logger.error(
|
|
2111
|
+
`Failed to get primary account for user: ${userId}`,
|
|
2112
|
+
error
|
|
2113
|
+
);
|
|
1978
2114
|
throw error;
|
|
1979
2115
|
}
|
|
1980
2116
|
}
|
|
@@ -1985,11 +2121,19 @@ var _AccountService = class _AccountService {
|
|
|
1985
2121
|
* @returns Connected account or null
|
|
1986
2122
|
*/
|
|
1987
2123
|
async findByProvider(provider, providerAccountId) {
|
|
1988
|
-
this.logger.debug(
|
|
2124
|
+
this.logger.debug(
|
|
2125
|
+
`Finding account by provider: ${provider}, ID: ${providerAccountId}`
|
|
2126
|
+
);
|
|
1989
2127
|
try {
|
|
1990
|
-
return await this.accountRepository.findByProvider(
|
|
2128
|
+
return await this.accountRepository.findByProvider(
|
|
2129
|
+
provider,
|
|
2130
|
+
providerAccountId
|
|
2131
|
+
);
|
|
1991
2132
|
} catch (error) {
|
|
1992
|
-
this.logger.error(
|
|
2133
|
+
this.logger.error(
|
|
2134
|
+
`Failed to find account by provider: ${provider}`,
|
|
2135
|
+
error
|
|
2136
|
+
);
|
|
1993
2137
|
throw error;
|
|
1994
2138
|
}
|
|
1995
2139
|
}
|
|
@@ -2002,10 +2146,17 @@ var _AccountService = class _AccountService {
|
|
|
2002
2146
|
async updateTokens(accountId, accessToken, refreshToken) {
|
|
2003
2147
|
this.logger.debug(`Updating tokens for account: ${accountId}`);
|
|
2004
2148
|
try {
|
|
2005
|
-
await this.accountRepository.updateTokens(
|
|
2149
|
+
await this.accountRepository.updateTokens(
|
|
2150
|
+
accountId,
|
|
2151
|
+
accessToken,
|
|
2152
|
+
refreshToken
|
|
2153
|
+
);
|
|
2006
2154
|
this.logger.log(`Tokens updated for account: ${accountId}`);
|
|
2007
2155
|
} catch (error) {
|
|
2008
|
-
this.logger.error(
|
|
2156
|
+
this.logger.error(
|
|
2157
|
+
`Failed to update tokens for account: ${accountId}`,
|
|
2158
|
+
error
|
|
2159
|
+
);
|
|
2009
2160
|
throw error;
|
|
2010
2161
|
}
|
|
2011
2162
|
}
|
|
@@ -2033,9 +2184,14 @@ var _AccountService = class _AccountService {
|
|
|
2033
2184
|
this.logger.debug(`Checking if user ${userId} has ${provider} account`);
|
|
2034
2185
|
try {
|
|
2035
2186
|
const accounts = await this.accountRepository.findByUserId(userId);
|
|
2036
|
-
return accounts.some(
|
|
2187
|
+
return accounts.some(
|
|
2188
|
+
(account) => account.provider === provider && account.isActive
|
|
2189
|
+
);
|
|
2037
2190
|
} catch (error) {
|
|
2038
|
-
this.logger.error(
|
|
2191
|
+
this.logger.error(
|
|
2192
|
+
`Failed to check provider account for user: ${userId}`,
|
|
2193
|
+
error
|
|
2194
|
+
);
|
|
2039
2195
|
return false;
|
|
2040
2196
|
}
|
|
2041
2197
|
}
|
|
@@ -2050,7 +2206,10 @@ var _AccountService = class _AccountService {
|
|
|
2050
2206
|
const accounts = await this.accountRepository.findByUserId(userId);
|
|
2051
2207
|
return accounts.filter((account) => account.isActive).length;
|
|
2052
2208
|
} catch (error) {
|
|
2053
|
-
this.logger.error(
|
|
2209
|
+
this.logger.error(
|
|
2210
|
+
`Failed to get account count for user: ${userId}`,
|
|
2211
|
+
error
|
|
2212
|
+
);
|
|
2054
2213
|
return 0;
|
|
2055
2214
|
}
|
|
2056
2215
|
}
|
|
@@ -2087,7 +2246,10 @@ var _BruteForceService = class _BruteForceService {
|
|
|
2087
2246
|
}
|
|
2088
2247
|
static {
|
|
2089
2248
|
// 30 min
|
|
2090
|
-
this.USER_PROGRESSIVE_DELAYS = {
|
|
2249
|
+
this.USER_PROGRESSIVE_DELAYS = {
|
|
2250
|
+
4: 5e3,
|
|
2251
|
+
5: 5e3
|
|
2252
|
+
};
|
|
2091
2253
|
}
|
|
2092
2254
|
static {
|
|
2093
2255
|
this.IP_HARD_LIMIT = 10;
|
|
@@ -2188,7 +2350,12 @@ var RateLimiterService = class {
|
|
|
2188
2350
|
}
|
|
2189
2351
|
if (requests > options.limit && options.blockMs) {
|
|
2190
2352
|
const blockUntil = Date.now() + options.blockMs;
|
|
2191
|
-
await this.redis.set(
|
|
2353
|
+
await this.redis.set(
|
|
2354
|
+
blockKey,
|
|
2355
|
+
blockUntil.toString(),
|
|
2356
|
+
"PX",
|
|
2357
|
+
options.blockMs
|
|
2358
|
+
);
|
|
2192
2359
|
await this.redis.del(rateKey);
|
|
2193
2360
|
return true;
|
|
2194
2361
|
}
|
|
@@ -2472,7 +2639,9 @@ var CookieStore = class {
|
|
|
2472
2639
|
*/
|
|
2473
2640
|
setCookie(sessionId, data, ttlSeconds) {
|
|
2474
2641
|
const encryptedData = this.encrypt(JSON.stringify(data));
|
|
2475
|
-
globalThis.console.log(
|
|
2642
|
+
globalThis.console.log(
|
|
2643
|
+
`Setting cookie: ${this.config.cookieName}=${encryptedData}; Max-Age=${ttlSeconds}`
|
|
2644
|
+
);
|
|
2476
2645
|
}
|
|
2477
2646
|
/**
|
|
2478
2647
|
* Clear HTTP cookie (mock implementation)
|
|
@@ -2678,7 +2847,9 @@ var MemoryStore = class {
|
|
|
2678
2847
|
async enforceSessionLimits(userId) {
|
|
2679
2848
|
const userSessions = await this.getByUserId(userId);
|
|
2680
2849
|
if (userSessions.length >= this.config.maxSessionsPerUser) {
|
|
2681
|
-
userSessions.sort(
|
|
2850
|
+
userSessions.sort(
|
|
2851
|
+
(a, b) => a.lastActivityAt.getTime() - b.lastActivityAt.getTime()
|
|
2852
|
+
);
|
|
2682
2853
|
const sessionsToRemove = userSessions.length - this.config.maxSessionsPerUser + 1;
|
|
2683
2854
|
for (let i = 0; i < sessionsToRemove; i++) {
|
|
2684
2855
|
await this.delete(userSessions[i].id);
|
|
@@ -2735,7 +2906,11 @@ var RedisStore = class {
|
|
|
2735
2906
|
const serializedData = this.serialize(data);
|
|
2736
2907
|
await this.client.set(key, serializedData, ttlSeconds);
|
|
2737
2908
|
const userSessionsTTL = Math.max(ttlSeconds, this.config.defaultTTL);
|
|
2738
|
-
await this.client.set(
|
|
2909
|
+
await this.client.set(
|
|
2910
|
+
`${userSessionsKey}${sessionId}`,
|
|
2911
|
+
"1",
|
|
2912
|
+
userSessionsTTL
|
|
2913
|
+
);
|
|
2739
2914
|
}
|
|
2740
2915
|
/**
|
|
2741
2916
|
* Retrieve session data from Redis
|
|
@@ -2784,7 +2959,10 @@ var RedisStore = class {
|
|
|
2784
2959
|
const userSessionKeys = await this.client.keys(userSessionsPattern);
|
|
2785
2960
|
let deletedCount = 0;
|
|
2786
2961
|
for (const userSessionKey of userSessionKeys) {
|
|
2787
|
-
const sessionId = userSessionKey.replace(
|
|
2962
|
+
const sessionId = userSessionKey.replace(
|
|
2963
|
+
this.getUserSessionsKey(userId),
|
|
2964
|
+
""
|
|
2965
|
+
);
|
|
2788
2966
|
const sessionKey = this.getSessionKey(sessionId);
|
|
2789
2967
|
const sessionDeleted = await this.client.del(sessionKey);
|
|
2790
2968
|
await this.client.del(userSessionKey);
|
|
@@ -2802,7 +2980,10 @@ var RedisStore = class {
|
|
|
2802
2980
|
const data = await this.get(sessionId);
|
|
2803
2981
|
if (data) {
|
|
2804
2982
|
data.lastActivityAt = /* @__PURE__ */ new Date();
|
|
2805
|
-
const remainingTTL = Math.max(
|
|
2983
|
+
const remainingTTL = Math.max(
|
|
2984
|
+
0,
|
|
2985
|
+
Math.floor((data.expiresAt.getTime() - Date.now()) / NUMERIX.THOUSAND)
|
|
2986
|
+
);
|
|
2806
2987
|
if (remainingTTL > 0) {
|
|
2807
2988
|
await this.set(sessionId, data, remainingTTL);
|
|
2808
2989
|
}
|
|
@@ -2828,7 +3009,10 @@ var RedisStore = class {
|
|
|
2828
3009
|
const userSessionKeys = await this.client.keys(userSessionsPattern);
|
|
2829
3010
|
const sessions = [];
|
|
2830
3011
|
for (const userSessionKey of userSessionKeys) {
|
|
2831
|
-
const sessionId = userSessionKey.replace(
|
|
3012
|
+
const sessionId = userSessionKey.replace(
|
|
3013
|
+
this.getUserSessionsKey(userId),
|
|
3014
|
+
""
|
|
3015
|
+
);
|
|
2832
3016
|
const sessionData = await this.get(sessionId);
|
|
2833
3017
|
if (sessionData) {
|
|
2834
3018
|
sessions.push(sessionData);
|
|
@@ -2923,7 +3107,9 @@ var RedisStore = class {
|
|
|
2923
3107
|
async enforceSessionLimits(userId) {
|
|
2924
3108
|
const userSessions = await this.getByUserId(userId);
|
|
2925
3109
|
if (userSessions.length >= this.config.maxSessionsPerUser) {
|
|
2926
|
-
userSessions.sort(
|
|
3110
|
+
userSessions.sort(
|
|
3111
|
+
(a, b) => a.lastActivityAt.getTime() - b.lastActivityAt.getTime()
|
|
3112
|
+
);
|
|
2927
3113
|
const sessionsToRemove = userSessions.length - this.config.maxSessionsPerUser + 1;
|
|
2928
3114
|
for (let i = 0; i < sessionsToRemove; i++) {
|
|
2929
3115
|
await this.delete(userSessions[i].id);
|
|
@@ -3015,7 +3201,9 @@ var EnhancedSessionManager = class {
|
|
|
3015
3201
|
const sessionId = this.generateSessionId();
|
|
3016
3202
|
await this.enforceSessionLimits(userContext.userId);
|
|
3017
3203
|
const now = /* @__PURE__ */ new Date();
|
|
3018
|
-
const expiresAt = new Date(
|
|
3204
|
+
const expiresAt = new Date(
|
|
3205
|
+
now.getTime() + this.config.sessionTTL * NUMERIX.THOUSAND
|
|
3206
|
+
);
|
|
3019
3207
|
const session = {
|
|
3020
3208
|
id: sessionId,
|
|
3021
3209
|
userId: userContext.userId,
|
|
@@ -3080,7 +3268,12 @@ var EnhancedSessionManager = class {
|
|
|
3080
3268
|
...updates,
|
|
3081
3269
|
lastActivityAt: /* @__PURE__ */ new Date()
|
|
3082
3270
|
};
|
|
3083
|
-
const remainingTTL = Math.max(
|
|
3271
|
+
const remainingTTL = Math.max(
|
|
3272
|
+
0,
|
|
3273
|
+
Math.floor(
|
|
3274
|
+
(updatedSession.expiresAt.getTime() - Date.now()) / NUMERIX.THOUSAND
|
|
3275
|
+
)
|
|
3276
|
+
);
|
|
3084
3277
|
if (remainingTTL <= 0) {
|
|
3085
3278
|
throw new Error("Session has expired");
|
|
3086
3279
|
}
|
|
@@ -3108,7 +3301,9 @@ var EnhancedSessionManager = class {
|
|
|
3108
3301
|
throw new Error("Session not found");
|
|
3109
3302
|
}
|
|
3110
3303
|
const now = /* @__PURE__ */ new Date();
|
|
3111
|
-
const newExpiresAt = new Date(
|
|
3304
|
+
const newExpiresAt = new Date(
|
|
3305
|
+
now.getTime() + this.config.sessionTTL * NUMERIX.THOUSAND
|
|
3306
|
+
);
|
|
3112
3307
|
const refreshedSession = {
|
|
3113
3308
|
...sessionData,
|
|
3114
3309
|
expiresAt: newExpiresAt,
|
|
@@ -3148,7 +3343,9 @@ var EnhancedSessionManager = class {
|
|
|
3148
3343
|
*/
|
|
3149
3344
|
async detectConcurrentSessions(userId) {
|
|
3150
3345
|
const sessionDataArray = await this.store.getByUserId(userId);
|
|
3151
|
-
return sessionDataArray.map(
|
|
3346
|
+
return sessionDataArray.map(
|
|
3347
|
+
(sessionData) => this.mapSessionDataToSession(sessionData)
|
|
3348
|
+
);
|
|
3152
3349
|
}
|
|
3153
3350
|
/**
|
|
3154
3351
|
* Apply maximum session policy for a user
|
|
@@ -3157,7 +3354,9 @@ var EnhancedSessionManager = class {
|
|
|
3157
3354
|
async enforceSessionLimits(userId) {
|
|
3158
3355
|
const userSessions = await this.store.getByUserId(userId);
|
|
3159
3356
|
if (userSessions.length >= this.config.maxConcurrentSessions) {
|
|
3160
|
-
userSessions.sort(
|
|
3357
|
+
userSessions.sort(
|
|
3358
|
+
(a, b) => a.lastActivityAt.getTime() - b.lastActivityAt.getTime()
|
|
3359
|
+
);
|
|
3161
3360
|
const sessionsToRemove = userSessions.length - this.config.maxConcurrentSessions + 1;
|
|
3162
3361
|
for (let i = 0; i < sessionsToRemove; i++) {
|
|
3163
3362
|
await this.deleteSession(userSessions[i].id);
|
|
@@ -3272,7 +3471,8 @@ async function createUser(email, authProvider, data, password) {
|
|
|
3272
3471
|
roles: data?.roles ?? [],
|
|
3273
3472
|
password_hash: passwordHash
|
|
3274
3473
|
}).select("*").single();
|
|
3275
|
-
if (error || !user)
|
|
3474
|
+
if (error || !user)
|
|
3475
|
+
throw new Error(error?.message ?? "Failed to create user");
|
|
3276
3476
|
return user;
|
|
3277
3477
|
}
|
|
3278
3478
|
__name(createUser, "createUser");
|
|
@@ -3290,7 +3490,9 @@ async function createUserSession(userId, deviceInfo) {
|
|
|
3290
3490
|
const thirtyTwo = 32;
|
|
3291
3491
|
const accessToken = randomBytes(thirtyTwo).toString("hex");
|
|
3292
3492
|
const tokenHash = await bcrypt.hash(accessToken, NUMERIX.TEN);
|
|
3293
|
-
const expiresAt = new Date(
|
|
3493
|
+
const expiresAt = new Date(
|
|
3494
|
+
Date.now() + NUMERIX.THOUSAND * NUMERIX.SIXTY * NUMERIX.SIXTY * NUMERIX.TWENTY_FOUR
|
|
3495
|
+
);
|
|
3294
3496
|
const { data, error } = await supabase.from("sessions").insert({
|
|
3295
3497
|
user_id: userId,
|
|
3296
3498
|
token_hash: tokenHash,
|
|
@@ -3298,7 +3500,8 @@ async function createUserSession(userId, deviceInfo) {
|
|
|
3298
3500
|
expires_at: expiresAt,
|
|
3299
3501
|
last_active_at: /* @__PURE__ */ new Date()
|
|
3300
3502
|
}).select("*").single();
|
|
3301
|
-
if (error || !data)
|
|
3503
|
+
if (error || !data)
|
|
3504
|
+
throw new Error(error?.message ?? "Failed to create session");
|
|
3302
3505
|
return {
|
|
3303
3506
|
id: data.id,
|
|
3304
3507
|
userId: data.user_id,
|
|
@@ -3336,13 +3539,16 @@ async function refreshSessionDB(sessionId) {
|
|
|
3336
3539
|
const thirtyTwo = 32;
|
|
3337
3540
|
const accessToken = randomBytes(thirtyTwo).toString("hex");
|
|
3338
3541
|
const tokenHash = await bcrypt.hash(accessToken, NUMERIX.TEN);
|
|
3339
|
-
const expiresAt = new Date(
|
|
3542
|
+
const expiresAt = new Date(
|
|
3543
|
+
Date.now() + NUMERIX.THOUSAND * NUMERIX.SIXTY * NUMERIX.SIXTY * NUMERIX.TWENTY_FOUR
|
|
3544
|
+
);
|
|
3340
3545
|
const { data, error } = await supabase.from("sessions").update({
|
|
3341
3546
|
token_hash: tokenHash,
|
|
3342
3547
|
expires_at: expiresAt,
|
|
3343
3548
|
last_active_at: /* @__PURE__ */ new Date()
|
|
3344
3549
|
}).eq("id", sessionId).select("*").single();
|
|
3345
|
-
if (error || !data)
|
|
3550
|
+
if (error || !data)
|
|
3551
|
+
throw new Error(error?.message ?? "Failed to refresh session");
|
|
3346
3552
|
return {
|
|
3347
3553
|
id: data.id,
|
|
3348
3554
|
userId: data.user_id,
|
|
@@ -3432,12 +3638,7 @@ var ClerkAdapter = class extends BaseAuthProviderAdapter {
|
|
|
3432
3638
|
* @param deviceInfo - Optional device metadata
|
|
3433
3639
|
*/
|
|
3434
3640
|
async signUp(provider, credentials, data) {
|
|
3435
|
-
await createUser(
|
|
3436
|
-
credentials.email,
|
|
3437
|
-
provider,
|
|
3438
|
-
data,
|
|
3439
|
-
credentials.password
|
|
3440
|
-
);
|
|
3641
|
+
await createUser(credentials.email, provider, data, credentials.password);
|
|
3441
3642
|
}
|
|
3442
3643
|
/**
|
|
3443
3644
|
* Sign out a user.
|
|
@@ -3682,7 +3883,10 @@ var CustomAdapter = class extends BaseAuthProviderAdapter {
|
|
|
3682
3883
|
return { user, session, tokens: { accessToken: session.accessToken } };
|
|
3683
3884
|
}
|
|
3684
3885
|
async signUp(provider, credentials, data, deviceInfo) {
|
|
3685
|
-
const userFindByEmail = await findUserByEmailProvider(
|
|
3886
|
+
const userFindByEmail = await findUserByEmailProvider(
|
|
3887
|
+
data?.email ?? "",
|
|
3888
|
+
provider
|
|
3889
|
+
);
|
|
3686
3890
|
if (userFindByEmail) {
|
|
3687
3891
|
throw new DatabasePackageError("User already register");
|
|
3688
3892
|
}
|
|
@@ -3763,14 +3967,26 @@ var TraditionalAuthStrategy = class {
|
|
|
3763
3967
|
const SALT_LENGTH = 32;
|
|
3764
3968
|
const HASH_LENGTH = 64;
|
|
3765
3969
|
const salt = randomBytes(SALT_LENGTH).toString("hex");
|
|
3766
|
-
const hash = pbkdf2Sync(
|
|
3970
|
+
const hash = pbkdf2Sync(
|
|
3971
|
+
password,
|
|
3972
|
+
salt,
|
|
3973
|
+
NUMERIX.THOUSAND,
|
|
3974
|
+
HASH_LENGTH,
|
|
3975
|
+
"sha512"
|
|
3976
|
+
).toString("hex");
|
|
3767
3977
|
return `pbkdf2$${salt}$${hash}`;
|
|
3768
3978
|
}
|
|
3769
3979
|
async verifyPassword(password, hash) {
|
|
3770
3980
|
const HASH_LENGTH = 64;
|
|
3771
3981
|
if (hash.startsWith("pbkdf2$")) {
|
|
3772
3982
|
const [, salt, storedHash] = hash.split("$");
|
|
3773
|
-
const computedHash = pbkdf2Sync(
|
|
3983
|
+
const computedHash = pbkdf2Sync(
|
|
3984
|
+
password,
|
|
3985
|
+
salt,
|
|
3986
|
+
NUMERIX.THOUSAND,
|
|
3987
|
+
HASH_LENGTH,
|
|
3988
|
+
"sha512"
|
|
3989
|
+
).toString("hex");
|
|
3774
3990
|
return computedHash === storedHash;
|
|
3775
3991
|
}
|
|
3776
3992
|
return false;
|
|
@@ -3921,22 +4137,29 @@ var FacebookProvider = class extends BaseAuthProvider {
|
|
|
3921
4137
|
__name(this, "FacebookProvider");
|
|
3922
4138
|
}
|
|
3923
4139
|
async authenticate(credentials) {
|
|
3924
|
-
const tokenResponse = await this.exchangeCodeForTokens(
|
|
4140
|
+
const tokenResponse = await this.exchangeCodeForTokens(
|
|
4141
|
+
credentials.code
|
|
4142
|
+
);
|
|
3925
4143
|
const userProfile = await this.getUserProfile(tokenResponse.access_token);
|
|
3926
4144
|
const tokens = {
|
|
3927
4145
|
accessToken: tokenResponse.access_token,
|
|
3928
4146
|
refreshToken: tokenResponse.refresh_token,
|
|
3929
|
-
expiresAt: new Date(
|
|
4147
|
+
expiresAt: new Date(
|
|
4148
|
+
Date.now() + tokenResponse.expires_in * NUMERIX.THOUSAND
|
|
4149
|
+
),
|
|
3930
4150
|
expiresIn: 0,
|
|
3931
4151
|
tokenType: ""
|
|
3932
4152
|
};
|
|
3933
4153
|
return { user: userProfile, tokens };
|
|
3934
4154
|
}
|
|
3935
4155
|
async refreshToken(refreshToken) {
|
|
3936
|
-
const response = await globalThis.fetch(
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
4156
|
+
const response = await globalThis.fetch(
|
|
4157
|
+
"https://graph.facebook.com/v18.0/oauth/access_token",
|
|
4158
|
+
{
|
|
4159
|
+
method: "GET",
|
|
4160
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" }
|
|
4161
|
+
}
|
|
4162
|
+
);
|
|
3940
4163
|
const data = await response.json();
|
|
3941
4164
|
return {
|
|
3942
4165
|
accessToken: data.access_token,
|
|
@@ -3947,12 +4170,17 @@ var FacebookProvider = class extends BaseAuthProvider {
|
|
|
3947
4170
|
};
|
|
3948
4171
|
}
|
|
3949
4172
|
async revokeToken(token) {
|
|
3950
|
-
await globalThis.fetch(
|
|
3951
|
-
|
|
3952
|
-
|
|
4173
|
+
await globalThis.fetch(
|
|
4174
|
+
`https://graph.facebook.com/v18.0/me/permissions?access_token=${token}`,
|
|
4175
|
+
{
|
|
4176
|
+
method: "DELETE"
|
|
4177
|
+
}
|
|
4178
|
+
);
|
|
3953
4179
|
}
|
|
3954
4180
|
async getUserProfile(accessToken) {
|
|
3955
|
-
const response = await globalThis.fetch(
|
|
4181
|
+
const response = await globalThis.fetch(
|
|
4182
|
+
`https://graph.facebook.com/v18.0/me?fields=id,name,email,picture&access_token=${accessToken}`
|
|
4183
|
+
);
|
|
3956
4184
|
const profile = await response.json();
|
|
3957
4185
|
return {
|
|
3958
4186
|
id: profile.id,
|
|
@@ -3981,10 +4209,13 @@ var FacebookProvider = class extends BaseAuthProvider {
|
|
|
3981
4209
|
return `https://www.facebook.com/v18.0/dialog/oauth?${params.toString()}`;
|
|
3982
4210
|
}
|
|
3983
4211
|
async exchangeCodeForTokens(code) {
|
|
3984
|
-
const response = await globalThis.fetch(
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
4212
|
+
const response = await globalThis.fetch(
|
|
4213
|
+
"https://graph.facebook.com/v18.0/oauth/access_token",
|
|
4214
|
+
{
|
|
4215
|
+
method: "GET",
|
|
4216
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" }
|
|
4217
|
+
}
|
|
4218
|
+
);
|
|
3988
4219
|
globalThis.console.log(code);
|
|
3989
4220
|
return await response.json();
|
|
3990
4221
|
}
|
|
@@ -4035,7 +4266,9 @@ var GitHubProvider = class extends BaseAuthProvider {
|
|
|
4035
4266
|
return {
|
|
4036
4267
|
accessToken: data.access_token,
|
|
4037
4268
|
refreshToken: data.refresh_token ?? refreshToken,
|
|
4038
|
-
expiresAt: new Date(
|
|
4269
|
+
expiresAt: new Date(
|
|
4270
|
+
Date.now() + (data.expires_in ?? NUMERIX.THIRTY_SIX_HUNDERD) * NUMERIX.THOUSAND
|
|
4271
|
+
),
|
|
4039
4272
|
expiresIn: 0,
|
|
4040
4273
|
tokenType: ""
|
|
4041
4274
|
};
|
|
@@ -4121,23 +4354,28 @@ var GoogleProvider = class extends BaseAuthProvider {
|
|
|
4121
4354
|
const tokens = {
|
|
4122
4355
|
accessToken: tokenResponse.access_token,
|
|
4123
4356
|
refreshToken: tokenResponse.refresh_token,
|
|
4124
|
-
expiresAt: new Date(
|
|
4357
|
+
expiresAt: new Date(
|
|
4358
|
+
Date.now() + tokenResponse.expires_in * NUMERIX.THOUSAND
|
|
4359
|
+
),
|
|
4125
4360
|
expiresIn: 0,
|
|
4126
4361
|
tokenType: ""
|
|
4127
4362
|
};
|
|
4128
4363
|
return { user: userProfile, tokens };
|
|
4129
4364
|
}
|
|
4130
4365
|
async refreshToken(refreshToken) {
|
|
4131
|
-
const response = await globalThis.fetch(
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
|
|
4366
|
+
const response = await globalThis.fetch(
|
|
4367
|
+
"https://oauth2.googleapis.com/token",
|
|
4368
|
+
{
|
|
4369
|
+
method: "POST",
|
|
4370
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
4371
|
+
body: new URLSearchParams({
|
|
4372
|
+
client_id: this.config.clientId,
|
|
4373
|
+
client_secret: this.config.clientSecret,
|
|
4374
|
+
refresh_token: refreshToken,
|
|
4375
|
+
grant_type: "refresh_token"
|
|
4376
|
+
})
|
|
4377
|
+
}
|
|
4378
|
+
);
|
|
4141
4379
|
const data = await response.json();
|
|
4142
4380
|
return {
|
|
4143
4381
|
accessToken: data.access_token,
|
|
@@ -4148,9 +4386,12 @@ var GoogleProvider = class extends BaseAuthProvider {
|
|
|
4148
4386
|
};
|
|
4149
4387
|
}
|
|
4150
4388
|
async revokeToken(token) {
|
|
4151
|
-
await globalThis.fetch(
|
|
4152
|
-
|
|
4153
|
-
|
|
4389
|
+
await globalThis.fetch(
|
|
4390
|
+
`https://oauth2.googleapis.com/revoke?token=${token}`,
|
|
4391
|
+
{
|
|
4392
|
+
method: "POST"
|
|
4393
|
+
}
|
|
4394
|
+
);
|
|
4154
4395
|
}
|
|
4155
4396
|
async getUserProfile(accessToken) {
|
|
4156
4397
|
const response = await globalThis.fetch(
|
|
@@ -4175,17 +4416,20 @@ var GoogleProvider = class extends BaseAuthProvider {
|
|
|
4175
4416
|
};
|
|
4176
4417
|
}
|
|
4177
4418
|
async exchangeCodeForTokens(code) {
|
|
4178
|
-
const response = await globalThis.fetch(
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4419
|
+
const response = await globalThis.fetch(
|
|
4420
|
+
"https://oauth2.googleapis.com/token",
|
|
4421
|
+
{
|
|
4422
|
+
method: "POST",
|
|
4423
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
4424
|
+
body: new URLSearchParams({
|
|
4425
|
+
client_id: this.config.clientId,
|
|
4426
|
+
client_secret: this.config.clientSecret,
|
|
4427
|
+
code,
|
|
4428
|
+
grant_type: "authorization_code",
|
|
4429
|
+
redirect_uri: this.config.redirectUri
|
|
4430
|
+
})
|
|
4431
|
+
}
|
|
4432
|
+
);
|
|
4189
4433
|
return await response.json();
|
|
4190
4434
|
}
|
|
4191
4435
|
getAuthUrl() {
|
|
@@ -4212,7 +4456,10 @@ var SignInFlow = class {
|
|
|
4212
4456
|
__name(this, "SignInFlow");
|
|
4213
4457
|
}
|
|
4214
4458
|
async execute(credentials) {
|
|
4215
|
-
const isValid = await this.validateCredentials(
|
|
4459
|
+
const isValid = await this.validateCredentials(
|
|
4460
|
+
credentials.email,
|
|
4461
|
+
credentials.password
|
|
4462
|
+
);
|
|
4216
4463
|
if (!isValid) {
|
|
4217
4464
|
throw new Error("Invalid credentials");
|
|
4218
4465
|
}
|
|
@@ -4225,7 +4472,9 @@ var SignInFlow = class {
|
|
|
4225
4472
|
const thirty2 = 30;
|
|
4226
4473
|
await this.sessionManager.createSession({
|
|
4227
4474
|
userId: user.id,
|
|
4228
|
-
expiresAt: new Date(
|
|
4475
|
+
expiresAt: new Date(
|
|
4476
|
+
Date.now() + thirty2 * NUMERIX.TWENTY_FOUR * NUMERIX.SIXTY * NUMERIX.SIXTY * NUMERIX.THOUSAND
|
|
4477
|
+
),
|
|
4229
4478
|
// 30 days
|
|
4230
4479
|
metadata: { rememberMe: true }
|
|
4231
4480
|
});
|
|
@@ -4308,7 +4557,10 @@ var SignUpFlow = class {
|
|
|
4308
4557
|
}
|
|
4309
4558
|
async verifyEmail(token) {
|
|
4310
4559
|
const payload = await this.jwtManager.verifyToken(token);
|
|
4311
|
-
const user = await this.userRepository.updateEmailVerification(
|
|
4560
|
+
const user = await this.userRepository.updateEmailVerification(
|
|
4561
|
+
payload.userId,
|
|
4562
|
+
true
|
|
4563
|
+
);
|
|
4312
4564
|
if (!user) {
|
|
4313
4565
|
throw new Error("User not found");
|
|
4314
4566
|
}
|
|
@@ -4328,7 +4580,10 @@ var AuthGuard = class {
|
|
|
4328
4580
|
}
|
|
4329
4581
|
// Explicit return type for canActivate
|
|
4330
4582
|
async canActivate(context) {
|
|
4331
|
-
const isPublic = this.reflector.get(
|
|
4583
|
+
const isPublic = this.reflector.get(
|
|
4584
|
+
"isPublic",
|
|
4585
|
+
context.getHandler()
|
|
4586
|
+
);
|
|
4332
4587
|
if (isPublic) return true;
|
|
4333
4588
|
const request = context.switchToHttp().getRequest();
|
|
4334
4589
|
const token = this.extractToken(request);
|
|
@@ -4372,7 +4627,10 @@ var RolesGuard = class {
|
|
|
4372
4627
|
__name(this, "RolesGuard");
|
|
4373
4628
|
}
|
|
4374
4629
|
async canActivate(context) {
|
|
4375
|
-
const requiredRoles = this.reflector.get(
|
|
4630
|
+
const requiredRoles = this.reflector.get(
|
|
4631
|
+
"roles",
|
|
4632
|
+
context.getHandler()
|
|
4633
|
+
);
|
|
4376
4634
|
if (!requiredRoles) return true;
|
|
4377
4635
|
const request = context.switchToHttp().getRequest();
|
|
4378
4636
|
const user = request.user;
|
|
@@ -4403,11 +4661,12 @@ var PermissionsGuard = class {
|
|
|
4403
4661
|
if (!permissionMetadata) return true;
|
|
4404
4662
|
const user = request.user;
|
|
4405
4663
|
if (!user) {
|
|
4406
|
-
throw new AuthenticationError(
|
|
4407
|
-
"AUTH_INVALID_CREDENTIALS"
|
|
4408
|
-
);
|
|
4664
|
+
throw new AuthenticationError("AUTH_INVALID_CREDENTIALS");
|
|
4409
4665
|
}
|
|
4410
|
-
const permissionContext = this.buildPermissionContext(
|
|
4666
|
+
const permissionContext = this.buildPermissionContext(
|
|
4667
|
+
request,
|
|
4668
|
+
permissionMetadata
|
|
4669
|
+
);
|
|
4411
4670
|
const result = await this.permissionChecker.checkPermission(
|
|
4412
4671
|
user.sub ?? user.userId ?? "",
|
|
4413
4672
|
permissionMetadata.resource,
|
|
@@ -4415,18 +4674,13 @@ var PermissionsGuard = class {
|
|
|
4415
4674
|
permissionContext
|
|
4416
4675
|
);
|
|
4417
4676
|
if (!result.granted) {
|
|
4418
|
-
throw new AuthenticationError(
|
|
4419
|
-
"AUTH_INSUFFICIENT_PERMISSIONS"
|
|
4420
|
-
);
|
|
4677
|
+
throw new AuthenticationError("AUTH_INSUFFICIENT_PERMISSIONS");
|
|
4421
4678
|
}
|
|
4422
4679
|
request.permissionResult = result;
|
|
4423
4680
|
return true;
|
|
4424
4681
|
}
|
|
4425
4682
|
getPermissionMetadata(context) {
|
|
4426
|
-
const permissionData = this.reflector.get(
|
|
4427
|
-
"permission",
|
|
4428
|
-
context.getHandler()
|
|
4429
|
-
);
|
|
4683
|
+
const permissionData = this.reflector.get("permission", context.getHandler());
|
|
4430
4684
|
if (!permissionData) return null;
|
|
4431
4685
|
if (Array.isArray(permissionData)) {
|
|
4432
4686
|
return { resource: permissionData[0], action: permissionData[1] };
|
|
@@ -4446,7 +4700,12 @@ var PermissionsGuard = class {
|
|
|
4446
4700
|
}
|
|
4447
4701
|
}
|
|
4448
4702
|
if (request.body) {
|
|
4449
|
-
const relevantBodyFields = [
|
|
4703
|
+
const relevantBodyFields = [
|
|
4704
|
+
"ownerId",
|
|
4705
|
+
"organizationId",
|
|
4706
|
+
"teamId",
|
|
4707
|
+
"projectId"
|
|
4708
|
+
];
|
|
4450
4709
|
for (const field of relevantBodyFields) {
|
|
4451
4710
|
if (request.body[field]) context[field] = request.body[field];
|
|
4452
4711
|
}
|
|
@@ -4459,9 +4718,7 @@ _init12 = __decoratorStart();
|
|
|
4459
4718
|
PermissionsGuard = __decorateElement(_init12, 0, "PermissionsGuard", _PermissionsGuard_decorators, PermissionsGuard);
|
|
4460
4719
|
__runInitializers(_init12, 1, PermissionsGuard);
|
|
4461
4720
|
var IS_PUBLIC_KEY = "isPublic";
|
|
4462
|
-
var Auth = /* @__PURE__ */ __name(() => applyDecorators(
|
|
4463
|
-
UseGuards(AuthGuard)
|
|
4464
|
-
), "Auth");
|
|
4721
|
+
var Auth = /* @__PURE__ */ __name(() => applyDecorators(UseGuards(AuthGuard)), "Auth");
|
|
4465
4722
|
var Public = /* @__PURE__ */ __name(() => SetMetadata(IS_PUBLIC_KEY, true), "Public");
|
|
4466
4723
|
var Roles = /* @__PURE__ */ __name((...roles) => SetMetadata("roles", roles), "Roles");
|
|
4467
4724
|
var Permissions = /* @__PURE__ */ __name((...permissions) => SetMetadata("permissions", permissions), "Permissions");
|
|
@@ -4979,7 +5236,9 @@ function useAuth() {
|
|
|
4979
5236
|
});
|
|
4980
5237
|
}, "linkAccount"),
|
|
4981
5238
|
unlinkAccount: /* @__PURE__ */ __name(async (accountId) => {
|
|
4982
|
-
return handleAuthAction(
|
|
5239
|
+
return handleAuthAction(
|
|
5240
|
+
async () => store.removeConnectedAccount(accountId)
|
|
5241
|
+
);
|
|
4983
5242
|
}, "unlinkAccount")
|
|
4984
5243
|
};
|
|
4985
5244
|
}
|
|
@@ -5042,9 +5301,12 @@ var useConnectedAccounts = /* @__PURE__ */ __name(() => {
|
|
|
5042
5301
|
const unlinkAccount = /* @__PURE__ */ __name(async (accountId) => {
|
|
5043
5302
|
setIsLoading(true);
|
|
5044
5303
|
try {
|
|
5045
|
-
const response = await globalThis.fetch(
|
|
5046
|
-
|
|
5047
|
-
|
|
5304
|
+
const response = await globalThis.fetch(
|
|
5305
|
+
`/api/auth/accounts/${accountId}/unlink`,
|
|
5306
|
+
{
|
|
5307
|
+
method: "DELETE"
|
|
5308
|
+
}
|
|
5309
|
+
);
|
|
5048
5310
|
if (!response.ok) throw new Error("Failed to unlink account");
|
|
5049
5311
|
setAccounts((prev) => prev.filter((acc) => acc.id !== accountId));
|
|
5050
5312
|
} finally {
|
|
@@ -5054,14 +5316,19 @@ var useConnectedAccounts = /* @__PURE__ */ __name(() => {
|
|
|
5054
5316
|
const setPrimaryAccount = /* @__PURE__ */ __name(async (accountId) => {
|
|
5055
5317
|
setIsLoading(true);
|
|
5056
5318
|
try {
|
|
5057
|
-
const response = await globalThis.fetch(
|
|
5058
|
-
|
|
5059
|
-
|
|
5319
|
+
const response = await globalThis.fetch(
|
|
5320
|
+
`/api/auth/accounts/${accountId}/primary`,
|
|
5321
|
+
{
|
|
5322
|
+
method: "PUT"
|
|
5323
|
+
}
|
|
5324
|
+
);
|
|
5060
5325
|
if (!response.ok) throw new Error("Failed to set primary account");
|
|
5061
|
-
setAccounts(
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5326
|
+
setAccounts(
|
|
5327
|
+
(prev) => prev.map((acc) => ({
|
|
5328
|
+
...acc,
|
|
5329
|
+
isPrimary: acc.id === accountId
|
|
5330
|
+
}))
|
|
5331
|
+
);
|
|
5065
5332
|
} finally {
|
|
5066
5333
|
setIsLoading(false);
|
|
5067
5334
|
}
|
|
@@ -5123,7 +5390,9 @@ var ProtectedRoute = /* @__PURE__ */ __name(({
|
|
|
5123
5390
|
}
|
|
5124
5391
|
if (requiredRoles.length > 0 && user) {
|
|
5125
5392
|
const userRoles = user.roles ?? [];
|
|
5126
|
-
const hasRequiredRole = requiredRoles.some(
|
|
5393
|
+
const hasRequiredRole = requiredRoles.some(
|
|
5394
|
+
(role) => userRoles.includes(role)
|
|
5395
|
+
);
|
|
5127
5396
|
if (!hasRequiredRole) {
|
|
5128
5397
|
return /* @__PURE__ */ jsxs("div", { children: [
|
|
5129
5398
|
"Access denied. Required roles: ",
|