strapi-plugin-magic-sessionmanager 3.7.0 → 4.0.0
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/README.md +90 -0
- package/admin/src/hooks/useLicense.js +1 -1
- package/admin/src/index.js +2 -2
- package/admin/src/pages/Settings.jsx +0 -1
- package/admin/src/utils/parseUserAgent.js +1 -1
- package/dist/_chunks/{Analytics-Bi-vcT63.js → Analytics-ioaeEh-E.js} +2 -2
- package/dist/_chunks/{Analytics-BM9i88xu.mjs → Analytics-mYu_uGwU.mjs} +2 -2
- package/dist/_chunks/{App-DcnJOCL9.mjs → App-BXpIS12l.mjs} +2 -2
- package/dist/_chunks/{App-BbiNy_cT.js → App-DdnUYWbC.js} +2 -2
- package/dist/_chunks/{License-DsxP-MAL.mjs → License-C03C2j9P.mjs} +1 -1
- package/dist/_chunks/{License-kYo8j2yl.js → License-DZYrOgcx.js} +1 -1
- package/dist/_chunks/{Settings-C3sW9eBD.mjs → Settings-0ocB3qHk.mjs} +2 -2
- package/dist/_chunks/{Settings-jW0TOE_d.js → Settings-C6_CqpCC.js} +2 -2
- package/dist/_chunks/{index-DG9XeVSg.mjs → index-DBRS3kt5.mjs} +7 -7
- package/dist/_chunks/{index-Dr2HT-Dd.js → index-DC8Y0qxx.js} +7 -7
- package/dist/_chunks/{useLicense-DOkJX-tk.mjs → useLicense-DSLL9n3Y.mjs} +2 -2
- package/dist/_chunks/{useLicense-BL_3bX9O.js → useLicense-qgGfMvse.js} +2 -2
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/server/index.js +117 -95
- package/dist/server/index.mjs +117 -95
- package/package.json +1 -1
- package/server/src/bootstrap.js +32 -26
- package/server/src/controllers/license.js +4 -4
- package/server/src/controllers/session.js +10 -6
- package/server/src/destroy.js +1 -1
- package/server/src/middlewares/last-seen.js +8 -3
- package/server/src/register.js +4 -4
- package/server/src/services/geolocation.js +4 -2
- package/server/src/services/license-guard.js +13 -10
- package/server/src/services/notifications.js +10 -10
- package/server/src/services/service.js +1 -1
- package/server/src/services/session.js +41 -31
- package/server/src/utils/encryption.js +1 -1
package/dist/server/index.js
CHANGED
|
@@ -8,7 +8,7 @@ function getDefaultExportFromCjs(x) {
|
|
|
8
8
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
|
|
9
9
|
}
|
|
10
10
|
var register$1 = async ({ strapi: strapi2 }) => {
|
|
11
|
-
strapi2.log.info("[magic-sessionmanager]
|
|
11
|
+
strapi2.log.info("[magic-sessionmanager] [START] Plugin registration starting...");
|
|
12
12
|
try {
|
|
13
13
|
const userCT = strapi2.contentType("plugin::users-permissions.user");
|
|
14
14
|
if (!userCT) {
|
|
@@ -17,11 +17,11 @@ var register$1 = async ({ strapi: strapi2 }) => {
|
|
|
17
17
|
}
|
|
18
18
|
if (userCT.attributes && userCT.attributes.sessions) {
|
|
19
19
|
delete userCT.attributes.sessions;
|
|
20
|
-
strapi2.log.info("[magic-sessionmanager]
|
|
20
|
+
strapi2.log.info("[magic-sessionmanager] [SUCCESS] Removed sessions field from User content type");
|
|
21
21
|
}
|
|
22
|
-
strapi2.log.info("[magic-sessionmanager]
|
|
22
|
+
strapi2.log.info("[magic-sessionmanager] [SUCCESS] Plugin registered successfully");
|
|
23
23
|
} catch (err) {
|
|
24
|
-
strapi2.log.error("[magic-sessionmanager]
|
|
24
|
+
strapi2.log.error("[magic-sessionmanager] [ERROR] Registration error:", err);
|
|
25
25
|
}
|
|
26
26
|
};
|
|
27
27
|
const getClientIp$1 = (ctx) => {
|
|
@@ -98,7 +98,7 @@ function getEncryptionKey() {
|
|
|
98
98
|
}
|
|
99
99
|
const strapiKeys = process.env.APP_KEYS || process.env.API_TOKEN_SALT || "default-insecure-key";
|
|
100
100
|
const key = crypto$1.createHash("sha256").update(strapiKeys).digest();
|
|
101
|
-
console.warn("[magic-sessionmanager/encryption]
|
|
101
|
+
console.warn("[magic-sessionmanager/encryption] [WARNING] No SESSION_ENCRYPTION_KEY found. Using fallback (not recommended for production).");
|
|
102
102
|
console.warn("[magic-sessionmanager/encryption] Set SESSION_ENCRYPTION_KEY in .env for better security.");
|
|
103
103
|
return key;
|
|
104
104
|
}
|
|
@@ -149,20 +149,21 @@ var encryption = {
|
|
|
149
149
|
decryptToken: decryptToken$3,
|
|
150
150
|
generateSessionId: generateSessionId$1
|
|
151
151
|
};
|
|
152
|
+
const SESSION_UID$3 = "plugin::magic-sessionmanager.session";
|
|
152
153
|
var lastSeen = ({ strapi: strapi2, sessionService }) => {
|
|
153
154
|
return async (ctx, next) => {
|
|
154
155
|
if (ctx.state.user && ctx.state.user.id) {
|
|
155
156
|
try {
|
|
156
157
|
const userId = ctx.state.user.id;
|
|
157
|
-
const activeSessions = await strapi2.
|
|
158
|
+
const activeSessions = await strapi2.documents(SESSION_UID$3).findMany({
|
|
158
159
|
filters: {
|
|
159
|
-
user: {
|
|
160
|
+
user: { documentId: userId },
|
|
160
161
|
isActive: true
|
|
161
162
|
},
|
|
162
163
|
limit: 1
|
|
163
164
|
});
|
|
164
165
|
if (!activeSessions || activeSessions.length === 0) {
|
|
165
|
-
strapi2.log.info(`[magic-sessionmanager]
|
|
166
|
+
strapi2.log.info(`[magic-sessionmanager] [BLOCKED] Blocked request - User ${userId} has no active sessions`);
|
|
166
167
|
return ctx.unauthorized("All sessions have been terminated. Please login again.");
|
|
167
168
|
}
|
|
168
169
|
} catch (err) {
|
|
@@ -186,15 +187,16 @@ var lastSeen = ({ strapi: strapi2, sessionService }) => {
|
|
|
186
187
|
};
|
|
187
188
|
const getClientIp = getClientIp_1;
|
|
188
189
|
const { encryptToken: encryptToken$1, decryptToken: decryptToken$2 } = encryption;
|
|
190
|
+
const SESSION_UID$2 = "plugin::magic-sessionmanager.session";
|
|
189
191
|
var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
190
|
-
strapi2.log.info("[magic-sessionmanager]
|
|
192
|
+
strapi2.log.info("[magic-sessionmanager] [START] Bootstrap starting...");
|
|
191
193
|
try {
|
|
192
194
|
const licenseGuardService = strapi2.plugin("magic-sessionmanager").service("license-guard");
|
|
193
195
|
setTimeout(async () => {
|
|
194
196
|
const licenseStatus = await licenseGuardService.initialize();
|
|
195
197
|
if (!licenseStatus.valid) {
|
|
196
198
|
strapi2.log.error("╔════════════════════════════════════════════════════════════════╗");
|
|
197
|
-
strapi2.log.error("║
|
|
199
|
+
strapi2.log.error("║ [ERROR] SESSION MANAGER - NO VALID LICENSE ║");
|
|
198
200
|
strapi2.log.error("║ ║");
|
|
199
201
|
strapi2.log.error("║ This plugin requires a valid license to operate. ║");
|
|
200
202
|
strapi2.log.error("║ Please activate your license via Admin UI: ║");
|
|
@@ -210,7 +212,7 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
210
212
|
});
|
|
211
213
|
const storedKey = await pluginStore.get({ key: "licenseKey" });
|
|
212
214
|
strapi2.log.info("╔════════════════════════════════════════════════════════════════╗");
|
|
213
|
-
strapi2.log.info("║
|
|
215
|
+
strapi2.log.info("║ [SUCCESS] SESSION MANAGER LICENSE ACTIVE ║");
|
|
214
216
|
strapi2.log.info("║ ║");
|
|
215
217
|
if (licenseStatus.data) {
|
|
216
218
|
strapi2.log.info(`║ License: ${licenseStatus.data.licenseKey}`.padEnd(66) + "║");
|
|
@@ -221,7 +223,7 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
221
223
|
strapi2.log.info(`║ Status: Grace Period Active`.padEnd(66) + "║");
|
|
222
224
|
}
|
|
223
225
|
strapi2.log.info("║ ║");
|
|
224
|
-
strapi2.log.info("║
|
|
226
|
+
strapi2.log.info("║ [RELOAD] Auto-pinging every 15 minutes ║");
|
|
225
227
|
strapi2.log.info("╚════════════════════════════════════════════════════════════════╝");
|
|
226
228
|
}
|
|
227
229
|
}, 3e3);
|
|
@@ -237,7 +239,7 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
237
239
|
strapi2.log.error("[magic-sessionmanager] Periodic cleanup error:", err);
|
|
238
240
|
}
|
|
239
241
|
}, cleanupInterval);
|
|
240
|
-
strapi2.log.info("[magic-sessionmanager]
|
|
242
|
+
strapi2.log.info("[magic-sessionmanager] [TIME] Periodic cleanup scheduled (every 30 minutes)");
|
|
241
243
|
if (!strapi2.sessionManagerIntervals) {
|
|
242
244
|
strapi2.sessionManagerIntervals = {};
|
|
243
245
|
}
|
|
@@ -253,7 +255,7 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
253
255
|
ctx.body = { message: "Logged out successfully" };
|
|
254
256
|
return;
|
|
255
257
|
}
|
|
256
|
-
const allSessions = await strapi2.
|
|
258
|
+
const allSessions = await strapi2.documents(SESSION_UID$2).findMany({
|
|
257
259
|
filters: {
|
|
258
260
|
isActive: true
|
|
259
261
|
}
|
|
@@ -268,8 +270,8 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
268
270
|
}
|
|
269
271
|
});
|
|
270
272
|
if (matchingSession) {
|
|
271
|
-
await sessionService.terminateSession({ sessionId: matchingSession.
|
|
272
|
-
strapi2.log.info(`[magic-sessionmanager]
|
|
273
|
+
await sessionService.terminateSession({ sessionId: matchingSession.documentId });
|
|
274
|
+
strapi2.log.info(`[magic-sessionmanager] [LOGOUT] Logout via /api/auth/logout - Session ${matchingSession.documentId} terminated`);
|
|
273
275
|
}
|
|
274
276
|
ctx.status = 200;
|
|
275
277
|
ctx.body = { message: "Logged out successfully" };
|
|
@@ -283,7 +285,7 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
283
285
|
auth: false
|
|
284
286
|
}
|
|
285
287
|
}]);
|
|
286
|
-
strapi2.log.info("[magic-sessionmanager]
|
|
288
|
+
strapi2.log.info("[magic-sessionmanager] [SUCCESS] /api/auth/logout route registered");
|
|
287
289
|
strapi2.server.use(async (ctx, next) => {
|
|
288
290
|
await next();
|
|
289
291
|
const isAuthLocal = ctx.path === "/api/auth/local" && ctx.method === "POST";
|
|
@@ -293,7 +295,7 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
293
295
|
const user = ctx.body.user;
|
|
294
296
|
const ip = getClientIp(ctx);
|
|
295
297
|
const userAgent = ctx.request.headers?.["user-agent"] || ctx.request.header?.["user-agent"] || "unknown";
|
|
296
|
-
strapi2.log.info(`[magic-sessionmanager]
|
|
298
|
+
strapi2.log.info(`[magic-sessionmanager] [CHECK] Login detected! User: ${user.id} (${user.email || user.username}) from IP: ${ip}`);
|
|
297
299
|
const config2 = strapi2.config.get("plugin::magic-sessionmanager") || {};
|
|
298
300
|
let shouldBlock = false;
|
|
299
301
|
let blockReason = "";
|
|
@@ -335,7 +337,7 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
335
337
|
}
|
|
336
338
|
}
|
|
337
339
|
if (shouldBlock) {
|
|
338
|
-
strapi2.log.warn(`[magic-sessionmanager]
|
|
340
|
+
strapi2.log.warn(`[magic-sessionmanager] [BLOCKED] Blocking login: ${blockReason}`);
|
|
339
341
|
ctx.status = 403;
|
|
340
342
|
ctx.body = {
|
|
341
343
|
error: {
|
|
@@ -355,7 +357,7 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
355
357
|
refreshToken: ctx.body.refreshToken
|
|
356
358
|
// Store Refresh Token (encrypted) if exists
|
|
357
359
|
});
|
|
358
|
-
strapi2.log.info(`[magic-sessionmanager]
|
|
360
|
+
strapi2.log.info(`[magic-sessionmanager] [SUCCESS] Session created for user ${user.id} (IP: ${ip})`);
|
|
359
361
|
if (geoData && (config2.enableEmailAlerts || config2.enableWebhooks)) {
|
|
360
362
|
try {
|
|
361
363
|
const notificationService = strapi2.plugin("magic-sessionmanager").service("notifications");
|
|
@@ -393,18 +395,18 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
393
395
|
}
|
|
394
396
|
}
|
|
395
397
|
} catch (err) {
|
|
396
|
-
strapi2.log.error("[magic-sessionmanager]
|
|
398
|
+
strapi2.log.error("[magic-sessionmanager] [ERROR] Error creating session:", err);
|
|
397
399
|
}
|
|
398
400
|
}
|
|
399
401
|
});
|
|
400
|
-
strapi2.log.info("[magic-sessionmanager]
|
|
402
|
+
strapi2.log.info("[magic-sessionmanager] [SUCCESS] Login/Logout interceptor middleware mounted");
|
|
401
403
|
strapi2.server.use(async (ctx, next) => {
|
|
402
404
|
const isRefreshToken = ctx.path === "/api/auth/refresh" && ctx.method === "POST";
|
|
403
405
|
if (isRefreshToken) {
|
|
404
406
|
try {
|
|
405
407
|
const refreshToken = ctx.request.body?.refreshToken;
|
|
406
408
|
if (refreshToken) {
|
|
407
|
-
const allSessions = await strapi2.
|
|
409
|
+
const allSessions = await strapi2.documents(SESSION_UID$2).findMany({
|
|
408
410
|
filters: {
|
|
409
411
|
isActive: true
|
|
410
412
|
}
|
|
@@ -419,7 +421,7 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
419
421
|
}
|
|
420
422
|
});
|
|
421
423
|
if (!matchingSession) {
|
|
422
|
-
strapi2.log.warn("[magic-sessionmanager]
|
|
424
|
+
strapi2.log.warn("[magic-sessionmanager] [BLOCKED] Blocked refresh token request - no active session");
|
|
423
425
|
ctx.status = 401;
|
|
424
426
|
ctx.body = {
|
|
425
427
|
error: {
|
|
@@ -430,7 +432,7 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
430
432
|
};
|
|
431
433
|
return;
|
|
432
434
|
}
|
|
433
|
-
strapi2.log.info(`[magic-sessionmanager]
|
|
435
|
+
strapi2.log.info(`[magic-sessionmanager] [SUCCESS] Refresh token allowed for session ${matchingSession.documentId}`);
|
|
434
436
|
}
|
|
435
437
|
} catch (err) {
|
|
436
438
|
strapi2.log.error("[magic-sessionmanager] Error checking refresh token:", err);
|
|
@@ -443,7 +445,7 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
443
445
|
const newAccessToken = ctx.body.jwt;
|
|
444
446
|
const newRefreshToken = ctx.body.refreshToken;
|
|
445
447
|
if (oldRefreshToken) {
|
|
446
|
-
const allSessions = await strapi2.
|
|
448
|
+
const allSessions = await strapi2.documents(SESSION_UID$2).findMany({
|
|
447
449
|
filters: {
|
|
448
450
|
isActive: true
|
|
449
451
|
}
|
|
@@ -460,14 +462,15 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
460
462
|
if (matchingSession) {
|
|
461
463
|
const encryptedToken = newAccessToken ? encryptToken$1(newAccessToken) : matchingSession.token;
|
|
462
464
|
const encryptedRefreshToken = newRefreshToken ? encryptToken$1(newRefreshToken) : matchingSession.refreshToken;
|
|
463
|
-
await strapi2.
|
|
465
|
+
await strapi2.documents(SESSION_UID$2).update({
|
|
466
|
+
documentId: matchingSession.documentId,
|
|
464
467
|
data: {
|
|
465
468
|
token: encryptedToken,
|
|
466
469
|
refreshToken: encryptedRefreshToken,
|
|
467
470
|
lastActive: /* @__PURE__ */ new Date()
|
|
468
471
|
}
|
|
469
472
|
});
|
|
470
|
-
strapi2.log.info(`[magic-sessionmanager]
|
|
473
|
+
strapi2.log.info(`[magic-sessionmanager] [REFRESH] Tokens refreshed for session ${matchingSession.documentId}`);
|
|
471
474
|
}
|
|
472
475
|
}
|
|
473
476
|
} catch (err) {
|
|
@@ -475,15 +478,15 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
|
|
|
475
478
|
}
|
|
476
479
|
}
|
|
477
480
|
});
|
|
478
|
-
strapi2.log.info("[magic-sessionmanager]
|
|
481
|
+
strapi2.log.info("[magic-sessionmanager] [SUCCESS] Refresh Token interceptor middleware mounted");
|
|
479
482
|
strapi2.server.use(
|
|
480
483
|
lastSeen({ strapi: strapi2, sessionService })
|
|
481
484
|
);
|
|
482
|
-
strapi2.log.info("[magic-sessionmanager]
|
|
483
|
-
strapi2.log.info("[magic-sessionmanager]
|
|
484
|
-
strapi2.log.info("[magic-sessionmanager]
|
|
485
|
+
strapi2.log.info("[magic-sessionmanager] [SUCCESS] LastSeen middleware mounted");
|
|
486
|
+
strapi2.log.info("[magic-sessionmanager] [SUCCESS] Bootstrap complete");
|
|
487
|
+
strapi2.log.info("[magic-sessionmanager] [READY] Session Manager ready! Sessions stored in plugin::magic-sessionmanager.session");
|
|
485
488
|
} catch (err) {
|
|
486
|
-
strapi2.log.error("[magic-sessionmanager]
|
|
489
|
+
strapi2.log.error("[magic-sessionmanager] [ERROR] Bootstrap error:", err);
|
|
487
490
|
}
|
|
488
491
|
};
|
|
489
492
|
var destroy$1 = async ({ strapi: strapi2 }) => {
|
|
@@ -495,7 +498,7 @@ var destroy$1 = async ({ strapi: strapi2 }) => {
|
|
|
495
498
|
clearInterval(strapi2.sessionManagerIntervals.cleanup);
|
|
496
499
|
strapi2.log.info("[magic-sessionmanager] 🛑 Session cleanup interval stopped");
|
|
497
500
|
}
|
|
498
|
-
strapi2.log.info("[magic-sessionmanager]
|
|
501
|
+
strapi2.log.info("[magic-sessionmanager] [SUCCESS] Plugin cleanup completed");
|
|
499
502
|
};
|
|
500
503
|
var config$1 = {
|
|
501
504
|
default: {
|
|
@@ -803,6 +806,8 @@ var routes$1 = {
|
|
|
803
806
|
"content-api": contentApi
|
|
804
807
|
};
|
|
805
808
|
const { decryptToken: decryptToken$1 } = encryption;
|
|
809
|
+
const SESSION_UID$1 = "plugin::magic-sessionmanager.session";
|
|
810
|
+
const USER_UID = "plugin::users-permissions.user";
|
|
806
811
|
var session$3 = {
|
|
807
812
|
/**
|
|
808
813
|
* Get ALL sessions (active + inactive) - Admin only
|
|
@@ -881,9 +886,9 @@ var session$3 = {
|
|
|
881
886
|
return ctx.throw(401, "Unauthorized");
|
|
882
887
|
}
|
|
883
888
|
const sessionService = strapi.plugin("magic-sessionmanager").service("session");
|
|
884
|
-
const sessions = await strapi.
|
|
889
|
+
const sessions = await strapi.documents(SESSION_UID$1).findMany({
|
|
885
890
|
filters: {
|
|
886
|
-
user: {
|
|
891
|
+
user: { documentId: userId },
|
|
887
892
|
isActive: true
|
|
888
893
|
}
|
|
889
894
|
});
|
|
@@ -897,8 +902,8 @@ var session$3 = {
|
|
|
897
902
|
}
|
|
898
903
|
});
|
|
899
904
|
if (matchingSession) {
|
|
900
|
-
await sessionService.terminateSession({ sessionId: matchingSession.
|
|
901
|
-
strapi.log.info(`[magic-sessionmanager] User ${userId} logged out (session ${matchingSession.
|
|
905
|
+
await sessionService.terminateSession({ sessionId: matchingSession.documentId });
|
|
906
|
+
strapi.log.info(`[magic-sessionmanager] User ${userId} logged out (session ${matchingSession.documentId})`);
|
|
902
907
|
}
|
|
903
908
|
ctx.body = {
|
|
904
909
|
message: "Logged out successfully"
|
|
@@ -1058,12 +1063,13 @@ var session$3 = {
|
|
|
1058
1063
|
async toggleUserBlock(ctx) {
|
|
1059
1064
|
try {
|
|
1060
1065
|
const { userId } = ctx.params;
|
|
1061
|
-
const user = await strapi.
|
|
1066
|
+
const user = await strapi.documents(USER_UID).findOne({ documentId: userId });
|
|
1062
1067
|
if (!user) {
|
|
1063
1068
|
return ctx.throw(404, "User not found");
|
|
1064
1069
|
}
|
|
1065
1070
|
const newBlockedStatus = !user.blocked;
|
|
1066
|
-
await strapi.
|
|
1071
|
+
await strapi.documents(USER_UID).update({
|
|
1072
|
+
documentId: userId,
|
|
1067
1073
|
data: {
|
|
1068
1074
|
blocked: newBlockedStatus
|
|
1069
1075
|
}
|
|
@@ -1257,16 +1263,16 @@ var license$1 = ({ strapi: strapi2 }) => ({
|
|
|
1257
1263
|
const licenseGuard2 = strapi2.plugin("magic-sessionmanager").service("license-guard");
|
|
1258
1264
|
const verification = await licenseGuard2.verifyLicense(trimmedKey);
|
|
1259
1265
|
if (!verification.valid) {
|
|
1260
|
-
strapi2.log.warn(`[magic-sessionmanager]
|
|
1266
|
+
strapi2.log.warn(`[magic-sessionmanager] [WARNING] Invalid license key attempted: ${trimmedKey.substring(0, 8)}...`);
|
|
1261
1267
|
return ctx.badRequest("Invalid or expired license key");
|
|
1262
1268
|
}
|
|
1263
1269
|
const license2 = await licenseGuard2.getLicenseByKey(trimmedKey);
|
|
1264
1270
|
if (!license2) {
|
|
1265
|
-
strapi2.log.warn(`[magic-sessionmanager]
|
|
1271
|
+
strapi2.log.warn(`[magic-sessionmanager] [WARNING] License not found in database: ${trimmedKey.substring(0, 8)}...`);
|
|
1266
1272
|
return ctx.badRequest("License not found");
|
|
1267
1273
|
}
|
|
1268
1274
|
if (license2.email.toLowerCase() !== trimmedEmail) {
|
|
1269
|
-
strapi2.log.warn(`[magic-sessionmanager]
|
|
1275
|
+
strapi2.log.warn(`[magic-sessionmanager] [WARNING] Email mismatch for license key: ${trimmedKey.substring(0, 8)}... (Attempted: ${trimmedEmail})`);
|
|
1270
1276
|
return ctx.badRequest("Email address does not match this license key");
|
|
1271
1277
|
}
|
|
1272
1278
|
await licenseGuard2.storeLicenseKey(trimmedKey);
|
|
@@ -1276,7 +1282,7 @@ var license$1 = ({ strapi: strapi2 }) => ({
|
|
|
1276
1282
|
pingInterval,
|
|
1277
1283
|
data: verification.data
|
|
1278
1284
|
};
|
|
1279
|
-
strapi2.log.info(`[magic-sessionmanager]
|
|
1285
|
+
strapi2.log.info(`[magic-sessionmanager] [SUCCESS] Existing license key validated and stored: ${trimmedKey.substring(0, 8)}... (Email: ${trimmedEmail})`);
|
|
1280
1286
|
return ctx.send({
|
|
1281
1287
|
success: true,
|
|
1282
1288
|
message: "License key validated and activated successfully",
|
|
@@ -1398,6 +1404,7 @@ var controllers$1 = {
|
|
|
1398
1404
|
settings
|
|
1399
1405
|
};
|
|
1400
1406
|
const { encryptToken, decryptToken, generateSessionId } = encryption;
|
|
1407
|
+
const SESSION_UID = "plugin::magic-sessionmanager.session";
|
|
1401
1408
|
var session$1 = ({ strapi: strapi2 }) => ({
|
|
1402
1409
|
/**
|
|
1403
1410
|
* Create a new session record
|
|
@@ -1410,23 +1417,24 @@ var session$1 = ({ strapi: strapi2 }) => ({
|
|
|
1410
1417
|
const sessionId = generateSessionId(userId);
|
|
1411
1418
|
const encryptedToken = token ? encryptToken(token) : null;
|
|
1412
1419
|
const encryptedRefreshToken = refreshToken ? encryptToken(refreshToken) : null;
|
|
1413
|
-
const session2 = await strapi2.
|
|
1420
|
+
const session2 = await strapi2.documents(SESSION_UID).create({
|
|
1414
1421
|
data: {
|
|
1415
1422
|
user: userId,
|
|
1423
|
+
// userId should be documentId (string)
|
|
1416
1424
|
ipAddress: ip.substring(0, 45),
|
|
1417
1425
|
userAgent: userAgent.substring(0, 500),
|
|
1418
1426
|
loginTime: now,
|
|
1419
1427
|
lastActive: now,
|
|
1420
1428
|
isActive: true,
|
|
1421
1429
|
token: encryptedToken,
|
|
1422
|
-
//
|
|
1430
|
+
// [SUCCESS] Encrypted Access Token
|
|
1423
1431
|
refreshToken: encryptedRefreshToken,
|
|
1424
|
-
//
|
|
1432
|
+
// [SUCCESS] Encrypted Refresh Token
|
|
1425
1433
|
sessionId
|
|
1426
|
-
//
|
|
1434
|
+
// [SUCCESS] Unique identifier
|
|
1427
1435
|
}
|
|
1428
1436
|
});
|
|
1429
|
-
strapi2.log.info(`[magic-sessionmanager]
|
|
1437
|
+
strapi2.log.info(`[magic-sessionmanager] [SUCCESS] Session ${session2.documentId} (${sessionId}) created for user ${userId}`);
|
|
1430
1438
|
return session2;
|
|
1431
1439
|
} catch (err) {
|
|
1432
1440
|
strapi2.log.error("[magic-sessionmanager] Error creating session:", err);
|
|
@@ -1442,7 +1450,8 @@ var session$1 = ({ strapi: strapi2 }) => ({
|
|
|
1442
1450
|
try {
|
|
1443
1451
|
const now = /* @__PURE__ */ new Date();
|
|
1444
1452
|
if (sessionId) {
|
|
1445
|
-
await strapi2.
|
|
1453
|
+
await strapi2.documents(SESSION_UID).update({
|
|
1454
|
+
documentId: sessionId,
|
|
1446
1455
|
data: {
|
|
1447
1456
|
isActive: false,
|
|
1448
1457
|
logoutTime: now
|
|
@@ -1450,14 +1459,16 @@ var session$1 = ({ strapi: strapi2 }) => ({
|
|
|
1450
1459
|
});
|
|
1451
1460
|
strapi2.log.info(`[magic-sessionmanager] Session ${sessionId} terminated`);
|
|
1452
1461
|
} else if (userId) {
|
|
1453
|
-
const activeSessions = await strapi2.
|
|
1462
|
+
const activeSessions = await strapi2.documents(SESSION_UID).findMany({
|
|
1454
1463
|
filters: {
|
|
1455
|
-
user: {
|
|
1464
|
+
user: { documentId: userId },
|
|
1465
|
+
// Deep filtering syntax
|
|
1456
1466
|
isActive: true
|
|
1457
1467
|
}
|
|
1458
1468
|
});
|
|
1459
1469
|
for (const session2 of activeSessions) {
|
|
1460
|
-
await strapi2.
|
|
1470
|
+
await strapi2.documents(SESSION_UID).update({
|
|
1471
|
+
documentId: session2.documentId,
|
|
1461
1472
|
data: {
|
|
1462
1473
|
isActive: false,
|
|
1463
1474
|
logoutTime: now
|
|
@@ -1477,7 +1488,7 @@ var session$1 = ({ strapi: strapi2 }) => ({
|
|
|
1477
1488
|
*/
|
|
1478
1489
|
async getAllSessions() {
|
|
1479
1490
|
try {
|
|
1480
|
-
const sessions = await strapi2.
|
|
1491
|
+
const sessions = await strapi2.documents(SESSION_UID).findMany({
|
|
1481
1492
|
populate: { user: { fields: ["id", "email", "username"] } },
|
|
1482
1493
|
sort: { loginTime: "desc" },
|
|
1483
1494
|
limit: 1e3
|
|
@@ -1509,7 +1520,7 @@ var session$1 = ({ strapi: strapi2 }) => ({
|
|
|
1509
1520
|
*/
|
|
1510
1521
|
async getActiveSessions() {
|
|
1511
1522
|
try {
|
|
1512
|
-
const sessions = await strapi2.
|
|
1523
|
+
const sessions = await strapi2.documents(SESSION_UID).findMany({
|
|
1513
1524
|
filters: { isActive: true },
|
|
1514
1525
|
populate: { user: { fields: ["id", "email", "username"] } },
|
|
1515
1526
|
sort: { loginTime: "desc" }
|
|
@@ -1541,8 +1552,8 @@ var session$1 = ({ strapi: strapi2 }) => ({
|
|
|
1541
1552
|
*/
|
|
1542
1553
|
async getUserSessions(userId) {
|
|
1543
1554
|
try {
|
|
1544
|
-
const sessions = await strapi2.
|
|
1545
|
-
filters: { user: {
|
|
1555
|
+
const sessions = await strapi2.documents(SESSION_UID).findMany({
|
|
1556
|
+
filters: { user: { documentId: userId } },
|
|
1546
1557
|
sort: { loginTime: "desc" }
|
|
1547
1558
|
});
|
|
1548
1559
|
const config2 = strapi2.config.get("plugin::magic-sessionmanager") || {};
|
|
@@ -1576,17 +1587,19 @@ var session$1 = ({ strapi: strapi2 }) => ({
|
|
|
1576
1587
|
const config2 = strapi2.config.get("plugin::magic-sessionmanager") || {};
|
|
1577
1588
|
const rateLimit = config2.lastSeenRateLimit || 3e4;
|
|
1578
1589
|
if (sessionId) {
|
|
1579
|
-
const session2 = await strapi2.
|
|
1590
|
+
const session2 = await strapi2.documents(SESSION_UID).findOne({ documentId: sessionId });
|
|
1580
1591
|
if (session2 && session2.lastActive) {
|
|
1581
1592
|
const lastActiveTime = new Date(session2.lastActive).getTime();
|
|
1582
1593
|
const currentTime = now.getTime();
|
|
1583
1594
|
if (currentTime - lastActiveTime > rateLimit) {
|
|
1584
|
-
await strapi2.
|
|
1595
|
+
await strapi2.documents(SESSION_UID).update({
|
|
1596
|
+
documentId: sessionId,
|
|
1585
1597
|
data: { lastActive: now }
|
|
1586
1598
|
});
|
|
1587
1599
|
}
|
|
1588
1600
|
} else if (session2) {
|
|
1589
|
-
await strapi2.
|
|
1601
|
+
await strapi2.documents(SESSION_UID).update({
|
|
1602
|
+
documentId: sessionId,
|
|
1590
1603
|
data: { lastActive: now }
|
|
1591
1604
|
});
|
|
1592
1605
|
}
|
|
@@ -1605,22 +1618,23 @@ var session$1 = ({ strapi: strapi2 }) => ({
|
|
|
1605
1618
|
const inactivityTimeout = config2.inactivityTimeout || 15 * 60 * 1e3;
|
|
1606
1619
|
const now = /* @__PURE__ */ new Date();
|
|
1607
1620
|
const cutoffTime = new Date(now.getTime() - inactivityTimeout);
|
|
1608
|
-
strapi2.log.info(`[magic-sessionmanager]
|
|
1609
|
-
const activeSessions = await strapi2.
|
|
1621
|
+
strapi2.log.info(`[magic-sessionmanager] [CLEANUP] Cleaning up sessions inactive since before ${cutoffTime.toISOString()}`);
|
|
1622
|
+
const activeSessions = await strapi2.documents(SESSION_UID).findMany({
|
|
1610
1623
|
filters: { isActive: true },
|
|
1611
|
-
fields: ["
|
|
1624
|
+
fields: ["lastActive", "loginTime"]
|
|
1612
1625
|
});
|
|
1613
1626
|
let deactivatedCount = 0;
|
|
1614
1627
|
for (const session2 of activeSessions) {
|
|
1615
1628
|
const lastActiveTime = session2.lastActive ? new Date(session2.lastActive) : new Date(session2.loginTime);
|
|
1616
1629
|
if (lastActiveTime < cutoffTime) {
|
|
1617
|
-
await strapi2.
|
|
1630
|
+
await strapi2.documents(SESSION_UID).update({
|
|
1631
|
+
documentId: session2.documentId,
|
|
1618
1632
|
data: { isActive: false }
|
|
1619
1633
|
});
|
|
1620
1634
|
deactivatedCount++;
|
|
1621
1635
|
}
|
|
1622
1636
|
}
|
|
1623
|
-
strapi2.log.info(`[magic-sessionmanager]
|
|
1637
|
+
strapi2.log.info(`[magic-sessionmanager] [SUCCESS] Cleanup complete: ${deactivatedCount} sessions deactivated`);
|
|
1624
1638
|
return deactivatedCount;
|
|
1625
1639
|
} catch (err) {
|
|
1626
1640
|
strapi2.log.error("[magic-sessionmanager] Error cleaning up inactive sessions:", err);
|
|
@@ -1635,8 +1649,8 @@ var session$1 = ({ strapi: strapi2 }) => ({
|
|
|
1635
1649
|
*/
|
|
1636
1650
|
async deleteSession(sessionId) {
|
|
1637
1651
|
try {
|
|
1638
|
-
await strapi2.
|
|
1639
|
-
strapi2.log.info(`[magic-sessionmanager]
|
|
1652
|
+
await strapi2.documents(SESSION_UID).delete({ documentId: sessionId });
|
|
1653
|
+
strapi2.log.info(`[magic-sessionmanager] [DELETE] Session ${sessionId} permanently deleted`);
|
|
1640
1654
|
return true;
|
|
1641
1655
|
} catch (err) {
|
|
1642
1656
|
strapi2.log.error("[magic-sessionmanager] Error deleting session:", err);
|
|
@@ -1650,17 +1664,16 @@ var session$1 = ({ strapi: strapi2 }) => ({
|
|
|
1650
1664
|
*/
|
|
1651
1665
|
async deleteInactiveSessions() {
|
|
1652
1666
|
try {
|
|
1653
|
-
strapi2.log.info("[magic-sessionmanager]
|
|
1654
|
-
const inactiveSessions = await strapi2.
|
|
1655
|
-
filters: { isActive: false }
|
|
1656
|
-
fields: ["id"]
|
|
1667
|
+
strapi2.log.info("[magic-sessionmanager] [DELETE] Deleting all inactive sessions...");
|
|
1668
|
+
const inactiveSessions = await strapi2.documents(SESSION_UID).findMany({
|
|
1669
|
+
filters: { isActive: false }
|
|
1657
1670
|
});
|
|
1658
1671
|
let deletedCount = 0;
|
|
1659
1672
|
for (const session2 of inactiveSessions) {
|
|
1660
|
-
await strapi2.
|
|
1673
|
+
await strapi2.documents(SESSION_UID).delete({ documentId: session2.documentId });
|
|
1661
1674
|
deletedCount++;
|
|
1662
1675
|
}
|
|
1663
|
-
strapi2.log.info(`[magic-sessionmanager]
|
|
1676
|
+
strapi2.log.info(`[magic-sessionmanager] [SUCCESS] Deleted ${deletedCount} inactive sessions`);
|
|
1664
1677
|
return deletedCount;
|
|
1665
1678
|
} catch (err) {
|
|
1666
1679
|
strapi2.log.error("[magic-sessionmanager] Error deleting inactive sessions:", err);
|
|
@@ -1668,8 +1681,13 @@ var session$1 = ({ strapi: strapi2 }) => ({
|
|
|
1668
1681
|
}
|
|
1669
1682
|
}
|
|
1670
1683
|
});
|
|
1684
|
+
const version = "3.7.0";
|
|
1685
|
+
const require$$2 = {
|
|
1686
|
+
version
|
|
1687
|
+
};
|
|
1671
1688
|
const crypto = require$$0__default.default;
|
|
1672
1689
|
const os = require$$1__default.default;
|
|
1690
|
+
const pluginPkg = require$$2;
|
|
1673
1691
|
const LICENSE_SERVER_URL = "https://magicapi.fitlex.me";
|
|
1674
1692
|
var licenseGuard$1 = ({ strapi: strapi2 }) => ({
|
|
1675
1693
|
/**
|
|
@@ -1724,7 +1742,9 @@ var licenseGuard$1 = ({ strapi: strapi2 }) => ({
|
|
|
1724
1742
|
}
|
|
1725
1743
|
},
|
|
1726
1744
|
getUserAgent() {
|
|
1727
|
-
|
|
1745
|
+
const pluginVersion = pluginPkg.version;
|
|
1746
|
+
const strapiVersion = strapi2.config.get("info.strapi") || "5.0.0";
|
|
1747
|
+
return `MagicSessionManager/${pluginVersion} Strapi/${strapiVersion} Node/${process.version} ${os.platform()}/${os.release()}`;
|
|
1728
1748
|
},
|
|
1729
1749
|
async createLicense({ email, firstName, lastName }) {
|
|
1730
1750
|
try {
|
|
@@ -1750,14 +1770,14 @@ var licenseGuard$1 = ({ strapi: strapi2 }) => ({
|
|
|
1750
1770
|
});
|
|
1751
1771
|
const data = await response.json();
|
|
1752
1772
|
if (data.success) {
|
|
1753
|
-
strapi2.log.info("[magic-sessionmanager]
|
|
1773
|
+
strapi2.log.info("[magic-sessionmanager] [SUCCESS] License created:", data.data.licenseKey);
|
|
1754
1774
|
return data.data;
|
|
1755
1775
|
} else {
|
|
1756
|
-
strapi2.log.error("[magic-sessionmanager]
|
|
1776
|
+
strapi2.log.error("[magic-sessionmanager] [ERROR] License creation failed:", data);
|
|
1757
1777
|
return null;
|
|
1758
1778
|
}
|
|
1759
1779
|
} catch (error) {
|
|
1760
|
-
strapi2.log.error("[magic-sessionmanager]
|
|
1780
|
+
strapi2.log.error("[magic-sessionmanager] [ERROR] Error creating license:", error);
|
|
1761
1781
|
return null;
|
|
1762
1782
|
}
|
|
1763
1783
|
},
|
|
@@ -1842,10 +1862,10 @@ var licenseGuard$1 = ({ strapi: strapi2 }) => ({
|
|
|
1842
1862
|
name: "magic-sessionmanager"
|
|
1843
1863
|
});
|
|
1844
1864
|
await pluginStore.set({ key: "licenseKey", value: licenseKey });
|
|
1845
|
-
strapi2.log.info(`[magic-sessionmanager]
|
|
1865
|
+
strapi2.log.info(`[magic-sessionmanager] [SUCCESS] License key stored: ${licenseKey.substring(0, 8)}...`);
|
|
1846
1866
|
},
|
|
1847
1867
|
startPinging(licenseKey, intervalMinutes = 15) {
|
|
1848
|
-
strapi2.log.info(`[magic-sessionmanager]
|
|
1868
|
+
strapi2.log.info(`[magic-sessionmanager] [TIME] Starting license pings every ${intervalMinutes} minutes`);
|
|
1849
1869
|
this.pingLicense(licenseKey);
|
|
1850
1870
|
const interval = setInterval(async () => {
|
|
1851
1871
|
try {
|
|
@@ -1862,14 +1882,14 @@ var licenseGuard$1 = ({ strapi: strapi2 }) => ({
|
|
|
1862
1882
|
*/
|
|
1863
1883
|
async initialize() {
|
|
1864
1884
|
try {
|
|
1865
|
-
strapi2.log.info("[magic-sessionmanager]
|
|
1885
|
+
strapi2.log.info("[magic-sessionmanager] [SECURE] Initializing License Guard...");
|
|
1866
1886
|
const pluginStore = strapi2.store({
|
|
1867
1887
|
type: "plugin",
|
|
1868
1888
|
name: "magic-sessionmanager"
|
|
1869
1889
|
});
|
|
1870
1890
|
const licenseKey = await pluginStore.get({ key: "licenseKey" });
|
|
1871
1891
|
if (!licenseKey) {
|
|
1872
|
-
strapi2.log.info("[magic-sessionmanager]
|
|
1892
|
+
strapi2.log.info("[magic-sessionmanager] [INFO] No license found - Running in demo mode");
|
|
1873
1893
|
return {
|
|
1874
1894
|
valid: false,
|
|
1875
1895
|
demo: true,
|
|
@@ -1904,7 +1924,7 @@ var licenseGuard$1 = ({ strapi: strapi2 }) => ({
|
|
|
1904
1924
|
gracePeriod: verification.gracePeriod || false
|
|
1905
1925
|
};
|
|
1906
1926
|
} else {
|
|
1907
|
-
strapi2.log.error("[magic-sessionmanager]
|
|
1927
|
+
strapi2.log.error("[magic-sessionmanager] [ERROR] License validation failed");
|
|
1908
1928
|
return {
|
|
1909
1929
|
valid: false,
|
|
1910
1930
|
demo: true,
|
|
@@ -1913,7 +1933,7 @@ var licenseGuard$1 = ({ strapi: strapi2 }) => ({
|
|
|
1913
1933
|
};
|
|
1914
1934
|
}
|
|
1915
1935
|
} catch (error) {
|
|
1916
|
-
strapi2.log.error("[magic-sessionmanager]
|
|
1936
|
+
strapi2.log.error("[magic-sessionmanager] [ERROR] Error initializing License Guard:", error);
|
|
1917
1937
|
return {
|
|
1918
1938
|
valid: false,
|
|
1919
1939
|
demo: true,
|
|
@@ -2026,9 +2046,11 @@ var geolocation$1 = ({ strapi: strapi2 }) => ({
|
|
|
2026
2046
|
},
|
|
2027
2047
|
/**
|
|
2028
2048
|
* Get country flag emoji
|
|
2049
|
+
* @param {string} countryCode - ISO 2-letter country code
|
|
2050
|
+
* @returns {string} Flag emoji or empty string
|
|
2029
2051
|
*/
|
|
2030
2052
|
getCountryFlag(countryCode) {
|
|
2031
|
-
if (!countryCode) return "
|
|
2053
|
+
if (!countryCode) return "";
|
|
2032
2054
|
const codePoints = countryCode.toUpperCase().split("").map((char) => 127397 + char.charCodeAt());
|
|
2033
2055
|
return String.fromCodePoint(...codePoints);
|
|
2034
2056
|
},
|
|
@@ -2040,7 +2062,7 @@ var geolocation$1 = ({ strapi: strapi2 }) => ({
|
|
|
2040
2062
|
ip: ipAddress,
|
|
2041
2063
|
country: "Unknown",
|
|
2042
2064
|
country_code: "XX",
|
|
2043
|
-
country_flag: "
|
|
2065
|
+
country_flag: "[GEO]",
|
|
2044
2066
|
city: "Unknown",
|
|
2045
2067
|
region: "Unknown",
|
|
2046
2068
|
timezone: "Unknown",
|
|
@@ -2145,9 +2167,9 @@ Login Details:
|
|
|
2145
2167
|
Security: VPN={{reason.isVpn}}, Proxy={{reason.isProxy}}, Threat={{reason.isThreat}}, Score={{reason.securityScore}}/100`
|
|
2146
2168
|
},
|
|
2147
2169
|
newLocation: {
|
|
2148
|
-
subject: "
|
|
2149
|
-
html: `<h2
|
|
2150
|
-
text:
|
|
2170
|
+
subject: "[LOCATION] New Location Login Detected",
|
|
2171
|
+
html: `<h2>[LOCATION] New Location Login</h2><p>Account: {{user.email}}</p><p>Time: {{session.loginTime}}</p><p>Location: {{geo.city}}, {{geo.country}}</p><p>IP: {{session.ipAddress}}</p>`,
|
|
2172
|
+
text: `[LOCATION] New Location Login
|
|
2151
2173
|
|
|
2152
2174
|
Account: {{user.email}}
|
|
2153
2175
|
Time: {{session.loginTime}}
|
|
@@ -2155,9 +2177,9 @@ Location: {{geo.city}}, {{geo.country}}
|
|
|
2155
2177
|
IP: {{session.ipAddress}}`
|
|
2156
2178
|
},
|
|
2157
2179
|
vpnProxy: {
|
|
2158
|
-
subject: "
|
|
2159
|
-
html: `<h2
|
|
2160
|
-
text:
|
|
2180
|
+
subject: "[WARNING] VPN/Proxy Login Detected",
|
|
2181
|
+
html: `<h2>[WARNING] VPN/Proxy Detected</h2><p>Account: {{user.email}}</p><p>Time: {{session.loginTime}}</p><p>IP: {{session.ipAddress}}</p><p>VPN: {{reason.isVpn}}, Proxy: {{reason.isProxy}}</p>`,
|
|
2182
|
+
text: `[WARNING] VPN/Proxy Detected
|
|
2161
2183
|
|
|
2162
2184
|
Account: {{user.email}}
|
|
2163
2185
|
Time: {{session.loginTime}}
|
|
@@ -2311,7 +2333,7 @@ ${user.username || "N/A"}`, inline: true },
|
|
|
2311
2333
|
};
|
|
2312
2334
|
if (geoData) {
|
|
2313
2335
|
embed.fields.push({
|
|
2314
|
-
name: "
|
|
2336
|
+
name: "[LOCATION] Location",
|
|
2315
2337
|
value: `${geoData.country_flag} ${geoData.city}, ${geoData.country}`,
|
|
2316
2338
|
inline: true
|
|
2317
2339
|
});
|
|
@@ -2321,7 +2343,7 @@ ${user.username || "N/A"}`, inline: true },
|
|
|
2321
2343
|
if (geoData.isProxy) warnings.push("Proxy");
|
|
2322
2344
|
if (geoData.isThreat) warnings.push("Threat");
|
|
2323
2345
|
embed.fields.push({
|
|
2324
|
-
name: "
|
|
2346
|
+
name: "[WARNING] Security",
|
|
2325
2347
|
value: `${warnings.join(", ")} detected
|
|
2326
2348
|
Score: ${geoData.securityScore}/100`,
|
|
2327
2349
|
inline: true
|
|
@@ -2333,12 +2355,12 @@ Score: ${geoData.securityScore}/100`,
|
|
|
2333
2355
|
getEventTitle(event) {
|
|
2334
2356
|
const titles = {
|
|
2335
2357
|
"login.suspicious": "🚨 Suspicious Login",
|
|
2336
|
-
"login.new_location": "
|
|
2358
|
+
"login.new_location": "[LOCATION] New Location Login",
|
|
2337
2359
|
"login.vpn": "🔴 VPN Login Detected",
|
|
2338
2360
|
"login.threat": "⛔ Threat IP Login",
|
|
2339
2361
|
"session.terminated": "🔴 Session Terminated"
|
|
2340
2362
|
};
|
|
2341
|
-
return titles[event] || "
|
|
2363
|
+
return titles[event] || "[STATS] Session Event";
|
|
2342
2364
|
},
|
|
2343
2365
|
getEventColor(event) {
|
|
2344
2366
|
const colors = {
|