strapi-plugin-magic-sessionmanager 4.3.4 → 4.4.1
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 +161 -46
- package/dist/server/index.mjs +161 -46
- package/package.json +1 -1
package/dist/server/index.js
CHANGED
|
@@ -329,21 +329,37 @@ var lastSeen = ({ strapi: strapi2, sessionService }) => {
|
|
|
329
329
|
limit: 1
|
|
330
330
|
});
|
|
331
331
|
if (!activeSessions || activeSessions.length === 0) {
|
|
332
|
-
const
|
|
333
|
-
filters: {
|
|
334
|
-
|
|
335
|
-
|
|
332
|
+
const inactiveSessions = await strapi2.documents(SESSION_UID$4).findMany({
|
|
333
|
+
filters: {
|
|
334
|
+
user: { documentId: userDocId2 },
|
|
335
|
+
isActive: false
|
|
336
|
+
},
|
|
337
|
+
limit: 5,
|
|
338
|
+
fields: ["documentId", "terminatedManually", "lastActive"],
|
|
339
|
+
sort: [{ lastActive: "desc" }]
|
|
336
340
|
});
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
341
|
+
if (inactiveSessions && inactiveSessions.length > 0) {
|
|
342
|
+
const manuallyTerminated = inactiveSessions.find((s3) => s3.terminatedManually === true);
|
|
343
|
+
if (manuallyTerminated) {
|
|
344
|
+
strapi2.log.info(`[magic-sessionmanager] [BLOCKED] User ${userDocId2.substring(0, 8)}... was manually logged out`);
|
|
345
|
+
return ctx.unauthorized("Session has been terminated. Please login again.");
|
|
346
|
+
}
|
|
347
|
+
const sessionToReactivate = inactiveSessions[0];
|
|
348
|
+
await strapi2.documents(SESSION_UID$4).update({
|
|
349
|
+
documentId: sessionToReactivate.documentId,
|
|
350
|
+
data: {
|
|
351
|
+
isActive: true,
|
|
352
|
+
lastActive: /* @__PURE__ */ new Date()
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
strapi2.log.info(`[magic-sessionmanager] [REACTIVATED] Session reactivated for user ${userDocId2.substring(0, 8)}...`);
|
|
356
|
+
} else {
|
|
357
|
+
if (strictMode) {
|
|
358
|
+
strapi2.log.info(`[magic-sessionmanager] [BLOCKED] No session exists (user: ${userDocId2.substring(0, 8)}..., strictMode)`);
|
|
359
|
+
return ctx.unauthorized("No valid session. Please login again.");
|
|
360
|
+
}
|
|
361
|
+
strapi2.log.warn(`[magic-sessionmanager] [WARN] No session for user ${userDocId2.substring(0, 8)}... (allowing)`);
|
|
345
362
|
}
|
|
346
|
-
strapi2.log.warn(`[magic-sessionmanager] [WARN] No session for user ${userDocId2.substring(0, 8)}... (allowing)`);
|
|
347
363
|
}
|
|
348
364
|
ctx.state.userDocumentId = userDocId2;
|
|
349
365
|
}
|
|
@@ -793,6 +809,7 @@ async function registerSessionAwareAuthStrategy(strapi2, log) {
|
|
|
793
809
|
const config2 = strapi2.config.get("plugin::magic-sessionmanager") || {};
|
|
794
810
|
const strictMode = config2.strictSessionEnforcement === true;
|
|
795
811
|
try {
|
|
812
|
+
const tokenHashValue = hashToken$2(token);
|
|
796
813
|
let userDocId = null;
|
|
797
814
|
const user = await strapi2.entityService.findOne(
|
|
798
815
|
"plugin::users-permissions.user",
|
|
@@ -804,43 +821,69 @@ async function registerSessionAwareAuthStrategy(strapi2, log) {
|
|
|
804
821
|
strapi2.log.debug("[magic-sessionmanager] [JWT] No documentId found, allowing through");
|
|
805
822
|
return decoded;
|
|
806
823
|
}
|
|
807
|
-
const
|
|
824
|
+
const thisSession = await strapi2.documents(SESSION_UID$3).findFirst({
|
|
825
|
+
filters: {
|
|
826
|
+
user: { documentId: userDocId },
|
|
827
|
+
tokenHash: tokenHashValue
|
|
828
|
+
},
|
|
829
|
+
fields: ["documentId", "isActive", "terminatedManually", "lastActive"]
|
|
830
|
+
});
|
|
831
|
+
if (thisSession) {
|
|
832
|
+
if (thisSession.terminatedManually === true) {
|
|
833
|
+
strapi2.log.info(
|
|
834
|
+
`[magic-sessionmanager] [JWT-BLOCKED] Session was manually terminated (user: ${userDocId.substring(0, 8)}...)`
|
|
835
|
+
);
|
|
836
|
+
return null;
|
|
837
|
+
}
|
|
838
|
+
if (thisSession.isActive) {
|
|
839
|
+
return decoded;
|
|
840
|
+
}
|
|
841
|
+
await strapi2.documents(SESSION_UID$3).update({
|
|
842
|
+
documentId: thisSession.documentId,
|
|
843
|
+
data: {
|
|
844
|
+
isActive: true,
|
|
845
|
+
lastActive: /* @__PURE__ */ new Date()
|
|
846
|
+
}
|
|
847
|
+
});
|
|
848
|
+
strapi2.log.info(
|
|
849
|
+
`[magic-sessionmanager] [JWT-REACTIVATED] Session reactivated for user ${userDocId.substring(0, 8)}...`
|
|
850
|
+
);
|
|
851
|
+
return decoded;
|
|
852
|
+
}
|
|
853
|
+
const anyActiveSessions = await strapi2.documents(SESSION_UID$3).findMany({
|
|
808
854
|
filters: {
|
|
809
855
|
user: { documentId: userDocId },
|
|
810
856
|
isActive: true
|
|
811
857
|
},
|
|
812
858
|
limit: 1
|
|
813
859
|
});
|
|
814
|
-
if (
|
|
860
|
+
if (anyActiveSessions && anyActiveSessions.length > 0) {
|
|
861
|
+
strapi2.log.debug(
|
|
862
|
+
`[magic-sessionmanager] [JWT] No session for token but user has other active sessions (allowing)`
|
|
863
|
+
);
|
|
815
864
|
return decoded;
|
|
816
865
|
}
|
|
817
|
-
const
|
|
818
|
-
filters: {
|
|
819
|
-
|
|
820
|
-
|
|
866
|
+
const terminatedSessions = await strapi2.documents(SESSION_UID$3).findMany({
|
|
867
|
+
filters: {
|
|
868
|
+
user: { documentId: userDocId },
|
|
869
|
+
terminatedManually: true
|
|
870
|
+
},
|
|
871
|
+
limit: 1
|
|
821
872
|
});
|
|
822
|
-
|
|
823
|
-
const hasInactiveSessions = allSessions?.some((s3) => s3.isActive === false);
|
|
824
|
-
if (hasInactiveSessions) {
|
|
873
|
+
if (terminatedSessions && terminatedSessions.length > 0) {
|
|
825
874
|
strapi2.log.info(
|
|
826
|
-
`[magic-sessionmanager] [JWT-BLOCKED] User ${userDocId.substring(0, 8)}...
|
|
875
|
+
`[magic-sessionmanager] [JWT-BLOCKED] User ${userDocId.substring(0, 8)}... has terminated sessions`
|
|
827
876
|
);
|
|
828
877
|
return null;
|
|
829
878
|
}
|
|
830
|
-
if (
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
`[magic-sessionmanager] [JWT-BLOCKED] No sessions exist for user ${userDocId.substring(0, 8)}... (strictMode enabled)`
|
|
834
|
-
);
|
|
835
|
-
return null;
|
|
836
|
-
}
|
|
837
|
-
strapi2.log.warn(
|
|
838
|
-
`[magic-sessionmanager] [JWT-WARN] No session found for user ${userDocId.substring(0, 8)}... (allowing - session may not have been created)`
|
|
879
|
+
if (strictMode) {
|
|
880
|
+
strapi2.log.info(
|
|
881
|
+
`[magic-sessionmanager] [JWT-BLOCKED] No sessions exist for user ${userDocId.substring(0, 8)}... (strictMode)`
|
|
839
882
|
);
|
|
840
|
-
return
|
|
883
|
+
return null;
|
|
841
884
|
}
|
|
842
885
|
strapi2.log.warn(
|
|
843
|
-
`[magic-sessionmanager] [JWT-
|
|
886
|
+
`[magic-sessionmanager] [JWT-WARN] No session for user ${userDocId.substring(0, 8)}... (allowing)`
|
|
844
887
|
);
|
|
845
888
|
return decoded;
|
|
846
889
|
} catch (err) {
|
|
@@ -960,6 +1003,11 @@ const attributes = {
|
|
|
960
1003
|
"default": true,
|
|
961
1004
|
required: true
|
|
962
1005
|
},
|
|
1006
|
+
terminatedManually: {
|
|
1007
|
+
type: "boolean",
|
|
1008
|
+
"default": false,
|
|
1009
|
+
required: false
|
|
1010
|
+
},
|
|
963
1011
|
geoLocation: {
|
|
964
1012
|
type: "json"
|
|
965
1013
|
},
|
|
@@ -1099,6 +1147,15 @@ var admin$1 = {
|
|
|
1099
1147
|
description: "Terminate a specific session (admin)"
|
|
1100
1148
|
}
|
|
1101
1149
|
},
|
|
1150
|
+
{
|
|
1151
|
+
method: "POST",
|
|
1152
|
+
path: "/sessions/:sessionId/simulate-timeout",
|
|
1153
|
+
handler: "session.simulateTimeout",
|
|
1154
|
+
config: {
|
|
1155
|
+
policies: ["admin::isAuthenticatedAdmin"],
|
|
1156
|
+
description: "Simulate session timeout for testing (sets isActive: false, terminatedManually: false)"
|
|
1157
|
+
}
|
|
1158
|
+
},
|
|
1102
1159
|
{
|
|
1103
1160
|
method: "DELETE",
|
|
1104
1161
|
path: "/sessions/:sessionId",
|
|
@@ -1680,6 +1737,40 @@ var session$3 = {
|
|
|
1680
1737
|
ctx.throw(500, "Error terminating session");
|
|
1681
1738
|
}
|
|
1682
1739
|
},
|
|
1740
|
+
/**
|
|
1741
|
+
* Simulate session timeout for testing (Admin action)
|
|
1742
|
+
* POST /magic-sessionmanager/sessions/:sessionId/simulate-timeout
|
|
1743
|
+
* Sets isActive: false, terminatedManually: false (as if cleanup job ran)
|
|
1744
|
+
* This allows testing session reactivation behavior
|
|
1745
|
+
*/
|
|
1746
|
+
async simulateTimeout(ctx) {
|
|
1747
|
+
try {
|
|
1748
|
+
const { sessionId } = ctx.params;
|
|
1749
|
+
const session2 = await strapi.documents(SESSION_UID$2).findOne({
|
|
1750
|
+
documentId: sessionId
|
|
1751
|
+
});
|
|
1752
|
+
if (!session2) {
|
|
1753
|
+
return ctx.notFound("Session not found");
|
|
1754
|
+
}
|
|
1755
|
+
await strapi.documents(SESSION_UID$2).update({
|
|
1756
|
+
documentId: sessionId,
|
|
1757
|
+
data: {
|
|
1758
|
+
isActive: false,
|
|
1759
|
+
terminatedManually: false
|
|
1760
|
+
// This allows reactivation!
|
|
1761
|
+
}
|
|
1762
|
+
});
|
|
1763
|
+
strapi.log.info(`[magic-sessionmanager] [TEST] Session ${sessionId} simulated timeout (terminatedManually: false)`);
|
|
1764
|
+
ctx.body = {
|
|
1765
|
+
message: `Session ${sessionId} marked as timed out (reactivatable)`,
|
|
1766
|
+
success: true,
|
|
1767
|
+
terminatedManually: false
|
|
1768
|
+
};
|
|
1769
|
+
} catch (err) {
|
|
1770
|
+
strapi.log.error("[magic-sessionmanager] Error simulating timeout:", err);
|
|
1771
|
+
ctx.throw(500, "Error simulating session timeout");
|
|
1772
|
+
}
|
|
1773
|
+
},
|
|
1683
1774
|
/**
|
|
1684
1775
|
* Terminate a single session (Admin action)
|
|
1685
1776
|
* POST /magic-sessionmanager/sessions/:sessionId/terminate
|
|
@@ -2221,10 +2312,11 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2221
2312
|
documentId: sessionId,
|
|
2222
2313
|
data: {
|
|
2223
2314
|
isActive: false,
|
|
2315
|
+
terminatedManually: true,
|
|
2224
2316
|
logoutTime: now
|
|
2225
2317
|
}
|
|
2226
2318
|
});
|
|
2227
|
-
log.info(`Session ${sessionId} terminated`);
|
|
2319
|
+
log.info(`Session ${sessionId} terminated (manual)`);
|
|
2228
2320
|
} else if (userId) {
|
|
2229
2321
|
let userDocumentId = userId;
|
|
2230
2322
|
if (!isNaN(userId)) {
|
|
@@ -2245,11 +2337,12 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2245
2337
|
documentId: session2.documentId,
|
|
2246
2338
|
data: {
|
|
2247
2339
|
isActive: false,
|
|
2340
|
+
terminatedManually: true,
|
|
2248
2341
|
logoutTime: now
|
|
2249
2342
|
}
|
|
2250
2343
|
});
|
|
2251
2344
|
}
|
|
2252
|
-
log.info(`All sessions terminated for user ${userDocumentId}`);
|
|
2345
|
+
log.info(`All sessions terminated (manual) for user ${userDocumentId}`);
|
|
2253
2346
|
}
|
|
2254
2347
|
} catch (err) {
|
|
2255
2348
|
log.error("Error terminating session:", err);
|
|
@@ -2590,7 +2683,11 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2590
2683
|
if (lastActiveTime < cutoffTime) {
|
|
2591
2684
|
await strapi2.documents(SESSION_UID$1).update({
|
|
2592
2685
|
documentId: session2.documentId,
|
|
2593
|
-
data: {
|
|
2686
|
+
data: {
|
|
2687
|
+
isActive: false,
|
|
2688
|
+
terminatedManually: false
|
|
2689
|
+
// Timeout, not manual - can be reactivated
|
|
2690
|
+
}
|
|
2594
2691
|
});
|
|
2595
2692
|
deactivatedCount++;
|
|
2596
2693
|
}
|
|
@@ -2643,7 +2740,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2643
2740
|
}
|
|
2644
2741
|
};
|
|
2645
2742
|
};
|
|
2646
|
-
const version$1 = "4.
|
|
2743
|
+
const version$1 = "4.4.0";
|
|
2647
2744
|
const require$$2 = {
|
|
2648
2745
|
version: version$1
|
|
2649
2746
|
};
|
|
@@ -38979,17 +39076,35 @@ var sessionRequired$1 = async (policyContext, config2, { strapi: strapi2 }) => {
|
|
|
38979
39076
|
if (activeSessions && activeSessions.length > 0) {
|
|
38980
39077
|
return true;
|
|
38981
39078
|
}
|
|
38982
|
-
const
|
|
38983
|
-
filters: {
|
|
38984
|
-
|
|
38985
|
-
|
|
39079
|
+
const inactiveSessions = await strapi2.documents(SESSION_UID).findMany({
|
|
39080
|
+
filters: {
|
|
39081
|
+
user: { documentId: userDocId },
|
|
39082
|
+
isActive: false
|
|
39083
|
+
},
|
|
39084
|
+
limit: 5,
|
|
39085
|
+
fields: ["documentId", "terminatedManually", "lastActive"],
|
|
39086
|
+
sort: [{ lastActive: "desc" }]
|
|
38986
39087
|
});
|
|
38987
|
-
|
|
38988
|
-
|
|
39088
|
+
if (inactiveSessions && inactiveSessions.length > 0) {
|
|
39089
|
+
const manuallyTerminated = inactiveSessions.find((s3) => s3.terminatedManually === true);
|
|
39090
|
+
if (manuallyTerminated) {
|
|
39091
|
+
strapi2.log.info(
|
|
39092
|
+
`[magic-sessionmanager] [POLICY-BLOCKED] User ${userDocId.substring(0, 8)}... was manually logged out`
|
|
39093
|
+
);
|
|
39094
|
+
throw new errors.UnauthorizedError("Session terminated. Please login again.");
|
|
39095
|
+
}
|
|
39096
|
+
const sessionToReactivate = inactiveSessions[0];
|
|
39097
|
+
await strapi2.documents(SESSION_UID).update({
|
|
39098
|
+
documentId: sessionToReactivate.documentId,
|
|
39099
|
+
data: {
|
|
39100
|
+
isActive: true,
|
|
39101
|
+
lastActive: /* @__PURE__ */ new Date()
|
|
39102
|
+
}
|
|
39103
|
+
});
|
|
38989
39104
|
strapi2.log.info(
|
|
38990
|
-
`[magic-sessionmanager] [POLICY-
|
|
39105
|
+
`[magic-sessionmanager] [POLICY-REACTIVATED] Session reactivated for user ${userDocId.substring(0, 8)}...`
|
|
38991
39106
|
);
|
|
38992
|
-
|
|
39107
|
+
return true;
|
|
38993
39108
|
}
|
|
38994
39109
|
if (strictMode) {
|
|
38995
39110
|
strapi2.log.info(
|
package/dist/server/index.mjs
CHANGED
|
@@ -316,21 +316,37 @@ var lastSeen = ({ strapi: strapi2, sessionService }) => {
|
|
|
316
316
|
limit: 1
|
|
317
317
|
});
|
|
318
318
|
if (!activeSessions || activeSessions.length === 0) {
|
|
319
|
-
const
|
|
320
|
-
filters: {
|
|
321
|
-
|
|
322
|
-
|
|
319
|
+
const inactiveSessions = await strapi2.documents(SESSION_UID$4).findMany({
|
|
320
|
+
filters: {
|
|
321
|
+
user: { documentId: userDocId2 },
|
|
322
|
+
isActive: false
|
|
323
|
+
},
|
|
324
|
+
limit: 5,
|
|
325
|
+
fields: ["documentId", "terminatedManually", "lastActive"],
|
|
326
|
+
sort: [{ lastActive: "desc" }]
|
|
323
327
|
});
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
328
|
+
if (inactiveSessions && inactiveSessions.length > 0) {
|
|
329
|
+
const manuallyTerminated = inactiveSessions.find((s3) => s3.terminatedManually === true);
|
|
330
|
+
if (manuallyTerminated) {
|
|
331
|
+
strapi2.log.info(`[magic-sessionmanager] [BLOCKED] User ${userDocId2.substring(0, 8)}... was manually logged out`);
|
|
332
|
+
return ctx.unauthorized("Session has been terminated. Please login again.");
|
|
333
|
+
}
|
|
334
|
+
const sessionToReactivate = inactiveSessions[0];
|
|
335
|
+
await strapi2.documents(SESSION_UID$4).update({
|
|
336
|
+
documentId: sessionToReactivate.documentId,
|
|
337
|
+
data: {
|
|
338
|
+
isActive: true,
|
|
339
|
+
lastActive: /* @__PURE__ */ new Date()
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
strapi2.log.info(`[magic-sessionmanager] [REACTIVATED] Session reactivated for user ${userDocId2.substring(0, 8)}...`);
|
|
343
|
+
} else {
|
|
344
|
+
if (strictMode) {
|
|
345
|
+
strapi2.log.info(`[magic-sessionmanager] [BLOCKED] No session exists (user: ${userDocId2.substring(0, 8)}..., strictMode)`);
|
|
346
|
+
return ctx.unauthorized("No valid session. Please login again.");
|
|
347
|
+
}
|
|
348
|
+
strapi2.log.warn(`[magic-sessionmanager] [WARN] No session for user ${userDocId2.substring(0, 8)}... (allowing)`);
|
|
332
349
|
}
|
|
333
|
-
strapi2.log.warn(`[magic-sessionmanager] [WARN] No session for user ${userDocId2.substring(0, 8)}... (allowing)`);
|
|
334
350
|
}
|
|
335
351
|
ctx.state.userDocumentId = userDocId2;
|
|
336
352
|
}
|
|
@@ -780,6 +796,7 @@ async function registerSessionAwareAuthStrategy(strapi2, log) {
|
|
|
780
796
|
const config2 = strapi2.config.get("plugin::magic-sessionmanager") || {};
|
|
781
797
|
const strictMode = config2.strictSessionEnforcement === true;
|
|
782
798
|
try {
|
|
799
|
+
const tokenHashValue = hashToken$2(token);
|
|
783
800
|
let userDocId = null;
|
|
784
801
|
const user = await strapi2.entityService.findOne(
|
|
785
802
|
"plugin::users-permissions.user",
|
|
@@ -791,43 +808,69 @@ async function registerSessionAwareAuthStrategy(strapi2, log) {
|
|
|
791
808
|
strapi2.log.debug("[magic-sessionmanager] [JWT] No documentId found, allowing through");
|
|
792
809
|
return decoded;
|
|
793
810
|
}
|
|
794
|
-
const
|
|
811
|
+
const thisSession = await strapi2.documents(SESSION_UID$3).findFirst({
|
|
812
|
+
filters: {
|
|
813
|
+
user: { documentId: userDocId },
|
|
814
|
+
tokenHash: tokenHashValue
|
|
815
|
+
},
|
|
816
|
+
fields: ["documentId", "isActive", "terminatedManually", "lastActive"]
|
|
817
|
+
});
|
|
818
|
+
if (thisSession) {
|
|
819
|
+
if (thisSession.terminatedManually === true) {
|
|
820
|
+
strapi2.log.info(
|
|
821
|
+
`[magic-sessionmanager] [JWT-BLOCKED] Session was manually terminated (user: ${userDocId.substring(0, 8)}...)`
|
|
822
|
+
);
|
|
823
|
+
return null;
|
|
824
|
+
}
|
|
825
|
+
if (thisSession.isActive) {
|
|
826
|
+
return decoded;
|
|
827
|
+
}
|
|
828
|
+
await strapi2.documents(SESSION_UID$3).update({
|
|
829
|
+
documentId: thisSession.documentId,
|
|
830
|
+
data: {
|
|
831
|
+
isActive: true,
|
|
832
|
+
lastActive: /* @__PURE__ */ new Date()
|
|
833
|
+
}
|
|
834
|
+
});
|
|
835
|
+
strapi2.log.info(
|
|
836
|
+
`[magic-sessionmanager] [JWT-REACTIVATED] Session reactivated for user ${userDocId.substring(0, 8)}...`
|
|
837
|
+
);
|
|
838
|
+
return decoded;
|
|
839
|
+
}
|
|
840
|
+
const anyActiveSessions = await strapi2.documents(SESSION_UID$3).findMany({
|
|
795
841
|
filters: {
|
|
796
842
|
user: { documentId: userDocId },
|
|
797
843
|
isActive: true
|
|
798
844
|
},
|
|
799
845
|
limit: 1
|
|
800
846
|
});
|
|
801
|
-
if (
|
|
847
|
+
if (anyActiveSessions && anyActiveSessions.length > 0) {
|
|
848
|
+
strapi2.log.debug(
|
|
849
|
+
`[magic-sessionmanager] [JWT] No session for token but user has other active sessions (allowing)`
|
|
850
|
+
);
|
|
802
851
|
return decoded;
|
|
803
852
|
}
|
|
804
|
-
const
|
|
805
|
-
filters: {
|
|
806
|
-
|
|
807
|
-
|
|
853
|
+
const terminatedSessions = await strapi2.documents(SESSION_UID$3).findMany({
|
|
854
|
+
filters: {
|
|
855
|
+
user: { documentId: userDocId },
|
|
856
|
+
terminatedManually: true
|
|
857
|
+
},
|
|
858
|
+
limit: 1
|
|
808
859
|
});
|
|
809
|
-
|
|
810
|
-
const hasInactiveSessions = allSessions?.some((s3) => s3.isActive === false);
|
|
811
|
-
if (hasInactiveSessions) {
|
|
860
|
+
if (terminatedSessions && terminatedSessions.length > 0) {
|
|
812
861
|
strapi2.log.info(
|
|
813
|
-
`[magic-sessionmanager] [JWT-BLOCKED] User ${userDocId.substring(0, 8)}...
|
|
862
|
+
`[magic-sessionmanager] [JWT-BLOCKED] User ${userDocId.substring(0, 8)}... has terminated sessions`
|
|
814
863
|
);
|
|
815
864
|
return null;
|
|
816
865
|
}
|
|
817
|
-
if (
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
`[magic-sessionmanager] [JWT-BLOCKED] No sessions exist for user ${userDocId.substring(0, 8)}... (strictMode enabled)`
|
|
821
|
-
);
|
|
822
|
-
return null;
|
|
823
|
-
}
|
|
824
|
-
strapi2.log.warn(
|
|
825
|
-
`[magic-sessionmanager] [JWT-WARN] No session found for user ${userDocId.substring(0, 8)}... (allowing - session may not have been created)`
|
|
866
|
+
if (strictMode) {
|
|
867
|
+
strapi2.log.info(
|
|
868
|
+
`[magic-sessionmanager] [JWT-BLOCKED] No sessions exist for user ${userDocId.substring(0, 8)}... (strictMode)`
|
|
826
869
|
);
|
|
827
|
-
return
|
|
870
|
+
return null;
|
|
828
871
|
}
|
|
829
872
|
strapi2.log.warn(
|
|
830
|
-
`[magic-sessionmanager] [JWT-
|
|
873
|
+
`[magic-sessionmanager] [JWT-WARN] No session for user ${userDocId.substring(0, 8)}... (allowing)`
|
|
831
874
|
);
|
|
832
875
|
return decoded;
|
|
833
876
|
} catch (err) {
|
|
@@ -947,6 +990,11 @@ const attributes = {
|
|
|
947
990
|
"default": true,
|
|
948
991
|
required: true
|
|
949
992
|
},
|
|
993
|
+
terminatedManually: {
|
|
994
|
+
type: "boolean",
|
|
995
|
+
"default": false,
|
|
996
|
+
required: false
|
|
997
|
+
},
|
|
950
998
|
geoLocation: {
|
|
951
999
|
type: "json"
|
|
952
1000
|
},
|
|
@@ -1086,6 +1134,15 @@ var admin$1 = {
|
|
|
1086
1134
|
description: "Terminate a specific session (admin)"
|
|
1087
1135
|
}
|
|
1088
1136
|
},
|
|
1137
|
+
{
|
|
1138
|
+
method: "POST",
|
|
1139
|
+
path: "/sessions/:sessionId/simulate-timeout",
|
|
1140
|
+
handler: "session.simulateTimeout",
|
|
1141
|
+
config: {
|
|
1142
|
+
policies: ["admin::isAuthenticatedAdmin"],
|
|
1143
|
+
description: "Simulate session timeout for testing (sets isActive: false, terminatedManually: false)"
|
|
1144
|
+
}
|
|
1145
|
+
},
|
|
1089
1146
|
{
|
|
1090
1147
|
method: "DELETE",
|
|
1091
1148
|
path: "/sessions/:sessionId",
|
|
@@ -1667,6 +1724,40 @@ var session$3 = {
|
|
|
1667
1724
|
ctx.throw(500, "Error terminating session");
|
|
1668
1725
|
}
|
|
1669
1726
|
},
|
|
1727
|
+
/**
|
|
1728
|
+
* Simulate session timeout for testing (Admin action)
|
|
1729
|
+
* POST /magic-sessionmanager/sessions/:sessionId/simulate-timeout
|
|
1730
|
+
* Sets isActive: false, terminatedManually: false (as if cleanup job ran)
|
|
1731
|
+
* This allows testing session reactivation behavior
|
|
1732
|
+
*/
|
|
1733
|
+
async simulateTimeout(ctx) {
|
|
1734
|
+
try {
|
|
1735
|
+
const { sessionId } = ctx.params;
|
|
1736
|
+
const session2 = await strapi.documents(SESSION_UID$2).findOne({
|
|
1737
|
+
documentId: sessionId
|
|
1738
|
+
});
|
|
1739
|
+
if (!session2) {
|
|
1740
|
+
return ctx.notFound("Session not found");
|
|
1741
|
+
}
|
|
1742
|
+
await strapi.documents(SESSION_UID$2).update({
|
|
1743
|
+
documentId: sessionId,
|
|
1744
|
+
data: {
|
|
1745
|
+
isActive: false,
|
|
1746
|
+
terminatedManually: false
|
|
1747
|
+
// This allows reactivation!
|
|
1748
|
+
}
|
|
1749
|
+
});
|
|
1750
|
+
strapi.log.info(`[magic-sessionmanager] [TEST] Session ${sessionId} simulated timeout (terminatedManually: false)`);
|
|
1751
|
+
ctx.body = {
|
|
1752
|
+
message: `Session ${sessionId} marked as timed out (reactivatable)`,
|
|
1753
|
+
success: true,
|
|
1754
|
+
terminatedManually: false
|
|
1755
|
+
};
|
|
1756
|
+
} catch (err) {
|
|
1757
|
+
strapi.log.error("[magic-sessionmanager] Error simulating timeout:", err);
|
|
1758
|
+
ctx.throw(500, "Error simulating session timeout");
|
|
1759
|
+
}
|
|
1760
|
+
},
|
|
1670
1761
|
/**
|
|
1671
1762
|
* Terminate a single session (Admin action)
|
|
1672
1763
|
* POST /magic-sessionmanager/sessions/:sessionId/terminate
|
|
@@ -2208,10 +2299,11 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2208
2299
|
documentId: sessionId,
|
|
2209
2300
|
data: {
|
|
2210
2301
|
isActive: false,
|
|
2302
|
+
terminatedManually: true,
|
|
2211
2303
|
logoutTime: now
|
|
2212
2304
|
}
|
|
2213
2305
|
});
|
|
2214
|
-
log.info(`Session ${sessionId} terminated`);
|
|
2306
|
+
log.info(`Session ${sessionId} terminated (manual)`);
|
|
2215
2307
|
} else if (userId) {
|
|
2216
2308
|
let userDocumentId = userId;
|
|
2217
2309
|
if (!isNaN(userId)) {
|
|
@@ -2232,11 +2324,12 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2232
2324
|
documentId: session2.documentId,
|
|
2233
2325
|
data: {
|
|
2234
2326
|
isActive: false,
|
|
2327
|
+
terminatedManually: true,
|
|
2235
2328
|
logoutTime: now
|
|
2236
2329
|
}
|
|
2237
2330
|
});
|
|
2238
2331
|
}
|
|
2239
|
-
log.info(`All sessions terminated for user ${userDocumentId}`);
|
|
2332
|
+
log.info(`All sessions terminated (manual) for user ${userDocumentId}`);
|
|
2240
2333
|
}
|
|
2241
2334
|
} catch (err) {
|
|
2242
2335
|
log.error("Error terminating session:", err);
|
|
@@ -2577,7 +2670,11 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2577
2670
|
if (lastActiveTime < cutoffTime) {
|
|
2578
2671
|
await strapi2.documents(SESSION_UID$1).update({
|
|
2579
2672
|
documentId: session2.documentId,
|
|
2580
|
-
data: {
|
|
2673
|
+
data: {
|
|
2674
|
+
isActive: false,
|
|
2675
|
+
terminatedManually: false
|
|
2676
|
+
// Timeout, not manual - can be reactivated
|
|
2677
|
+
}
|
|
2581
2678
|
});
|
|
2582
2679
|
deactivatedCount++;
|
|
2583
2680
|
}
|
|
@@ -2630,7 +2727,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2630
2727
|
}
|
|
2631
2728
|
};
|
|
2632
2729
|
};
|
|
2633
|
-
const version$1 = "4.
|
|
2730
|
+
const version$1 = "4.4.0";
|
|
2634
2731
|
const require$$2 = {
|
|
2635
2732
|
version: version$1
|
|
2636
2733
|
};
|
|
@@ -38966,17 +39063,35 @@ var sessionRequired$1 = async (policyContext, config2, { strapi: strapi2 }) => {
|
|
|
38966
39063
|
if (activeSessions && activeSessions.length > 0) {
|
|
38967
39064
|
return true;
|
|
38968
39065
|
}
|
|
38969
|
-
const
|
|
38970
|
-
filters: {
|
|
38971
|
-
|
|
38972
|
-
|
|
39066
|
+
const inactiveSessions = await strapi2.documents(SESSION_UID).findMany({
|
|
39067
|
+
filters: {
|
|
39068
|
+
user: { documentId: userDocId },
|
|
39069
|
+
isActive: false
|
|
39070
|
+
},
|
|
39071
|
+
limit: 5,
|
|
39072
|
+
fields: ["documentId", "terminatedManually", "lastActive"],
|
|
39073
|
+
sort: [{ lastActive: "desc" }]
|
|
38973
39074
|
});
|
|
38974
|
-
|
|
38975
|
-
|
|
39075
|
+
if (inactiveSessions && inactiveSessions.length > 0) {
|
|
39076
|
+
const manuallyTerminated = inactiveSessions.find((s3) => s3.terminatedManually === true);
|
|
39077
|
+
if (manuallyTerminated) {
|
|
39078
|
+
strapi2.log.info(
|
|
39079
|
+
`[magic-sessionmanager] [POLICY-BLOCKED] User ${userDocId.substring(0, 8)}... was manually logged out`
|
|
39080
|
+
);
|
|
39081
|
+
throw new errors.UnauthorizedError("Session terminated. Please login again.");
|
|
39082
|
+
}
|
|
39083
|
+
const sessionToReactivate = inactiveSessions[0];
|
|
39084
|
+
await strapi2.documents(SESSION_UID).update({
|
|
39085
|
+
documentId: sessionToReactivate.documentId,
|
|
39086
|
+
data: {
|
|
39087
|
+
isActive: true,
|
|
39088
|
+
lastActive: /* @__PURE__ */ new Date()
|
|
39089
|
+
}
|
|
39090
|
+
});
|
|
38976
39091
|
strapi2.log.info(
|
|
38977
|
-
`[magic-sessionmanager] [POLICY-
|
|
39092
|
+
`[magic-sessionmanager] [POLICY-REACTIVATED] Session reactivated for user ${userDocId.substring(0, 8)}...`
|
|
38978
39093
|
);
|
|
38979
|
-
|
|
39094
|
+
return true;
|
|
38980
39095
|
}
|
|
38981
39096
|
if (strictMode) {
|
|
38982
39097
|
strapi2.log.info(
|
package/package.json
CHANGED