strapi-plugin-magic-sessionmanager 4.2.12 → 4.2.13
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 +196 -46
- package/dist/server/index.mjs +196 -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,7 +238,30 @@ var lastSeen = ({ strapi: strapi2 }) => {
|
|
|
226
238
|
await next();
|
|
227
239
|
return;
|
|
228
240
|
}
|
|
229
|
-
const skipPaths = [
|
|
241
|
+
const skipPaths = [
|
|
242
|
+
"/admin",
|
|
243
|
+
// Admin panel routes (have their own auth)
|
|
244
|
+
"/_health",
|
|
245
|
+
// Health check
|
|
246
|
+
"/favicon.ico",
|
|
247
|
+
// Static assets
|
|
248
|
+
"/api/auth/local",
|
|
249
|
+
// Login endpoint
|
|
250
|
+
"/api/auth/register",
|
|
251
|
+
// Registration endpoint
|
|
252
|
+
"/api/auth/forgot-password",
|
|
253
|
+
// Password reset
|
|
254
|
+
"/api/auth/reset-password",
|
|
255
|
+
// Password reset
|
|
256
|
+
"/api/auth/logout",
|
|
257
|
+
// Logout endpoint (handled separately)
|
|
258
|
+
"/api/auth/refresh",
|
|
259
|
+
// Refresh token (has own validation in bootstrap.js)
|
|
260
|
+
"/api/connect",
|
|
261
|
+
// OAuth providers
|
|
262
|
+
"/api/magic-link"
|
|
263
|
+
// Magic link auth (if using magic-link plugin)
|
|
264
|
+
];
|
|
230
265
|
if (skipPaths.some((p) => ctx.path.startsWith(p))) {
|
|
231
266
|
await next();
|
|
232
267
|
return;
|
|
@@ -248,10 +283,8 @@ var lastSeen = ({ strapi: strapi2 }) => {
|
|
|
248
283
|
ctx.state.sessionUserId = matchingSession.user.documentId;
|
|
249
284
|
}
|
|
250
285
|
} else {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
return ctx.unauthorized("This session has been terminated. Please login again.");
|
|
254
|
-
}
|
|
286
|
+
strapi2.log.info(`[magic-sessionmanager] [BLOCKED] Request blocked - session terminated or invalid (token hash: ${currentTokenHash.substring(0, 8)}...)`);
|
|
287
|
+
return ctx.unauthorized("This session has been terminated. Please login again.");
|
|
255
288
|
}
|
|
256
289
|
} catch (err) {
|
|
257
290
|
strapi2.log.debug("[magic-sessionmanager] Error checking session:", err.message);
|
|
@@ -265,6 +298,7 @@ var lastSeen = ({ strapi: strapi2 }) => {
|
|
|
265
298
|
const lastTouch = lastTouchCache.get(matchingSession.documentId) || 0;
|
|
266
299
|
if (now - lastTouch > rateLimit) {
|
|
267
300
|
lastTouchCache.set(matchingSession.documentId, now);
|
|
301
|
+
cleanupOldCacheEntries();
|
|
268
302
|
await strapi2.documents(SESSION_UID$3).update({
|
|
269
303
|
documentId: matchingSession.documentId,
|
|
270
304
|
data: { lastActive: /* @__PURE__ */ new Date() }
|
|
@@ -351,20 +385,13 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
351
385
|
ctx.body = { message: "Logged out successfully" };
|
|
352
386
|
return;
|
|
353
387
|
}
|
|
354
|
-
const
|
|
388
|
+
const tokenHashValue = hashToken$2(token);
|
|
389
|
+
const matchingSession = await strapi2.documents(SESSION_UID$2).findFirst({
|
|
355
390
|
filters: {
|
|
391
|
+
tokenHash: tokenHashValue,
|
|
356
392
|
isActive: true
|
|
357
393
|
}
|
|
358
394
|
});
|
|
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
395
|
if (matchingSession) {
|
|
369
396
|
await sessionService.terminateSession({ sessionId: matchingSession.documentId });
|
|
370
397
|
log.info(`[LOGOUT] Logout via /api/auth/logout - Session ${matchingSession.documentId} terminated`);
|
|
@@ -509,20 +536,13 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
509
536
|
try {
|
|
510
537
|
const refreshToken = ctx.request.body?.refreshToken;
|
|
511
538
|
if (refreshToken) {
|
|
512
|
-
const
|
|
539
|
+
const refreshTokenHashValue = hashToken$2(refreshToken);
|
|
540
|
+
const matchingSession = await strapi2.documents(SESSION_UID$2).findFirst({
|
|
513
541
|
filters: {
|
|
542
|
+
refreshTokenHash: refreshTokenHashValue,
|
|
514
543
|
isActive: true
|
|
515
544
|
}
|
|
516
545
|
});
|
|
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
546
|
if (!matchingSession) {
|
|
527
547
|
log.warn("[BLOCKED] Blocked refresh token request - no active session");
|
|
528
548
|
ctx.status = 401;
|
|
@@ -548,20 +568,13 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
548
568
|
const newAccessToken = ctx.body.jwt;
|
|
549
569
|
const newRefreshToken = ctx.body.refreshToken;
|
|
550
570
|
if (oldRefreshToken) {
|
|
551
|
-
const
|
|
571
|
+
const oldRefreshTokenHash = hashToken$2(oldRefreshToken);
|
|
572
|
+
const matchingSession = await strapi2.documents(SESSION_UID$2).findFirst({
|
|
552
573
|
filters: {
|
|
574
|
+
refreshTokenHash: oldRefreshTokenHash,
|
|
553
575
|
isActive: true
|
|
554
576
|
}
|
|
555
577
|
});
|
|
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
578
|
if (matchingSession) {
|
|
566
579
|
const encryptedToken = newAccessToken ? encryptToken$1(newAccessToken) : matchingSession.token;
|
|
567
580
|
const encryptedRefreshToken = newRefreshToken ? encryptToken$1(newRefreshToken) : matchingSession.refreshToken;
|
|
@@ -690,11 +703,11 @@ var destroy$1 = async ({ strapi: strapi2 }) => {
|
|
|
690
703
|
const log = createLogger$2(strapi2);
|
|
691
704
|
if (strapi2.licenseGuard && strapi2.licenseGuard.pingInterval) {
|
|
692
705
|
clearInterval(strapi2.licenseGuard.pingInterval);
|
|
693
|
-
log.info("
|
|
706
|
+
log.info("[STOP] License pinging stopped");
|
|
694
707
|
}
|
|
695
708
|
if (strapi2.sessionManagerIntervals && strapi2.sessionManagerIntervals.cleanup) {
|
|
696
709
|
clearInterval(strapi2.sessionManagerIntervals.cleanup);
|
|
697
|
-
log.info("
|
|
710
|
+
log.info("[STOP] Session cleanup interval stopped");
|
|
698
711
|
}
|
|
699
712
|
log.info("[SUCCESS] Plugin cleanup completed");
|
|
700
713
|
};
|
|
@@ -1175,6 +1188,7 @@ var session$3 = {
|
|
|
1175
1188
|
* GET /api/magic-sessionmanager/my-sessions
|
|
1176
1189
|
* Automatically uses the authenticated user's documentId
|
|
1177
1190
|
* Marks which session is the current one (based on JWT token hash)
|
|
1191
|
+
* Fetches geolocation data on-demand if not already stored
|
|
1178
1192
|
*/
|
|
1179
1193
|
async getOwnSessions(ctx) {
|
|
1180
1194
|
try {
|
|
@@ -1191,7 +1205,8 @@ var session$3 = {
|
|
|
1191
1205
|
const config2 = strapi.config.get("plugin::magic-sessionmanager") || {};
|
|
1192
1206
|
const inactivityTimeout = config2.inactivityTimeout || 15 * 60 * 1e3;
|
|
1193
1207
|
const now = /* @__PURE__ */ new Date();
|
|
1194
|
-
const
|
|
1208
|
+
const geolocationService = strapi.plugin("magic-sessionmanager").service("geolocation");
|
|
1209
|
+
const sessionsWithCurrent = await Promise.all(allSessions.map(async (session2) => {
|
|
1195
1210
|
const lastActiveTime = session2.lastActive ? new Date(session2.lastActive) : new Date(session2.loginTime);
|
|
1196
1211
|
const timeSinceActive = now - lastActiveTime;
|
|
1197
1212
|
const isTrulyActive = session2.isActive && timeSinceActive < inactivityTimeout;
|
|
@@ -1208,6 +1223,31 @@ var session$3 = {
|
|
|
1208
1223
|
geoLocation = null;
|
|
1209
1224
|
}
|
|
1210
1225
|
}
|
|
1226
|
+
if (!geoLocation && session2.ipAddress) {
|
|
1227
|
+
try {
|
|
1228
|
+
const geoData = await geolocationService.getIpInfo(session2.ipAddress);
|
|
1229
|
+
if (geoData && geoData.country !== "Unknown") {
|
|
1230
|
+
geoLocation = {
|
|
1231
|
+
country: geoData.country,
|
|
1232
|
+
country_code: geoData.country_code,
|
|
1233
|
+
country_flag: geoData.country_flag,
|
|
1234
|
+
city: geoData.city,
|
|
1235
|
+
region: geoData.region,
|
|
1236
|
+
timezone: geoData.timezone
|
|
1237
|
+
};
|
|
1238
|
+
strapi.documents(SESSION_UID$1).update({
|
|
1239
|
+
documentId: session2.documentId,
|
|
1240
|
+
data: {
|
|
1241
|
+
geoLocation: JSON.stringify(geoLocation),
|
|
1242
|
+
securityScore: geoData.securityScore || null
|
|
1243
|
+
}
|
|
1244
|
+
}).catch(() => {
|
|
1245
|
+
});
|
|
1246
|
+
}
|
|
1247
|
+
} catch (geoErr) {
|
|
1248
|
+
strapi.log.debug("[magic-sessionmanager] Geolocation lookup failed:", geoErr.message);
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1211
1251
|
const {
|
|
1212
1252
|
token,
|
|
1213
1253
|
tokenHash,
|
|
@@ -1231,7 +1271,7 @@ var session$3 = {
|
|
|
1231
1271
|
isTrulyActive,
|
|
1232
1272
|
minutesSinceActive: Math.floor(timeSinceActive / 1e3 / 60)
|
|
1233
1273
|
};
|
|
1234
|
-
});
|
|
1274
|
+
}));
|
|
1235
1275
|
sessionsWithCurrent.sort((a, b) => {
|
|
1236
1276
|
if (a.isCurrentSession) return -1;
|
|
1237
1277
|
if (b.isCurrentSession) return 1;
|
|
@@ -1333,6 +1373,7 @@ var session$3 = {
|
|
|
1333
1373
|
* Get current session info based on JWT token hash
|
|
1334
1374
|
* GET /api/magic-sessionmanager/current-session
|
|
1335
1375
|
* Returns the session associated with the current JWT token
|
|
1376
|
+
* Fetches geolocation on-demand if not already stored
|
|
1336
1377
|
*/
|
|
1337
1378
|
async getCurrentSession(ctx) {
|
|
1338
1379
|
try {
|
|
@@ -1369,6 +1410,32 @@ var session$3 = {
|
|
|
1369
1410
|
geoLocation = null;
|
|
1370
1411
|
}
|
|
1371
1412
|
}
|
|
1413
|
+
if (!geoLocation && currentSession.ipAddress) {
|
|
1414
|
+
try {
|
|
1415
|
+
const geolocationService = strapi.plugin("magic-sessionmanager").service("geolocation");
|
|
1416
|
+
const geoData = await geolocationService.getIpInfo(currentSession.ipAddress);
|
|
1417
|
+
if (geoData && geoData.country !== "Unknown") {
|
|
1418
|
+
geoLocation = {
|
|
1419
|
+
country: geoData.country,
|
|
1420
|
+
country_code: geoData.country_code,
|
|
1421
|
+
country_flag: geoData.country_flag,
|
|
1422
|
+
city: geoData.city,
|
|
1423
|
+
region: geoData.region,
|
|
1424
|
+
timezone: geoData.timezone
|
|
1425
|
+
};
|
|
1426
|
+
strapi.documents(SESSION_UID$1).update({
|
|
1427
|
+
documentId: currentSession.documentId,
|
|
1428
|
+
data: {
|
|
1429
|
+
geoLocation: JSON.stringify(geoLocation),
|
|
1430
|
+
securityScore: geoData.securityScore || null
|
|
1431
|
+
}
|
|
1432
|
+
}).catch(() => {
|
|
1433
|
+
});
|
|
1434
|
+
}
|
|
1435
|
+
} catch (geoErr) {
|
|
1436
|
+
strapi.log.debug("[magic-sessionmanager] Geolocation lookup failed:", geoErr.message);
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1372
1439
|
const {
|
|
1373
1440
|
token: _,
|
|
1374
1441
|
tokenHash: _th,
|
|
@@ -2035,6 +2102,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2035
2102
|
},
|
|
2036
2103
|
/**
|
|
2037
2104
|
* Get ALL sessions (active + inactive) with accurate online status
|
|
2105
|
+
* Fetches geolocation on-demand for sessions without it (limited to prevent API abuse)
|
|
2038
2106
|
* @returns {Promise<Array>} All sessions with enhanced data
|
|
2039
2107
|
*/
|
|
2040
2108
|
async getAllSessions() {
|
|
@@ -2047,8 +2115,10 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2047
2115
|
});
|
|
2048
2116
|
const config2 = strapi2.config.get("plugin::magic-sessionmanager") || {};
|
|
2049
2117
|
const inactivityTimeout = config2.inactivityTimeout || 15 * 60 * 1e3;
|
|
2118
|
+
const geolocationService = strapi2.plugin("magic-sessionmanager").service("geolocation");
|
|
2119
|
+
let geoLookupsRemaining = 20;
|
|
2050
2120
|
const now = /* @__PURE__ */ new Date();
|
|
2051
|
-
const enhancedSessions = sessions.map((session2) => {
|
|
2121
|
+
const enhancedSessions = await Promise.all(sessions.map(async (session2) => {
|
|
2052
2122
|
const lastActiveTime = session2.lastActive ? new Date(session2.lastActive) : new Date(session2.loginTime);
|
|
2053
2123
|
const timeSinceActive = now - lastActiveTime;
|
|
2054
2124
|
const isTrulyActive = session2.isActive && timeSinceActive < inactivityTimeout;
|
|
@@ -2064,6 +2134,32 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2064
2134
|
geoLocation = null;
|
|
2065
2135
|
}
|
|
2066
2136
|
}
|
|
2137
|
+
if (!geoLocation && session2.ipAddress && geoLookupsRemaining > 0) {
|
|
2138
|
+
geoLookupsRemaining--;
|
|
2139
|
+
try {
|
|
2140
|
+
const geoData = await geolocationService.getIpInfo(session2.ipAddress);
|
|
2141
|
+
if (geoData && geoData.country !== "Unknown") {
|
|
2142
|
+
geoLocation = {
|
|
2143
|
+
country: geoData.country,
|
|
2144
|
+
country_code: geoData.country_code,
|
|
2145
|
+
country_flag: geoData.country_flag,
|
|
2146
|
+
city: geoData.city,
|
|
2147
|
+
region: geoData.region,
|
|
2148
|
+
timezone: geoData.timezone
|
|
2149
|
+
};
|
|
2150
|
+
strapi2.documents(SESSION_UID).update({
|
|
2151
|
+
documentId: session2.documentId,
|
|
2152
|
+
data: {
|
|
2153
|
+
geoLocation: JSON.stringify(geoLocation),
|
|
2154
|
+
securityScore: geoData.securityScore || null
|
|
2155
|
+
}
|
|
2156
|
+
}).catch(() => {
|
|
2157
|
+
});
|
|
2158
|
+
}
|
|
2159
|
+
} catch (geoErr) {
|
|
2160
|
+
log.debug("Geolocation lookup failed:", geoErr.message);
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2067
2163
|
const {
|
|
2068
2164
|
token,
|
|
2069
2165
|
tokenHash,
|
|
@@ -2085,7 +2181,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2085
2181
|
isTrulyActive,
|
|
2086
2182
|
minutesSinceActive: Math.floor(timeSinceActive / 1e3 / 60)
|
|
2087
2183
|
};
|
|
2088
|
-
});
|
|
2184
|
+
}));
|
|
2089
2185
|
return enhancedSessions;
|
|
2090
2186
|
} catch (err) {
|
|
2091
2187
|
log.error("Error getting all sessions:", err);
|
|
@@ -2094,6 +2190,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2094
2190
|
},
|
|
2095
2191
|
/**
|
|
2096
2192
|
* Get all active sessions with accurate online status
|
|
2193
|
+
* Fetches geolocation on-demand for sessions without it
|
|
2097
2194
|
* @returns {Promise<Array>} Active sessions with user data and online status
|
|
2098
2195
|
*/
|
|
2099
2196
|
async getActiveSessions() {
|
|
@@ -2105,8 +2202,9 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2105
2202
|
});
|
|
2106
2203
|
const config2 = strapi2.config.get("plugin::magic-sessionmanager") || {};
|
|
2107
2204
|
const inactivityTimeout = config2.inactivityTimeout || 15 * 60 * 1e3;
|
|
2205
|
+
const geolocationService = strapi2.plugin("magic-sessionmanager").service("geolocation");
|
|
2108
2206
|
const now = /* @__PURE__ */ new Date();
|
|
2109
|
-
const enhancedSessions = sessions.map((session2) => {
|
|
2207
|
+
const enhancedSessions = await Promise.all(sessions.map(async (session2) => {
|
|
2110
2208
|
const lastActiveTime = session2.lastActive ? new Date(session2.lastActive) : new Date(session2.loginTime);
|
|
2111
2209
|
const timeSinceActive = now - lastActiveTime;
|
|
2112
2210
|
const isTrulyActive = timeSinceActive < inactivityTimeout;
|
|
@@ -2122,6 +2220,31 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2122
2220
|
geoLocation = null;
|
|
2123
2221
|
}
|
|
2124
2222
|
}
|
|
2223
|
+
if (!geoLocation && session2.ipAddress) {
|
|
2224
|
+
try {
|
|
2225
|
+
const geoData = await geolocationService.getIpInfo(session2.ipAddress);
|
|
2226
|
+
if (geoData && geoData.country !== "Unknown") {
|
|
2227
|
+
geoLocation = {
|
|
2228
|
+
country: geoData.country,
|
|
2229
|
+
country_code: geoData.country_code,
|
|
2230
|
+
country_flag: geoData.country_flag,
|
|
2231
|
+
city: geoData.city,
|
|
2232
|
+
region: geoData.region,
|
|
2233
|
+
timezone: geoData.timezone
|
|
2234
|
+
};
|
|
2235
|
+
strapi2.documents(SESSION_UID).update({
|
|
2236
|
+
documentId: session2.documentId,
|
|
2237
|
+
data: {
|
|
2238
|
+
geoLocation: JSON.stringify(geoLocation),
|
|
2239
|
+
securityScore: geoData.securityScore || null
|
|
2240
|
+
}
|
|
2241
|
+
}).catch(() => {
|
|
2242
|
+
});
|
|
2243
|
+
}
|
|
2244
|
+
} catch (geoErr) {
|
|
2245
|
+
log.debug("Geolocation lookup failed:", geoErr.message);
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2125
2248
|
const {
|
|
2126
2249
|
token,
|
|
2127
2250
|
tokenHash,
|
|
@@ -2141,7 +2264,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2141
2264
|
isTrulyActive,
|
|
2142
2265
|
minutesSinceActive: Math.floor(timeSinceActive / 1e3 / 60)
|
|
2143
2266
|
};
|
|
2144
|
-
});
|
|
2267
|
+
}));
|
|
2145
2268
|
return enhancedSessions.filter((s) => s.isTrulyActive);
|
|
2146
2269
|
} catch (err) {
|
|
2147
2270
|
log.error("Error getting active sessions:", err);
|
|
@@ -2151,6 +2274,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2151
2274
|
/**
|
|
2152
2275
|
* Get all sessions for a specific user
|
|
2153
2276
|
* Supports both numeric id (legacy) and documentId (Strapi v5)
|
|
2277
|
+
* Fetches geolocation on-demand for sessions without it
|
|
2154
2278
|
* @param {string|number} userId - User documentId or numeric id
|
|
2155
2279
|
* @returns {Promise<Array>} User's sessions with accurate online status
|
|
2156
2280
|
*/
|
|
@@ -2169,8 +2293,9 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2169
2293
|
});
|
|
2170
2294
|
const config2 = strapi2.config.get("plugin::magic-sessionmanager") || {};
|
|
2171
2295
|
const inactivityTimeout = config2.inactivityTimeout || 15 * 60 * 1e3;
|
|
2296
|
+
const geolocationService = strapi2.plugin("magic-sessionmanager").service("geolocation");
|
|
2172
2297
|
const now = /* @__PURE__ */ new Date();
|
|
2173
|
-
const enhancedSessions = sessions.map((session2) => {
|
|
2298
|
+
const enhancedSessions = await Promise.all(sessions.map(async (session2) => {
|
|
2174
2299
|
const lastActiveTime = session2.lastActive ? new Date(session2.lastActive) : new Date(session2.loginTime);
|
|
2175
2300
|
const timeSinceActive = now - lastActiveTime;
|
|
2176
2301
|
const isTrulyActive = session2.isActive && timeSinceActive < inactivityTimeout;
|
|
@@ -2186,6 +2311,31 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2186
2311
|
geoLocation = null;
|
|
2187
2312
|
}
|
|
2188
2313
|
}
|
|
2314
|
+
if (!geoLocation && session2.ipAddress) {
|
|
2315
|
+
try {
|
|
2316
|
+
const geoData = await geolocationService.getIpInfo(session2.ipAddress);
|
|
2317
|
+
if (geoData && geoData.country !== "Unknown") {
|
|
2318
|
+
geoLocation = {
|
|
2319
|
+
country: geoData.country,
|
|
2320
|
+
country_code: geoData.country_code,
|
|
2321
|
+
country_flag: geoData.country_flag,
|
|
2322
|
+
city: geoData.city,
|
|
2323
|
+
region: geoData.region,
|
|
2324
|
+
timezone: geoData.timezone
|
|
2325
|
+
};
|
|
2326
|
+
strapi2.documents(SESSION_UID).update({
|
|
2327
|
+
documentId: session2.documentId,
|
|
2328
|
+
data: {
|
|
2329
|
+
geoLocation: JSON.stringify(geoLocation),
|
|
2330
|
+
securityScore: geoData.securityScore || null
|
|
2331
|
+
}
|
|
2332
|
+
}).catch(() => {
|
|
2333
|
+
});
|
|
2334
|
+
}
|
|
2335
|
+
} catch (geoErr) {
|
|
2336
|
+
log.debug("Geolocation lookup failed:", geoErr.message);
|
|
2337
|
+
}
|
|
2338
|
+
}
|
|
2189
2339
|
const {
|
|
2190
2340
|
token,
|
|
2191
2341
|
tokenHash,
|
|
@@ -2205,7 +2355,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2205
2355
|
isTrulyActive,
|
|
2206
2356
|
minutesSinceActive: Math.floor(timeSinceActive / 1e3 / 60)
|
|
2207
2357
|
};
|
|
2208
|
-
});
|
|
2358
|
+
}));
|
|
2209
2359
|
return enhancedSessions;
|
|
2210
2360
|
} catch (err) {
|
|
2211
2361
|
log.error("Error getting user sessions:", err);
|
|
@@ -2318,7 +2468,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2318
2468
|
}
|
|
2319
2469
|
};
|
|
2320
2470
|
};
|
|
2321
|
-
const version = "4.2.
|
|
2471
|
+
const version = "4.2.13";
|
|
2322
2472
|
const require$$2 = {
|
|
2323
2473
|
version
|
|
2324
2474
|
};
|
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,7 +234,30 @@ var lastSeen = ({ strapi: strapi2 }) => {
|
|
|
222
234
|
await next();
|
|
223
235
|
return;
|
|
224
236
|
}
|
|
225
|
-
const skipPaths = [
|
|
237
|
+
const skipPaths = [
|
|
238
|
+
"/admin",
|
|
239
|
+
// Admin panel routes (have their own auth)
|
|
240
|
+
"/_health",
|
|
241
|
+
// Health check
|
|
242
|
+
"/favicon.ico",
|
|
243
|
+
// Static assets
|
|
244
|
+
"/api/auth/local",
|
|
245
|
+
// Login endpoint
|
|
246
|
+
"/api/auth/register",
|
|
247
|
+
// Registration endpoint
|
|
248
|
+
"/api/auth/forgot-password",
|
|
249
|
+
// Password reset
|
|
250
|
+
"/api/auth/reset-password",
|
|
251
|
+
// Password reset
|
|
252
|
+
"/api/auth/logout",
|
|
253
|
+
// Logout endpoint (handled separately)
|
|
254
|
+
"/api/auth/refresh",
|
|
255
|
+
// Refresh token (has own validation in bootstrap.js)
|
|
256
|
+
"/api/connect",
|
|
257
|
+
// OAuth providers
|
|
258
|
+
"/api/magic-link"
|
|
259
|
+
// Magic link auth (if using magic-link plugin)
|
|
260
|
+
];
|
|
226
261
|
if (skipPaths.some((p) => ctx.path.startsWith(p))) {
|
|
227
262
|
await next();
|
|
228
263
|
return;
|
|
@@ -244,10 +279,8 @@ var lastSeen = ({ strapi: strapi2 }) => {
|
|
|
244
279
|
ctx.state.sessionUserId = matchingSession.user.documentId;
|
|
245
280
|
}
|
|
246
281
|
} else {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
return ctx.unauthorized("This session has been terminated. Please login again.");
|
|
250
|
-
}
|
|
282
|
+
strapi2.log.info(`[magic-sessionmanager] [BLOCKED] Request blocked - session terminated or invalid (token hash: ${currentTokenHash.substring(0, 8)}...)`);
|
|
283
|
+
return ctx.unauthorized("This session has been terminated. Please login again.");
|
|
251
284
|
}
|
|
252
285
|
} catch (err) {
|
|
253
286
|
strapi2.log.debug("[magic-sessionmanager] Error checking session:", err.message);
|
|
@@ -261,6 +294,7 @@ var lastSeen = ({ strapi: strapi2 }) => {
|
|
|
261
294
|
const lastTouch = lastTouchCache.get(matchingSession.documentId) || 0;
|
|
262
295
|
if (now - lastTouch > rateLimit) {
|
|
263
296
|
lastTouchCache.set(matchingSession.documentId, now);
|
|
297
|
+
cleanupOldCacheEntries();
|
|
264
298
|
await strapi2.documents(SESSION_UID$3).update({
|
|
265
299
|
documentId: matchingSession.documentId,
|
|
266
300
|
data: { lastActive: /* @__PURE__ */ new Date() }
|
|
@@ -347,20 +381,13 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
347
381
|
ctx.body = { message: "Logged out successfully" };
|
|
348
382
|
return;
|
|
349
383
|
}
|
|
350
|
-
const
|
|
384
|
+
const tokenHashValue = hashToken$2(token);
|
|
385
|
+
const matchingSession = await strapi2.documents(SESSION_UID$2).findFirst({
|
|
351
386
|
filters: {
|
|
387
|
+
tokenHash: tokenHashValue,
|
|
352
388
|
isActive: true
|
|
353
389
|
}
|
|
354
390
|
});
|
|
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
391
|
if (matchingSession) {
|
|
365
392
|
await sessionService.terminateSession({ sessionId: matchingSession.documentId });
|
|
366
393
|
log.info(`[LOGOUT] Logout via /api/auth/logout - Session ${matchingSession.documentId} terminated`);
|
|
@@ -505,20 +532,13 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
505
532
|
try {
|
|
506
533
|
const refreshToken = ctx.request.body?.refreshToken;
|
|
507
534
|
if (refreshToken) {
|
|
508
|
-
const
|
|
535
|
+
const refreshTokenHashValue = hashToken$2(refreshToken);
|
|
536
|
+
const matchingSession = await strapi2.documents(SESSION_UID$2).findFirst({
|
|
509
537
|
filters: {
|
|
538
|
+
refreshTokenHash: refreshTokenHashValue,
|
|
510
539
|
isActive: true
|
|
511
540
|
}
|
|
512
541
|
});
|
|
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
542
|
if (!matchingSession) {
|
|
523
543
|
log.warn("[BLOCKED] Blocked refresh token request - no active session");
|
|
524
544
|
ctx.status = 401;
|
|
@@ -544,20 +564,13 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
544
564
|
const newAccessToken = ctx.body.jwt;
|
|
545
565
|
const newRefreshToken = ctx.body.refreshToken;
|
|
546
566
|
if (oldRefreshToken) {
|
|
547
|
-
const
|
|
567
|
+
const oldRefreshTokenHash = hashToken$2(oldRefreshToken);
|
|
568
|
+
const matchingSession = await strapi2.documents(SESSION_UID$2).findFirst({
|
|
548
569
|
filters: {
|
|
570
|
+
refreshTokenHash: oldRefreshTokenHash,
|
|
549
571
|
isActive: true
|
|
550
572
|
}
|
|
551
573
|
});
|
|
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
574
|
if (matchingSession) {
|
|
562
575
|
const encryptedToken = newAccessToken ? encryptToken$1(newAccessToken) : matchingSession.token;
|
|
563
576
|
const encryptedRefreshToken = newRefreshToken ? encryptToken$1(newRefreshToken) : matchingSession.refreshToken;
|
|
@@ -686,11 +699,11 @@ var destroy$1 = async ({ strapi: strapi2 }) => {
|
|
|
686
699
|
const log = createLogger$2(strapi2);
|
|
687
700
|
if (strapi2.licenseGuard && strapi2.licenseGuard.pingInterval) {
|
|
688
701
|
clearInterval(strapi2.licenseGuard.pingInterval);
|
|
689
|
-
log.info("
|
|
702
|
+
log.info("[STOP] License pinging stopped");
|
|
690
703
|
}
|
|
691
704
|
if (strapi2.sessionManagerIntervals && strapi2.sessionManagerIntervals.cleanup) {
|
|
692
705
|
clearInterval(strapi2.sessionManagerIntervals.cleanup);
|
|
693
|
-
log.info("
|
|
706
|
+
log.info("[STOP] Session cleanup interval stopped");
|
|
694
707
|
}
|
|
695
708
|
log.info("[SUCCESS] Plugin cleanup completed");
|
|
696
709
|
};
|
|
@@ -1171,6 +1184,7 @@ var session$3 = {
|
|
|
1171
1184
|
* GET /api/magic-sessionmanager/my-sessions
|
|
1172
1185
|
* Automatically uses the authenticated user's documentId
|
|
1173
1186
|
* Marks which session is the current one (based on JWT token hash)
|
|
1187
|
+
* Fetches geolocation data on-demand if not already stored
|
|
1174
1188
|
*/
|
|
1175
1189
|
async getOwnSessions(ctx) {
|
|
1176
1190
|
try {
|
|
@@ -1187,7 +1201,8 @@ var session$3 = {
|
|
|
1187
1201
|
const config2 = strapi.config.get("plugin::magic-sessionmanager") || {};
|
|
1188
1202
|
const inactivityTimeout = config2.inactivityTimeout || 15 * 60 * 1e3;
|
|
1189
1203
|
const now = /* @__PURE__ */ new Date();
|
|
1190
|
-
const
|
|
1204
|
+
const geolocationService = strapi.plugin("magic-sessionmanager").service("geolocation");
|
|
1205
|
+
const sessionsWithCurrent = await Promise.all(allSessions.map(async (session2) => {
|
|
1191
1206
|
const lastActiveTime = session2.lastActive ? new Date(session2.lastActive) : new Date(session2.loginTime);
|
|
1192
1207
|
const timeSinceActive = now - lastActiveTime;
|
|
1193
1208
|
const isTrulyActive = session2.isActive && timeSinceActive < inactivityTimeout;
|
|
@@ -1204,6 +1219,31 @@ var session$3 = {
|
|
|
1204
1219
|
geoLocation = null;
|
|
1205
1220
|
}
|
|
1206
1221
|
}
|
|
1222
|
+
if (!geoLocation && session2.ipAddress) {
|
|
1223
|
+
try {
|
|
1224
|
+
const geoData = await geolocationService.getIpInfo(session2.ipAddress);
|
|
1225
|
+
if (geoData && geoData.country !== "Unknown") {
|
|
1226
|
+
geoLocation = {
|
|
1227
|
+
country: geoData.country,
|
|
1228
|
+
country_code: geoData.country_code,
|
|
1229
|
+
country_flag: geoData.country_flag,
|
|
1230
|
+
city: geoData.city,
|
|
1231
|
+
region: geoData.region,
|
|
1232
|
+
timezone: geoData.timezone
|
|
1233
|
+
};
|
|
1234
|
+
strapi.documents(SESSION_UID$1).update({
|
|
1235
|
+
documentId: session2.documentId,
|
|
1236
|
+
data: {
|
|
1237
|
+
geoLocation: JSON.stringify(geoLocation),
|
|
1238
|
+
securityScore: geoData.securityScore || null
|
|
1239
|
+
}
|
|
1240
|
+
}).catch(() => {
|
|
1241
|
+
});
|
|
1242
|
+
}
|
|
1243
|
+
} catch (geoErr) {
|
|
1244
|
+
strapi.log.debug("[magic-sessionmanager] Geolocation lookup failed:", geoErr.message);
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1207
1247
|
const {
|
|
1208
1248
|
token,
|
|
1209
1249
|
tokenHash,
|
|
@@ -1227,7 +1267,7 @@ var session$3 = {
|
|
|
1227
1267
|
isTrulyActive,
|
|
1228
1268
|
minutesSinceActive: Math.floor(timeSinceActive / 1e3 / 60)
|
|
1229
1269
|
};
|
|
1230
|
-
});
|
|
1270
|
+
}));
|
|
1231
1271
|
sessionsWithCurrent.sort((a, b) => {
|
|
1232
1272
|
if (a.isCurrentSession) return -1;
|
|
1233
1273
|
if (b.isCurrentSession) return 1;
|
|
@@ -1329,6 +1369,7 @@ var session$3 = {
|
|
|
1329
1369
|
* Get current session info based on JWT token hash
|
|
1330
1370
|
* GET /api/magic-sessionmanager/current-session
|
|
1331
1371
|
* Returns the session associated with the current JWT token
|
|
1372
|
+
* Fetches geolocation on-demand if not already stored
|
|
1332
1373
|
*/
|
|
1333
1374
|
async getCurrentSession(ctx) {
|
|
1334
1375
|
try {
|
|
@@ -1365,6 +1406,32 @@ var session$3 = {
|
|
|
1365
1406
|
geoLocation = null;
|
|
1366
1407
|
}
|
|
1367
1408
|
}
|
|
1409
|
+
if (!geoLocation && currentSession.ipAddress) {
|
|
1410
|
+
try {
|
|
1411
|
+
const geolocationService = strapi.plugin("magic-sessionmanager").service("geolocation");
|
|
1412
|
+
const geoData = await geolocationService.getIpInfo(currentSession.ipAddress);
|
|
1413
|
+
if (geoData && geoData.country !== "Unknown") {
|
|
1414
|
+
geoLocation = {
|
|
1415
|
+
country: geoData.country,
|
|
1416
|
+
country_code: geoData.country_code,
|
|
1417
|
+
country_flag: geoData.country_flag,
|
|
1418
|
+
city: geoData.city,
|
|
1419
|
+
region: geoData.region,
|
|
1420
|
+
timezone: geoData.timezone
|
|
1421
|
+
};
|
|
1422
|
+
strapi.documents(SESSION_UID$1).update({
|
|
1423
|
+
documentId: currentSession.documentId,
|
|
1424
|
+
data: {
|
|
1425
|
+
geoLocation: JSON.stringify(geoLocation),
|
|
1426
|
+
securityScore: geoData.securityScore || null
|
|
1427
|
+
}
|
|
1428
|
+
}).catch(() => {
|
|
1429
|
+
});
|
|
1430
|
+
}
|
|
1431
|
+
} catch (geoErr) {
|
|
1432
|
+
strapi.log.debug("[magic-sessionmanager] Geolocation lookup failed:", geoErr.message);
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1368
1435
|
const {
|
|
1369
1436
|
token: _,
|
|
1370
1437
|
tokenHash: _th,
|
|
@@ -2031,6 +2098,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2031
2098
|
},
|
|
2032
2099
|
/**
|
|
2033
2100
|
* Get ALL sessions (active + inactive) with accurate online status
|
|
2101
|
+
* Fetches geolocation on-demand for sessions without it (limited to prevent API abuse)
|
|
2034
2102
|
* @returns {Promise<Array>} All sessions with enhanced data
|
|
2035
2103
|
*/
|
|
2036
2104
|
async getAllSessions() {
|
|
@@ -2043,8 +2111,10 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2043
2111
|
});
|
|
2044
2112
|
const config2 = strapi2.config.get("plugin::magic-sessionmanager") || {};
|
|
2045
2113
|
const inactivityTimeout = config2.inactivityTimeout || 15 * 60 * 1e3;
|
|
2114
|
+
const geolocationService = strapi2.plugin("magic-sessionmanager").service("geolocation");
|
|
2115
|
+
let geoLookupsRemaining = 20;
|
|
2046
2116
|
const now = /* @__PURE__ */ new Date();
|
|
2047
|
-
const enhancedSessions = sessions.map((session2) => {
|
|
2117
|
+
const enhancedSessions = await Promise.all(sessions.map(async (session2) => {
|
|
2048
2118
|
const lastActiveTime = session2.lastActive ? new Date(session2.lastActive) : new Date(session2.loginTime);
|
|
2049
2119
|
const timeSinceActive = now - lastActiveTime;
|
|
2050
2120
|
const isTrulyActive = session2.isActive && timeSinceActive < inactivityTimeout;
|
|
@@ -2060,6 +2130,32 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2060
2130
|
geoLocation = null;
|
|
2061
2131
|
}
|
|
2062
2132
|
}
|
|
2133
|
+
if (!geoLocation && session2.ipAddress && geoLookupsRemaining > 0) {
|
|
2134
|
+
geoLookupsRemaining--;
|
|
2135
|
+
try {
|
|
2136
|
+
const geoData = await geolocationService.getIpInfo(session2.ipAddress);
|
|
2137
|
+
if (geoData && geoData.country !== "Unknown") {
|
|
2138
|
+
geoLocation = {
|
|
2139
|
+
country: geoData.country,
|
|
2140
|
+
country_code: geoData.country_code,
|
|
2141
|
+
country_flag: geoData.country_flag,
|
|
2142
|
+
city: geoData.city,
|
|
2143
|
+
region: geoData.region,
|
|
2144
|
+
timezone: geoData.timezone
|
|
2145
|
+
};
|
|
2146
|
+
strapi2.documents(SESSION_UID).update({
|
|
2147
|
+
documentId: session2.documentId,
|
|
2148
|
+
data: {
|
|
2149
|
+
geoLocation: JSON.stringify(geoLocation),
|
|
2150
|
+
securityScore: geoData.securityScore || null
|
|
2151
|
+
}
|
|
2152
|
+
}).catch(() => {
|
|
2153
|
+
});
|
|
2154
|
+
}
|
|
2155
|
+
} catch (geoErr) {
|
|
2156
|
+
log.debug("Geolocation lookup failed:", geoErr.message);
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
2063
2159
|
const {
|
|
2064
2160
|
token,
|
|
2065
2161
|
tokenHash,
|
|
@@ -2081,7 +2177,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2081
2177
|
isTrulyActive,
|
|
2082
2178
|
minutesSinceActive: Math.floor(timeSinceActive / 1e3 / 60)
|
|
2083
2179
|
};
|
|
2084
|
-
});
|
|
2180
|
+
}));
|
|
2085
2181
|
return enhancedSessions;
|
|
2086
2182
|
} catch (err) {
|
|
2087
2183
|
log.error("Error getting all sessions:", err);
|
|
@@ -2090,6 +2186,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2090
2186
|
},
|
|
2091
2187
|
/**
|
|
2092
2188
|
* Get all active sessions with accurate online status
|
|
2189
|
+
* Fetches geolocation on-demand for sessions without it
|
|
2093
2190
|
* @returns {Promise<Array>} Active sessions with user data and online status
|
|
2094
2191
|
*/
|
|
2095
2192
|
async getActiveSessions() {
|
|
@@ -2101,8 +2198,9 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2101
2198
|
});
|
|
2102
2199
|
const config2 = strapi2.config.get("plugin::magic-sessionmanager") || {};
|
|
2103
2200
|
const inactivityTimeout = config2.inactivityTimeout || 15 * 60 * 1e3;
|
|
2201
|
+
const geolocationService = strapi2.plugin("magic-sessionmanager").service("geolocation");
|
|
2104
2202
|
const now = /* @__PURE__ */ new Date();
|
|
2105
|
-
const enhancedSessions = sessions.map((session2) => {
|
|
2203
|
+
const enhancedSessions = await Promise.all(sessions.map(async (session2) => {
|
|
2106
2204
|
const lastActiveTime = session2.lastActive ? new Date(session2.lastActive) : new Date(session2.loginTime);
|
|
2107
2205
|
const timeSinceActive = now - lastActiveTime;
|
|
2108
2206
|
const isTrulyActive = timeSinceActive < inactivityTimeout;
|
|
@@ -2118,6 +2216,31 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2118
2216
|
geoLocation = null;
|
|
2119
2217
|
}
|
|
2120
2218
|
}
|
|
2219
|
+
if (!geoLocation && session2.ipAddress) {
|
|
2220
|
+
try {
|
|
2221
|
+
const geoData = await geolocationService.getIpInfo(session2.ipAddress);
|
|
2222
|
+
if (geoData && geoData.country !== "Unknown") {
|
|
2223
|
+
geoLocation = {
|
|
2224
|
+
country: geoData.country,
|
|
2225
|
+
country_code: geoData.country_code,
|
|
2226
|
+
country_flag: geoData.country_flag,
|
|
2227
|
+
city: geoData.city,
|
|
2228
|
+
region: geoData.region,
|
|
2229
|
+
timezone: geoData.timezone
|
|
2230
|
+
};
|
|
2231
|
+
strapi2.documents(SESSION_UID).update({
|
|
2232
|
+
documentId: session2.documentId,
|
|
2233
|
+
data: {
|
|
2234
|
+
geoLocation: JSON.stringify(geoLocation),
|
|
2235
|
+
securityScore: geoData.securityScore || null
|
|
2236
|
+
}
|
|
2237
|
+
}).catch(() => {
|
|
2238
|
+
});
|
|
2239
|
+
}
|
|
2240
|
+
} catch (geoErr) {
|
|
2241
|
+
log.debug("Geolocation lookup failed:", geoErr.message);
|
|
2242
|
+
}
|
|
2243
|
+
}
|
|
2121
2244
|
const {
|
|
2122
2245
|
token,
|
|
2123
2246
|
tokenHash,
|
|
@@ -2137,7 +2260,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2137
2260
|
isTrulyActive,
|
|
2138
2261
|
minutesSinceActive: Math.floor(timeSinceActive / 1e3 / 60)
|
|
2139
2262
|
};
|
|
2140
|
-
});
|
|
2263
|
+
}));
|
|
2141
2264
|
return enhancedSessions.filter((s) => s.isTrulyActive);
|
|
2142
2265
|
} catch (err) {
|
|
2143
2266
|
log.error("Error getting active sessions:", err);
|
|
@@ -2147,6 +2270,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2147
2270
|
/**
|
|
2148
2271
|
* Get all sessions for a specific user
|
|
2149
2272
|
* Supports both numeric id (legacy) and documentId (Strapi v5)
|
|
2273
|
+
* Fetches geolocation on-demand for sessions without it
|
|
2150
2274
|
* @param {string|number} userId - User documentId or numeric id
|
|
2151
2275
|
* @returns {Promise<Array>} User's sessions with accurate online status
|
|
2152
2276
|
*/
|
|
@@ -2165,8 +2289,9 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2165
2289
|
});
|
|
2166
2290
|
const config2 = strapi2.config.get("plugin::magic-sessionmanager") || {};
|
|
2167
2291
|
const inactivityTimeout = config2.inactivityTimeout || 15 * 60 * 1e3;
|
|
2292
|
+
const geolocationService = strapi2.plugin("magic-sessionmanager").service("geolocation");
|
|
2168
2293
|
const now = /* @__PURE__ */ new Date();
|
|
2169
|
-
const enhancedSessions = sessions.map((session2) => {
|
|
2294
|
+
const enhancedSessions = await Promise.all(sessions.map(async (session2) => {
|
|
2170
2295
|
const lastActiveTime = session2.lastActive ? new Date(session2.lastActive) : new Date(session2.loginTime);
|
|
2171
2296
|
const timeSinceActive = now - lastActiveTime;
|
|
2172
2297
|
const isTrulyActive = session2.isActive && timeSinceActive < inactivityTimeout;
|
|
@@ -2182,6 +2307,31 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2182
2307
|
geoLocation = null;
|
|
2183
2308
|
}
|
|
2184
2309
|
}
|
|
2310
|
+
if (!geoLocation && session2.ipAddress) {
|
|
2311
|
+
try {
|
|
2312
|
+
const geoData = await geolocationService.getIpInfo(session2.ipAddress);
|
|
2313
|
+
if (geoData && geoData.country !== "Unknown") {
|
|
2314
|
+
geoLocation = {
|
|
2315
|
+
country: geoData.country,
|
|
2316
|
+
country_code: geoData.country_code,
|
|
2317
|
+
country_flag: geoData.country_flag,
|
|
2318
|
+
city: geoData.city,
|
|
2319
|
+
region: geoData.region,
|
|
2320
|
+
timezone: geoData.timezone
|
|
2321
|
+
};
|
|
2322
|
+
strapi2.documents(SESSION_UID).update({
|
|
2323
|
+
documentId: session2.documentId,
|
|
2324
|
+
data: {
|
|
2325
|
+
geoLocation: JSON.stringify(geoLocation),
|
|
2326
|
+
securityScore: geoData.securityScore || null
|
|
2327
|
+
}
|
|
2328
|
+
}).catch(() => {
|
|
2329
|
+
});
|
|
2330
|
+
}
|
|
2331
|
+
} catch (geoErr) {
|
|
2332
|
+
log.debug("Geolocation lookup failed:", geoErr.message);
|
|
2333
|
+
}
|
|
2334
|
+
}
|
|
2185
2335
|
const {
|
|
2186
2336
|
token,
|
|
2187
2337
|
tokenHash,
|
|
@@ -2201,7 +2351,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2201
2351
|
isTrulyActive,
|
|
2202
2352
|
minutesSinceActive: Math.floor(timeSinceActive / 1e3 / 60)
|
|
2203
2353
|
};
|
|
2204
|
-
});
|
|
2354
|
+
}));
|
|
2205
2355
|
return enhancedSessions;
|
|
2206
2356
|
} catch (err) {
|
|
2207
2357
|
log.error("Error getting user sessions:", err);
|
|
@@ -2314,7 +2464,7 @@ var session$1 = ({ strapi: strapi2 }) => {
|
|
|
2314
2464
|
}
|
|
2315
2465
|
};
|
|
2316
2466
|
};
|
|
2317
|
-
const version = "4.2.
|
|
2467
|
+
const version = "4.2.13";
|
|
2318
2468
|
const require$$2 = {
|
|
2319
2469
|
version
|
|
2320
2470
|
};
|
package/package.json
CHANGED