@strapi/core 0.0.0-experimental.00b482b8dcda6164537baf70d52b4b2535560c36 → 0.0.0-experimental.011bfeb83dc6344ffdc0f9c757af54f61c74e22f
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.
Potentially problematic release.
This version of @strapi/core might be problematic. Click here for more details.
- package/dist/Strapi.d.ts.map +1 -1
- package/dist/Strapi.js +16 -1
- package/dist/Strapi.js.map +1 -1
- package/dist/Strapi.mjs +16 -1
- package/dist/Strapi.mjs.map +1 -1
- package/dist/package.json.js +12 -12
- package/dist/package.json.mjs +12 -12
- package/dist/providers/index.js +1 -1
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/index.mjs +1 -1
- package/dist/providers/index.mjs.map +1 -1
- package/dist/providers/{sessionManager.d.ts → session-manager.d.ts} +1 -1
- package/dist/providers/session-manager.d.ts.map +1 -0
- package/dist/providers/session-manager.js +23 -0
- package/dist/providers/session-manager.js.map +1 -0
- package/dist/providers/session-manager.mjs +21 -0
- package/dist/providers/session-manager.mjs.map +1 -0
- package/dist/services/document-service/components.d.ts +26 -1
- package/dist/services/document-service/components.d.ts.map +1 -1
- package/dist/services/document-service/components.js +16 -4
- package/dist/services/document-service/components.js.map +1 -1
- package/dist/services/document-service/components.mjs +15 -5
- package/dist/services/document-service/components.mjs.map +1 -1
- package/dist/services/document-service/utils/clean-component-join-table.d.ts +7 -0
- package/dist/services/document-service/utils/clean-component-join-table.d.ts.map +1 -0
- package/dist/services/metrics/index.js +2 -1
- package/dist/services/metrics/index.js.map +1 -1
- package/dist/services/metrics/index.mjs +2 -1
- package/dist/services/metrics/index.mjs.map +1 -1
- package/dist/services/metrics/middleware.d.ts +2 -1
- package/dist/services/metrics/middleware.d.ts.map +1 -1
- package/dist/services/metrics/middleware.js +2 -2
- package/dist/services/metrics/middleware.js.map +1 -1
- package/dist/services/metrics/middleware.mjs +2 -2
- package/dist/services/metrics/middleware.mjs.map +1 -1
- package/dist/services/metrics/sender.d.ts.map +1 -1
- package/dist/services/metrics/sender.js +2 -1
- package/dist/services/metrics/sender.js.map +1 -1
- package/dist/services/metrics/sender.mjs +2 -1
- package/dist/services/metrics/sender.mjs.map +1 -1
- package/dist/services/session-manager.d.ts +72 -20
- package/dist/services/session-manager.d.ts.map +1 -1
- package/dist/services/session-manager.js +199 -50
- package/dist/services/session-manager.js.map +1 -1
- package/dist/services/session-manager.mjs +199 -50
- package/dist/services/session-manager.mjs.map +1 -1
- package/package.json +12 -12
- package/dist/providers/sessionManager.d.ts.map +0 -1
- package/dist/providers/sessionManager.js +0 -36
- package/dist/providers/sessionManager.js.map +0 -1
- package/dist/providers/sessionManager.mjs +0 -34
- package/dist/providers/sessionManager.mjs.map +0 -1
|
@@ -61,7 +61,82 @@ class DatabaseSessionProvider {
|
|
|
61
61
|
this.contentType = contentType;
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
|
+
class OriginSessionManager {
|
|
65
|
+
async generateRefreshToken(userId, deviceId, options) {
|
|
66
|
+
return this.sessionManager.generateRefreshToken(userId, deviceId, this.origin, options);
|
|
67
|
+
}
|
|
68
|
+
async generateAccessToken(refreshToken) {
|
|
69
|
+
return this.sessionManager.generateAccessToken(refreshToken, this.origin);
|
|
70
|
+
}
|
|
71
|
+
async rotateRefreshToken(refreshToken) {
|
|
72
|
+
return this.sessionManager.rotateRefreshToken(refreshToken, this.origin);
|
|
73
|
+
}
|
|
74
|
+
validateAccessToken(token) {
|
|
75
|
+
return this.sessionManager.validateAccessToken(token, this.origin);
|
|
76
|
+
}
|
|
77
|
+
async validateRefreshToken(token) {
|
|
78
|
+
return this.sessionManager.validateRefreshToken(token, this.origin);
|
|
79
|
+
}
|
|
80
|
+
async invalidateRefreshToken(userId, deviceId) {
|
|
81
|
+
return this.sessionManager.invalidateRefreshToken(this.origin, userId, deviceId);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Returns true when a session exists and is not expired for this origin.
|
|
85
|
+
* If the session exists but is expired, it will be deleted as part of this check.
|
|
86
|
+
*/ async isSessionActive(sessionId) {
|
|
87
|
+
return this.sessionManager.isSessionActive(sessionId, this.origin);
|
|
88
|
+
}
|
|
89
|
+
constructor(sessionManager, origin){
|
|
90
|
+
this.sessionManager = sessionManager;
|
|
91
|
+
this.origin = origin;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
64
94
|
class SessionManager {
|
|
95
|
+
/**
|
|
96
|
+
* Define configuration for a specific origin
|
|
97
|
+
*/ defineOrigin(origin, config) {
|
|
98
|
+
this.originConfigs.set(origin, config);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Check if an origin is defined
|
|
102
|
+
*/ hasOrigin(origin) {
|
|
103
|
+
return this.originConfigs.has(origin);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Get configuration for a specific origin, throw error if not defined
|
|
107
|
+
*/ getConfigForOrigin(origin) {
|
|
108
|
+
const originConfig = this.originConfigs.get(origin);
|
|
109
|
+
if (originConfig) {
|
|
110
|
+
return originConfig;
|
|
111
|
+
}
|
|
112
|
+
throw new Error(`SessionManager: Origin '${origin}' is not defined. Please define it using defineOrigin('${origin}', config).`);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Get the appropriate JWT key based on the algorithm
|
|
116
|
+
*/ getJwtKey(config, algorithm, operation) {
|
|
117
|
+
const isAsymmetric = algorithm.startsWith('RS') || algorithm.startsWith('ES') || algorithm.startsWith('PS');
|
|
118
|
+
if (isAsymmetric) {
|
|
119
|
+
// For asymmetric algorithms, check if user has provided proper key configuration
|
|
120
|
+
if (operation === 'sign') {
|
|
121
|
+
const privateKey = config.jwtOptions?.privateKey;
|
|
122
|
+
if (privateKey) {
|
|
123
|
+
return privateKey;
|
|
124
|
+
}
|
|
125
|
+
throw new Error(`SessionManager: Private key is required for asymmetric algorithm ${algorithm}. Please configure admin.auth.options.privateKey.`);
|
|
126
|
+
} else {
|
|
127
|
+
const publicKey = config.jwtOptions?.publicKey;
|
|
128
|
+
if (publicKey) {
|
|
129
|
+
return publicKey;
|
|
130
|
+
}
|
|
131
|
+
throw new Error(`SessionManager: Public key is required for asymmetric algorithm ${algorithm}. Please configure admin.auth.options.publicKey.`);
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
if (!config.jwtSecret) {
|
|
135
|
+
throw new Error(`SessionManager: Secret key is required for symmetric algorithm ${algorithm}`);
|
|
136
|
+
}
|
|
137
|
+
return config.jwtSecret;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
65
140
|
generateSessionId() {
|
|
66
141
|
return crypto.randomBytes(16).toString('hex');
|
|
67
142
|
}
|
|
@@ -72,13 +147,24 @@ class SessionManager {
|
|
|
72
147
|
await this.provider.deleteExpired();
|
|
73
148
|
}
|
|
74
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Get the cleanup every calls threshold
|
|
152
|
+
*/ get cleanupThreshold() {
|
|
153
|
+
return this.cleanupEveryCalls;
|
|
154
|
+
}
|
|
75
155
|
async generateRefreshToken(userId, deviceId, origin, options) {
|
|
156
|
+
if (!origin || typeof origin !== 'string') {
|
|
157
|
+
throw new Error('SessionManager: Origin parameter is required and must be a non-empty string');
|
|
158
|
+
}
|
|
76
159
|
await this.maybeCleanupExpired();
|
|
160
|
+
const config = this.getConfigForOrigin(origin);
|
|
161
|
+
const algorithm = config.algorithm || DEFAULT_ALGORITHM;
|
|
162
|
+
const jwtKey = this.getJwtKey(config, algorithm, 'sign');
|
|
77
163
|
const sessionId = this.generateSessionId();
|
|
78
|
-
const
|
|
79
|
-
const isRefresh =
|
|
80
|
-
const idleLifespan = isRefresh ?
|
|
81
|
-
const maxLifespan = isRefresh ?
|
|
164
|
+
const tokenType = options?.type ?? 'refresh';
|
|
165
|
+
const isRefresh = tokenType === 'refresh';
|
|
166
|
+
const idleLifespan = isRefresh ? config.idleRefreshTokenLifespan : config.idleSessionLifespan;
|
|
167
|
+
const maxLifespan = isRefresh ? config.maxRefreshTokenLifespan : config.maxSessionLifespan;
|
|
82
168
|
const now = Date.now();
|
|
83
169
|
const expiresAt = new Date(now + idleLifespan * 1000);
|
|
84
170
|
const absoluteExpiresAt = new Date(now + maxLifespan * 1000);
|
|
@@ -86,12 +172,12 @@ class SessionManager {
|
|
|
86
172
|
const record = await this.provider.create({
|
|
87
173
|
userId,
|
|
88
174
|
sessionId,
|
|
89
|
-
deviceId
|
|
175
|
+
...deviceId && {
|
|
176
|
+
deviceId
|
|
177
|
+
},
|
|
90
178
|
origin,
|
|
91
|
-
parentId: null,
|
|
92
179
|
childId: null,
|
|
93
|
-
|
|
94
|
-
type: familyType,
|
|
180
|
+
type: tokenType,
|
|
95
181
|
status: 'active',
|
|
96
182
|
expiresAt,
|
|
97
183
|
absoluteExpiresAt
|
|
@@ -105,23 +191,33 @@ class SessionManager {
|
|
|
105
191
|
iat: issuedAtSeconds,
|
|
106
192
|
exp: expiresAtSeconds
|
|
107
193
|
};
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
194
|
+
// Filter out conflicting options that are already handled by the payload or used for key selection
|
|
195
|
+
const jwtOptions = config.jwtOptions || {};
|
|
196
|
+
const { expiresIn, privateKey, publicKey, ...jwtSignOptions } = jwtOptions;
|
|
197
|
+
const token = jwt.sign(payload, jwtKey, {
|
|
198
|
+
algorithm,
|
|
199
|
+
noTimestamp: true,
|
|
200
|
+
...jwtSignOptions
|
|
111
201
|
});
|
|
112
202
|
return {
|
|
113
203
|
token,
|
|
114
204
|
sessionId,
|
|
115
|
-
absoluteExpiresAt: absoluteExpiresAt.toISOString()
|
|
116
|
-
familyId: record.familyId
|
|
205
|
+
absoluteExpiresAt: absoluteExpiresAt.toISOString()
|
|
117
206
|
};
|
|
118
207
|
}
|
|
119
|
-
validateAccessToken(token) {
|
|
208
|
+
validateAccessToken(token, origin) {
|
|
209
|
+
if (!origin || typeof origin !== 'string') {
|
|
210
|
+
throw new Error('SessionManager: Origin parameter is required and must be a non-empty string');
|
|
211
|
+
}
|
|
120
212
|
try {
|
|
121
|
-
const
|
|
213
|
+
const config = this.getConfigForOrigin(origin);
|
|
214
|
+
const algorithm = config.algorithm || DEFAULT_ALGORITHM;
|
|
215
|
+
const jwtKey = this.getJwtKey(config, algorithm, 'verify');
|
|
216
|
+
const payload = jwt.verify(token, jwtKey, {
|
|
122
217
|
algorithms: [
|
|
123
|
-
|
|
124
|
-
]
|
|
218
|
+
algorithm
|
|
219
|
+
],
|
|
220
|
+
...config.jwtOptions
|
|
125
221
|
});
|
|
126
222
|
// Ensure this is an access token
|
|
127
223
|
if (!payload || payload.type !== 'access') {
|
|
@@ -141,14 +237,21 @@ class SessionManager {
|
|
|
141
237
|
};
|
|
142
238
|
}
|
|
143
239
|
}
|
|
144
|
-
async validateRefreshToken(token) {
|
|
240
|
+
async validateRefreshToken(token, origin) {
|
|
241
|
+
if (!origin || typeof origin !== 'string') {
|
|
242
|
+
throw new Error('SessionManager: Origin parameter is required and must be a non-empty string');
|
|
243
|
+
}
|
|
145
244
|
try {
|
|
245
|
+
const config = this.getConfigForOrigin(origin);
|
|
246
|
+
const algorithm = config.algorithm || DEFAULT_ALGORITHM;
|
|
247
|
+
const jwtKey = this.getJwtKey(config, algorithm, 'verify');
|
|
146
248
|
const verifyOptions = {
|
|
147
249
|
algorithms: [
|
|
148
|
-
|
|
149
|
-
]
|
|
250
|
+
algorithm
|
|
251
|
+
],
|
|
252
|
+
...config.jwtOptions
|
|
150
253
|
};
|
|
151
|
-
const payload = jwt.verify(token,
|
|
254
|
+
const payload = jwt.verify(token, jwtKey, verifyOptions);
|
|
152
255
|
if (payload.type !== 'refresh') {
|
|
153
256
|
return {
|
|
154
257
|
isValid: false
|
|
@@ -204,8 +307,11 @@ class SessionManager {
|
|
|
204
307
|
deviceId
|
|
205
308
|
});
|
|
206
309
|
}
|
|
207
|
-
async generateAccessToken(refreshToken) {
|
|
208
|
-
|
|
310
|
+
async generateAccessToken(refreshToken, origin) {
|
|
311
|
+
if (!origin || typeof origin !== 'string') {
|
|
312
|
+
throw new Error('SessionManager: Origin parameter is required and must be a non-empty string');
|
|
313
|
+
}
|
|
314
|
+
const validation = await this.validateRefreshToken(refreshToken, origin);
|
|
209
315
|
if (!validation.isValid) {
|
|
210
316
|
return {
|
|
211
317
|
error: 'invalid_refresh_token'
|
|
@@ -216,20 +322,34 @@ class SessionManager {
|
|
|
216
322
|
sessionId: validation.sessionId,
|
|
217
323
|
type: 'access'
|
|
218
324
|
};
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
325
|
+
const config = this.getConfigForOrigin(origin);
|
|
326
|
+
const algorithm = config.algorithm || DEFAULT_ALGORITHM;
|
|
327
|
+
const jwtKey = this.getJwtKey(config, algorithm, 'sign');
|
|
328
|
+
// Filter out conflicting options that are already handled by the payload or used for key selection
|
|
329
|
+
const jwtOptions = config.jwtOptions || {};
|
|
330
|
+
const { expiresIn, privateKey, publicKey, ...jwtSignOptions } = jwtOptions;
|
|
331
|
+
const token = jwt.sign(payload, jwtKey, {
|
|
332
|
+
algorithm,
|
|
333
|
+
expiresIn: config.accessTokenLifespan,
|
|
334
|
+
...jwtSignOptions
|
|
222
335
|
});
|
|
223
336
|
return {
|
|
224
337
|
token
|
|
225
338
|
};
|
|
226
339
|
}
|
|
227
|
-
async rotateRefreshToken(refreshToken) {
|
|
340
|
+
async rotateRefreshToken(refreshToken, origin) {
|
|
341
|
+
if (!origin || typeof origin !== 'string') {
|
|
342
|
+
throw new Error('SessionManager: Origin parameter is required and must be a non-empty string');
|
|
343
|
+
}
|
|
228
344
|
try {
|
|
229
|
-
const
|
|
345
|
+
const config = this.getConfigForOrigin(origin);
|
|
346
|
+
const algorithm = config.algorithm || DEFAULT_ALGORITHM;
|
|
347
|
+
const jwtKey = this.getJwtKey(config, algorithm, 'verify');
|
|
348
|
+
const payload = jwt.verify(refreshToken, jwtKey, {
|
|
230
349
|
algorithms: [
|
|
231
|
-
|
|
232
|
-
]
|
|
350
|
+
algorithm
|
|
351
|
+
],
|
|
352
|
+
...config.jwtOptions
|
|
233
353
|
});
|
|
234
354
|
if (!payload || payload.type !== 'refresh') {
|
|
235
355
|
return {
|
|
@@ -255,9 +375,12 @@ class SessionManager {
|
|
|
255
375
|
iat: childIat,
|
|
256
376
|
exp: childExp
|
|
257
377
|
};
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
378
|
+
// Filter out conflicting options that are already handled by the payload
|
|
379
|
+
const { expiresIn, ...jwtSignOptions } = config.jwtOptions || {};
|
|
380
|
+
const childToken = jwt.sign(childPayload, jwtKey, {
|
|
381
|
+
algorithm,
|
|
382
|
+
noTimestamp: true,
|
|
383
|
+
...jwtSignOptions
|
|
261
384
|
});
|
|
262
385
|
let absoluteExpiresAt;
|
|
263
386
|
if (child.absoluteExpiresAt) {
|
|
@@ -269,14 +392,13 @@ class SessionManager {
|
|
|
269
392
|
token: childToken,
|
|
270
393
|
sessionId: child.sessionId,
|
|
271
394
|
absoluteExpiresAt,
|
|
272
|
-
familyId: String(child.familyId ?? child.sessionId),
|
|
273
395
|
type: child.type ?? 'refresh'
|
|
274
396
|
};
|
|
275
397
|
}
|
|
276
398
|
}
|
|
277
399
|
const now = Date.now();
|
|
278
|
-
const
|
|
279
|
-
const idleLifespan =
|
|
400
|
+
const tokenType = current.type ?? 'refresh';
|
|
401
|
+
const idleLifespan = tokenType === 'refresh' ? config.idleRefreshTokenLifespan : config.idleSessionLifespan;
|
|
280
402
|
// Enforce idle window since creation of the current token
|
|
281
403
|
if (current.createdAt && now - new Date(current.createdAt).getTime() > idleLifespan * 1000) {
|
|
282
404
|
return {
|
|
@@ -296,12 +418,12 @@ class SessionManager {
|
|
|
296
418
|
const childRecord = await this.provider.create({
|
|
297
419
|
userId: current.userId,
|
|
298
420
|
sessionId: childSessionId,
|
|
299
|
-
|
|
421
|
+
...current.deviceId && {
|
|
422
|
+
deviceId: current.deviceId
|
|
423
|
+
},
|
|
300
424
|
origin: current.origin,
|
|
301
|
-
parentId: current.sessionId,
|
|
302
425
|
childId: null,
|
|
303
|
-
|
|
304
|
-
type: familyType,
|
|
426
|
+
type: tokenType,
|
|
305
427
|
status: 'active',
|
|
306
428
|
expiresAt: childExpiresAt,
|
|
307
429
|
absoluteExpiresAt: current.absoluteExpiresAt ?? new Date(absolute)
|
|
@@ -315,9 +437,12 @@ class SessionManager {
|
|
|
315
437
|
iat: childIat,
|
|
316
438
|
exp: childExp
|
|
317
439
|
};
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
440
|
+
// Filter out conflicting options that are already handled by the payload
|
|
441
|
+
const { expiresIn, ...jwtSignOptions } = config.jwtOptions || {};
|
|
442
|
+
const childToken = jwt.sign(payloadOut, jwtKey, {
|
|
443
|
+
algorithm,
|
|
444
|
+
noTimestamp: true,
|
|
445
|
+
...jwtSignOptions
|
|
321
446
|
});
|
|
322
447
|
await this.provider.updateBySessionId(current.sessionId, {
|
|
323
448
|
status: 'rotated',
|
|
@@ -333,8 +458,7 @@ class SessionManager {
|
|
|
333
458
|
token: childToken,
|
|
334
459
|
sessionId: childSessionId,
|
|
335
460
|
absoluteExpiresAt,
|
|
336
|
-
|
|
337
|
-
type: familyType
|
|
461
|
+
type: tokenType
|
|
338
462
|
};
|
|
339
463
|
} catch {
|
|
340
464
|
return {
|
|
@@ -345,11 +469,14 @@ class SessionManager {
|
|
|
345
469
|
/**
|
|
346
470
|
* Returns true when a session exists and is not expired.
|
|
347
471
|
* If the session exists but is expired, it will be deleted as part of this check.
|
|
348
|
-
*/ async isSessionActive(sessionId) {
|
|
472
|
+
*/ async isSessionActive(sessionId, origin) {
|
|
349
473
|
const session = await this.provider.findBySessionId(sessionId);
|
|
350
474
|
if (!session) {
|
|
351
475
|
return false;
|
|
352
476
|
}
|
|
477
|
+
if (session.origin !== origin) {
|
|
478
|
+
return false;
|
|
479
|
+
}
|
|
353
480
|
if (new Date(session.expiresAt) <= new Date()) {
|
|
354
481
|
// Clean up expired session eagerly
|
|
355
482
|
await this.provider.deleteBySessionId(sessionId);
|
|
@@ -357,20 +484,42 @@ class SessionManager {
|
|
|
357
484
|
}
|
|
358
485
|
return true;
|
|
359
486
|
}
|
|
360
|
-
constructor(provider
|
|
487
|
+
constructor(provider){
|
|
488
|
+
// Store origin-specific configurations
|
|
489
|
+
this.originConfigs = new Map();
|
|
361
490
|
// Run expired cleanup only every N calls to avoid extra queries
|
|
362
491
|
this.cleanupInvocationCounter = 0;
|
|
363
492
|
this.cleanupEveryCalls = 50;
|
|
364
493
|
this.provider = provider;
|
|
365
|
-
this.config = config;
|
|
366
494
|
}
|
|
367
495
|
}
|
|
368
496
|
const createDatabaseProvider = (db, contentType)=>{
|
|
369
497
|
return new DatabaseSessionProvider(db, contentType);
|
|
370
498
|
};
|
|
371
|
-
const createSessionManager = ({ db
|
|
499
|
+
const createSessionManager = ({ db })=>{
|
|
372
500
|
const provider = createDatabaseProvider(db, 'admin::session');
|
|
373
|
-
|
|
501
|
+
const sessionManager = new SessionManager(provider);
|
|
502
|
+
// Add callable functionality
|
|
503
|
+
const fluentApi = (origin)=>{
|
|
504
|
+
if (!origin || typeof origin !== 'string') {
|
|
505
|
+
throw new Error('SessionManager: Origin parameter is required and must be a non-empty string');
|
|
506
|
+
}
|
|
507
|
+
return new OriginSessionManager(sessionManager, origin);
|
|
508
|
+
};
|
|
509
|
+
// Attach only the public SessionManagerService API to the callable
|
|
510
|
+
const api = fluentApi;
|
|
511
|
+
api.generateSessionId = sessionManager.generateSessionId.bind(sessionManager);
|
|
512
|
+
api.defineOrigin = sessionManager.defineOrigin.bind(sessionManager);
|
|
513
|
+
api.hasOrigin = sessionManager.hasOrigin.bind(sessionManager);
|
|
514
|
+
// Note: isSessionActive is origin-scoped and exposed on OriginSessionManager only
|
|
515
|
+
// Forward the cleanupThreshold getter (used in tests)
|
|
516
|
+
Object.defineProperty(api, 'cleanupThreshold', {
|
|
517
|
+
get () {
|
|
518
|
+
return sessionManager.cleanupThreshold;
|
|
519
|
+
},
|
|
520
|
+
enumerable: true
|
|
521
|
+
});
|
|
522
|
+
return api;
|
|
374
523
|
};
|
|
375
524
|
|
|
376
525
|
export { createDatabaseProvider, createSessionManager };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-manager.mjs","sources":["../../src/services/session-manager.ts"],"sourcesContent":["import crypto from 'crypto';\nimport jwt from 'jsonwebtoken';\nimport type { Algorithm, VerifyOptions } from 'jsonwebtoken';\nimport type { Database } from '@strapi/database';\nimport { DEFAULT_ALGORITHM } from '../constants';\n\nexport interface SessionProvider {\n create(session: SessionData): Promise<SessionData>;\n findBySessionId(sessionId: string): Promise<SessionData | null>;\n updateBySessionId(sessionId: string, data: Partial<SessionData>): Promise<void>;\n deleteBySessionId(sessionId: string): Promise<void>;\n deleteExpired(): Promise<void>;\n deleteBy(criteria: { userId?: string; origin?: string; deviceId?: string }): Promise<void>;\n}\n\nexport interface SessionData {\n id?: string;\n userId: string; // User ID stored as string (key-value store)\n sessionId: string;\n deviceId: string;\n origin: string;\n parentId?: string | null;\n childId?: string | null;\n familyId?: string | null;\n type?: 'refresh' | 'session';\n status?: 'active' | 'rotated' | 'revoked';\n expiresAt: Date;\n absoluteExpiresAt?: Date | null;\n createdAt?: Date;\n updatedAt?: Date;\n}\n\nexport interface RefreshTokenPayload {\n userId: string;\n sessionId: string;\n type: 'refresh';\n exp: number;\n iat: number;\n}\n\nexport interface AccessTokenPayload {\n userId: string;\n sessionId: string;\n type: 'access';\n exp: number;\n iat: number;\n}\n\nexport type TokenPayload = RefreshTokenPayload | AccessTokenPayload;\n\nexport interface ValidateRefreshTokenResult {\n isValid: boolean;\n userId?: string;\n sessionId?: string;\n error?:\n | 'invalid_token'\n | 'token_expired'\n | 'session_not_found'\n | 'session_expired'\n | 'wrong_token_type';\n}\n\nclass DatabaseSessionProvider implements SessionProvider {\n private db: Database;\n\n private contentType: string;\n\n constructor(db: Database, contentType: string) {\n this.db = db;\n this.contentType = contentType;\n }\n\n async create(session: SessionData): Promise<SessionData> {\n const result = await this.db.query(this.contentType).create({\n data: session,\n });\n return result as SessionData;\n }\n\n async findBySessionId(sessionId: string): Promise<SessionData | null> {\n const result = await this.db.query(this.contentType).findOne({\n where: { sessionId },\n });\n return result as SessionData | null;\n }\n\n async updateBySessionId(sessionId: string, data: Partial<SessionData>): Promise<void> {\n await this.db.query(this.contentType).update({ where: { sessionId }, data });\n }\n\n async deleteBySessionId(sessionId: string): Promise<void> {\n await this.db.query(this.contentType).delete({\n where: { sessionId },\n });\n }\n\n async deleteExpired(): Promise<void> {\n await this.db.query(this.contentType).deleteMany({\n where: { absoluteExpiresAt: { $lt: new Date() } },\n });\n }\n\n async deleteBy(criteria: { userId?: string; origin?: string; deviceId?: string }): Promise<void> {\n await this.db.query(this.contentType).deleteMany({\n where: {\n ...(criteria.userId ? { userId: criteria.userId } : {}),\n ...(criteria.origin ? { origin: criteria.origin } : {}),\n ...(criteria.deviceId ? { deviceId: criteria.deviceId } : {}),\n },\n });\n }\n}\n\nexport interface SessionManagerConfig {\n jwtSecret: string;\n accessTokenLifespan: number;\n maxRefreshTokenLifespan: number;\n idleRefreshTokenLifespan: number;\n maxSessionLifespan: number;\n idleSessionLifespan: number;\n /**\n * JWT signing/verification algorithm. Defaults to 'HS256' when not provided.\n */\n algorithm?: Algorithm;\n}\n\nclass SessionManager {\n private provider: SessionProvider;\n\n private config: SessionManagerConfig;\n\n // Run expired cleanup only every N calls to avoid extra queries\n private cleanupInvocationCounter: number = 0;\n\n private readonly cleanupEveryCalls: number = 50;\n\n constructor(provider: SessionProvider, config: SessionManagerConfig) {\n this.provider = provider;\n this.config = config;\n }\n\n generateSessionId(): string {\n return crypto.randomBytes(16).toString('hex');\n }\n\n private async maybeCleanupExpired(): Promise<void> {\n this.cleanupInvocationCounter += 1;\n if (this.cleanupInvocationCounter >= this.cleanupEveryCalls) {\n this.cleanupInvocationCounter = 0;\n\n await this.provider.deleteExpired();\n }\n }\n\n async generateRefreshToken(\n userId: string,\n deviceId: string,\n origin: string,\n options?: { familyType?: 'refresh' | 'session' }\n ): Promise<{ token: string; sessionId: string; absoluteExpiresAt: string; familyId: string }> {\n await this.maybeCleanupExpired();\n\n const sessionId = this.generateSessionId();\n const familyType = options?.familyType ?? 'refresh';\n const isRefresh = familyType === 'refresh';\n\n const idleLifespan = isRefresh\n ? this.config.idleRefreshTokenLifespan\n : this.config.idleSessionLifespan;\n\n const maxLifespan = isRefresh\n ? this.config.maxRefreshTokenLifespan\n : this.config.maxSessionLifespan;\n\n const now = Date.now();\n const expiresAt = new Date(now + idleLifespan * 1000);\n const absoluteExpiresAt = new Date(now + maxLifespan * 1000);\n\n // Create the root record first so createdAt can be used for signing.\n const record = await this.provider.create({\n userId,\n sessionId,\n deviceId,\n origin,\n parentId: null,\n childId: null,\n familyId: sessionId,\n type: familyType,\n status: 'active',\n expiresAt,\n absoluteExpiresAt,\n });\n\n const issuedAtSeconds = Math.floor(new Date(record.createdAt ?? new Date()).getTime() / 1000);\n const expiresAtSeconds = Math.floor(new Date(record.expiresAt).getTime() / 1000);\n\n const payload: RefreshTokenPayload = {\n userId,\n sessionId,\n type: 'refresh',\n iat: issuedAtSeconds,\n exp: expiresAtSeconds,\n };\n\n const token = jwt.sign(payload, this.config.jwtSecret, {\n algorithm: this.config.algorithm ?? DEFAULT_ALGORITHM,\n noTimestamp: true,\n });\n\n return {\n token,\n sessionId,\n absoluteExpiresAt: absoluteExpiresAt.toISOString(),\n familyId: record.familyId!,\n };\n }\n\n validateAccessToken(\n token: string\n ): { isValid: true; payload: AccessTokenPayload } | { isValid: false; payload: null } {\n try {\n const payload = jwt.verify(token, this.config.jwtSecret, {\n algorithms: [this.config.algorithm ?? DEFAULT_ALGORITHM],\n }) as TokenPayload;\n\n // Ensure this is an access token\n if (!payload || payload.type !== 'access') {\n return { isValid: false, payload: null };\n }\n\n return { isValid: true, payload };\n } catch (err) {\n return { isValid: false, payload: null };\n }\n }\n\n async validateRefreshToken(token: string): Promise<ValidateRefreshTokenResult> {\n try {\n const verifyOptions: VerifyOptions = {\n algorithms: [this.config.algorithm ?? DEFAULT_ALGORITHM],\n };\n\n const payload = jwt.verify(\n token,\n this.config.jwtSecret,\n verifyOptions\n ) as RefreshTokenPayload;\n\n if (payload.type !== 'refresh') {\n return { isValid: false };\n }\n\n const session = await this.provider.findBySessionId(payload.sessionId);\n if (!session) {\n return { isValid: false };\n }\n\n const now = new Date();\n if (new Date(session.expiresAt) <= now) {\n return { isValid: false };\n }\n\n // Absolute family expiry check\n if (session.absoluteExpiresAt && new Date(session.absoluteExpiresAt) <= now) {\n return { isValid: false };\n }\n\n // Only 'active' sessions are eligible to create access tokens.\n if (session.status !== 'active') {\n return { isValid: false };\n }\n\n if (session.userId !== payload.userId) {\n return { isValid: false };\n }\n\n return {\n isValid: true,\n userId: payload.userId,\n sessionId: payload.sessionId,\n };\n } catch (error: any) {\n if (error instanceof jwt.JsonWebTokenError) {\n return { isValid: false };\n }\n\n throw error;\n }\n }\n\n async invalidateRefreshToken(origin: string, userId: string, deviceId?: string): Promise<void> {\n await this.provider.deleteBy({ userId, origin, deviceId });\n }\n\n async generateAccessToken(refreshToken: string): Promise<{ token: string } | { error: string }> {\n const validation = await this.validateRefreshToken(refreshToken);\n\n if (!validation.isValid) {\n return { error: 'invalid_refresh_token' };\n }\n\n const payload: Omit<AccessTokenPayload, 'iat' | 'exp'> = {\n userId: String(validation.userId!),\n sessionId: validation.sessionId!,\n type: 'access',\n };\n\n const token = jwt.sign(payload, this.config.jwtSecret, {\n algorithm: this.config.algorithm ?? DEFAULT_ALGORITHM,\n expiresIn: this.config.accessTokenLifespan,\n });\n\n return { token };\n }\n\n async rotateRefreshToken(refreshToken: string): Promise<\n | {\n token: string;\n sessionId: string;\n absoluteExpiresAt: string;\n familyId: string;\n type: 'refresh' | 'session';\n }\n | { error: string }\n > {\n try {\n const payload = jwt.verify(refreshToken, this.config.jwtSecret, {\n algorithms: [this.config.algorithm ?? DEFAULT_ALGORITHM],\n }) as RefreshTokenPayload;\n\n if (!payload || payload.type !== 'refresh') {\n return { error: 'invalid_refresh_token' };\n }\n\n const current = await this.provider.findBySessionId(payload.sessionId);\n if (!current) {\n return { error: 'invalid_refresh_token' };\n }\n\n // If parent already has a child, return the same child token\n if (current.childId) {\n const child = await this.provider.findBySessionId(current.childId);\n\n if (child) {\n const childIat = Math.floor(new Date(child.createdAt ?? new Date()).getTime() / 1000);\n const childExp = Math.floor(new Date(child.expiresAt).getTime() / 1000);\n\n const childPayload: RefreshTokenPayload = {\n userId: child.userId,\n sessionId: child.sessionId,\n type: 'refresh',\n iat: childIat,\n exp: childExp,\n };\n\n const childToken = jwt.sign(childPayload, this.config.jwtSecret, {\n algorithm: this.config.algorithm ?? DEFAULT_ALGORITHM,\n noTimestamp: true,\n });\n\n let absoluteExpiresAt;\n if (child.absoluteExpiresAt) {\n absoluteExpiresAt =\n typeof child.absoluteExpiresAt === 'string'\n ? child.absoluteExpiresAt\n : child.absoluteExpiresAt.toISOString();\n } else {\n absoluteExpiresAt = new Date(0).toISOString();\n }\n\n return {\n token: childToken,\n sessionId: child.sessionId,\n absoluteExpiresAt,\n familyId: String(child.familyId ?? child.sessionId),\n type: child.type ?? 'refresh',\n };\n }\n }\n\n const now = Date.now();\n const familyType = current.type ?? 'refresh';\n const idleLifespan =\n familyType === 'refresh'\n ? this.config.idleRefreshTokenLifespan\n : this.config.idleSessionLifespan;\n\n // Enforce idle window since creation of the current token\n if (current.createdAt && now - new Date(current.createdAt).getTime() > idleLifespan * 1000) {\n return { error: 'idle_window_elapsed' };\n }\n\n // Enforce max family window using absoluteExpiresAt\n const absolute = current.absoluteExpiresAt\n ? new Date(current.absoluteExpiresAt).getTime()\n : now;\n if (absolute <= now) {\n return { error: 'max_window_elapsed' };\n }\n\n // Create child token\n const childSessionId = this.generateSessionId();\n const childExpiresAt = new Date(now + idleLifespan * 1000);\n\n const childRecord = await this.provider.create({\n userId: current.userId,\n sessionId: childSessionId,\n deviceId: current.deviceId,\n origin: current.origin,\n parentId: current.sessionId,\n childId: null,\n familyId: current.familyId ?? current.sessionId,\n type: familyType,\n status: 'active',\n expiresAt: childExpiresAt,\n absoluteExpiresAt: current.absoluteExpiresAt ?? new Date(absolute),\n });\n\n const childIat = Math.floor(new Date(childRecord.createdAt ?? new Date()).getTime() / 1000);\n const childExp = Math.floor(new Date(childRecord.expiresAt).getTime() / 1000);\n const payloadOut: RefreshTokenPayload = {\n userId: current.userId,\n sessionId: childSessionId,\n type: 'refresh',\n iat: childIat,\n exp: childExp,\n };\n const childToken = jwt.sign(payloadOut, this.config.jwtSecret, {\n algorithm: this.config.algorithm ?? DEFAULT_ALGORITHM,\n noTimestamp: true,\n });\n\n await this.provider.updateBySessionId(current.sessionId, {\n status: 'rotated',\n childId: childSessionId,\n });\n\n let absoluteExpiresAt;\n if (childRecord.absoluteExpiresAt) {\n absoluteExpiresAt =\n typeof childRecord.absoluteExpiresAt === 'string'\n ? childRecord.absoluteExpiresAt\n : childRecord.absoluteExpiresAt.toISOString();\n } else {\n absoluteExpiresAt = new Date(absolute).toISOString();\n }\n\n return {\n token: childToken,\n sessionId: childSessionId,\n absoluteExpiresAt,\n familyId: String(childRecord.familyId ?? childRecord.sessionId),\n type: familyType,\n };\n } catch {\n return { error: 'invalid_refresh_token' };\n }\n }\n\n /**\n * Returns true when a session exists and is not expired.\n * If the session exists but is expired, it will be deleted as part of this check.\n */\n async isSessionActive(sessionId: string): Promise<boolean> {\n const session = await this.provider.findBySessionId(sessionId);\n if (!session) {\n return false;\n }\n\n if (new Date(session.expiresAt) <= new Date()) {\n // Clean up expired session eagerly\n await this.provider.deleteBySessionId(sessionId);\n\n return false;\n }\n\n return true;\n }\n}\n\nconst createDatabaseProvider = (db: Database, contentType: string): SessionProvider => {\n return new DatabaseSessionProvider(db, contentType);\n};\n\nconst createSessionManager = ({ db, config }: { db: Database; config: SessionManagerConfig }) => {\n const provider = createDatabaseProvider(db, 'admin::session');\n return new SessionManager(provider, config);\n};\n\nexport { createSessionManager, createDatabaseProvider };\n"],"names":["DatabaseSessionProvider","create","session","result","db","query","contentType","data","findBySessionId","sessionId","findOne","where","updateBySessionId","update","deleteBySessionId","delete","deleteExpired","deleteMany","absoluteExpiresAt","$lt","Date","deleteBy","criteria","userId","origin","deviceId","constructor","SessionManager","generateSessionId","crypto","randomBytes","toString","maybeCleanupExpired","cleanupInvocationCounter","cleanupEveryCalls","provider","generateRefreshToken","options","familyType","isRefresh","idleLifespan","config","idleRefreshTokenLifespan","idleSessionLifespan","maxLifespan","maxRefreshTokenLifespan","maxSessionLifespan","now","expiresAt","record","parentId","childId","familyId","type","status","issuedAtSeconds","Math","floor","createdAt","getTime","expiresAtSeconds","payload","iat","exp","token","jwt","sign","jwtSecret","algorithm","DEFAULT_ALGORITHM","noTimestamp","toISOString","validateAccessToken","verify","algorithms","isValid","err","validateRefreshToken","verifyOptions","error","JsonWebTokenError","invalidateRefreshToken","generateAccessToken","refreshToken","validation","String","expiresIn","accessTokenLifespan","rotateRefreshToken","current","child","childIat","childExp","childPayload","childToken","absolute","childSessionId","childExpiresAt","childRecord","payloadOut","isSessionActive","createDatabaseProvider","createSessionManager"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"session-manager.mjs","sources":["../../src/services/session-manager.ts"],"sourcesContent":["import crypto from 'crypto';\nimport jwt from 'jsonwebtoken';\nimport type { VerifyOptions, Algorithm } from 'jsonwebtoken';\nimport type { Database } from '@strapi/database';\nimport { DEFAULT_ALGORITHM } from '../constants';\n\nexport interface SessionProvider {\n create(session: SessionData): Promise<SessionData>;\n findBySessionId(sessionId: string): Promise<SessionData | null>;\n updateBySessionId(sessionId: string, data: Partial<SessionData>): Promise<void>;\n deleteBySessionId(sessionId: string): Promise<void>;\n deleteExpired(): Promise<void>;\n deleteBy(criteria: { userId?: string; origin?: string; deviceId?: string }): Promise<void>;\n}\n\nexport interface SessionData {\n id?: string;\n userId: string; // User ID stored as string (key-value store)\n sessionId: string;\n deviceId?: string; // Optional for origins that don't need device tracking\n origin: string;\n childId?: string | null;\n\n type?: 'refresh' | 'session';\n status?: 'active' | 'rotated' | 'revoked';\n expiresAt: Date;\n absoluteExpiresAt?: Date | null;\n createdAt?: Date;\n updatedAt?: Date;\n}\n\nexport interface RefreshTokenPayload {\n userId: string;\n sessionId: string;\n type: 'refresh';\n exp: number;\n iat: number;\n}\n\nexport interface AccessTokenPayload {\n userId: string;\n sessionId: string;\n type: 'access';\n exp: number;\n iat: number;\n}\n\nexport type TokenPayload = RefreshTokenPayload | AccessTokenPayload;\n\nexport interface ValidateRefreshTokenResult {\n isValid: boolean;\n userId?: string;\n sessionId?: string;\n error?:\n | 'invalid_token'\n | 'token_expired'\n | 'session_not_found'\n | 'session_expired'\n | 'wrong_token_type';\n}\n\nclass DatabaseSessionProvider implements SessionProvider {\n private db: Database;\n\n private contentType: string;\n\n constructor(db: Database, contentType: string) {\n this.db = db;\n this.contentType = contentType;\n }\n\n async create(session: SessionData): Promise<SessionData> {\n const result = await this.db.query(this.contentType).create({\n data: session,\n });\n return result as SessionData;\n }\n\n async findBySessionId(sessionId: string): Promise<SessionData | null> {\n const result = await this.db.query(this.contentType).findOne({\n where: { sessionId },\n });\n return result as SessionData | null;\n }\n\n async updateBySessionId(sessionId: string, data: Partial<SessionData>): Promise<void> {\n await this.db.query(this.contentType).update({ where: { sessionId }, data });\n }\n\n async deleteBySessionId(sessionId: string): Promise<void> {\n await this.db.query(this.contentType).delete({\n where: { sessionId },\n });\n }\n\n async deleteExpired(): Promise<void> {\n await this.db.query(this.contentType).deleteMany({\n where: { absoluteExpiresAt: { $lt: new Date() } },\n });\n }\n\n async deleteBy(criteria: { userId?: string; origin?: string; deviceId?: string }): Promise<void> {\n await this.db.query(this.contentType).deleteMany({\n where: {\n ...(criteria.userId ? { userId: criteria.userId } : {}),\n ...(criteria.origin ? { origin: criteria.origin } : {}),\n ...(criteria.deviceId ? { deviceId: criteria.deviceId } : {}),\n },\n });\n }\n}\n\nexport interface SessionManagerConfig {\n jwtSecret?: string;\n accessTokenLifespan: number;\n maxRefreshTokenLifespan: number;\n idleRefreshTokenLifespan: number;\n maxSessionLifespan: number;\n idleSessionLifespan: number;\n algorithm?: Algorithm;\n jwtOptions?: Record<string, unknown>;\n}\n\nclass OriginSessionManager {\n constructor(\n private sessionManager: SessionManager,\n private origin: string\n ) {}\n\n async generateRefreshToken(\n userId: string,\n deviceId: string | undefined,\n options?: { type?: 'refresh' | 'session' }\n ): Promise<{ token: string; sessionId: string; absoluteExpiresAt: string }> {\n return this.sessionManager.generateRefreshToken(userId, deviceId, this.origin, options);\n }\n\n async generateAccessToken(refreshToken: string): Promise<{ token: string } | { error: string }> {\n return this.sessionManager.generateAccessToken(refreshToken, this.origin);\n }\n\n async rotateRefreshToken(refreshToken: string): Promise<\n | {\n token: string;\n sessionId: string;\n absoluteExpiresAt: string;\n type: 'refresh' | 'session';\n }\n | { error: string }\n > {\n return this.sessionManager.rotateRefreshToken(refreshToken, this.origin);\n }\n\n validateAccessToken(\n token: string\n ): { isValid: true; payload: AccessTokenPayload } | { isValid: false; payload: null } {\n return this.sessionManager.validateAccessToken(token, this.origin);\n }\n\n async validateRefreshToken(token: string): Promise<ValidateRefreshTokenResult> {\n return this.sessionManager.validateRefreshToken(token, this.origin);\n }\n\n async invalidateRefreshToken(userId: string, deviceId?: string): Promise<void> {\n return this.sessionManager.invalidateRefreshToken(this.origin, userId, deviceId);\n }\n\n /**\n * Returns true when a session exists and is not expired for this origin.\n * If the session exists but is expired, it will be deleted as part of this check.\n */\n async isSessionActive(sessionId: string): Promise<boolean> {\n return this.sessionManager.isSessionActive(sessionId, this.origin);\n }\n}\n\nclass SessionManager {\n private provider: SessionProvider;\n\n // Store origin-specific configurations\n private originConfigs: Map<string, SessionManagerConfig> = new Map();\n\n // Run expired cleanup only every N calls to avoid extra queries\n private cleanupInvocationCounter: number = 0;\n\n private readonly cleanupEveryCalls: number = 50;\n\n constructor(provider: SessionProvider) {\n this.provider = provider;\n }\n\n /**\n * Define configuration for a specific origin\n */\n defineOrigin(origin: string, config: SessionManagerConfig): void {\n this.originConfigs.set(origin, config);\n }\n\n /**\n * Check if an origin is defined\n */\n hasOrigin(origin: string): boolean {\n return this.originConfigs.has(origin);\n }\n\n /**\n * Get configuration for a specific origin, throw error if not defined\n */\n private getConfigForOrigin(origin: string): SessionManagerConfig {\n const originConfig = this.originConfigs.get(origin);\n if (originConfig) {\n return originConfig;\n }\n throw new Error(\n `SessionManager: Origin '${origin}' is not defined. Please define it using defineOrigin('${origin}', config).`\n );\n }\n\n /**\n * Get the appropriate JWT key based on the algorithm\n */\n private getJwtKey(\n config: SessionManagerConfig,\n algorithm: Algorithm,\n operation: 'sign' | 'verify'\n ): string {\n const isAsymmetric =\n algorithm.startsWith('RS') || algorithm.startsWith('ES') || algorithm.startsWith('PS');\n\n if (isAsymmetric) {\n // For asymmetric algorithms, check if user has provided proper key configuration\n if (operation === 'sign') {\n const privateKey = config.jwtOptions?.privateKey as string;\n if (privateKey) {\n return privateKey;\n }\n throw new Error(\n `SessionManager: Private key is required for asymmetric algorithm ${algorithm}. Please configure admin.auth.options.privateKey.`\n );\n } else {\n const publicKey = config.jwtOptions?.publicKey as string;\n if (publicKey) {\n return publicKey;\n }\n throw new Error(\n `SessionManager: Public key is required for asymmetric algorithm ${algorithm}. Please configure admin.auth.options.publicKey.`\n );\n }\n } else {\n if (!config.jwtSecret) {\n throw new Error(\n `SessionManager: Secret key is required for symmetric algorithm ${algorithm}`\n );\n }\n return config.jwtSecret;\n }\n }\n\n generateSessionId(): string {\n return crypto.randomBytes(16).toString('hex');\n }\n\n private async maybeCleanupExpired(): Promise<void> {\n this.cleanupInvocationCounter += 1;\n if (this.cleanupInvocationCounter >= this.cleanupEveryCalls) {\n this.cleanupInvocationCounter = 0;\n\n await this.provider.deleteExpired();\n }\n }\n\n /**\n * Get the cleanup every calls threshold\n */\n get cleanupThreshold(): number {\n return this.cleanupEveryCalls;\n }\n\n async generateRefreshToken(\n userId: string,\n deviceId: string | undefined,\n origin: string,\n options?: { type?: 'refresh' | 'session' }\n ): Promise<{ token: string; sessionId: string; absoluteExpiresAt: string }> {\n if (!origin || typeof origin !== 'string') {\n throw new Error(\n 'SessionManager: Origin parameter is required and must be a non-empty string'\n );\n }\n\n await this.maybeCleanupExpired();\n\n const config = this.getConfigForOrigin(origin);\n const algorithm = config.algorithm || DEFAULT_ALGORITHM;\n const jwtKey = this.getJwtKey(config, algorithm, 'sign');\n const sessionId = this.generateSessionId();\n const tokenType = options?.type ?? 'refresh';\n const isRefresh = tokenType === 'refresh';\n\n const idleLifespan = isRefresh ? config.idleRefreshTokenLifespan : config.idleSessionLifespan;\n\n const maxLifespan = isRefresh ? config.maxRefreshTokenLifespan : config.maxSessionLifespan;\n\n const now = Date.now();\n const expiresAt = new Date(now + idleLifespan * 1000);\n const absoluteExpiresAt = new Date(now + maxLifespan * 1000);\n\n // Create the root record first so createdAt can be used for signing.\n const record = await this.provider.create({\n userId,\n sessionId,\n ...(deviceId && { deviceId }),\n origin,\n childId: null,\n type: tokenType,\n status: 'active',\n expiresAt,\n absoluteExpiresAt,\n });\n\n const issuedAtSeconds = Math.floor(new Date(record.createdAt ?? new Date()).getTime() / 1000);\n const expiresAtSeconds = Math.floor(new Date(record.expiresAt).getTime() / 1000);\n\n const payload: RefreshTokenPayload = {\n userId,\n sessionId,\n type: 'refresh',\n iat: issuedAtSeconds,\n exp: expiresAtSeconds,\n };\n\n // Filter out conflicting options that are already handled by the payload or used for key selection\n const jwtOptions = config.jwtOptions || {};\n const { expiresIn, privateKey, publicKey, ...jwtSignOptions } = jwtOptions;\n\n const token = jwt.sign(payload, jwtKey, {\n algorithm,\n noTimestamp: true,\n ...jwtSignOptions,\n });\n\n return {\n token,\n sessionId,\n absoluteExpiresAt: absoluteExpiresAt.toISOString(),\n };\n }\n\n validateAccessToken(\n token: string,\n origin: string\n ): { isValid: true; payload: AccessTokenPayload } | { isValid: false; payload: null } {\n if (!origin || typeof origin !== 'string') {\n throw new Error(\n 'SessionManager: Origin parameter is required and must be a non-empty string'\n );\n }\n\n try {\n const config = this.getConfigForOrigin(origin);\n const algorithm = config.algorithm || DEFAULT_ALGORITHM;\n const jwtKey = this.getJwtKey(config, algorithm, 'verify');\n const payload = jwt.verify(token, jwtKey, {\n algorithms: [algorithm],\n ...config.jwtOptions,\n }) as TokenPayload;\n\n // Ensure this is an access token\n if (!payload || payload.type !== 'access') {\n return { isValid: false, payload: null };\n }\n\n return { isValid: true, payload };\n } catch (err) {\n return { isValid: false, payload: null };\n }\n }\n\n async validateRefreshToken(token: string, origin: string): Promise<ValidateRefreshTokenResult> {\n if (!origin || typeof origin !== 'string') {\n throw new Error(\n 'SessionManager: Origin parameter is required and must be a non-empty string'\n );\n }\n\n try {\n const config = this.getConfigForOrigin(origin);\n const algorithm = config.algorithm || DEFAULT_ALGORITHM;\n const jwtKey = this.getJwtKey(config, algorithm, 'verify');\n const verifyOptions: VerifyOptions = {\n algorithms: [algorithm],\n ...config.jwtOptions,\n };\n\n const payload = jwt.verify(token, jwtKey, verifyOptions) as RefreshTokenPayload;\n\n if (payload.type !== 'refresh') {\n return { isValid: false };\n }\n\n const session = await this.provider.findBySessionId(payload.sessionId);\n if (!session) {\n return { isValid: false };\n }\n\n const now = new Date();\n if (new Date(session.expiresAt) <= now) {\n return { isValid: false };\n }\n\n // Absolute family expiry check\n if (session.absoluteExpiresAt && new Date(session.absoluteExpiresAt) <= now) {\n return { isValid: false };\n }\n\n // Only 'active' sessions are eligible to create access tokens.\n if (session.status !== 'active') {\n return { isValid: false };\n }\n\n if (session.userId !== payload.userId) {\n return { isValid: false };\n }\n\n return {\n isValid: true,\n userId: payload.userId,\n sessionId: payload.sessionId,\n };\n } catch (error: any) {\n if (error instanceof jwt.JsonWebTokenError) {\n return { isValid: false };\n }\n\n throw error;\n }\n }\n\n async invalidateRefreshToken(origin: string, userId: string, deviceId?: string): Promise<void> {\n await this.provider.deleteBy({ userId, origin, deviceId });\n }\n\n async generateAccessToken(\n refreshToken: string,\n origin: string\n ): Promise<{ token: string } | { error: string }> {\n if (!origin || typeof origin !== 'string') {\n throw new Error(\n 'SessionManager: Origin parameter is required and must be a non-empty string'\n );\n }\n\n const validation = await this.validateRefreshToken(refreshToken, origin);\n\n if (!validation.isValid) {\n return { error: 'invalid_refresh_token' };\n }\n\n const payload: Omit<AccessTokenPayload, 'iat' | 'exp'> = {\n userId: String(validation.userId!),\n sessionId: validation.sessionId!,\n type: 'access',\n };\n\n const config = this.getConfigForOrigin(origin);\n const algorithm = config.algorithm || DEFAULT_ALGORITHM;\n const jwtKey = this.getJwtKey(config, algorithm, 'sign');\n // Filter out conflicting options that are already handled by the payload or used for key selection\n const jwtOptions = config.jwtOptions || {};\n const { expiresIn, privateKey, publicKey, ...jwtSignOptions } = jwtOptions;\n\n const token = jwt.sign(payload, jwtKey, {\n algorithm,\n expiresIn: config.accessTokenLifespan,\n ...jwtSignOptions,\n });\n\n return { token };\n }\n\n async rotateRefreshToken(\n refreshToken: string,\n origin: string\n ): Promise<\n | {\n token: string;\n sessionId: string;\n absoluteExpiresAt: string;\n type: 'refresh' | 'session';\n }\n | { error: string }\n > {\n if (!origin || typeof origin !== 'string') {\n throw new Error(\n 'SessionManager: Origin parameter is required and must be a non-empty string'\n );\n }\n\n try {\n const config = this.getConfigForOrigin(origin);\n const algorithm = config.algorithm || DEFAULT_ALGORITHM;\n const jwtKey = this.getJwtKey(config, algorithm, 'verify');\n const payload = jwt.verify(refreshToken, jwtKey, {\n algorithms: [algorithm],\n ...config.jwtOptions,\n }) as RefreshTokenPayload;\n\n if (!payload || payload.type !== 'refresh') {\n return { error: 'invalid_refresh_token' };\n }\n\n const current = await this.provider.findBySessionId(payload.sessionId);\n if (!current) {\n return { error: 'invalid_refresh_token' };\n }\n\n // If parent already has a child, return the same child token\n if (current.childId) {\n const child = await this.provider.findBySessionId(current.childId);\n\n if (child) {\n const childIat = Math.floor(new Date(child.createdAt ?? new Date()).getTime() / 1000);\n const childExp = Math.floor(new Date(child.expiresAt).getTime() / 1000);\n\n const childPayload: RefreshTokenPayload = {\n userId: child.userId,\n sessionId: child.sessionId,\n type: 'refresh',\n iat: childIat,\n exp: childExp,\n };\n\n // Filter out conflicting options that are already handled by the payload\n const { expiresIn, ...jwtSignOptions } = config.jwtOptions || {};\n\n const childToken = jwt.sign(childPayload, jwtKey, {\n algorithm,\n noTimestamp: true,\n ...jwtSignOptions,\n });\n\n let absoluteExpiresAt;\n if (child.absoluteExpiresAt) {\n absoluteExpiresAt =\n typeof child.absoluteExpiresAt === 'string'\n ? child.absoluteExpiresAt\n : child.absoluteExpiresAt.toISOString();\n } else {\n absoluteExpiresAt = new Date(0).toISOString();\n }\n\n return {\n token: childToken,\n sessionId: child.sessionId,\n absoluteExpiresAt,\n type: child.type ?? 'refresh',\n };\n }\n }\n\n const now = Date.now();\n const tokenType = current.type ?? 'refresh';\n const idleLifespan =\n tokenType === 'refresh' ? config.idleRefreshTokenLifespan : config.idleSessionLifespan;\n\n // Enforce idle window since creation of the current token\n if (current.createdAt && now - new Date(current.createdAt).getTime() > idleLifespan * 1000) {\n return { error: 'idle_window_elapsed' };\n }\n\n // Enforce max family window using absoluteExpiresAt\n const absolute = current.absoluteExpiresAt\n ? new Date(current.absoluteExpiresAt).getTime()\n : now;\n if (absolute <= now) {\n return { error: 'max_window_elapsed' };\n }\n\n // Create child token\n const childSessionId = this.generateSessionId();\n const childExpiresAt = new Date(now + idleLifespan * 1000);\n\n const childRecord = await this.provider.create({\n userId: current.userId,\n sessionId: childSessionId,\n ...(current.deviceId && { deviceId: current.deviceId }),\n origin: current.origin,\n childId: null,\n type: tokenType,\n status: 'active',\n expiresAt: childExpiresAt,\n absoluteExpiresAt: current.absoluteExpiresAt ?? new Date(absolute),\n });\n\n const childIat = Math.floor(new Date(childRecord.createdAt ?? new Date()).getTime() / 1000);\n const childExp = Math.floor(new Date(childRecord.expiresAt).getTime() / 1000);\n const payloadOut: RefreshTokenPayload = {\n userId: current.userId,\n sessionId: childSessionId,\n type: 'refresh',\n iat: childIat,\n exp: childExp,\n };\n // Filter out conflicting options that are already handled by the payload\n const { expiresIn, ...jwtSignOptions } = config.jwtOptions || {};\n\n const childToken = jwt.sign(payloadOut, jwtKey, {\n algorithm,\n noTimestamp: true,\n ...jwtSignOptions,\n });\n\n await this.provider.updateBySessionId(current.sessionId, {\n status: 'rotated',\n childId: childSessionId,\n });\n\n let absoluteExpiresAt;\n if (childRecord.absoluteExpiresAt) {\n absoluteExpiresAt =\n typeof childRecord.absoluteExpiresAt === 'string'\n ? childRecord.absoluteExpiresAt\n : childRecord.absoluteExpiresAt.toISOString();\n } else {\n absoluteExpiresAt = new Date(absolute).toISOString();\n }\n\n return {\n token: childToken,\n sessionId: childSessionId,\n absoluteExpiresAt,\n type: tokenType,\n };\n } catch {\n return { error: 'invalid_refresh_token' };\n }\n }\n\n /**\n * Returns true when a session exists and is not expired.\n * If the session exists but is expired, it will be deleted as part of this check.\n */\n async isSessionActive(sessionId: string, origin: string): Promise<boolean> {\n const session = await this.provider.findBySessionId(sessionId);\n if (!session) {\n return false;\n }\n\n if (session.origin !== origin) {\n return false;\n }\n\n if (new Date(session.expiresAt) <= new Date()) {\n // Clean up expired session eagerly\n await this.provider.deleteBySessionId(sessionId);\n\n return false;\n }\n\n return true;\n }\n}\n\nconst createDatabaseProvider = (db: Database, contentType: string): SessionProvider => {\n return new DatabaseSessionProvider(db, contentType);\n};\n\nconst createSessionManager = ({\n db,\n}: {\n db: Database;\n}): SessionManager & ((origin: string) => OriginSessionManager) => {\n const provider = createDatabaseProvider(db, 'admin::session');\n const sessionManager = new SessionManager(provider);\n\n // Add callable functionality\n const fluentApi = (origin: string): OriginSessionManager => {\n if (!origin || typeof origin !== 'string') {\n throw new Error(\n 'SessionManager: Origin parameter is required and must be a non-empty string'\n );\n }\n return new OriginSessionManager(sessionManager, origin);\n };\n\n // Attach only the public SessionManagerService API to the callable\n const api = fluentApi as unknown as any;\n api.generateSessionId = sessionManager.generateSessionId.bind(sessionManager);\n api.defineOrigin = sessionManager.defineOrigin.bind(sessionManager);\n api.hasOrigin = sessionManager.hasOrigin.bind(sessionManager);\n // Note: isSessionActive is origin-scoped and exposed on OriginSessionManager only\n\n // Forward the cleanupThreshold getter (used in tests)\n Object.defineProperty(api, 'cleanupThreshold', {\n get() {\n return sessionManager.cleanupThreshold;\n },\n enumerable: true,\n });\n\n return api as SessionManager & ((origin: string) => OriginSessionManager);\n};\n\nexport { createSessionManager, createDatabaseProvider };\n"],"names":["DatabaseSessionProvider","create","session","result","db","query","contentType","data","findBySessionId","sessionId","findOne","where","updateBySessionId","update","deleteBySessionId","delete","deleteExpired","deleteMany","absoluteExpiresAt","$lt","Date","deleteBy","criteria","userId","origin","deviceId","constructor","OriginSessionManager","generateRefreshToken","options","sessionManager","generateAccessToken","refreshToken","rotateRefreshToken","validateAccessToken","token","validateRefreshToken","invalidateRefreshToken","isSessionActive","SessionManager","defineOrigin","config","originConfigs","set","hasOrigin","has","getConfigForOrigin","originConfig","get","Error","algorithm","operation","isAsymmetric","startsWith","privateKey","jwtOptions","publicKey","jwtSecret","generateSessionId","crypto","randomBytes","toString","maybeCleanupExpired","cleanupInvocationCounter","cleanupEveryCalls","provider","cleanupThreshold","DEFAULT_ALGORITHM","jwtKey","getJwtKey","tokenType","type","isRefresh","idleLifespan","idleRefreshTokenLifespan","idleSessionLifespan","maxLifespan","maxRefreshTokenLifespan","maxSessionLifespan","now","expiresAt","record","childId","status","issuedAtSeconds","Math","floor","createdAt","getTime","expiresAtSeconds","payload","iat","exp","expiresIn","jwtSignOptions","jwt","sign","noTimestamp","toISOString","verify","algorithms","isValid","err","verifyOptions","error","JsonWebTokenError","validation","String","accessTokenLifespan","current","child","childIat","childExp","childPayload","childToken","absolute","childSessionId","childExpiresAt","childRecord","payloadOut","Map","createDatabaseProvider","createSessionManager","fluentApi","api","bind","Object","defineProperty","enumerable"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@strapi/core",
|
|
3
|
-
"version": "0.0.0-experimental.
|
|
3
|
+
"version": "0.0.0-experimental.011bfeb83dc6344ffdc0f9c757af54f61c74e22f",
|
|
4
4
|
"description": "Core of Strapi",
|
|
5
5
|
"homepage": "https://strapi.io",
|
|
6
6
|
"bugs": {
|
|
@@ -56,14 +56,14 @@
|
|
|
56
56
|
"@koa/cors": "5.0.0",
|
|
57
57
|
"@koa/router": "12.0.2",
|
|
58
58
|
"@paralleldrive/cuid2": "2.2.2",
|
|
59
|
-
"@strapi/admin": "0.0.0-experimental.
|
|
60
|
-
"@strapi/database": "0.0.0-experimental.
|
|
61
|
-
"@strapi/generators": "0.0.0-experimental.
|
|
62
|
-
"@strapi/logger": "0.0.0-experimental.
|
|
63
|
-
"@strapi/permissions": "0.0.0-experimental.
|
|
64
|
-
"@strapi/types": "0.0.0-experimental.
|
|
65
|
-
"@strapi/typescript-utils": "0.0.0-experimental.
|
|
66
|
-
"@strapi/utils": "0.0.0-experimental.
|
|
59
|
+
"@strapi/admin": "0.0.0-experimental.011bfeb83dc6344ffdc0f9c757af54f61c74e22f",
|
|
60
|
+
"@strapi/database": "0.0.0-experimental.011bfeb83dc6344ffdc0f9c757af54f61c74e22f",
|
|
61
|
+
"@strapi/generators": "0.0.0-experimental.011bfeb83dc6344ffdc0f9c757af54f61c74e22f",
|
|
62
|
+
"@strapi/logger": "0.0.0-experimental.011bfeb83dc6344ffdc0f9c757af54f61c74e22f",
|
|
63
|
+
"@strapi/permissions": "0.0.0-experimental.011bfeb83dc6344ffdc0f9c757af54f61c74e22f",
|
|
64
|
+
"@strapi/types": "0.0.0-experimental.011bfeb83dc6344ffdc0f9c757af54f61c74e22f",
|
|
65
|
+
"@strapi/typescript-utils": "0.0.0-experimental.011bfeb83dc6344ffdc0f9c757af54f61c74e22f",
|
|
66
|
+
"@strapi/utils": "0.0.0-experimental.011bfeb83dc6344ffdc0f9c757af54f61c74e22f",
|
|
67
67
|
"@vercel/stega": "0.1.2",
|
|
68
68
|
"bcryptjs": "2.4.3",
|
|
69
69
|
"boxen": "5.1.2",
|
|
@@ -131,12 +131,12 @@
|
|
|
131
131
|
"@types/node": "18.19.24",
|
|
132
132
|
"@types/node-schedule": "2.1.7",
|
|
133
133
|
"@types/statuses": "2.0.1",
|
|
134
|
-
"eslint-config-custom": "0.0.0-experimental.
|
|
134
|
+
"eslint-config-custom": "0.0.0-experimental.011bfeb83dc6344ffdc0f9c757af54f61c74e22f",
|
|
135
135
|
"supertest": "6.3.3",
|
|
136
|
-
"tsconfig": "0.0.0-experimental.
|
|
136
|
+
"tsconfig": "0.0.0-experimental.011bfeb83dc6344ffdc0f9c757af54f61c74e22f"
|
|
137
137
|
},
|
|
138
138
|
"engines": {
|
|
139
|
-
"node": ">=
|
|
139
|
+
"node": ">=20.0.0 <=24.x.x",
|
|
140
140
|
"npm": ">=6.0.0"
|
|
141
141
|
}
|
|
142
142
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sessionManager.d.ts","sourceRoot":"","sources":["../../src/providers/sessionManager.ts"],"names":[],"mappings":";AAYA,wBAkDG"}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var provider = require('./provider.js');
|
|
4
|
-
var sessionManager$1 = require('../services/session-manager.js');
|
|
5
|
-
|
|
6
|
-
var sessionManager = provider.defineProvider({
|
|
7
|
-
init (strapi) {
|
|
8
|
-
// Get JWT secret from admin auth settings (same as admin token service)
|
|
9
|
-
const adminAuth = strapi.config.get('admin.auth', {});
|
|
10
|
-
const jwtSecret = adminAuth.secret;
|
|
11
|
-
if (!jwtSecret) {
|
|
12
|
-
throw new Error('Missing admin.auth.secret configuration. The SessionManager requires a JWT secret');
|
|
13
|
-
}
|
|
14
|
-
const accessTokenLifespan = strapi.config.get('admin.auth.sessions.accessTokenLifespan', 30 * 60);
|
|
15
|
-
const maxRefreshTokenLifespan = strapi.config.get('admin.auth.sessions.maxRefreshTokenLifespan', 30 * 24 * 60 * 60);
|
|
16
|
-
const idleRefreshTokenLifespan = strapi.config.get('admin.auth.sessions.idleRefreshTokenLifespan', 7 * 24 * 60 * 60);
|
|
17
|
-
const maxSessionLifespan = strapi.config.get('admin.auth.sessions.maxSessionLifespan', 7 * 24 * 60 * 60);
|
|
18
|
-
const idleSessionLifespan = strapi.config.get('admin.auth.sessions.idleSessionLifespan', 60 * 60);
|
|
19
|
-
const config = {
|
|
20
|
-
jwtSecret,
|
|
21
|
-
accessTokenLifespan,
|
|
22
|
-
maxRefreshTokenLifespan,
|
|
23
|
-
idleRefreshTokenLifespan,
|
|
24
|
-
maxSessionLifespan,
|
|
25
|
-
idleSessionLifespan,
|
|
26
|
-
algorithm: adminAuth.options?.algorithm
|
|
27
|
-
};
|
|
28
|
-
strapi.add('sessionManager', ()=>sessionManager$1.createSessionManager({
|
|
29
|
-
db: strapi.db,
|
|
30
|
-
config
|
|
31
|
-
}));
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
module.exports = sessionManager;
|
|
36
|
-
//# sourceMappingURL=sessionManager.js.map
|