strapi-plugin-magic-sessionmanager 4.2.12 → 4.2.14
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 +212 -46
- package/dist/server/index.mjs +212 -46
- package/package.json +1 -1
package/dist/server/index.js
CHANGED
|
@@ -219,6 +219,18 @@ var encryption = {
|
|
|
219
219
|
const SESSION_UID$3 = "plugin::magic-sessionmanager.session";
|
|
220
220
|
const { hashToken: hashToken$3 } = encryption;
|
|
221
221
|
const lastTouchCache = /* @__PURE__ */ new Map();
|
|
222
|
+
const CACHE_MAX_SIZE = 1e4;
|
|
223
|
+
const CACHE_CLEANUP_AGE = 60 * 60 * 1e3;
|
|
224
|
+
function cleanupOldCacheEntries() {
|
|
225
|
+
if (lastTouchCache.size < CACHE_MAX_SIZE) return;
|
|
226
|
+
const now = Date.now();
|
|
227
|
+
const cutoff = now - CACHE_CLEANUP_AGE;
|
|
228
|
+
for (const [key, timestamp] of lastTouchCache.entries()) {
|
|
229
|
+
if (timestamp < cutoff) {
|
|
230
|
+
lastTouchCache.delete(key);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
222
234
|
var lastSeen = ({ strapi: strapi2 }) => {
|
|
223
235
|
return async (ctx, next) => {
|
|
224
236
|
const currentToken = ctx.request.headers.authorization?.replace("Bearer ", "");
|
|
@@ -226,11 +238,50 @@ var lastSeen = ({ strapi: strapi2 }) => {
|
|
|
226
238
|
await next();
|
|
227
239
|
return;
|
|
228
240
|
}
|
|
229
|
-
const skipPaths = [
|
|
241
|
+
const skipPaths = [
|
|
242
|
+
"/admin",
|
|
243
|
+
// Admin panel UI
|
|
244
|
+
"/content-manager",
|
|
245
|
+
// Content Manager
|
|
246
|
+
"/content-type-builder",
|
|
247
|
+
// Content-Type Builder
|
|
248
|
+
"/upload",
|
|
249
|
+
// Media Library
|
|
250
|
+
"/i18n",
|
|
251
|
+
// Internationalization
|
|
252
|
+
"/users-permissions",
|
|
253
|
+
// Users & Permissions settings
|
|
254
|
+
"/email",
|
|
255
|
+
// Email plugin
|
|
256
|
+
"/_health",
|
|
257
|
+
// Health check
|
|
258
|
+
"/favicon.ico",
|
|
259
|
+
// Static assets
|
|
260
|
+
"/api/auth/local",
|
|
261
|
+
// Login endpoint
|
|
262
|
+
"/api/auth/register",
|
|
263
|
+
// Registration endpoint
|
|
264
|
+
"/api/auth/forgot-password",
|
|
265
|
+
// Password reset
|
|
266
|
+
"/api/auth/reset-password",
|
|
267
|
+
// Password reset
|
|
268
|
+
"/api/auth/logout",
|
|
269
|
+
// Logout endpoint (handled separately)
|
|
270
|
+
"/api/auth/refresh",
|
|
271
|
+
// Refresh token (has own validation in bootstrap.js)
|
|
272
|
+
"/api/connect",
|
|
273
|
+
// OAuth providers
|
|
274
|
+
"/api/magic-link"
|
|
275
|
+
// Magic link auth (if using magic-link plugin)
|
|
276
|
+
];
|
|
230
277
|
if (skipPaths.some((p) => ctx.path.startsWith(p))) {
|
|
231
278
|
await next();
|
|
232
279
|
return;
|
|
233
280
|
}
|
|
281
|
+
if (!ctx.path.startsWith("/api/")) {
|
|
282
|
+
await next();
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
234
285
|
let matchingSession = null;
|
|
235
286
|
try {
|
|
236
287
|
const currentTokenHash = hashToken$3(currentToken);
|
|
@@ -248,10 +299,8 @@ var lastSeen = ({ strapi: strapi2 }) => {
|
|
|
248
299
|
ctx.state.sessionUserId = matchingSession.user.documentId;
|
|
249
300
|
}
|
|
250
301
|
} else {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
return ctx.unauthorized("This session has been terminated. Please login again.");
|
|
254
|
-
}
|
|
302
|
+
strapi2.log.info(`[magic-sessionmanager] [BLOCKED] Request blocked - session terminated or invalid (token hash: ${currentTokenHash.substring(0, 8)}...)`);
|
|
303
|
+
return ctx.unauthorized("This session has been terminated. Please login again.");
|
|
255
304
|
}
|
|
256
305
|
} catch (err) {
|
|
257
306
|
strapi2.log.debug("[magic-sessionmanager] Error checking session:", err.message);
|
|
@@ -265,6 +314,7 @@ var lastSeen = ({ strapi: strapi2 }) => {
|
|
|
265
314
|
const lastTouch = lastTouchCache.get(matchingSession.documentId) || 0;
|
|
266
315
|
if (now - lastTouch > rateLimit) {
|
|
267
316
|
lastTouchCache.set(matchingSession.documentId, now);
|
|
317
|
+
cleanupOldCacheEntries();
|
|
268
318
|
await strapi2.documents(SESSION_UID$3).update({
|
|
269
319
|
documentId: matchingSession.documentId,
|
|
270
320
|
data: { lastActive: /* @__PURE__ */ new Date() }
|
|
@@ -351,20 +401,13 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
351
401
|
ctx.body = { message: "Logged out successfully" };
|
|
352
402
|
return;
|
|
353
403
|
}
|
|
354
|
-
const
|
|
404
|
+
const tokenHashValue = hashToken$2(token);
|
|
405
|
+
const matchingSession = await strapi2.documents(SESSION_UID$2).findFirst({
|
|
355
406
|
filters: {
|
|
407
|
+
tokenHash: tokenHashValue,
|
|
356
408
|
isActive: true
|
|
357
409
|
}
|
|
358
410
|
});
|
|
359
|
-
const matchingSession = allSessions.find((session2) => {
|
|
360
|
-
if (!session2.token) return false;
|
|
361
|
-
try {
|
|
362
|
-
const decrypted = decryptToken$2(session2.token);
|
|
363
|
-
return decrypted === token;
|
|
364
|
-
} catch (err) {
|
|
365
|
-
return false;
|
|
366
|
-
}
|
|
367
|
-
});
|
|
368
411
|
if (matchingSession) {
|
|
369
412
|
await sessionService.terminateSession({ sessionId: matchingSession.documentId });
|
|
370
413
|
log.info(`[LOGOUT] Logout via /api/auth/logout - Session ${matchingSession.documentId} terminated`);
|
|
@@ -509,20 +552,13 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
509
552
|
try {
|
|
510
553
|
const refreshToken = ctx.request.body?.refreshToken;
|
|
511
554
|
if (refreshToken) {
|
|
512
|
-
const
|
|
555
|
+
const refreshTokenHashValue = hashToken$2(refreshToken);
|
|
556
|
+
const matchingSession = await strapi2.documents(SESSION_UID$2).findFirst({
|
|
513
557
|
filters: {
|
|
558
|
+
refreshTokenHash: refreshTokenHashValue,
|
|
514
559
|
isActive: true
|
|
515
560
|
}
|
|
516
561
|
});
|
|
517
|
-
const matchingSession = allSessions.find((session2) => {
|
|
518
|
-
if (!session2.refreshToken) return false;
|
|
519
|
-
try {
|
|
520
|
-
const decrypted = decryptToken$2(session2.refreshToken);
|
|
521
|
-
return decrypted === refreshToken;
|
|
522
|
-
} catch (err) {
|
|
523
|
-
return false;
|
|
524
|
-
}
|
|
525
|
-
});
|
|
526
562
|
if (!matchingSession) {
|
|
527
563
|
log.warn("[BLOCKED] Blocked refresh token request - no active session");
|
|
528
564
|
ctx.status = 401;
|
|
@@ -548,20 +584,13 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
548
584
|
const newAccessToken = ctx.body.jwt;
|
|
549
585
|
const newRefreshToken = ctx.body.refreshToken;
|
|
550
586
|
if (oldRefreshToken) {
|
|
551
|
-
const
|
|
587
|
+
const oldRefreshTokenHash = hashToken$2(oldRefreshToken);
|
|
588
|
+
const matchingSession = await strapi2.documents(SESSION_UID$2).findFirst({
|
|
552
589
|
filters: {
|
|
590
|
+
refreshTokenHash: oldRefreshTokenHash,
|
|
553
591
|
isActive: true
|
|
554
592
|
}
|
|
555
593
|
});
|
|
556
|
-
const matchingSession = allSessions.find((session2) => {
|
|
557
|
-
if (!session2.refreshToken) return false;
|
|
558
|
-
try {
|
|
559
|
-
const decrypted = decryptToken$2(session2.refreshToken);
|
|
560
|
-
return decrypted === oldRefreshToken;
|
|
561
|
-
} catch (err) {
|
|
562
|
-
return false;
|
|
563
|
-
}
|
|
564
|
-
});
|
|
565
594
|
if (matchingSession) {
|
|
566
595
|
const encryptedToken = newAccessToken ? encryptToken$1(newAccessToken) : matchingSession.token;
|
|
567
596
|
const encryptedRefreshToken = newRefreshToken ? encryptToken$1(newRefreshToken) : matchingSession.refreshToken;
|
|
@@ -690,11 +719,11 @@ var destroy$1 = async ({ strapi: strapi2 }) => {
|
|
|
690
719
|
const log = createLogger$2(strapi2);
|
|
691
720
|
if (strapi2.licenseGuard && strapi2.licenseGuard.pingInterval) {
|
|
692
721
|
clearInterval(strapi2.licenseGuard.pingInterval);
|
|
693
|
-
log.info("
|
|
722
|
+
log.info("[STOP] License pinging stopped");
|
|
694
723
|
}
|
|
695
724
|
if (strapi2.sessionManagerIntervals && strapi2.sessionManagerIntervals.cleanup) {
|
|
696
725
|
clearInterval(strapi2.sessionManagerIntervals.cleanup);
|
|
697
|
-
log.info("
|
|
726
|
+
log.info("[STOP] Session cleanup interval stopped");
|
|
698
727
|
}
|
|
699
728
|
log.info("[SUCCESS] Plugin cleanup completed");
|
|
700
729
|
};
|
|
@@ -1175,6 +1204,7 @@ var session$3 = {
|
|
|
1175
1204
|
* GET /api/magic-sessionmanager/my-sessions
|
|
1176
1205
|
* Automatically uses the authenticated user's documentId
|
|
1177
1206
|
* Marks which session is the current one (based on JWT token hash)
|
|
1207
|
+
* Fetches geolocation data on-demand if not already stored
|
|
1178
1208
|
*/
|
|
1179
1209
|
async getOwnSessions(ctx) {
|
|
1180
1210
|
try {
|
|
@@ -1191,7 +1221,8 @@ var session$3 = {
|
|
|
1191
1221
|
const config2 = strapi.config.get("plugin::magic-sessionmanager") || {};
|
|
1192
1222
|
const inactivityTimeout = config2.inactivityTimeout || 15 * 60 * 1e3;
|
|
1193
1223
|
const now = /* @__PURE__ */ new Date();
|
|
1194
|
-
const
|
|
1224
|
+
const geolocationService = strapi.plugin("magic-sessionmanager").service("geolocation");
|
|
1225
|
+
const sessionsWithCurrent = await Promise.all(allSessions.map(async (session2) => {
|
|
1195
1226
|
const lastActiveTime = session2.lastActive ? new Date(session2.lastActive) : new Date(session2.loginTime);
|
|
1196
1227
|
const timeSinceActive = now - lastActiveTime;
|
|
1197
1228
|
const isTrulyActive = session2.isActive && timeSinceActive < inactivityTimeout;
|
|
@@ -1208,6 +1239,31 @@ var session$3 = {
|
|
|
1208
1239
|
geoLocation = null;
|
|
1209
1240
|
}
|
|
1210
1241
|
}
|
|
1242
|
+
if (!geoLocation && session2.ipAddress) {
|
|
1243
|
+
try {
|
|
1244
|
+
const geoData = await geolocationService.getIpInfo(session2.ipAddress);
|
|
1245
|
+
if (geoData && geoData.country !== "Unknown") {
|
|
1246
|
+
geoLocation = {
|
|
1247
|
+
country: geoData.country,
|
|
1248
|
+
country_code: geoData.country_code,
|
|
1249
|
+
country_flag: geoData.country_flag,
|
|
1250
|
+
city: geoData.city,
|
|
1251
|
+
region: geoData.region,
|
|
1252
|
+
timezone: geoData.timezone
|
|
1253
|
+
};
|
|
1254
|
+
strapi.documents(SESSION_UID$1).update({
|
|
1255
|
+
documentId: session2.documentId,
|
|
1256
|
+
data: {
|
|
1257
|
+
geoLocation: JSON.stringify(geoLocation),
|
|
1258
|
+
securityScore: geoData.securityScore || null
|
|
1259
|
+
}
|
|
1260
|
+
}).catch(() => {
|
|
1261
|
+
});
|
|
1262
|
+
}
|
|
1263
|
+
} catch (geoErr) {
|
|
1264
|
+
strapi.log.debug("[magic-sessionmanager] Geolocation lookup failed:", geoErr.message);
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1211
1267
|
const {
|
|
1212
1268
|
token,
|
|
1213
1269
|
tokenHash,
|
|
@@ -1231,7 +1287,7 @@ var session$3 = {
|
|
|
1231
1287
|
isTrulyActive,
|
|
1232
1288
|
minutesSinceActive: Math.floor(timeSinceActive / 1e3 / 60)
|
|
1233
1289
|
};
|
|
1234
|
-
});
|
|
1290
|
+
}));
|
|
1235
1291
|
sessionsWithCurrent.sort((a, b) => {
|
|
1236
1292
|
if (a.isCurrentSession) return -1;
|
|
1237
1293
|
if (b.isCurrentSession) return 1;
|
|
@@ -1333,6 +1389,7 @@ var session$3 = {
|
|
|
1333
1389
|
* Get current session info based on JWT token hash
|
|
1334
1390
|
* GET /api/magic-sessionmanager/current-session
|
|
1335
1391
|
* Returns the session associated with the current JWT token
|
|
1392
|
+
* Fetches geolocation on-demand if not already stored
|
|
1336
1393
|
*/
|
|
1337
1394
|
async getCurrentSession(ctx) {
|
|
1338
1395
|
try {
|
|
@@ -1369,6 +1426,32 @@ var session$3 = {
|
|
|
1369
1426
|
geoLocation = null;
|
|
1370
1427
|
}
|
|
1371
1428
|
}
|
|
1429
|
+
if (!geoLocation && currentSession.ipAddress) {
|
|
1430
|
+
try {
|
|
1431
|
+
const geolocationService = strapi.plugin("magic-sessionmanager").service("geolocation");
|
|
1432
|
+
const geoData = await geolocationService.getIpInfo(currentSession.ipAddress);
|
|
1433
|
+
if (geoData && geoData.country !== "Unknown") {
|
|
1434
|
+
geoLocation = {
|
|
1435
|
+
country: geoData.country,
|
|
1436
|
+
country_code: geoData.country_code,
|
|
1437
|
+
country_flag: geoData.country_flag,
|
|
1438
|
+
city: geoData.city,
|
|
1439
|
+
region: geoData.region,
|
|
1440
|
+
timezone: geoData.timezone
|
|
1441
|
+
};
|
|
1442
|
+
strapi.documents(SESSION_UID$1).update({
|
|
1443
|
+
documentId: currentSession.documentId,
|
|
1444
|
+
data: {
|
|
1445
|
+
geoLocation: JSON.stringify(geoLocation),
|
|
1446
|
+
securityScore: geoData.securityScore || null
|
|
1447
|
+
}
|
|
1448
|
+
}).catch(() => {
|
|
1449
|
+
});
|
|
1450
|
+
}
|
|
1451
|
+
} catch (geoErr) {
|
|
1452
|
+
strapi.log.debug("[magic-sessionmanager] Geolocation lookup failed:", geoErr.message);
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1372
1455
|
const {
|
|
1373
1456
|
token: _,
|
|
1374
1457
|
tokenHash: _th,
|
|
@@ -2035,6 +2118,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2035
2118
|
},
|
|
2036
2119
|
/**
|
|
2037
2120
|
* Get ALL sessions (active + inactive) with accurate online status
|
|
2121
|
+
* Fetches geolocation on-demand for sessions without it (limited to prevent API abuse)
|
|
2038
2122
|
* @returns {Promise<Array>} All sessions with enhanced data
|
|
2039
2123
|
*/
|
|
2040
2124
|
async getAllSessions() {
|
|
@@ -2047,8 +2131,10 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2047
2131
|
});
|
|
2048
2132
|
const config2 = strapi2.config.get("plugin::magic-sessionmanager") || {};
|
|
2049
2133
|
const inactivityTimeout = config2.inactivityTimeout || 15 * 60 * 1e3;
|
|
2134
|
+
const geolocationService = strapi2.plugin("magic-sessionmanager").service("geolocation");
|
|
2135
|
+
let geoLookupsRemaining = 20;
|
|
2050
2136
|
const now = /* @__PURE__ */ new Date();
|
|
2051
|
-
const enhancedSessions = sessions.map((session2) => {
|
|
2137
|
+
const enhancedSessions = await Promise.all(sessions.map(async (session2) => {
|
|
2052
2138
|
const lastActiveTime = session2.lastActive ? new Date(session2.lastActive) : new Date(session2.loginTime);
|
|
2053
2139
|
const timeSinceActive = now - lastActiveTime;
|
|
2054
2140
|
const isTrulyActive = session2.isActive && timeSinceActive < inactivityTimeout;
|
|
@@ -2064,6 +2150,32 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2064
2150
|
geoLocation = null;
|
|
2065
2151
|
}
|
|
2066
2152
|
}
|
|
2153
|
+
if (!geoLocation && session2.ipAddress && geoLookupsRemaining > 0) {
|
|
2154
|
+
geoLookupsRemaining--;
|
|
2155
|
+
try {
|
|
2156
|
+
const geoData = await geolocationService.getIpInfo(session2.ipAddress);
|
|
2157
|
+
if (geoData && geoData.country !== "Unknown") {
|
|
2158
|
+
geoLocation = {
|
|
2159
|
+
country: geoData.country,
|
|
2160
|
+
country_code: geoData.country_code,
|
|
2161
|
+
country_flag: geoData.country_flag,
|
|
2162
|
+
city: geoData.city,
|
|
2163
|
+
region: geoData.region,
|
|
2164
|
+
timezone: geoData.timezone
|
|
2165
|
+
};
|
|
2166
|
+
strapi2.documents(SESSION_UID).update({
|
|
2167
|
+
documentId: session2.documentId,
|
|
2168
|
+
data: {
|
|
2169
|
+
geoLocation: JSON.stringify(geoLocation),
|
|
2170
|
+
securityScore: geoData.securityScore || null
|
|
2171
|
+
}
|
|
2172
|
+
}).catch(() => {
|
|
2173
|
+
});
|
|
2174
|
+
}
|
|
2175
|
+
} catch (geoErr) {
|
|
2176
|
+
log.debug("Geolocation lookup failed:", geoErr.message);
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2067
2179
|
const {
|
|
2068
2180
|
token,
|
|
2069
2181
|
tokenHash,
|
|
@@ -2085,7 +2197,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2085
2197
|
isTrulyActive,
|
|
2086
2198
|
minutesSinceActive: Math.floor(timeSinceActive / 1e3 / 60)
|
|
2087
2199
|
};
|
|
2088
|
-
});
|
|
2200
|
+
}));
|
|
2089
2201
|
return enhancedSessions;
|
|
2090
2202
|
} catch (err) {
|
|
2091
2203
|
log.error("Error getting all sessions:", err);
|
|
@@ -2094,6 +2206,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2094
2206
|
},
|
|
2095
2207
|
/**
|
|
2096
2208
|
* Get all active sessions with accurate online status
|
|
2209
|
+
* Fetches geolocation on-demand for sessions without it
|
|
2097
2210
|
* @returns {Promise<Array>} Active sessions with user data and online status
|
|
2098
2211
|
*/
|
|
2099
2212
|
async getActiveSessions() {
|
|
@@ -2105,8 +2218,9 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2105
2218
|
});
|
|
2106
2219
|
const config2 = strapi2.config.get("plugin::magic-sessionmanager") || {};
|
|
2107
2220
|
const inactivityTimeout = config2.inactivityTimeout || 15 * 60 * 1e3;
|
|
2221
|
+
const geolocationService = strapi2.plugin("magic-sessionmanager").service("geolocation");
|
|
2108
2222
|
const now = /* @__PURE__ */ new Date();
|
|
2109
|
-
const enhancedSessions = sessions.map((session2) => {
|
|
2223
|
+
const enhancedSessions = await Promise.all(sessions.map(async (session2) => {
|
|
2110
2224
|
const lastActiveTime = session2.lastActive ? new Date(session2.lastActive) : new Date(session2.loginTime);
|
|
2111
2225
|
const timeSinceActive = now - lastActiveTime;
|
|
2112
2226
|
const isTrulyActive = timeSinceActive < inactivityTimeout;
|
|
@@ -2122,6 +2236,31 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2122
2236
|
geoLocation = null;
|
|
2123
2237
|
}
|
|
2124
2238
|
}
|
|
2239
|
+
if (!geoLocation && session2.ipAddress) {
|
|
2240
|
+
try {
|
|
2241
|
+
const geoData = await geolocationService.getIpInfo(session2.ipAddress);
|
|
2242
|
+
if (geoData && geoData.country !== "Unknown") {
|
|
2243
|
+
geoLocation = {
|
|
2244
|
+
country: geoData.country,
|
|
2245
|
+
country_code: geoData.country_code,
|
|
2246
|
+
country_flag: geoData.country_flag,
|
|
2247
|
+
city: geoData.city,
|
|
2248
|
+
region: geoData.region,
|
|
2249
|
+
timezone: geoData.timezone
|
|
2250
|
+
};
|
|
2251
|
+
strapi2.documents(SESSION_UID).update({
|
|
2252
|
+
documentId: session2.documentId,
|
|
2253
|
+
data: {
|
|
2254
|
+
geoLocation: JSON.stringify(geoLocation),
|
|
2255
|
+
securityScore: geoData.securityScore || null
|
|
2256
|
+
}
|
|
2257
|
+
}).catch(() => {
|
|
2258
|
+
});
|
|
2259
|
+
}
|
|
2260
|
+
} catch (geoErr) {
|
|
2261
|
+
log.debug("Geolocation lookup failed:", geoErr.message);
|
|
2262
|
+
}
|
|
2263
|
+
}
|
|
2125
2264
|
const {
|
|
2126
2265
|
token,
|
|
2127
2266
|
tokenHash,
|
|
@@ -2141,7 +2280,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2141
2280
|
isTrulyActive,
|
|
2142
2281
|
minutesSinceActive: Math.floor(timeSinceActive / 1e3 / 60)
|
|
2143
2282
|
};
|
|
2144
|
-
});
|
|
2283
|
+
}));
|
|
2145
2284
|
return enhancedSessions.filter((s) => s.isTrulyActive);
|
|
2146
2285
|
} catch (err) {
|
|
2147
2286
|
log.error("Error getting active sessions:", err);
|
|
@@ -2151,6 +2290,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2151
2290
|
/**
|
|
2152
2291
|
* Get all sessions for a specific user
|
|
2153
2292
|
* Supports both numeric id (legacy) and documentId (Strapi v5)
|
|
2293
|
+
* Fetches geolocation on-demand for sessions without it
|
|
2154
2294
|
* @param {string|number} userId - User documentId or numeric id
|
|
2155
2295
|
* @returns {Promise<Array>} User's sessions with accurate online status
|
|
2156
2296
|
*/
|
|
@@ -2169,8 +2309,9 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2169
2309
|
});
|
|
2170
2310
|
const config2 = strapi2.config.get("plugin::magic-sessionmanager") || {};
|
|
2171
2311
|
const inactivityTimeout = config2.inactivityTimeout || 15 * 60 * 1e3;
|
|
2312
|
+
const geolocationService = strapi2.plugin("magic-sessionmanager").service("geolocation");
|
|
2172
2313
|
const now = /* @__PURE__ */ new Date();
|
|
2173
|
-
const enhancedSessions = sessions.map((session2) => {
|
|
2314
|
+
const enhancedSessions = await Promise.all(sessions.map(async (session2) => {
|
|
2174
2315
|
const lastActiveTime = session2.lastActive ? new Date(session2.lastActive) : new Date(session2.loginTime);
|
|
2175
2316
|
const timeSinceActive = now - lastActiveTime;
|
|
2176
2317
|
const isTrulyActive = session2.isActive && timeSinceActive < inactivityTimeout;
|
|
@@ -2186,6 +2327,31 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2186
2327
|
geoLocation = null;
|
|
2187
2328
|
}
|
|
2188
2329
|
}
|
|
2330
|
+
if (!geoLocation && session2.ipAddress) {
|
|
2331
|
+
try {
|
|
2332
|
+
const geoData = await geolocationService.getIpInfo(session2.ipAddress);
|
|
2333
|
+
if (geoData && geoData.country !== "Unknown") {
|
|
2334
|
+
geoLocation = {
|
|
2335
|
+
country: geoData.country,
|
|
2336
|
+
country_code: geoData.country_code,
|
|
2337
|
+
country_flag: geoData.country_flag,
|
|
2338
|
+
city: geoData.city,
|
|
2339
|
+
region: geoData.region,
|
|
2340
|
+
timezone: geoData.timezone
|
|
2341
|
+
};
|
|
2342
|
+
strapi2.documents(SESSION_UID).update({
|
|
2343
|
+
documentId: session2.documentId,
|
|
2344
|
+
data: {
|
|
2345
|
+
geoLocation: JSON.stringify(geoLocation),
|
|
2346
|
+
securityScore: geoData.securityScore || null
|
|
2347
|
+
}
|
|
2348
|
+
}).catch(() => {
|
|
2349
|
+
});
|
|
2350
|
+
}
|
|
2351
|
+
} catch (geoErr) {
|
|
2352
|
+
log.debug("Geolocation lookup failed:", geoErr.message);
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2189
2355
|
const {
|
|
2190
2356
|
token,
|
|
2191
2357
|
tokenHash,
|
|
@@ -2205,7 +2371,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2205
2371
|
isTrulyActive,
|
|
2206
2372
|
minutesSinceActive: Math.floor(timeSinceActive / 1e3 / 60)
|
|
2207
2373
|
};
|
|
2208
|
-
});
|
|
2374
|
+
}));
|
|
2209
2375
|
return enhancedSessions;
|
|
2210
2376
|
} catch (err) {
|
|
2211
2377
|
log.error("Error getting user sessions:", err);
|
|
@@ -2318,7 +2484,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2318
2484
|
}
|
|
2319
2485
|
};
|
|
2320
2486
|
};
|
|
2321
|
-
const version = "4.2.
|
|
2487
|
+
const version = "4.2.13";
|
|
2322
2488
|
const require$$2 = {
|
|
2323
2489
|
version
|
|
2324
2490
|
};
|
package/dist/server/index.mjs
CHANGED
|
@@ -215,6 +215,18 @@ var encryption = {
|
|
|
215
215
|
const SESSION_UID$3 = "plugin::magic-sessionmanager.session";
|
|
216
216
|
const { hashToken: hashToken$3 } = encryption;
|
|
217
217
|
const lastTouchCache = /* @__PURE__ */ new Map();
|
|
218
|
+
const CACHE_MAX_SIZE = 1e4;
|
|
219
|
+
const CACHE_CLEANUP_AGE = 60 * 60 * 1e3;
|
|
220
|
+
function cleanupOldCacheEntries() {
|
|
221
|
+
if (lastTouchCache.size < CACHE_MAX_SIZE) return;
|
|
222
|
+
const now = Date.now();
|
|
223
|
+
const cutoff = now - CACHE_CLEANUP_AGE;
|
|
224
|
+
for (const [key, timestamp] of lastTouchCache.entries()) {
|
|
225
|
+
if (timestamp < cutoff) {
|
|
226
|
+
lastTouchCache.delete(key);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
218
230
|
var lastSeen = ({ strapi: strapi2 }) => {
|
|
219
231
|
return async (ctx, next) => {
|
|
220
232
|
const currentToken = ctx.request.headers.authorization?.replace("Bearer ", "");
|
|
@@ -222,11 +234,50 @@ var lastSeen = ({ strapi: strapi2 }) => {
|
|
|
222
234
|
await next();
|
|
223
235
|
return;
|
|
224
236
|
}
|
|
225
|
-
const skipPaths = [
|
|
237
|
+
const skipPaths = [
|
|
238
|
+
"/admin",
|
|
239
|
+
// Admin panel UI
|
|
240
|
+
"/content-manager",
|
|
241
|
+
// Content Manager
|
|
242
|
+
"/content-type-builder",
|
|
243
|
+
// Content-Type Builder
|
|
244
|
+
"/upload",
|
|
245
|
+
// Media Library
|
|
246
|
+
"/i18n",
|
|
247
|
+
// Internationalization
|
|
248
|
+
"/users-permissions",
|
|
249
|
+
// Users & Permissions settings
|
|
250
|
+
"/email",
|
|
251
|
+
// Email plugin
|
|
252
|
+
"/_health",
|
|
253
|
+
// Health check
|
|
254
|
+
"/favicon.ico",
|
|
255
|
+
// Static assets
|
|
256
|
+
"/api/auth/local",
|
|
257
|
+
// Login endpoint
|
|
258
|
+
"/api/auth/register",
|
|
259
|
+
// Registration endpoint
|
|
260
|
+
"/api/auth/forgot-password",
|
|
261
|
+
// Password reset
|
|
262
|
+
"/api/auth/reset-password",
|
|
263
|
+
// Password reset
|
|
264
|
+
"/api/auth/logout",
|
|
265
|
+
// Logout endpoint (handled separately)
|
|
266
|
+
"/api/auth/refresh",
|
|
267
|
+
// Refresh token (has own validation in bootstrap.js)
|
|
268
|
+
"/api/connect",
|
|
269
|
+
// OAuth providers
|
|
270
|
+
"/api/magic-link"
|
|
271
|
+
// Magic link auth (if using magic-link plugin)
|
|
272
|
+
];
|
|
226
273
|
if (skipPaths.some((p) => ctx.path.startsWith(p))) {
|
|
227
274
|
await next();
|
|
228
275
|
return;
|
|
229
276
|
}
|
|
277
|
+
if (!ctx.path.startsWith("/api/")) {
|
|
278
|
+
await next();
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
230
281
|
let matchingSession = null;
|
|
231
282
|
try {
|
|
232
283
|
const currentTokenHash = hashToken$3(currentToken);
|
|
@@ -244,10 +295,8 @@ var lastSeen = ({ strapi: strapi2 }) => {
|
|
|
244
295
|
ctx.state.sessionUserId = matchingSession.user.documentId;
|
|
245
296
|
}
|
|
246
297
|
} else {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
return ctx.unauthorized("This session has been terminated. Please login again.");
|
|
250
|
-
}
|
|
298
|
+
strapi2.log.info(`[magic-sessionmanager] [BLOCKED] Request blocked - session terminated or invalid (token hash: ${currentTokenHash.substring(0, 8)}...)`);
|
|
299
|
+
return ctx.unauthorized("This session has been terminated. Please login again.");
|
|
251
300
|
}
|
|
252
301
|
} catch (err) {
|
|
253
302
|
strapi2.log.debug("[magic-sessionmanager] Error checking session:", err.message);
|
|
@@ -261,6 +310,7 @@ var lastSeen = ({ strapi: strapi2 }) => {
|
|
|
261
310
|
const lastTouch = lastTouchCache.get(matchingSession.documentId) || 0;
|
|
262
311
|
if (now - lastTouch > rateLimit) {
|
|
263
312
|
lastTouchCache.set(matchingSession.documentId, now);
|
|
313
|
+
cleanupOldCacheEntries();
|
|
264
314
|
await strapi2.documents(SESSION_UID$3).update({
|
|
265
315
|
documentId: matchingSession.documentId,
|
|
266
316
|
data: { lastActive: /* @__PURE__ */ new Date() }
|
|
@@ -347,20 +397,13 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
347
397
|
ctx.body = { message: "Logged out successfully" };
|
|
348
398
|
return;
|
|
349
399
|
}
|
|
350
|
-
const
|
|
400
|
+
const tokenHashValue = hashToken$2(token);
|
|
401
|
+
const matchingSession = await strapi2.documents(SESSION_UID$2).findFirst({
|
|
351
402
|
filters: {
|
|
403
|
+
tokenHash: tokenHashValue,
|
|
352
404
|
isActive: true
|
|
353
405
|
}
|
|
354
406
|
});
|
|
355
|
-
const matchingSession = allSessions.find((session2) => {
|
|
356
|
-
if (!session2.token) return false;
|
|
357
|
-
try {
|
|
358
|
-
const decrypted = decryptToken$2(session2.token);
|
|
359
|
-
return decrypted === token;
|
|
360
|
-
} catch (err) {
|
|
361
|
-
return false;
|
|
362
|
-
}
|
|
363
|
-
});
|
|
364
407
|
if (matchingSession) {
|
|
365
408
|
await sessionService.terminateSession({ sessionId: matchingSession.documentId });
|
|
366
409
|
log.info(`[LOGOUT] Logout via /api/auth/logout - Session ${matchingSession.documentId} terminated`);
|
|
@@ -505,20 +548,13 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
505
548
|
try {
|
|
506
549
|
const refreshToken = ctx.request.body?.refreshToken;
|
|
507
550
|
if (refreshToken) {
|
|
508
|
-
const
|
|
551
|
+
const refreshTokenHashValue = hashToken$2(refreshToken);
|
|
552
|
+
const matchingSession = await strapi2.documents(SESSION_UID$2).findFirst({
|
|
509
553
|
filters: {
|
|
554
|
+
refreshTokenHash: refreshTokenHashValue,
|
|
510
555
|
isActive: true
|
|
511
556
|
}
|
|
512
557
|
});
|
|
513
|
-
const matchingSession = allSessions.find((session2) => {
|
|
514
|
-
if (!session2.refreshToken) return false;
|
|
515
|
-
try {
|
|
516
|
-
const decrypted = decryptToken$2(session2.refreshToken);
|
|
517
|
-
return decrypted === refreshToken;
|
|
518
|
-
} catch (err) {
|
|
519
|
-
return false;
|
|
520
|
-
}
|
|
521
|
-
});
|
|
522
558
|
if (!matchingSession) {
|
|
523
559
|
log.warn("[BLOCKED] Blocked refresh token request - no active session");
|
|
524
560
|
ctx.status = 401;
|
|
@@ -544,20 +580,13 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
544
580
|
const newAccessToken = ctx.body.jwt;
|
|
545
581
|
const newRefreshToken = ctx.body.refreshToken;
|
|
546
582
|
if (oldRefreshToken) {
|
|
547
|
-
const
|
|
583
|
+
const oldRefreshTokenHash = hashToken$2(oldRefreshToken);
|
|
584
|
+
const matchingSession = await strapi2.documents(SESSION_UID$2).findFirst({
|
|
548
585
|
filters: {
|
|
586
|
+
refreshTokenHash: oldRefreshTokenHash,
|
|
549
587
|
isActive: true
|
|
550
588
|
}
|
|
551
589
|
});
|
|
552
|
-
const matchingSession = allSessions.find((session2) => {
|
|
553
|
-
if (!session2.refreshToken) return false;
|
|
554
|
-
try {
|
|
555
|
-
const decrypted = decryptToken$2(session2.refreshToken);
|
|
556
|
-
return decrypted === oldRefreshToken;
|
|
557
|
-
} catch (err) {
|
|
558
|
-
return false;
|
|
559
|
-
}
|
|
560
|
-
});
|
|
561
590
|
if (matchingSession) {
|
|
562
591
|
const encryptedToken = newAccessToken ? encryptToken$1(newAccessToken) : matchingSession.token;
|
|
563
592
|
const encryptedRefreshToken = newRefreshToken ? encryptToken$1(newRefreshToken) : matchingSession.refreshToken;
|
|
@@ -686,11 +715,11 @@ var destroy$1 = async ({ strapi: strapi2 }) => {
|
|
|
686
715
|
const log = createLogger$2(strapi2);
|
|
687
716
|
if (strapi2.licenseGuard && strapi2.licenseGuard.pingInterval) {
|
|
688
717
|
clearInterval(strapi2.licenseGuard.pingInterval);
|
|
689
|
-
log.info("
|
|
718
|
+
log.info("[STOP] License pinging stopped");
|
|
690
719
|
}
|
|
691
720
|
if (strapi2.sessionManagerIntervals && strapi2.sessionManagerIntervals.cleanup) {
|
|
692
721
|
clearInterval(strapi2.sessionManagerIntervals.cleanup);
|
|
693
|
-
log.info("
|
|
722
|
+
log.info("[STOP] Session cleanup interval stopped");
|
|
694
723
|
}
|
|
695
724
|
log.info("[SUCCESS] Plugin cleanup completed");
|
|
696
725
|
};
|
|
@@ -1171,6 +1200,7 @@ var session$3 = {
|
|
|
1171
1200
|
* GET /api/magic-sessionmanager/my-sessions
|
|
1172
1201
|
* Automatically uses the authenticated user's documentId
|
|
1173
1202
|
* Marks which session is the current one (based on JWT token hash)
|
|
1203
|
+
* Fetches geolocation data on-demand if not already stored
|
|
1174
1204
|
*/
|
|
1175
1205
|
async getOwnSessions(ctx) {
|
|
1176
1206
|
try {
|
|
@@ -1187,7 +1217,8 @@ var session$3 = {
|
|
|
1187
1217
|
const config2 = strapi.config.get("plugin::magic-sessionmanager") || {};
|
|
1188
1218
|
const inactivityTimeout = config2.inactivityTimeout || 15 * 60 * 1e3;
|
|
1189
1219
|
const now = /* @__PURE__ */ new Date();
|
|
1190
|
-
const
|
|
1220
|
+
const geolocationService = strapi.plugin("magic-sessionmanager").service("geolocation");
|
|
1221
|
+
const sessionsWithCurrent = await Promise.all(allSessions.map(async (session2) => {
|
|
1191
1222
|
const lastActiveTime = session2.lastActive ? new Date(session2.lastActive) : new Date(session2.loginTime);
|
|
1192
1223
|
const timeSinceActive = now - lastActiveTime;
|
|
1193
1224
|
const isTrulyActive = session2.isActive && timeSinceActive < inactivityTimeout;
|
|
@@ -1204,6 +1235,31 @@ var session$3 = {
|
|
|
1204
1235
|
geoLocation = null;
|
|
1205
1236
|
}
|
|
1206
1237
|
}
|
|
1238
|
+
if (!geoLocation && session2.ipAddress) {
|
|
1239
|
+
try {
|
|
1240
|
+
const geoData = await geolocationService.getIpInfo(session2.ipAddress);
|
|
1241
|
+
if (geoData && geoData.country !== "Unknown") {
|
|
1242
|
+
geoLocation = {
|
|
1243
|
+
country: geoData.country,
|
|
1244
|
+
country_code: geoData.country_code,
|
|
1245
|
+
country_flag: geoData.country_flag,
|
|
1246
|
+
city: geoData.city,
|
|
1247
|
+
region: geoData.region,
|
|
1248
|
+
timezone: geoData.timezone
|
|
1249
|
+
};
|
|
1250
|
+
strapi.documents(SESSION_UID$1).update({
|
|
1251
|
+
documentId: session2.documentId,
|
|
1252
|
+
data: {
|
|
1253
|
+
geoLocation: JSON.stringify(geoLocation),
|
|
1254
|
+
securityScore: geoData.securityScore || null
|
|
1255
|
+
}
|
|
1256
|
+
}).catch(() => {
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
} catch (geoErr) {
|
|
1260
|
+
strapi.log.debug("[magic-sessionmanager] Geolocation lookup failed:", geoErr.message);
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1207
1263
|
const {
|
|
1208
1264
|
token,
|
|
1209
1265
|
tokenHash,
|
|
@@ -1227,7 +1283,7 @@ var session$3 = {
|
|
|
1227
1283
|
isTrulyActive,
|
|
1228
1284
|
minutesSinceActive: Math.floor(timeSinceActive / 1e3 / 60)
|
|
1229
1285
|
};
|
|
1230
|
-
});
|
|
1286
|
+
}));
|
|
1231
1287
|
sessionsWithCurrent.sort((a, b) => {
|
|
1232
1288
|
if (a.isCurrentSession) return -1;
|
|
1233
1289
|
if (b.isCurrentSession) return 1;
|
|
@@ -1329,6 +1385,7 @@ var session$3 = {
|
|
|
1329
1385
|
* Get current session info based on JWT token hash
|
|
1330
1386
|
* GET /api/magic-sessionmanager/current-session
|
|
1331
1387
|
* Returns the session associated with the current JWT token
|
|
1388
|
+
* Fetches geolocation on-demand if not already stored
|
|
1332
1389
|
*/
|
|
1333
1390
|
async getCurrentSession(ctx) {
|
|
1334
1391
|
try {
|
|
@@ -1365,6 +1422,32 @@ var session$3 = {
|
|
|
1365
1422
|
geoLocation = null;
|
|
1366
1423
|
}
|
|
1367
1424
|
}
|
|
1425
|
+
if (!geoLocation && currentSession.ipAddress) {
|
|
1426
|
+
try {
|
|
1427
|
+
const geolocationService = strapi.plugin("magic-sessionmanager").service("geolocation");
|
|
1428
|
+
const geoData = await geolocationService.getIpInfo(currentSession.ipAddress);
|
|
1429
|
+
if (geoData && geoData.country !== "Unknown") {
|
|
1430
|
+
geoLocation = {
|
|
1431
|
+
country: geoData.country,
|
|
1432
|
+
country_code: geoData.country_code,
|
|
1433
|
+
country_flag: geoData.country_flag,
|
|
1434
|
+
city: geoData.city,
|
|
1435
|
+
region: geoData.region,
|
|
1436
|
+
timezone: geoData.timezone
|
|
1437
|
+
};
|
|
1438
|
+
strapi.documents(SESSION_UID$1).update({
|
|
1439
|
+
documentId: currentSession.documentId,
|
|
1440
|
+
data: {
|
|
1441
|
+
geoLocation: JSON.stringify(geoLocation),
|
|
1442
|
+
securityScore: geoData.securityScore || null
|
|
1443
|
+
}
|
|
1444
|
+
}).catch(() => {
|
|
1445
|
+
});
|
|
1446
|
+
}
|
|
1447
|
+
} catch (geoErr) {
|
|
1448
|
+
strapi.log.debug("[magic-sessionmanager] Geolocation lookup failed:", geoErr.message);
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1368
1451
|
const {
|
|
1369
1452
|
token: _,
|
|
1370
1453
|
tokenHash: _th,
|
|
@@ -2031,6 +2114,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2031
2114
|
},
|
|
2032
2115
|
/**
|
|
2033
2116
|
* Get ALL sessions (active + inactive) with accurate online status
|
|
2117
|
+
* Fetches geolocation on-demand for sessions without it (limited to prevent API abuse)
|
|
2034
2118
|
* @returns {Promise<Array>} All sessions with enhanced data
|
|
2035
2119
|
*/
|
|
2036
2120
|
async getAllSessions() {
|
|
@@ -2043,8 +2127,10 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2043
2127
|
});
|
|
2044
2128
|
const config2 = strapi2.config.get("plugin::magic-sessionmanager") || {};
|
|
2045
2129
|
const inactivityTimeout = config2.inactivityTimeout || 15 * 60 * 1e3;
|
|
2130
|
+
const geolocationService = strapi2.plugin("magic-sessionmanager").service("geolocation");
|
|
2131
|
+
let geoLookupsRemaining = 20;
|
|
2046
2132
|
const now = /* @__PURE__ */ new Date();
|
|
2047
|
-
const enhancedSessions = sessions.map((session2) => {
|
|
2133
|
+
const enhancedSessions = await Promise.all(sessions.map(async (session2) => {
|
|
2048
2134
|
const lastActiveTime = session2.lastActive ? new Date(session2.lastActive) : new Date(session2.loginTime);
|
|
2049
2135
|
const timeSinceActive = now - lastActiveTime;
|
|
2050
2136
|
const isTrulyActive = session2.isActive && timeSinceActive < inactivityTimeout;
|
|
@@ -2060,6 +2146,32 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2060
2146
|
geoLocation = null;
|
|
2061
2147
|
}
|
|
2062
2148
|
}
|
|
2149
|
+
if (!geoLocation && session2.ipAddress && geoLookupsRemaining > 0) {
|
|
2150
|
+
geoLookupsRemaining--;
|
|
2151
|
+
try {
|
|
2152
|
+
const geoData = await geolocationService.getIpInfo(session2.ipAddress);
|
|
2153
|
+
if (geoData && geoData.country !== "Unknown") {
|
|
2154
|
+
geoLocation = {
|
|
2155
|
+
country: geoData.country,
|
|
2156
|
+
country_code: geoData.country_code,
|
|
2157
|
+
country_flag: geoData.country_flag,
|
|
2158
|
+
city: geoData.city,
|
|
2159
|
+
region: geoData.region,
|
|
2160
|
+
timezone: geoData.timezone
|
|
2161
|
+
};
|
|
2162
|
+
strapi2.documents(SESSION_UID).update({
|
|
2163
|
+
documentId: session2.documentId,
|
|
2164
|
+
data: {
|
|
2165
|
+
geoLocation: JSON.stringify(geoLocation),
|
|
2166
|
+
securityScore: geoData.securityScore || null
|
|
2167
|
+
}
|
|
2168
|
+
}).catch(() => {
|
|
2169
|
+
});
|
|
2170
|
+
}
|
|
2171
|
+
} catch (geoErr) {
|
|
2172
|
+
log.debug("Geolocation lookup failed:", geoErr.message);
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2063
2175
|
const {
|
|
2064
2176
|
token,
|
|
2065
2177
|
tokenHash,
|
|
@@ -2081,7 +2193,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2081
2193
|
isTrulyActive,
|
|
2082
2194
|
minutesSinceActive: Math.floor(timeSinceActive / 1e3 / 60)
|
|
2083
2195
|
};
|
|
2084
|
-
});
|
|
2196
|
+
}));
|
|
2085
2197
|
return enhancedSessions;
|
|
2086
2198
|
} catch (err) {
|
|
2087
2199
|
log.error("Error getting all sessions:", err);
|
|
@@ -2090,6 +2202,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2090
2202
|
},
|
|
2091
2203
|
/**
|
|
2092
2204
|
* Get all active sessions with accurate online status
|
|
2205
|
+
* Fetches geolocation on-demand for sessions without it
|
|
2093
2206
|
* @returns {Promise<Array>} Active sessions with user data and online status
|
|
2094
2207
|
*/
|
|
2095
2208
|
async getActiveSessions() {
|
|
@@ -2101,8 +2214,9 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2101
2214
|
});
|
|
2102
2215
|
const config2 = strapi2.config.get("plugin::magic-sessionmanager") || {};
|
|
2103
2216
|
const inactivityTimeout = config2.inactivityTimeout || 15 * 60 * 1e3;
|
|
2217
|
+
const geolocationService = strapi2.plugin("magic-sessionmanager").service("geolocation");
|
|
2104
2218
|
const now = /* @__PURE__ */ new Date();
|
|
2105
|
-
const enhancedSessions = sessions.map((session2) => {
|
|
2219
|
+
const enhancedSessions = await Promise.all(sessions.map(async (session2) => {
|
|
2106
2220
|
const lastActiveTime = session2.lastActive ? new Date(session2.lastActive) : new Date(session2.loginTime);
|
|
2107
2221
|
const timeSinceActive = now - lastActiveTime;
|
|
2108
2222
|
const isTrulyActive = timeSinceActive < inactivityTimeout;
|
|
@@ -2118,6 +2232,31 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2118
2232
|
geoLocation = null;
|
|
2119
2233
|
}
|
|
2120
2234
|
}
|
|
2235
|
+
if (!geoLocation && session2.ipAddress) {
|
|
2236
|
+
try {
|
|
2237
|
+
const geoData = await geolocationService.getIpInfo(session2.ipAddress);
|
|
2238
|
+
if (geoData && geoData.country !== "Unknown") {
|
|
2239
|
+
geoLocation = {
|
|
2240
|
+
country: geoData.country,
|
|
2241
|
+
country_code: geoData.country_code,
|
|
2242
|
+
country_flag: geoData.country_flag,
|
|
2243
|
+
city: geoData.city,
|
|
2244
|
+
region: geoData.region,
|
|
2245
|
+
timezone: geoData.timezone
|
|
2246
|
+
};
|
|
2247
|
+
strapi2.documents(SESSION_UID).update({
|
|
2248
|
+
documentId: session2.documentId,
|
|
2249
|
+
data: {
|
|
2250
|
+
geoLocation: JSON.stringify(geoLocation),
|
|
2251
|
+
securityScore: geoData.securityScore || null
|
|
2252
|
+
}
|
|
2253
|
+
}).catch(() => {
|
|
2254
|
+
});
|
|
2255
|
+
}
|
|
2256
|
+
} catch (geoErr) {
|
|
2257
|
+
log.debug("Geolocation lookup failed:", geoErr.message);
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2121
2260
|
const {
|
|
2122
2261
|
token,
|
|
2123
2262
|
tokenHash,
|
|
@@ -2137,7 +2276,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2137
2276
|
isTrulyActive,
|
|
2138
2277
|
minutesSinceActive: Math.floor(timeSinceActive / 1e3 / 60)
|
|
2139
2278
|
};
|
|
2140
|
-
});
|
|
2279
|
+
}));
|
|
2141
2280
|
return enhancedSessions.filter((s) => s.isTrulyActive);
|
|
2142
2281
|
} catch (err) {
|
|
2143
2282
|
log.error("Error getting active sessions:", err);
|
|
@@ -2147,6 +2286,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2147
2286
|
/**
|
|
2148
2287
|
* Get all sessions for a specific user
|
|
2149
2288
|
* Supports both numeric id (legacy) and documentId (Strapi v5)
|
|
2289
|
+
* Fetches geolocation on-demand for sessions without it
|
|
2150
2290
|
* @param {string|number} userId - User documentId or numeric id
|
|
2151
2291
|
* @returns {Promise<Array>} User's sessions with accurate online status
|
|
2152
2292
|
*/
|
|
@@ -2165,8 +2305,9 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2165
2305
|
});
|
|
2166
2306
|
const config2 = strapi2.config.get("plugin::magic-sessionmanager") || {};
|
|
2167
2307
|
const inactivityTimeout = config2.inactivityTimeout || 15 * 60 * 1e3;
|
|
2308
|
+
const geolocationService = strapi2.plugin("magic-sessionmanager").service("geolocation");
|
|
2168
2309
|
const now = /* @__PURE__ */ new Date();
|
|
2169
|
-
const enhancedSessions = sessions.map((session2) => {
|
|
2310
|
+
const enhancedSessions = await Promise.all(sessions.map(async (session2) => {
|
|
2170
2311
|
const lastActiveTime = session2.lastActive ? new Date(session2.lastActive) : new Date(session2.loginTime);
|
|
2171
2312
|
const timeSinceActive = now - lastActiveTime;
|
|
2172
2313
|
const isTrulyActive = session2.isActive && timeSinceActive < inactivityTimeout;
|
|
@@ -2182,6 +2323,31 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2182
2323
|
geoLocation = null;
|
|
2183
2324
|
}
|
|
2184
2325
|
}
|
|
2326
|
+
if (!geoLocation && session2.ipAddress) {
|
|
2327
|
+
try {
|
|
2328
|
+
const geoData = await geolocationService.getIpInfo(session2.ipAddress);
|
|
2329
|
+
if (geoData && geoData.country !== "Unknown") {
|
|
2330
|
+
geoLocation = {
|
|
2331
|
+
country: geoData.country,
|
|
2332
|
+
country_code: geoData.country_code,
|
|
2333
|
+
country_flag: geoData.country_flag,
|
|
2334
|
+
city: geoData.city,
|
|
2335
|
+
region: geoData.region,
|
|
2336
|
+
timezone: geoData.timezone
|
|
2337
|
+
};
|
|
2338
|
+
strapi2.documents(SESSION_UID).update({
|
|
2339
|
+
documentId: session2.documentId,
|
|
2340
|
+
data: {
|
|
2341
|
+
geoLocation: JSON.stringify(geoLocation),
|
|
2342
|
+
securityScore: geoData.securityScore || null
|
|
2343
|
+
}
|
|
2344
|
+
}).catch(() => {
|
|
2345
|
+
});
|
|
2346
|
+
}
|
|
2347
|
+
} catch (geoErr) {
|
|
2348
|
+
log.debug("Geolocation lookup failed:", geoErr.message);
|
|
2349
|
+
}
|
|
2350
|
+
}
|
|
2185
2351
|
const {
|
|
2186
2352
|
token,
|
|
2187
2353
|
tokenHash,
|
|
@@ -2201,7 +2367,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2201
2367
|
isTrulyActive,
|
|
2202
2368
|
minutesSinceActive: Math.floor(timeSinceActive / 1e3 / 60)
|
|
2203
2369
|
};
|
|
2204
|
-
});
|
|
2370
|
+
}));
|
|
2205
2371
|
return enhancedSessions;
|
|
2206
2372
|
} catch (err) {
|
|
2207
2373
|
log.error("Error getting user sessions:", err);
|
|
@@ -2314,7 +2480,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2314
2480
|
}
|
|
2315
2481
|
};
|
|
2316
2482
|
};
|
|
2317
|
-
const version = "4.2.
|
|
2483
|
+
const version = "4.2.13";
|
|
2318
2484
|
const require$$2 = {
|
|
2319
2485
|
version
|
|
2320
2486
|
};
|
package/package.json
CHANGED