@plyaz/auth 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/pull_request_template.md +71 -0
- package/.github/workflows/deploy.yml +9 -0
- package/.github/workflows/publish.yml +14 -0
- package/.github/workflows/security.yml +20 -0
- package/README.md +89 -0
- package/commits.txt +5 -0
- package/dist/common/index.cjs +48 -0
- package/dist/common/index.cjs.map +1 -0
- package/dist/common/index.mjs +43 -0
- package/dist/common/index.mjs.map +1 -0
- package/dist/index.cjs +20411 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.mjs +5139 -0
- package/dist/index.mjs.map +1 -0
- package/eslint.config.mjs +13 -0
- package/index.html +13 -0
- package/package.json +141 -0
- package/src/adapters/auth-adapter-factory.ts +26 -0
- package/src/adapters/auth-adapter.mapper.ts +53 -0
- package/src/adapters/base-auth.adapter.ts +119 -0
- package/src/adapters/clerk/clerk.adapter.ts +204 -0
- package/src/adapters/custom/custom.adapter.ts +119 -0
- package/src/adapters/index.ts +4 -0
- package/src/adapters/next-auth/authOptions.ts +81 -0
- package/src/adapters/next-auth/next-auth.adapter.ts +211 -0
- package/src/api/client.ts +37 -0
- package/src/audit/audit.logger.ts +52 -0
- package/src/client/components/ProtectedRoute.tsx +37 -0
- package/src/client/hooks/useAuth.ts +128 -0
- package/src/client/hooks/useConnectedAccounts.ts +108 -0
- package/src/client/hooks/usePermissions.ts +36 -0
- package/src/client/hooks/useRBAC.ts +36 -0
- package/src/client/hooks/useSession.ts +18 -0
- package/src/client/providers/AuthProvider.tsx +104 -0
- package/src/client/store/auth.store.ts +306 -0
- package/src/client/utils/storage.ts +70 -0
- package/src/common/constants/oauth-providers.ts +49 -0
- package/src/common/errors/auth.errors.ts +64 -0
- package/src/common/errors/specific-auth-errors.ts +201 -0
- package/src/common/index.ts +19 -0
- package/src/common/regex/index.ts +27 -0
- package/src/common/types/auth.types.ts +641 -0
- package/src/common/types/index.ts +297 -0
- package/src/common/utils/index.ts +84 -0
- package/src/core/blacklist/token.blacklist.ts +60 -0
- package/src/core/index.ts +2 -0
- package/src/core/jwt/jwt.manager.ts +131 -0
- package/src/core/session/session.manager.ts +56 -0
- package/src/db/repositories/connected-account.repository.ts +415 -0
- package/src/db/repositories/role.repository.ts +519 -0
- package/src/db/repositories/session.repository.ts +308 -0
- package/src/db/repositories/user.repository.ts +320 -0
- package/src/flows/index.ts +2 -0
- package/src/flows/sign-in.flow.ts +106 -0
- package/src/flows/sign-up.flow.ts +121 -0
- package/src/index.ts +54 -0
- package/src/libs/clerk.helper.ts +36 -0
- package/src/libs/supabase.helper.ts +255 -0
- package/src/libs/supabaseClient.ts +6 -0
- package/src/providers/base/auth-provider.interface.ts +42 -0
- package/src/providers/base/index.ts +1 -0
- package/src/providers/index.ts +2 -0
- package/src/providers/oauth/facebook.provider.ts +97 -0
- package/src/providers/oauth/github.provider.ts +148 -0
- package/src/providers/oauth/google.provider.ts +126 -0
- package/src/providers/oauth/index.ts +3 -0
- package/src/rbac/dynamic-roles.ts +552 -0
- package/src/rbac/index.ts +4 -0
- package/src/rbac/permission-checker.ts +464 -0
- package/src/rbac/role-hierarchy.ts +545 -0
- package/src/rbac/role.manager.ts +75 -0
- package/src/security/csrf/csrf.protection.ts +37 -0
- package/src/security/index.ts +3 -0
- package/src/security/rate-limiting/auth/auth.controller.ts +12 -0
- package/src/security/rate-limiting/auth/rate-limiting.interface.ts +67 -0
- package/src/security/rate-limiting/auth.module.ts +32 -0
- package/src/server/auth.module.ts +158 -0
- package/src/server/decorators/auth.decorator.ts +43 -0
- package/src/server/decorators/auth.decorators.ts +31 -0
- package/src/server/decorators/current-user.decorator.ts +49 -0
- package/src/server/decorators/permission.decorator.ts +49 -0
- package/src/server/guards/auth.guard.ts +56 -0
- package/src/server/guards/custom-throttler.guard.ts +46 -0
- package/src/server/guards/permissions.guard.ts +115 -0
- package/src/server/guards/roles.guard.ts +31 -0
- package/src/server/middleware/auth.middleware.ts +46 -0
- package/src/server/middleware/index.ts +2 -0
- package/src/server/middleware/middleware.ts +11 -0
- package/src/server/middleware/session.middleware.ts +255 -0
- package/src/server/services/account.service.ts +269 -0
- package/src/server/services/auth.service.ts +79 -0
- package/src/server/services/brute-force.service.ts +98 -0
- package/src/server/services/index.ts +15 -0
- package/src/server/services/rate-limiter.service.ts +60 -0
- package/src/server/services/session.service.ts +287 -0
- package/src/server/services/token.service.ts +262 -0
- package/src/session/cookie-store.ts +255 -0
- package/src/session/enhanced-session-manager.ts +406 -0
- package/src/session/index.ts +14 -0
- package/src/session/memory-store.ts +320 -0
- package/src/session/redis-store.ts +443 -0
- package/src/strategies/oauth.strategy.ts +128 -0
- package/src/strategies/traditional-auth.strategy.ts +116 -0
- package/src/tokens/index.ts +4 -0
- package/src/tokens/refresh-token-manager.ts +448 -0
- package/src/tokens/token-validator.ts +311 -0
- package/tsconfig.build.json +28 -0
- package/tsconfig.json +38 -0
- package/tsup.config.mjs +28 -0
- package/vitest.config.mjs +16 -0
- package/vitest.setup.d.ts +2 -0
- package/vitest.setup.d.ts.map +1 -0
- package/vitest.setup.ts +1 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Memory-based session store for @plyaz/auth
|
|
3
|
+
* @module @plyaz/auth/session/memory-store
|
|
4
|
+
*
|
|
5
|
+
* @description
|
|
6
|
+
* Implements session storage using in-memory storage. Provides fast session
|
|
7
|
+
* access but sessions are lost on server restart. Suitable for development,
|
|
8
|
+
* testing, or single-instance applications where session persistence across
|
|
9
|
+
* restarts is not required.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { MemoryStore } from '@plyaz/auth';
|
|
14
|
+
*
|
|
15
|
+
* const store = new MemoryStore({
|
|
16
|
+
* maxSessionsPerUser: 10,
|
|
17
|
+
* cleanupInterval: 300
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* await store.set('session_123', sessionData, 3600);
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { NUMERIX } from "@plyaz/config";
|
|
25
|
+
import type { SessionData, SessionStore, SessionStoreConfig } from "@plyaz/types";
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Memory store configuration
|
|
30
|
+
*/
|
|
31
|
+
export interface MemoryStoreConfig extends Partial<SessionStoreConfig> {
|
|
32
|
+
/** Enable automatic cleanup */
|
|
33
|
+
autoCleanup?: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Memory-based session store implementation
|
|
38
|
+
* Stores session data in server memory (Map)
|
|
39
|
+
*/
|
|
40
|
+
export class MemoryStore implements SessionStore {
|
|
41
|
+
private readonly config: Required<MemoryStoreConfig>;
|
|
42
|
+
private readonly sessions = new Map<string, SessionData>();
|
|
43
|
+
private readonly userSessions = new Map<string, Set<string>>();
|
|
44
|
+
private cleanupTimer?:string;
|
|
45
|
+
|
|
46
|
+
constructor(config: MemoryStoreConfig = {}) {
|
|
47
|
+
this.config = {
|
|
48
|
+
defaultTTL: 3600,
|
|
49
|
+
maxSessionsPerUser: 5,
|
|
50
|
+
cleanupInterval: 300,
|
|
51
|
+
keyPrefix: 'session:',
|
|
52
|
+
autoCleanup: true,
|
|
53
|
+
...config
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// Start automatic cleanup if enabled
|
|
57
|
+
if (this.config.autoCleanup) {
|
|
58
|
+
this.startCleanupTimer();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Store session data in memory
|
|
64
|
+
* @param sessionId - Session identifier
|
|
65
|
+
* @param data - Session data to store
|
|
66
|
+
* @param ttlSeconds - Time to live in seconds
|
|
67
|
+
*/
|
|
68
|
+
async set(sessionId: string, data: SessionData, ttlSeconds: number): Promise<void> {
|
|
69
|
+
const sessionData: SessionData = {
|
|
70
|
+
...data,
|
|
71
|
+
expiresAt: new Date(Date.now() + ttlSeconds * NUMERIX.THOUSAND)
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// Enforce session limits per user
|
|
75
|
+
await this.enforceSessionLimits(data.userId);
|
|
76
|
+
|
|
77
|
+
// Store session
|
|
78
|
+
this.sessions.set(sessionId, sessionData);
|
|
79
|
+
|
|
80
|
+
// Track user sessions
|
|
81
|
+
if (!this.userSessions.has(data.userId)) {
|
|
82
|
+
this.userSessions.set(data.userId, new Set());
|
|
83
|
+
}
|
|
84
|
+
this.userSessions.get(data.userId)!.add(sessionId);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Retrieve session data from memory
|
|
89
|
+
* @param sessionId - Session identifier
|
|
90
|
+
* @returns Session data or null if not found/expired
|
|
91
|
+
*/
|
|
92
|
+
async get(sessionId: string): Promise<SessionData | null> {
|
|
93
|
+
const data = this.sessions.get(sessionId);
|
|
94
|
+
|
|
95
|
+
if (!data) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Check expiration
|
|
100
|
+
if (data.expiresAt < new Date()) {
|
|
101
|
+
await this.delete(sessionId);
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return data;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Delete session from memory
|
|
110
|
+
* @param sessionId - Session identifier
|
|
111
|
+
*/
|
|
112
|
+
async delete(sessionId: string): Promise<void> {
|
|
113
|
+
const data = this.sessions.get(sessionId);
|
|
114
|
+
|
|
115
|
+
if (data) {
|
|
116
|
+
// Remove from sessions
|
|
117
|
+
this.sessions.delete(sessionId);
|
|
118
|
+
|
|
119
|
+
// Remove from user sessions tracking
|
|
120
|
+
const userSessionSet = this.userSessions.get(data.userId);
|
|
121
|
+
if (userSessionSet) {
|
|
122
|
+
userSessionSet.delete(sessionId);
|
|
123
|
+
if (userSessionSet.size === 0) {
|
|
124
|
+
this.userSessions.delete(data.userId);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Delete all sessions for a user
|
|
132
|
+
* @param userId - User identifier
|
|
133
|
+
* @returns Number of deleted sessions
|
|
134
|
+
*/
|
|
135
|
+
async deleteByUserId(userId: string): Promise<number> {
|
|
136
|
+
const userSessionSet = this.userSessions.get(userId);
|
|
137
|
+
|
|
138
|
+
if (!userSessionSet) {
|
|
139
|
+
return 0;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const sessionIds = Array.from(userSessionSet);
|
|
143
|
+
let deletedCount = 0;
|
|
144
|
+
|
|
145
|
+
for (const sessionId of sessionIds) {
|
|
146
|
+
if (this.sessions.has(sessionId)) {
|
|
147
|
+
this.sessions.delete(sessionId);
|
|
148
|
+
deletedCount++;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Clear user session tracking
|
|
153
|
+
this.userSessions.delete(userId);
|
|
154
|
+
|
|
155
|
+
return deletedCount;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Update session activity timestamp
|
|
160
|
+
* @param sessionId - Session identifier
|
|
161
|
+
*/
|
|
162
|
+
async updateActivity(sessionId: string): Promise<void> {
|
|
163
|
+
const data = this.sessions.get(sessionId);
|
|
164
|
+
if (data) {
|
|
165
|
+
data.lastActivityAt = new Date();
|
|
166
|
+
this.sessions.set(sessionId, data);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Check if session exists and is valid
|
|
172
|
+
* @param sessionId - Session identifier
|
|
173
|
+
* @returns True if session exists and is valid
|
|
174
|
+
*/
|
|
175
|
+
async exists(sessionId: string): Promise<boolean> {
|
|
176
|
+
const data = await this.get(sessionId);
|
|
177
|
+
return data !== null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Get all active sessions for a user
|
|
182
|
+
* @param userId - User identifier
|
|
183
|
+
* @returns Array of session data
|
|
184
|
+
*/
|
|
185
|
+
async getByUserId(userId: string): Promise<SessionData[]> {
|
|
186
|
+
const userSessionSet = this.userSessions.get(userId);
|
|
187
|
+
|
|
188
|
+
if (!userSessionSet) {
|
|
189
|
+
return [];
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const userSessions: SessionData[] = [];
|
|
193
|
+
const now = new Date();
|
|
194
|
+
|
|
195
|
+
for (const sessionId of userSessionSet) {
|
|
196
|
+
const data = this.sessions.get(sessionId);
|
|
197
|
+
if (data && data.expiresAt > now) {
|
|
198
|
+
userSessions.push(data);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return userSessions;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Clean up expired sessions
|
|
207
|
+
* @returns Number of cleaned sessions
|
|
208
|
+
*/
|
|
209
|
+
async cleanup(): Promise<number> {
|
|
210
|
+
let cleanedCount = 0;
|
|
211
|
+
const now = new Date();
|
|
212
|
+
const expiredSessions: string[] = [];
|
|
213
|
+
|
|
214
|
+
// Find expired sessions
|
|
215
|
+
for (const [sessionId, data] of this.sessions.entries()) {
|
|
216
|
+
if (data.expiresAt < now) {
|
|
217
|
+
expiredSessions.push(sessionId);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Delete expired sessions
|
|
222
|
+
for (const sessionId of expiredSessions) {
|
|
223
|
+
await this.delete(sessionId);
|
|
224
|
+
cleanedCount++;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return cleanedCount;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Get session count for a user
|
|
232
|
+
* @param userId - User identifier
|
|
233
|
+
* @returns Session count
|
|
234
|
+
*/
|
|
235
|
+
async getSessionCount(userId: string): Promise<number> {
|
|
236
|
+
const sessions = await this.getByUserId(userId);
|
|
237
|
+
return sessions.length;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Get total number of active sessions
|
|
242
|
+
* @returns Total session count
|
|
243
|
+
*/
|
|
244
|
+
getTotalSessionCount(): number {
|
|
245
|
+
return this.sessions.size;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Get memory usage statistics
|
|
250
|
+
* @returns Memory usage information
|
|
251
|
+
*/
|
|
252
|
+
getStats(): {
|
|
253
|
+
totalSessions: number;
|
|
254
|
+
totalUsers: number;
|
|
255
|
+
memoryUsage: number;
|
|
256
|
+
} {
|
|
257
|
+
return {
|
|
258
|
+
totalSessions: this.sessions.size,
|
|
259
|
+
totalUsers: this.userSessions.size,
|
|
260
|
+
memoryUsage: this.estimateMemoryUsage()
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Destroy the store and cleanup resources
|
|
266
|
+
*/
|
|
267
|
+
destroy(): void {
|
|
268
|
+
if (this.cleanupTimer) {
|
|
269
|
+
|
|
270
|
+
this.cleanupTimer = undefined;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
this.sessions.clear();
|
|
274
|
+
this.userSessions.clear();
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Enforce session limits per user
|
|
279
|
+
* @param userId - User identifier
|
|
280
|
+
* @private
|
|
281
|
+
*/
|
|
282
|
+
private async enforceSessionLimits(userId: string): Promise<void> {
|
|
283
|
+
const userSessions = await this.getByUserId(userId);
|
|
284
|
+
|
|
285
|
+
if (userSessions.length >= this.config.maxSessionsPerUser) {
|
|
286
|
+
// Sort by last activity (oldest first)
|
|
287
|
+
userSessions.sort((a, b) => a.lastActivityAt.getTime() - b.lastActivityAt.getTime());
|
|
288
|
+
|
|
289
|
+
// Remove oldest sessions to make room
|
|
290
|
+
const sessionsToRemove = userSessions.length - this.config.maxSessionsPerUser + 1;
|
|
291
|
+
for (let i = 0; i < sessionsToRemove; i++) {
|
|
292
|
+
await this.delete(userSessions[i].id);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Start automatic cleanup timer
|
|
299
|
+
* @private
|
|
300
|
+
*/
|
|
301
|
+
private startCleanupTimer(): void {
|
|
302
|
+
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Estimate memory usage (rough calculation)
|
|
307
|
+
* @returns Estimated memory usage in bytes
|
|
308
|
+
* @private
|
|
309
|
+
*/
|
|
310
|
+
private estimateMemoryUsage(): number {
|
|
311
|
+
let totalSize = 0;
|
|
312
|
+
|
|
313
|
+
for (const [sessionId, data] of this.sessions.entries()) {
|
|
314
|
+
totalSize += sessionId.length * NUMERIX.TWO; // UTF-16 encoding
|
|
315
|
+
totalSize += JSON.stringify(data).length * NUMERIX.TWO;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return totalSize;
|
|
319
|
+
}
|
|
320
|
+
}
|