strapi-plugin-magic-sessionmanager 4.3.1 → 4.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/server/index.js +125 -31
- package/dist/server/index.mjs +125 -31
- package/package.json +1 -1
package/dist/server/index.js
CHANGED
|
@@ -319,6 +319,8 @@ var lastSeen = ({ strapi: strapi2, sessionService }) => {
|
|
|
319
319
|
userDocId2 = await getDocumentIdFromNumericId(strapi2, ctx.state.user.id);
|
|
320
320
|
}
|
|
321
321
|
if (userDocId2) {
|
|
322
|
+
const config2 = strapi2.config.get("plugin::magic-sessionmanager") || {};
|
|
323
|
+
const strictMode = config2.strictSessionEnforcement === true;
|
|
322
324
|
const activeSessions = await strapi2.documents(SESSION_UID$4).findMany({
|
|
323
325
|
filters: {
|
|
324
326
|
user: { documentId: userDocId2 },
|
|
@@ -327,8 +329,17 @@ var lastSeen = ({ strapi: strapi2, sessionService }) => {
|
|
|
327
329
|
limit: 1
|
|
328
330
|
});
|
|
329
331
|
if (!activeSessions || activeSessions.length === 0) {
|
|
330
|
-
|
|
331
|
-
|
|
332
|
+
const allSessions = await strapi2.documents(SESSION_UID$4).findMany({
|
|
333
|
+
filters: { user: { documentId: userDocId2 } },
|
|
334
|
+
limit: 1,
|
|
335
|
+
fields: ["isActive"]
|
|
336
|
+
});
|
|
337
|
+
const hasInactiveSessions = allSessions?.some((s3) => s3.isActive === false);
|
|
338
|
+
if (strictMode && hasInactiveSessions) {
|
|
339
|
+
strapi2.log.info(`[magic-sessionmanager] [BLOCKED] Session terminated (user: ${userDocId2.substring(0, 8)}...)`);
|
|
340
|
+
return ctx.unauthorized("Session has been terminated. Please login again.");
|
|
341
|
+
}
|
|
342
|
+
strapi2.log.debug(`[magic-sessionmanager] [WARN] No active session for user ${userDocId2.substring(0, 8)}... (allowing)`);
|
|
332
343
|
}
|
|
333
344
|
ctx.state.userDocumentId = userDocId2;
|
|
334
345
|
}
|
|
@@ -516,9 +527,20 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
516
527
|
}
|
|
517
528
|
let userDocId = user.documentId;
|
|
518
529
|
if (!userDocId && user.id) {
|
|
519
|
-
const fullUser = await strapi2.entityService.findOne(USER_UID$2, user.id
|
|
520
|
-
|
|
530
|
+
const fullUser = await strapi2.entityService.findOne(USER_UID$2, user.id, {
|
|
531
|
+
fields: ["documentId"]
|
|
532
|
+
});
|
|
533
|
+
userDocId = fullUser?.documentId;
|
|
534
|
+
if (!userDocId) {
|
|
535
|
+
log.error(`[ERROR] Could not get documentId for user ${user.id} - session NOT created!`);
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
521
538
|
}
|
|
539
|
+
if (!userDocId) {
|
|
540
|
+
log.error("[ERROR] No user documentId available - cannot create session");
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
log.debug(`[SESSION] Creating session for user documentId: ${userDocId}`);
|
|
522
544
|
const newSession = await sessionService.createSession({
|
|
523
545
|
userId: userDocId,
|
|
524
546
|
ip,
|
|
@@ -530,7 +552,11 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
530
552
|
geoData
|
|
531
553
|
// Store geolocation data if available
|
|
532
554
|
});
|
|
533
|
-
|
|
555
|
+
if (newSession?.documentId) {
|
|
556
|
+
log.info(`[SUCCESS] Session ${newSession.documentId} created for user ${userDocId} (IP: ${ip})`);
|
|
557
|
+
} else {
|
|
558
|
+
log.error(`[ERROR] Session creation returned no documentId for user ${userDocId}`);
|
|
559
|
+
}
|
|
534
560
|
if (geoData && (config2.enableEmailAlerts || config2.enableWebhooks)) {
|
|
535
561
|
try {
|
|
536
562
|
const notificationService = strapi2.plugin("magic-sessionmanager").service("notifications");
|
|
@@ -760,6 +786,8 @@ async function registerSessionAwareAuthStrategy(strapi2, log) {
|
|
|
760
786
|
if (!decoded || !decoded.id) {
|
|
761
787
|
return decoded;
|
|
762
788
|
}
|
|
789
|
+
const config2 = strapi2.config.get("plugin::magic-sessionmanager") || {};
|
|
790
|
+
const strictMode = config2.strictSessionEnforcement === true;
|
|
763
791
|
try {
|
|
764
792
|
let userDocId = null;
|
|
765
793
|
const user = await strapi2.entityService.findOne(
|
|
@@ -769,6 +797,7 @@ async function registerSessionAwareAuthStrategy(strapi2, log) {
|
|
|
769
797
|
);
|
|
770
798
|
userDocId = user?.documentId;
|
|
771
799
|
if (!userDocId) {
|
|
800
|
+
strapi2.log.debug("[magic-sessionmanager] [JWT] No documentId found, allowing through");
|
|
772
801
|
return decoded;
|
|
773
802
|
}
|
|
774
803
|
const activeSessions = await strapi2.documents(SESSION_UID$3).findMany({
|
|
@@ -778,15 +807,46 @@ async function registerSessionAwareAuthStrategy(strapi2, log) {
|
|
|
778
807
|
},
|
|
779
808
|
limit: 1
|
|
780
809
|
});
|
|
781
|
-
if (
|
|
810
|
+
if (activeSessions && activeSessions.length > 0) {
|
|
811
|
+
return decoded;
|
|
812
|
+
}
|
|
813
|
+
const allSessions = await strapi2.documents(SESSION_UID$3).findMany({
|
|
814
|
+
filters: { user: { documentId: userDocId } },
|
|
815
|
+
limit: 5,
|
|
816
|
+
fields: ["isActive", "lastActive"]
|
|
817
|
+
});
|
|
818
|
+
const totalSessions = allSessions?.length || 0;
|
|
819
|
+
const hasInactiveSessions = allSessions?.some((s3) => s3.isActive === false);
|
|
820
|
+
if (!strictMode) {
|
|
821
|
+
if (totalSessions === 0) {
|
|
822
|
+
strapi2.log.warn(
|
|
823
|
+
`[magic-sessionmanager] [JWT-WARN] No session found for user ${userDocId.substring(0, 8)}... (allowing - session may not have been created)`
|
|
824
|
+
);
|
|
825
|
+
} else if (hasInactiveSessions) {
|
|
826
|
+
strapi2.log.warn(
|
|
827
|
+
`[magic-sessionmanager] [JWT-WARN] User ${userDocId.substring(0, 8)}... has ${totalSessions} inactive sessions but no active ones (allowing - strictMode off)`
|
|
828
|
+
);
|
|
829
|
+
}
|
|
830
|
+
return decoded;
|
|
831
|
+
}
|
|
832
|
+
if (totalSessions === 0) {
|
|
833
|
+
strapi2.log.warn(
|
|
834
|
+
`[magic-sessionmanager] [JWT-ALLOW] No sessions exist for user ${userDocId.substring(0, 8)}... (allowing - possible race condition)`
|
|
835
|
+
);
|
|
836
|
+
return decoded;
|
|
837
|
+
}
|
|
838
|
+
if (hasInactiveSessions) {
|
|
782
839
|
strapi2.log.info(
|
|
783
|
-
`[magic-sessionmanager] [JWT-BLOCKED]
|
|
840
|
+
`[magic-sessionmanager] [JWT-BLOCKED] User ${userDocId.substring(0, 8)}... was logged out (${totalSessions} inactive sessions)`
|
|
784
841
|
);
|
|
785
842
|
return null;
|
|
786
843
|
}
|
|
844
|
+
strapi2.log.warn(
|
|
845
|
+
`[magic-sessionmanager] [JWT-ALLOW] Unexpected session state for user ${userDocId.substring(0, 8)}... (allowing)`
|
|
846
|
+
);
|
|
787
847
|
return decoded;
|
|
788
848
|
} catch (err) {
|
|
789
|
-
strapi2.log.
|
|
849
|
+
strapi2.log.warn("[magic-sessionmanager] [JWT] Session check error (allowing):", err.message);
|
|
790
850
|
return decoded;
|
|
791
851
|
}
|
|
792
852
|
};
|
|
@@ -2585,7 +2645,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2585
2645
|
}
|
|
2586
2646
|
};
|
|
2587
2647
|
};
|
|
2588
|
-
const version$1 = "4.3.
|
|
2648
|
+
const version$1 = "4.3.2";
|
|
2589
2649
|
const require$$2 = {
|
|
2590
2650
|
version: version$1
|
|
2591
2651
|
};
|
|
@@ -17213,6 +17273,16 @@ const providerFactory = (options2 = {}) => {
|
|
|
17213
17273
|
}
|
|
17214
17274
|
};
|
|
17215
17275
|
};
|
|
17276
|
+
const parallelWithOrderedErrors = async (promises) => {
|
|
17277
|
+
const results = await Promise.allSettled(promises);
|
|
17278
|
+
for (let i2 = 0; i2 < results.length; i2 += 1) {
|
|
17279
|
+
const result = results[i2];
|
|
17280
|
+
if (result.status === "rejected") {
|
|
17281
|
+
throw result.reason;
|
|
17282
|
+
}
|
|
17283
|
+
}
|
|
17284
|
+
return results.map((r) => r.value);
|
|
17285
|
+
};
|
|
17216
17286
|
const traverseEntity = async (visitor2, options2, entity) => {
|
|
17217
17287
|
const { path: path2 = {
|
|
17218
17288
|
raw: null,
|
|
@@ -17313,15 +17383,13 @@ const traverseEntity = async (visitor2, options2, entity) => {
|
|
|
17313
17383
|
const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
|
|
17314
17384
|
const method = isMorphRelation ? traverseMorphRelationTarget : traverseRelationTarget(getModel(attribute.target));
|
|
17315
17385
|
if (fp.isArray(value)) {
|
|
17316
|
-
|
|
17317
|
-
for (let i3 = 0; i3 < value.length; i3 += 1) {
|
|
17386
|
+
copy[key] = await parallelWithOrderedErrors(value.map((item, i3) => {
|
|
17318
17387
|
const arrayPath = {
|
|
17319
17388
|
...newPath,
|
|
17320
17389
|
rawWithIndices: fp.isNil(newPath.rawWithIndices) ? `${i3}` : `${newPath.rawWithIndices}.${i3}`
|
|
17321
17390
|
};
|
|
17322
|
-
|
|
17323
|
-
}
|
|
17324
|
-
copy[key] = res;
|
|
17391
|
+
return method(visitor2, arrayPath, item);
|
|
17392
|
+
}));
|
|
17325
17393
|
} else {
|
|
17326
17394
|
copy[key] = await method(visitor2, newPath, value);
|
|
17327
17395
|
}
|
|
@@ -17335,15 +17403,13 @@ const traverseEntity = async (visitor2, options2, entity) => {
|
|
|
17335
17403
|
path: newPath
|
|
17336
17404
|
};
|
|
17337
17405
|
if (fp.isArray(value)) {
|
|
17338
|
-
|
|
17339
|
-
for (let i3 = 0; i3 < value.length; i3 += 1) {
|
|
17406
|
+
copy[key] = await parallelWithOrderedErrors(value.map((item, i3) => {
|
|
17340
17407
|
const arrayPath = {
|
|
17341
17408
|
...newPath,
|
|
17342
17409
|
rawWithIndices: fp.isNil(newPath.rawWithIndices) ? `${i3}` : `${newPath.rawWithIndices}.${i3}`
|
|
17343
17410
|
};
|
|
17344
|
-
|
|
17345
|
-
}
|
|
17346
|
-
copy[key] = res;
|
|
17411
|
+
return traverseMediaTarget(visitor2, arrayPath, item);
|
|
17412
|
+
}));
|
|
17347
17413
|
} else {
|
|
17348
17414
|
copy[key] = await traverseMediaTarget(visitor2, newPath, value);
|
|
17349
17415
|
}
|
|
@@ -17358,15 +17424,13 @@ const traverseEntity = async (visitor2, options2, entity) => {
|
|
|
17358
17424
|
};
|
|
17359
17425
|
const targetSchema = getModel(attribute.component);
|
|
17360
17426
|
if (fp.isArray(value)) {
|
|
17361
|
-
|
|
17362
|
-
for (let i3 = 0; i3 < value.length; i3 += 1) {
|
|
17427
|
+
copy[key] = await parallelWithOrderedErrors(value.map((item, i3) => {
|
|
17363
17428
|
const arrayPath = {
|
|
17364
17429
|
...newPath,
|
|
17365
17430
|
rawWithIndices: fp.isNil(newPath.rawWithIndices) ? `${i3}` : `${newPath.rawWithIndices}.${i3}`
|
|
17366
17431
|
};
|
|
17367
|
-
|
|
17368
|
-
}
|
|
17369
|
-
copy[key] = res;
|
|
17432
|
+
return traverseComponent(visitor2, arrayPath, targetSchema, item);
|
|
17433
|
+
}));
|
|
17370
17434
|
} else {
|
|
17371
17435
|
copy[key] = await traverseComponent(visitor2, newPath, targetSchema, value);
|
|
17372
17436
|
}
|
|
@@ -17379,15 +17443,13 @@ const traverseEntity = async (visitor2, options2, entity) => {
|
|
|
17379
17443
|
attribute,
|
|
17380
17444
|
path: newPath
|
|
17381
17445
|
};
|
|
17382
|
-
|
|
17383
|
-
for (let i3 = 0; i3 < value.length; i3 += 1) {
|
|
17446
|
+
copy[key] = await parallelWithOrderedErrors(value.map((item, i3) => {
|
|
17384
17447
|
const arrayPath = {
|
|
17385
17448
|
...newPath,
|
|
17386
17449
|
rawWithIndices: fp.isNil(newPath.rawWithIndices) ? `${i3}` : `${newPath.rawWithIndices}.${i3}`
|
|
17387
17450
|
};
|
|
17388
|
-
|
|
17389
|
-
}
|
|
17390
|
-
copy[key] = res;
|
|
17451
|
+
return visitDynamicZoneEntry(visitor2, arrayPath, item);
|
|
17452
|
+
}));
|
|
17391
17453
|
continue;
|
|
17392
17454
|
}
|
|
17393
17455
|
}
|
|
@@ -18133,6 +18195,23 @@ const generateInstallId = (projectId, installId) => {
|
|
|
18133
18195
|
return require$$1__default.default.randomUUID();
|
|
18134
18196
|
}
|
|
18135
18197
|
};
|
|
18198
|
+
const createModelCache = (getModelFn) => {
|
|
18199
|
+
const cache = /* @__PURE__ */ new Map();
|
|
18200
|
+
return {
|
|
18201
|
+
getModel(uid) {
|
|
18202
|
+
const cached2 = cache.get(uid);
|
|
18203
|
+
if (cached2) {
|
|
18204
|
+
return cached2;
|
|
18205
|
+
}
|
|
18206
|
+
const model = getModelFn(uid);
|
|
18207
|
+
cache.set(uid, model);
|
|
18208
|
+
return model;
|
|
18209
|
+
},
|
|
18210
|
+
clear() {
|
|
18211
|
+
cache.clear();
|
|
18212
|
+
}
|
|
18213
|
+
};
|
|
18214
|
+
};
|
|
18136
18215
|
var map$2;
|
|
18137
18216
|
try {
|
|
18138
18217
|
map$2 = Map;
|
|
@@ -38821,6 +38900,7 @@ const dist = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty
|
|
|
38821
38900
|
augmentSchema,
|
|
38822
38901
|
contentTypes: contentTypes$1,
|
|
38823
38902
|
createContentApiRoutesFactory,
|
|
38903
|
+
createModelCache,
|
|
38824
38904
|
dates,
|
|
38825
38905
|
env,
|
|
38826
38906
|
errors: errors$1,
|
|
@@ -38889,6 +38969,8 @@ var sessionRequired$1 = async (policyContext, config2, { strapi: strapi2 }) => {
|
|
|
38889
38969
|
if (!userDocId) {
|
|
38890
38970
|
return true;
|
|
38891
38971
|
}
|
|
38972
|
+
const config3 = strapi2.config.get("plugin::magic-sessionmanager") || {};
|
|
38973
|
+
const strictMode = config3.strictSessionEnforcement === true;
|
|
38892
38974
|
const activeSessions = await strapi2.documents(SESSION_UID).findMany({
|
|
38893
38975
|
filters: {
|
|
38894
38976
|
user: { documentId: userDocId },
|
|
@@ -38896,12 +38978,24 @@ var sessionRequired$1 = async (policyContext, config2, { strapi: strapi2 }) => {
|
|
|
38896
38978
|
},
|
|
38897
38979
|
limit: 1
|
|
38898
38980
|
});
|
|
38899
|
-
if (
|
|
38981
|
+
if (activeSessions && activeSessions.length > 0) {
|
|
38982
|
+
return true;
|
|
38983
|
+
}
|
|
38984
|
+
const allSessions = await strapi2.documents(SESSION_UID).findMany({
|
|
38985
|
+
filters: { user: { documentId: userDocId } },
|
|
38986
|
+
limit: 1,
|
|
38987
|
+
fields: ["isActive"]
|
|
38988
|
+
});
|
|
38989
|
+
const hasInactiveSessions = allSessions?.some((s3) => s3.isActive === false);
|
|
38990
|
+
if (strictMode && hasInactiveSessions) {
|
|
38900
38991
|
strapi2.log.info(
|
|
38901
|
-
`[magic-sessionmanager] [POLICY-BLOCKED]
|
|
38992
|
+
`[magic-sessionmanager] [POLICY-BLOCKED] Session terminated (user: ${userDocId.substring(0, 8)}...)`
|
|
38902
38993
|
);
|
|
38903
38994
|
throw new errors.UnauthorizedError("Session terminated. Please login again.");
|
|
38904
38995
|
}
|
|
38996
|
+
strapi2.log.debug(
|
|
38997
|
+
`[magic-sessionmanager] [POLICY-WARN] No active session for user ${userDocId.substring(0, 8)}... (allowing)`
|
|
38998
|
+
);
|
|
38905
38999
|
return true;
|
|
38906
39000
|
} catch (err) {
|
|
38907
39001
|
if (err instanceof errors.UnauthorizedError) {
|
package/dist/server/index.mjs
CHANGED
|
@@ -306,6 +306,8 @@ var lastSeen = ({ strapi: strapi2, sessionService }) => {
|
|
|
306
306
|
userDocId2 = await getDocumentIdFromNumericId(strapi2, ctx.state.user.id);
|
|
307
307
|
}
|
|
308
308
|
if (userDocId2) {
|
|
309
|
+
const config2 = strapi2.config.get("plugin::magic-sessionmanager") || {};
|
|
310
|
+
const strictMode = config2.strictSessionEnforcement === true;
|
|
309
311
|
const activeSessions = await strapi2.documents(SESSION_UID$4).findMany({
|
|
310
312
|
filters: {
|
|
311
313
|
user: { documentId: userDocId2 },
|
|
@@ -314,8 +316,17 @@ var lastSeen = ({ strapi: strapi2, sessionService }) => {
|
|
|
314
316
|
limit: 1
|
|
315
317
|
});
|
|
316
318
|
if (!activeSessions || activeSessions.length === 0) {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
+
const allSessions = await strapi2.documents(SESSION_UID$4).findMany({
|
|
320
|
+
filters: { user: { documentId: userDocId2 } },
|
|
321
|
+
limit: 1,
|
|
322
|
+
fields: ["isActive"]
|
|
323
|
+
});
|
|
324
|
+
const hasInactiveSessions = allSessions?.some((s3) => s3.isActive === false);
|
|
325
|
+
if (strictMode && hasInactiveSessions) {
|
|
326
|
+
strapi2.log.info(`[magic-sessionmanager] [BLOCKED] Session terminated (user: ${userDocId2.substring(0, 8)}...)`);
|
|
327
|
+
return ctx.unauthorized("Session has been terminated. Please login again.");
|
|
328
|
+
}
|
|
329
|
+
strapi2.log.debug(`[magic-sessionmanager] [WARN] No active session for user ${userDocId2.substring(0, 8)}... (allowing)`);
|
|
319
330
|
}
|
|
320
331
|
ctx.state.userDocumentId = userDocId2;
|
|
321
332
|
}
|
|
@@ -503,9 +514,20 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
503
514
|
}
|
|
504
515
|
let userDocId = user.documentId;
|
|
505
516
|
if (!userDocId && user.id) {
|
|
506
|
-
const fullUser = await strapi2.entityService.findOne(USER_UID$2, user.id
|
|
507
|
-
|
|
517
|
+
const fullUser = await strapi2.entityService.findOne(USER_UID$2, user.id, {
|
|
518
|
+
fields: ["documentId"]
|
|
519
|
+
});
|
|
520
|
+
userDocId = fullUser?.documentId;
|
|
521
|
+
if (!userDocId) {
|
|
522
|
+
log.error(`[ERROR] Could not get documentId for user ${user.id} - session NOT created!`);
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
508
525
|
}
|
|
526
|
+
if (!userDocId) {
|
|
527
|
+
log.error("[ERROR] No user documentId available - cannot create session");
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
log.debug(`[SESSION] Creating session for user documentId: ${userDocId}`);
|
|
509
531
|
const newSession = await sessionService.createSession({
|
|
510
532
|
userId: userDocId,
|
|
511
533
|
ip,
|
|
@@ -517,7 +539,11 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
517
539
|
geoData
|
|
518
540
|
// Store geolocation data if available
|
|
519
541
|
});
|
|
520
|
-
|
|
542
|
+
if (newSession?.documentId) {
|
|
543
|
+
log.info(`[SUCCESS] Session ${newSession.documentId} created for user ${userDocId} (IP: ${ip})`);
|
|
544
|
+
} else {
|
|
545
|
+
log.error(`[ERROR] Session creation returned no documentId for user ${userDocId}`);
|
|
546
|
+
}
|
|
521
547
|
if (geoData && (config2.enableEmailAlerts || config2.enableWebhooks)) {
|
|
522
548
|
try {
|
|
523
549
|
const notificationService = strapi2.plugin("magic-sessionmanager").service("notifications");
|
|
@@ -747,6 +773,8 @@ async function registerSessionAwareAuthStrategy(strapi2, log) {
|
|
|
747
773
|
if (!decoded || !decoded.id) {
|
|
748
774
|
return decoded;
|
|
749
775
|
}
|
|
776
|
+
const config2 = strapi2.config.get("plugin::magic-sessionmanager") || {};
|
|
777
|
+
const strictMode = config2.strictSessionEnforcement === true;
|
|
750
778
|
try {
|
|
751
779
|
let userDocId = null;
|
|
752
780
|
const user = await strapi2.entityService.findOne(
|
|
@@ -756,6 +784,7 @@ async function registerSessionAwareAuthStrategy(strapi2, log) {
|
|
|
756
784
|
);
|
|
757
785
|
userDocId = user?.documentId;
|
|
758
786
|
if (!userDocId) {
|
|
787
|
+
strapi2.log.debug("[magic-sessionmanager] [JWT] No documentId found, allowing through");
|
|
759
788
|
return decoded;
|
|
760
789
|
}
|
|
761
790
|
const activeSessions = await strapi2.documents(SESSION_UID$3).findMany({
|
|
@@ -765,15 +794,46 @@ async function registerSessionAwareAuthStrategy(strapi2, log) {
|
|
|
765
794
|
},
|
|
766
795
|
limit: 1
|
|
767
796
|
});
|
|
768
|
-
if (
|
|
797
|
+
if (activeSessions && activeSessions.length > 0) {
|
|
798
|
+
return decoded;
|
|
799
|
+
}
|
|
800
|
+
const allSessions = await strapi2.documents(SESSION_UID$3).findMany({
|
|
801
|
+
filters: { user: { documentId: userDocId } },
|
|
802
|
+
limit: 5,
|
|
803
|
+
fields: ["isActive", "lastActive"]
|
|
804
|
+
});
|
|
805
|
+
const totalSessions = allSessions?.length || 0;
|
|
806
|
+
const hasInactiveSessions = allSessions?.some((s3) => s3.isActive === false);
|
|
807
|
+
if (!strictMode) {
|
|
808
|
+
if (totalSessions === 0) {
|
|
809
|
+
strapi2.log.warn(
|
|
810
|
+
`[magic-sessionmanager] [JWT-WARN] No session found for user ${userDocId.substring(0, 8)}... (allowing - session may not have been created)`
|
|
811
|
+
);
|
|
812
|
+
} else if (hasInactiveSessions) {
|
|
813
|
+
strapi2.log.warn(
|
|
814
|
+
`[magic-sessionmanager] [JWT-WARN] User ${userDocId.substring(0, 8)}... has ${totalSessions} inactive sessions but no active ones (allowing - strictMode off)`
|
|
815
|
+
);
|
|
816
|
+
}
|
|
817
|
+
return decoded;
|
|
818
|
+
}
|
|
819
|
+
if (totalSessions === 0) {
|
|
820
|
+
strapi2.log.warn(
|
|
821
|
+
`[magic-sessionmanager] [JWT-ALLOW] No sessions exist for user ${userDocId.substring(0, 8)}... (allowing - possible race condition)`
|
|
822
|
+
);
|
|
823
|
+
return decoded;
|
|
824
|
+
}
|
|
825
|
+
if (hasInactiveSessions) {
|
|
769
826
|
strapi2.log.info(
|
|
770
|
-
`[magic-sessionmanager] [JWT-BLOCKED]
|
|
827
|
+
`[magic-sessionmanager] [JWT-BLOCKED] User ${userDocId.substring(0, 8)}... was logged out (${totalSessions} inactive sessions)`
|
|
771
828
|
);
|
|
772
829
|
return null;
|
|
773
830
|
}
|
|
831
|
+
strapi2.log.warn(
|
|
832
|
+
`[magic-sessionmanager] [JWT-ALLOW] Unexpected session state for user ${userDocId.substring(0, 8)}... (allowing)`
|
|
833
|
+
);
|
|
774
834
|
return decoded;
|
|
775
835
|
} catch (err) {
|
|
776
|
-
strapi2.log.
|
|
836
|
+
strapi2.log.warn("[magic-sessionmanager] [JWT] Session check error (allowing):", err.message);
|
|
777
837
|
return decoded;
|
|
778
838
|
}
|
|
779
839
|
};
|
|
@@ -2572,7 +2632,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2572
2632
|
}
|
|
2573
2633
|
};
|
|
2574
2634
|
};
|
|
2575
|
-
const version$1 = "4.3.
|
|
2635
|
+
const version$1 = "4.3.2";
|
|
2576
2636
|
const require$$2 = {
|
|
2577
2637
|
version: version$1
|
|
2578
2638
|
};
|
|
@@ -17200,6 +17260,16 @@ const providerFactory = (options2 = {}) => {
|
|
|
17200
17260
|
}
|
|
17201
17261
|
};
|
|
17202
17262
|
};
|
|
17263
|
+
const parallelWithOrderedErrors = async (promises) => {
|
|
17264
|
+
const results = await Promise.allSettled(promises);
|
|
17265
|
+
for (let i2 = 0; i2 < results.length; i2 += 1) {
|
|
17266
|
+
const result = results[i2];
|
|
17267
|
+
if (result.status === "rejected") {
|
|
17268
|
+
throw result.reason;
|
|
17269
|
+
}
|
|
17270
|
+
}
|
|
17271
|
+
return results.map((r) => r.value);
|
|
17272
|
+
};
|
|
17203
17273
|
const traverseEntity = async (visitor2, options2, entity) => {
|
|
17204
17274
|
const { path: path2 = {
|
|
17205
17275
|
raw: null,
|
|
@@ -17300,15 +17370,13 @@ const traverseEntity = async (visitor2, options2, entity) => {
|
|
|
17300
17370
|
const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
|
|
17301
17371
|
const method = isMorphRelation ? traverseMorphRelationTarget : traverseRelationTarget(getModel(attribute.target));
|
|
17302
17372
|
if (fp.isArray(value)) {
|
|
17303
|
-
|
|
17304
|
-
for (let i3 = 0; i3 < value.length; i3 += 1) {
|
|
17373
|
+
copy[key] = await parallelWithOrderedErrors(value.map((item, i3) => {
|
|
17305
17374
|
const arrayPath = {
|
|
17306
17375
|
...newPath,
|
|
17307
17376
|
rawWithIndices: fp.isNil(newPath.rawWithIndices) ? `${i3}` : `${newPath.rawWithIndices}.${i3}`
|
|
17308
17377
|
};
|
|
17309
|
-
|
|
17310
|
-
}
|
|
17311
|
-
copy[key] = res;
|
|
17378
|
+
return method(visitor2, arrayPath, item);
|
|
17379
|
+
}));
|
|
17312
17380
|
} else {
|
|
17313
17381
|
copy[key] = await method(visitor2, newPath, value);
|
|
17314
17382
|
}
|
|
@@ -17322,15 +17390,13 @@ const traverseEntity = async (visitor2, options2, entity) => {
|
|
|
17322
17390
|
path: newPath
|
|
17323
17391
|
};
|
|
17324
17392
|
if (fp.isArray(value)) {
|
|
17325
|
-
|
|
17326
|
-
for (let i3 = 0; i3 < value.length; i3 += 1) {
|
|
17393
|
+
copy[key] = await parallelWithOrderedErrors(value.map((item, i3) => {
|
|
17327
17394
|
const arrayPath = {
|
|
17328
17395
|
...newPath,
|
|
17329
17396
|
rawWithIndices: fp.isNil(newPath.rawWithIndices) ? `${i3}` : `${newPath.rawWithIndices}.${i3}`
|
|
17330
17397
|
};
|
|
17331
|
-
|
|
17332
|
-
}
|
|
17333
|
-
copy[key] = res;
|
|
17398
|
+
return traverseMediaTarget(visitor2, arrayPath, item);
|
|
17399
|
+
}));
|
|
17334
17400
|
} else {
|
|
17335
17401
|
copy[key] = await traverseMediaTarget(visitor2, newPath, value);
|
|
17336
17402
|
}
|
|
@@ -17345,15 +17411,13 @@ const traverseEntity = async (visitor2, options2, entity) => {
|
|
|
17345
17411
|
};
|
|
17346
17412
|
const targetSchema = getModel(attribute.component);
|
|
17347
17413
|
if (fp.isArray(value)) {
|
|
17348
|
-
|
|
17349
|
-
for (let i3 = 0; i3 < value.length; i3 += 1) {
|
|
17414
|
+
copy[key] = await parallelWithOrderedErrors(value.map((item, i3) => {
|
|
17350
17415
|
const arrayPath = {
|
|
17351
17416
|
...newPath,
|
|
17352
17417
|
rawWithIndices: fp.isNil(newPath.rawWithIndices) ? `${i3}` : `${newPath.rawWithIndices}.${i3}`
|
|
17353
17418
|
};
|
|
17354
|
-
|
|
17355
|
-
}
|
|
17356
|
-
copy[key] = res;
|
|
17419
|
+
return traverseComponent(visitor2, arrayPath, targetSchema, item);
|
|
17420
|
+
}));
|
|
17357
17421
|
} else {
|
|
17358
17422
|
copy[key] = await traverseComponent(visitor2, newPath, targetSchema, value);
|
|
17359
17423
|
}
|
|
@@ -17366,15 +17430,13 @@ const traverseEntity = async (visitor2, options2, entity) => {
|
|
|
17366
17430
|
attribute,
|
|
17367
17431
|
path: newPath
|
|
17368
17432
|
};
|
|
17369
|
-
|
|
17370
|
-
for (let i3 = 0; i3 < value.length; i3 += 1) {
|
|
17433
|
+
copy[key] = await parallelWithOrderedErrors(value.map((item, i3) => {
|
|
17371
17434
|
const arrayPath = {
|
|
17372
17435
|
...newPath,
|
|
17373
17436
|
rawWithIndices: fp.isNil(newPath.rawWithIndices) ? `${i3}` : `${newPath.rawWithIndices}.${i3}`
|
|
17374
17437
|
};
|
|
17375
|
-
|
|
17376
|
-
}
|
|
17377
|
-
copy[key] = res;
|
|
17438
|
+
return visitDynamicZoneEntry(visitor2, arrayPath, item);
|
|
17439
|
+
}));
|
|
17378
17440
|
continue;
|
|
17379
17441
|
}
|
|
17380
17442
|
}
|
|
@@ -18120,6 +18182,23 @@ const generateInstallId = (projectId, installId) => {
|
|
|
18120
18182
|
return require$$1.randomUUID();
|
|
18121
18183
|
}
|
|
18122
18184
|
};
|
|
18185
|
+
const createModelCache = (getModelFn) => {
|
|
18186
|
+
const cache = /* @__PURE__ */ new Map();
|
|
18187
|
+
return {
|
|
18188
|
+
getModel(uid) {
|
|
18189
|
+
const cached2 = cache.get(uid);
|
|
18190
|
+
if (cached2) {
|
|
18191
|
+
return cached2;
|
|
18192
|
+
}
|
|
18193
|
+
const model = getModelFn(uid);
|
|
18194
|
+
cache.set(uid, model);
|
|
18195
|
+
return model;
|
|
18196
|
+
},
|
|
18197
|
+
clear() {
|
|
18198
|
+
cache.clear();
|
|
18199
|
+
}
|
|
18200
|
+
};
|
|
18201
|
+
};
|
|
18123
18202
|
var map$2;
|
|
18124
18203
|
try {
|
|
18125
18204
|
map$2 = Map;
|
|
@@ -38808,6 +38887,7 @@ const dist = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty
|
|
|
38808
38887
|
augmentSchema,
|
|
38809
38888
|
contentTypes: contentTypes$1,
|
|
38810
38889
|
createContentApiRoutesFactory,
|
|
38890
|
+
createModelCache,
|
|
38811
38891
|
dates,
|
|
38812
38892
|
env,
|
|
38813
38893
|
errors: errors$1,
|
|
@@ -38876,6 +38956,8 @@ var sessionRequired$1 = async (policyContext, config2, { strapi: strapi2 }) => {
|
|
|
38876
38956
|
if (!userDocId) {
|
|
38877
38957
|
return true;
|
|
38878
38958
|
}
|
|
38959
|
+
const config3 = strapi2.config.get("plugin::magic-sessionmanager") || {};
|
|
38960
|
+
const strictMode = config3.strictSessionEnforcement === true;
|
|
38879
38961
|
const activeSessions = await strapi2.documents(SESSION_UID).findMany({
|
|
38880
38962
|
filters: {
|
|
38881
38963
|
user: { documentId: userDocId },
|
|
@@ -38883,12 +38965,24 @@ var sessionRequired$1 = async (policyContext, config2, { strapi: strapi2 }) => {
|
|
|
38883
38965
|
},
|
|
38884
38966
|
limit: 1
|
|
38885
38967
|
});
|
|
38886
|
-
if (
|
|
38968
|
+
if (activeSessions && activeSessions.length > 0) {
|
|
38969
|
+
return true;
|
|
38970
|
+
}
|
|
38971
|
+
const allSessions = await strapi2.documents(SESSION_UID).findMany({
|
|
38972
|
+
filters: { user: { documentId: userDocId } },
|
|
38973
|
+
limit: 1,
|
|
38974
|
+
fields: ["isActive"]
|
|
38975
|
+
});
|
|
38976
|
+
const hasInactiveSessions = allSessions?.some((s3) => s3.isActive === false);
|
|
38977
|
+
if (strictMode && hasInactiveSessions) {
|
|
38887
38978
|
strapi2.log.info(
|
|
38888
|
-
`[magic-sessionmanager] [POLICY-BLOCKED]
|
|
38979
|
+
`[magic-sessionmanager] [POLICY-BLOCKED] Session terminated (user: ${userDocId.substring(0, 8)}...)`
|
|
38889
38980
|
);
|
|
38890
38981
|
throw new errors.UnauthorizedError("Session terminated. Please login again.");
|
|
38891
38982
|
}
|
|
38983
|
+
strapi2.log.debug(
|
|
38984
|
+
`[magic-sessionmanager] [POLICY-WARN] No active session for user ${userDocId.substring(0, 8)}... (allowing)`
|
|
38985
|
+
);
|
|
38892
38986
|
return true;
|
|
38893
38987
|
} catch (err) {
|
|
38894
38988
|
if (err instanceof errors.UnauthorizedError) {
|
package/package.json
CHANGED