strapi-plugin-magic-sessionmanager 4.1.0 → 4.2.2
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 +2 -0
- package/dist/server/index.js +635 -559
- package/dist/server/index.mjs +635 -559
- package/package.json +1 -1
- package/server/src/bootstrap.js +57 -53
- package/server/src/config/index.js +3 -0
- package/server/src/destroy.js +7 -3
- package/server/src/register.js +9 -5
- package/server/src/services/license-guard.js +21 -16
- package/server/src/services/session.js +24 -19
- package/server/src/utils/logger.js +84 -0
package/package.json
CHANGED
package/server/src/bootstrap.js
CHANGED
|
@@ -11,12 +11,15 @@
|
|
|
11
11
|
|
|
12
12
|
const getClientIp = require('./utils/getClientIp');
|
|
13
13
|
const { encryptToken, decryptToken } = require('./utils/encryption');
|
|
14
|
+
const { createLogger } = require('./utils/logger');
|
|
14
15
|
|
|
15
16
|
const SESSION_UID = 'plugin::magic-sessionmanager.session';
|
|
16
17
|
const USER_UID = 'plugin::users-permissions.user';
|
|
17
18
|
|
|
18
19
|
module.exports = async ({ strapi }) => {
|
|
19
|
-
|
|
20
|
+
const log = createLogger(strapi);
|
|
21
|
+
|
|
22
|
+
log.info('[START] Bootstrap starting...');
|
|
20
23
|
|
|
21
24
|
try {
|
|
22
25
|
// Initialize License Guard
|
|
@@ -27,16 +30,16 @@ module.exports = async ({ strapi }) => {
|
|
|
27
30
|
const licenseStatus = await licenseGuardService.initialize();
|
|
28
31
|
|
|
29
32
|
if (!licenseStatus.valid) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
log.error('╔════════════════════════════════════════════════════════════════╗');
|
|
34
|
+
log.error('║ [ERROR] SESSION MANAGER - NO VALID LICENSE ║');
|
|
35
|
+
log.error('║ ║');
|
|
36
|
+
log.error('║ This plugin requires a valid license to operate. ║');
|
|
37
|
+
log.error('║ Please activate your license via Admin UI: ║');
|
|
38
|
+
log.error('║ Go to Settings → Sessions → License ║');
|
|
39
|
+
log.error('║ ║');
|
|
40
|
+
log.error('║ The plugin will run with limited functionality until ║');
|
|
41
|
+
log.error('║ a valid license is activated. ║');
|
|
42
|
+
log.error('╚════════════════════════════════════════════════════════════════╝');
|
|
40
43
|
} else if (licenseStatus.valid) {
|
|
41
44
|
const pluginStore = strapi.store({
|
|
42
45
|
type: 'plugin',
|
|
@@ -44,22 +47,22 @@ module.exports = async ({ strapi }) => {
|
|
|
44
47
|
});
|
|
45
48
|
const storedKey = await pluginStore.get({ key: 'licenseKey' });
|
|
46
49
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
log.info('╔════════════════════════════════════════════════════════════════╗');
|
|
51
|
+
log.info('║ [SUCCESS] SESSION MANAGER LICENSE ACTIVE ║');
|
|
52
|
+
log.info('║ ║');
|
|
50
53
|
|
|
51
54
|
if (licenseStatus.data) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
log.info(`║ License: ${licenseStatus.data.licenseKey}`.padEnd(66) + '║');
|
|
56
|
+
log.info(`║ User: ${licenseStatus.data.firstName} ${licenseStatus.data.lastName}`.padEnd(66) + '║');
|
|
57
|
+
log.info(`║ Email: ${licenseStatus.data.email}`.padEnd(66) + '║');
|
|
55
58
|
} else if (storedKey) {
|
|
56
|
-
|
|
57
|
-
|
|
59
|
+
log.info(`║ License: ${storedKey} (Offline Mode)`.padEnd(66) + '║');
|
|
60
|
+
log.info(`║ Status: Grace Period Active`.padEnd(66) + '║');
|
|
58
61
|
}
|
|
59
62
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
+
log.info('║ ║');
|
|
64
|
+
log.info('║ [RELOAD] Auto-pinging every 15 minutes ║');
|
|
65
|
+
log.info('╚════════════════════════════════════════════════════════════════╝');
|
|
63
66
|
}
|
|
64
67
|
}, 3000); // Wait 3 seconds for API to be ready
|
|
65
68
|
|
|
@@ -69,7 +72,7 @@ module.exports = async ({ strapi }) => {
|
|
|
69
72
|
.service('session');
|
|
70
73
|
|
|
71
74
|
// Cleanup inactive sessions on startup
|
|
72
|
-
|
|
75
|
+
log.info('Running initial session cleanup...');
|
|
73
76
|
await sessionService.cleanupInactiveSessions();
|
|
74
77
|
|
|
75
78
|
// Schedule periodic cleanup every 30 minutes
|
|
@@ -81,11 +84,11 @@ module.exports = async ({ strapi }) => {
|
|
|
81
84
|
const service = strapi.plugin('magic-sessionmanager').service('session');
|
|
82
85
|
await service.cleanupInactiveSessions();
|
|
83
86
|
} catch (err) {
|
|
84
|
-
|
|
87
|
+
log.error('Periodic cleanup error:', err);
|
|
85
88
|
}
|
|
86
89
|
}, cleanupInterval);
|
|
87
90
|
|
|
88
|
-
|
|
91
|
+
log.info('[TIME] Periodic cleanup scheduled (every 30 minutes)');
|
|
89
92
|
|
|
90
93
|
// Store interval handle for cleanup on shutdown
|
|
91
94
|
if (!strapi.sessionManagerIntervals) {
|
|
@@ -128,13 +131,13 @@ module.exports = async ({ strapi }) => {
|
|
|
128
131
|
|
|
129
132
|
if (matchingSession) {
|
|
130
133
|
await sessionService.terminateSession({ sessionId: matchingSession.documentId });
|
|
131
|
-
|
|
134
|
+
log.info(`[LOGOUT] Logout via /api/auth/logout - Session ${matchingSession.documentId} terminated`);
|
|
132
135
|
}
|
|
133
136
|
|
|
134
137
|
ctx.status = 200;
|
|
135
138
|
ctx.body = { message: 'Logged out successfully' };
|
|
136
139
|
} catch (err) {
|
|
137
|
-
|
|
140
|
+
log.error('Logout error:', err);
|
|
138
141
|
ctx.status = 200;
|
|
139
142
|
ctx.body = { message: 'Logged out successfully' };
|
|
140
143
|
}
|
|
@@ -144,7 +147,7 @@ module.exports = async ({ strapi }) => {
|
|
|
144
147
|
},
|
|
145
148
|
}]);
|
|
146
149
|
|
|
147
|
-
|
|
150
|
+
log.info('[SUCCESS] /api/auth/logout route registered');
|
|
148
151
|
|
|
149
152
|
// Middleware to intercept logins
|
|
150
153
|
strapi.server.use(async (ctx, next) => {
|
|
@@ -164,7 +167,7 @@ module.exports = async ({ strapi }) => {
|
|
|
164
167
|
const userAgent = ctx.request.headers?.['user-agent'] || ctx.request.header?.['user-agent'] || 'unknown';
|
|
165
168
|
|
|
166
169
|
// Strapi v5: Use documentId for session creation
|
|
167
|
-
|
|
170
|
+
log.info(`[CHECK] Login detected! User: ${user.documentId || user.id} (${user.email || user.username}) from IP: ${ip}`);
|
|
168
171
|
|
|
169
172
|
// Get config
|
|
170
173
|
const config = strapi.config.get('plugin::magic-sessionmanager') || {};
|
|
@@ -216,13 +219,13 @@ module.exports = async ({ strapi }) => {
|
|
|
216
219
|
}
|
|
217
220
|
}
|
|
218
221
|
} catch (geoErr) {
|
|
219
|
-
|
|
222
|
+
log.warn('Geolocation check failed:', geoErr.message);
|
|
220
223
|
}
|
|
221
224
|
}
|
|
222
225
|
|
|
223
226
|
// Block if needed
|
|
224
227
|
if (shouldBlock) {
|
|
225
|
-
|
|
228
|
+
log.warn(`[BLOCKED] Blocking login: ${blockReason}`);
|
|
226
229
|
|
|
227
230
|
// Don't create session, return error
|
|
228
231
|
ctx.status = 403;
|
|
@@ -252,7 +255,7 @@ module.exports = async ({ strapi }) => {
|
|
|
252
255
|
refreshToken: ctx.body.refreshToken, // Store Refresh Token (encrypted) if exists
|
|
253
256
|
});
|
|
254
257
|
|
|
255
|
-
|
|
258
|
+
log.info(`[SUCCESS] Session created for user ${userDocId} (IP: ${ip})`);
|
|
256
259
|
|
|
257
260
|
// Advanced: Send notifications
|
|
258
261
|
if (geoData && (config.enableEmailAlerts || config.enableWebhooks)) {
|
|
@@ -295,17 +298,17 @@ module.exports = async ({ strapi }) => {
|
|
|
295
298
|
}
|
|
296
299
|
}
|
|
297
300
|
} catch (notifErr) {
|
|
298
|
-
|
|
301
|
+
log.warn('Notification failed:', notifErr.message);
|
|
299
302
|
}
|
|
300
303
|
}
|
|
301
304
|
} catch (err) {
|
|
302
|
-
|
|
305
|
+
log.error('[ERROR] Error creating session:', err);
|
|
303
306
|
// Don't throw - login should still succeed even if session creation fails
|
|
304
307
|
}
|
|
305
308
|
}
|
|
306
309
|
});
|
|
307
310
|
|
|
308
|
-
|
|
311
|
+
log.info('[SUCCESS] Login/Logout interceptor middleware mounted');
|
|
309
312
|
|
|
310
313
|
// Middleware to block refresh token requests for terminated sessions
|
|
311
314
|
strapi.server.use(async (ctx, next) => {
|
|
@@ -337,7 +340,7 @@ module.exports = async ({ strapi }) => {
|
|
|
337
340
|
|
|
338
341
|
if (!matchingSession) {
|
|
339
342
|
// No active session with this refresh token - Block!
|
|
340
|
-
|
|
343
|
+
log.warn('[BLOCKED] Blocked refresh token request - no active session');
|
|
341
344
|
ctx.status = 401;
|
|
342
345
|
ctx.body = {
|
|
343
346
|
error: {
|
|
@@ -349,10 +352,10 @@ module.exports = async ({ strapi }) => {
|
|
|
349
352
|
return; // Don't continue
|
|
350
353
|
}
|
|
351
354
|
|
|
352
|
-
|
|
355
|
+
log.info(`[SUCCESS] Refresh token allowed for session ${matchingSession.documentId}`);
|
|
353
356
|
}
|
|
354
357
|
} catch (err) {
|
|
355
|
-
|
|
358
|
+
log.error('Error checking refresh token:', err);
|
|
356
359
|
// On error, allow request to continue (fail-open for availability)
|
|
357
360
|
}
|
|
358
361
|
}
|
|
@@ -398,32 +401,32 @@ module.exports = async ({ strapi }) => {
|
|
|
398
401
|
},
|
|
399
402
|
});
|
|
400
403
|
|
|
401
|
-
|
|
404
|
+
log.info(`[REFRESH] Tokens refreshed for session ${matchingSession.documentId}`);
|
|
402
405
|
}
|
|
403
406
|
}
|
|
404
407
|
} catch (err) {
|
|
405
|
-
|
|
408
|
+
log.error('Error updating refreshed tokens:', err);
|
|
406
409
|
}
|
|
407
410
|
}
|
|
408
411
|
});
|
|
409
412
|
|
|
410
|
-
|
|
413
|
+
log.info('[SUCCESS] Refresh Token interceptor middleware mounted');
|
|
411
414
|
|
|
412
415
|
// Mount lastSeen update middleware
|
|
413
416
|
strapi.server.use(
|
|
414
417
|
require('./middlewares/last-seen')({ strapi, sessionService })
|
|
415
418
|
);
|
|
416
419
|
|
|
417
|
-
|
|
420
|
+
log.info('[SUCCESS] LastSeen middleware mounted');
|
|
418
421
|
|
|
419
422
|
// Auto-enable Content-API permissions for authenticated users
|
|
420
|
-
await ensureContentApiPermissions(strapi);
|
|
423
|
+
await ensureContentApiPermissions(strapi, log);
|
|
421
424
|
|
|
422
|
-
|
|
423
|
-
|
|
425
|
+
log.info('[SUCCESS] Bootstrap complete');
|
|
426
|
+
log.info('[READY] Session Manager ready! Sessions stored in plugin::magic-sessionmanager.session');
|
|
424
427
|
|
|
425
428
|
} catch (err) {
|
|
426
|
-
|
|
429
|
+
log.error('[ERROR] Bootstrap error:', err);
|
|
427
430
|
}
|
|
428
431
|
};
|
|
429
432
|
|
|
@@ -431,8 +434,9 @@ module.exports = async ({ strapi }) => {
|
|
|
431
434
|
* Auto-enable Content-API permissions for authenticated users
|
|
432
435
|
* This ensures plugin endpoints are accessible after installation
|
|
433
436
|
* @param {object} strapi - Strapi instance
|
|
437
|
+
* @param {object} log - Logger instance
|
|
434
438
|
*/
|
|
435
|
-
async function ensureContentApiPermissions(strapi) {
|
|
439
|
+
async function ensureContentApiPermissions(strapi, log) {
|
|
436
440
|
try {
|
|
437
441
|
// Get the authenticated role
|
|
438
442
|
const authenticatedRole = await strapi.query('plugin::users-permissions.role').findOne({
|
|
@@ -440,7 +444,7 @@ async function ensureContentApiPermissions(strapi) {
|
|
|
440
444
|
});
|
|
441
445
|
|
|
442
446
|
if (!authenticatedRole) {
|
|
443
|
-
|
|
447
|
+
log.warn('Authenticated role not found - skipping permission setup');
|
|
444
448
|
return;
|
|
445
449
|
}
|
|
446
450
|
|
|
@@ -465,7 +469,7 @@ async function ensureContentApiPermissions(strapi) {
|
|
|
465
469
|
const missingActions = requiredActions.filter(action => !existingActions.includes(action));
|
|
466
470
|
|
|
467
471
|
if (missingActions.length === 0) {
|
|
468
|
-
|
|
472
|
+
log.debug('Content-API permissions already configured');
|
|
469
473
|
return;
|
|
470
474
|
}
|
|
471
475
|
|
|
@@ -477,12 +481,12 @@ async function ensureContentApiPermissions(strapi) {
|
|
|
477
481
|
role: authenticatedRole.id,
|
|
478
482
|
},
|
|
479
483
|
});
|
|
480
|
-
|
|
484
|
+
log.info(`[PERMISSION] Enabled ${action} for authenticated users`);
|
|
481
485
|
}
|
|
482
486
|
|
|
483
|
-
|
|
487
|
+
log.info('[SUCCESS] Content-API permissions configured for authenticated users');
|
|
484
488
|
} catch (err) {
|
|
485
|
-
|
|
486
|
-
|
|
489
|
+
log.warn('Could not auto-configure permissions:', err.message);
|
|
490
|
+
log.warn('Please manually enable plugin permissions in Settings > Users & Permissions > Roles > Authenticated');
|
|
487
491
|
}
|
|
488
492
|
}
|
package/server/src/destroy.js
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const { createLogger } = require('./utils/logger');
|
|
4
|
+
|
|
3
5
|
module.exports = async ({ strapi }) => {
|
|
6
|
+
const log = createLogger(strapi);
|
|
7
|
+
|
|
4
8
|
// Stop license pinging
|
|
5
9
|
if (strapi.licenseGuard && strapi.licenseGuard.pingInterval) {
|
|
6
10
|
clearInterval(strapi.licenseGuard.pingInterval);
|
|
7
|
-
|
|
11
|
+
log.info('🛑 License pinging stopped');
|
|
8
12
|
}
|
|
9
13
|
|
|
10
14
|
// Stop cleanup interval
|
|
11
15
|
if (strapi.sessionManagerIntervals && strapi.sessionManagerIntervals.cleanup) {
|
|
12
16
|
clearInterval(strapi.sessionManagerIntervals.cleanup);
|
|
13
|
-
|
|
17
|
+
log.info('🛑 Session cleanup interval stopped');
|
|
14
18
|
}
|
|
15
19
|
|
|
16
|
-
|
|
20
|
+
log.info('[SUCCESS] Plugin cleanup completed');
|
|
17
21
|
};
|
|
18
22
|
|
package/server/src/register.js
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const { createLogger } = require('./utils/logger');
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* Register hook
|
|
5
7
|
* Sessions relation is hidden from UI to keep User interface clean
|
|
6
8
|
* Sessions are accessed via the Session Manager plugin UI components
|
|
7
9
|
*/
|
|
8
10
|
module.exports = async ({ strapi }) => {
|
|
9
|
-
|
|
11
|
+
const log = createLogger(strapi);
|
|
12
|
+
|
|
13
|
+
log.info('[START] Plugin registration starting...');
|
|
10
14
|
|
|
11
15
|
try {
|
|
12
16
|
// Get the user content type
|
|
13
17
|
const userCT = strapi.contentType('plugin::users-permissions.user');
|
|
14
18
|
|
|
15
19
|
if (!userCT) {
|
|
16
|
-
|
|
20
|
+
log.error('User content type not found');
|
|
17
21
|
return;
|
|
18
22
|
}
|
|
19
23
|
|
|
@@ -21,12 +25,12 @@ module.exports = async ({ strapi }) => {
|
|
|
21
25
|
// Sessions are managed through SessionInfoPanel sidebar instead
|
|
22
26
|
if (userCT.attributes && userCT.attributes.sessions) {
|
|
23
27
|
delete userCT.attributes.sessions;
|
|
24
|
-
|
|
28
|
+
log.info('[SUCCESS] Removed sessions field from User content type');
|
|
25
29
|
}
|
|
26
30
|
|
|
27
|
-
|
|
31
|
+
log.info('[SUCCESS] Plugin registered successfully');
|
|
28
32
|
|
|
29
33
|
} catch (err) {
|
|
30
|
-
|
|
34
|
+
log.error('[ERROR] Registration error:', err);
|
|
31
35
|
}
|
|
32
36
|
};
|
|
@@ -6,11 +6,15 @@
|
|
|
6
6
|
const crypto = require('crypto');
|
|
7
7
|
const os = require('os');
|
|
8
8
|
const pluginPkg = require('../../../package.json');
|
|
9
|
+
const { createLogger } = require('../utils/logger');
|
|
9
10
|
|
|
10
11
|
// FIXED LICENSE SERVER URL
|
|
11
12
|
const LICENSE_SERVER_URL = 'https://magicapi.fitlex.me';
|
|
12
13
|
|
|
13
|
-
module.exports = ({ strapi }) =>
|
|
14
|
+
module.exports = ({ strapi }) => {
|
|
15
|
+
const log = createLogger(strapi);
|
|
16
|
+
|
|
17
|
+
return {
|
|
14
18
|
/**
|
|
15
19
|
* Get license server URL
|
|
16
20
|
*/
|
|
@@ -101,14 +105,14 @@ module.exports = ({ strapi }) => ({
|
|
|
101
105
|
const data = await response.json();
|
|
102
106
|
|
|
103
107
|
if (data.success) {
|
|
104
|
-
|
|
108
|
+
log.info('[SUCCESS] License created:', data.data.licenseKey);
|
|
105
109
|
return data.data;
|
|
106
110
|
} else {
|
|
107
|
-
|
|
111
|
+
log.error('[ERROR] License creation failed:', data);
|
|
108
112
|
return null;
|
|
109
113
|
}
|
|
110
114
|
} catch (error) {
|
|
111
|
-
|
|
115
|
+
log.error('[ERROR] Error creating license:', error);
|
|
112
116
|
return null;
|
|
113
117
|
}
|
|
114
118
|
},
|
|
@@ -151,7 +155,7 @@ module.exports = ({ strapi }) => ({
|
|
|
151
155
|
const licenseServerUrl = this.getLicenseServerUrl();
|
|
152
156
|
const url = `${licenseServerUrl}/api/licenses/key/${licenseKey}`;
|
|
153
157
|
|
|
154
|
-
|
|
158
|
+
log.debug(`[magic-sessionmanager/license-guard] Fetching license from: ${url}`);
|
|
155
159
|
|
|
156
160
|
const response = await fetch(url, {
|
|
157
161
|
method: 'GET',
|
|
@@ -161,14 +165,14 @@ module.exports = ({ strapi }) => ({
|
|
|
161
165
|
const data = await response.json();
|
|
162
166
|
|
|
163
167
|
if (data.success && data.data) {
|
|
164
|
-
|
|
168
|
+
log.debug(`[magic-sessionmanager/license-guard] License fetched: ${data.data.email}, featurePremium: ${data.data.featurePremium}`);
|
|
165
169
|
return data.data;
|
|
166
170
|
}
|
|
167
171
|
|
|
168
|
-
|
|
172
|
+
log.warn(`[magic-sessionmanager/license-guard] License API returned no data`);
|
|
169
173
|
return null;
|
|
170
174
|
} catch (error) {
|
|
171
|
-
|
|
175
|
+
log.error('[magic-sessionmanager/license-guard] Error fetching license by key:', error);
|
|
172
176
|
return null;
|
|
173
177
|
}
|
|
174
178
|
},
|
|
@@ -207,11 +211,11 @@ module.exports = ({ strapi }) => ({
|
|
|
207
211
|
name: 'magic-sessionmanager'
|
|
208
212
|
});
|
|
209
213
|
await pluginStore.set({ key: 'licenseKey', value: licenseKey });
|
|
210
|
-
|
|
214
|
+
log.info(`[SUCCESS] License key stored: ${licenseKey.substring(0, 8)}...`);
|
|
211
215
|
},
|
|
212
216
|
|
|
213
217
|
startPinging(licenseKey, intervalMinutes = 15) {
|
|
214
|
-
|
|
218
|
+
log.info(`[TIME] Starting license pings every ${intervalMinutes} minutes`);
|
|
215
219
|
|
|
216
220
|
// Immediate ping
|
|
217
221
|
this.pingLicense(licenseKey);
|
|
@@ -220,7 +224,7 @@ module.exports = ({ strapi }) => ({
|
|
|
220
224
|
try {
|
|
221
225
|
await this.pingLicense(licenseKey);
|
|
222
226
|
} catch (error) {
|
|
223
|
-
|
|
227
|
+
log.error('Ping error:', error);
|
|
224
228
|
}
|
|
225
229
|
}, intervalMinutes * 60 * 1000);
|
|
226
230
|
|
|
@@ -233,7 +237,7 @@ module.exports = ({ strapi }) => ({
|
|
|
233
237
|
*/
|
|
234
238
|
async initialize() {
|
|
235
239
|
try {
|
|
236
|
-
|
|
240
|
+
log.info('[SECURE] Initializing License Guard...');
|
|
237
241
|
|
|
238
242
|
// Check if license key exists in plugin store
|
|
239
243
|
const pluginStore = strapi.store({
|
|
@@ -243,7 +247,7 @@ module.exports = ({ strapi }) => ({
|
|
|
243
247
|
const licenseKey = await pluginStore.get({ key: 'licenseKey' });
|
|
244
248
|
|
|
245
249
|
if (!licenseKey) {
|
|
246
|
-
|
|
250
|
+
log.info('[INFO] No license found - Running in demo mode');
|
|
247
251
|
return {
|
|
248
252
|
valid: false,
|
|
249
253
|
demo: true,
|
|
@@ -290,7 +294,7 @@ module.exports = ({ strapi }) => ({
|
|
|
290
294
|
gracePeriod: verification.gracePeriod || false,
|
|
291
295
|
};
|
|
292
296
|
} else {
|
|
293
|
-
|
|
297
|
+
log.error('[ERROR] License validation failed');
|
|
294
298
|
return {
|
|
295
299
|
valid: false,
|
|
296
300
|
demo: true,
|
|
@@ -299,7 +303,7 @@ module.exports = ({ strapi }) => ({
|
|
|
299
303
|
};
|
|
300
304
|
}
|
|
301
305
|
} catch (error) {
|
|
302
|
-
|
|
306
|
+
log.error('[ERROR] Error initializing License Guard:', error);
|
|
303
307
|
return {
|
|
304
308
|
valid: false,
|
|
305
309
|
demo: true,
|
|
@@ -308,4 +312,5 @@ module.exports = ({ strapi }) => ({
|
|
|
308
312
|
};
|
|
309
313
|
}
|
|
310
314
|
},
|
|
311
|
-
}
|
|
315
|
+
};
|
|
316
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const { encryptToken, decryptToken, generateSessionId } = require('../utils/encryption');
|
|
4
|
+
const { createLogger } = require('../utils/logger');
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Session Service
|
|
@@ -20,7 +21,10 @@ const { encryptToken, decryptToken, generateSessionId } = require('../utils/encr
|
|
|
20
21
|
const SESSION_UID = 'plugin::magic-sessionmanager.session';
|
|
21
22
|
const USER_UID = 'plugin::users-permissions.user';
|
|
22
23
|
|
|
23
|
-
module.exports = ({ strapi }) =>
|
|
24
|
+
module.exports = ({ strapi }) => {
|
|
25
|
+
const log = createLogger(strapi);
|
|
26
|
+
|
|
27
|
+
return {
|
|
24
28
|
/**
|
|
25
29
|
* Create a new session record
|
|
26
30
|
* @param {Object} params - { userId, ip, userAgent, token, refreshToken }
|
|
@@ -52,11 +56,11 @@ module.exports = ({ strapi }) => ({
|
|
|
52
56
|
},
|
|
53
57
|
});
|
|
54
58
|
|
|
55
|
-
|
|
59
|
+
log.info(`[SUCCESS] Session ${session.documentId} (${sessionId}) created for user ${userId}`);
|
|
56
60
|
|
|
57
61
|
return session;
|
|
58
62
|
} catch (err) {
|
|
59
|
-
|
|
63
|
+
log.error('Error creating session:', err);
|
|
60
64
|
throw err;
|
|
61
65
|
}
|
|
62
66
|
},
|
|
@@ -81,7 +85,7 @@ module.exports = ({ strapi }) => ({
|
|
|
81
85
|
},
|
|
82
86
|
});
|
|
83
87
|
|
|
84
|
-
|
|
88
|
+
log.info(`Session ${sessionId} terminated`);
|
|
85
89
|
} else if (userId) {
|
|
86
90
|
// Strapi v5: If numeric id provided, look up documentId first
|
|
87
91
|
let userDocumentId = userId;
|
|
@@ -111,10 +115,10 @@ module.exports = ({ strapi }) => ({
|
|
|
111
115
|
});
|
|
112
116
|
}
|
|
113
117
|
|
|
114
|
-
|
|
118
|
+
log.info(`All sessions terminated for user ${userDocumentId}`);
|
|
115
119
|
}
|
|
116
120
|
} catch (err) {
|
|
117
|
-
|
|
121
|
+
log.error('Error terminating session:', err);
|
|
118
122
|
throw err;
|
|
119
123
|
}
|
|
120
124
|
},
|
|
@@ -156,7 +160,7 @@ module.exports = ({ strapi }) => ({
|
|
|
156
160
|
|
|
157
161
|
return enhancedSessions;
|
|
158
162
|
} catch (err) {
|
|
159
|
-
|
|
163
|
+
log.error('Error getting all sessions:', err);
|
|
160
164
|
throw err;
|
|
161
165
|
}
|
|
162
166
|
},
|
|
@@ -199,7 +203,7 @@ module.exports = ({ strapi }) => ({
|
|
|
199
203
|
// Only return truly active sessions
|
|
200
204
|
return enhancedSessions.filter(s => s.isTrulyActive);
|
|
201
205
|
} catch (err) {
|
|
202
|
-
|
|
206
|
+
log.error('Error getting active sessions:', err);
|
|
203
207
|
throw err;
|
|
204
208
|
}
|
|
205
209
|
},
|
|
@@ -253,7 +257,7 @@ module.exports = ({ strapi }) => ({
|
|
|
253
257
|
|
|
254
258
|
return enhancedSessions;
|
|
255
259
|
} catch (err) {
|
|
256
|
-
|
|
260
|
+
log.error('Error getting user sessions:', err);
|
|
257
261
|
throw err;
|
|
258
262
|
}
|
|
259
263
|
},
|
|
@@ -290,7 +294,7 @@ module.exports = ({ strapi }) => ({
|
|
|
290
294
|
}
|
|
291
295
|
}
|
|
292
296
|
} catch (err) {
|
|
293
|
-
|
|
297
|
+
log.debug('Error touching session:', err.message);
|
|
294
298
|
// Don't throw - this is a non-critical operation
|
|
295
299
|
}
|
|
296
300
|
},
|
|
@@ -309,7 +313,7 @@ module.exports = ({ strapi }) => ({
|
|
|
309
313
|
const now = new Date();
|
|
310
314
|
const cutoffTime = new Date(now.getTime() - inactivityTimeout);
|
|
311
315
|
|
|
312
|
-
|
|
316
|
+
log.info(`[CLEANUP] Cleaning up sessions inactive since before ${cutoffTime.toISOString()}`);
|
|
313
317
|
|
|
314
318
|
// Find all active sessions
|
|
315
319
|
const activeSessions = await strapi.documents(SESSION_UID).findMany({
|
|
@@ -331,10 +335,10 @@ module.exports = ({ strapi }) => ({
|
|
|
331
335
|
}
|
|
332
336
|
}
|
|
333
337
|
|
|
334
|
-
|
|
338
|
+
log.info(`[SUCCESS] Cleanup complete: ${deactivatedCount} sessions deactivated`);
|
|
335
339
|
return deactivatedCount;
|
|
336
340
|
} catch (err) {
|
|
337
|
-
|
|
341
|
+
log.error('Error cleaning up inactive sessions:', err);
|
|
338
342
|
throw err;
|
|
339
343
|
}
|
|
340
344
|
},
|
|
@@ -348,10 +352,10 @@ module.exports = ({ strapi }) => ({
|
|
|
348
352
|
async deleteSession(sessionId) {
|
|
349
353
|
try {
|
|
350
354
|
await strapi.documents(SESSION_UID).delete({ documentId: sessionId });
|
|
351
|
-
|
|
355
|
+
log.info(`[DELETE] Session ${sessionId} permanently deleted`);
|
|
352
356
|
return true;
|
|
353
357
|
} catch (err) {
|
|
354
|
-
|
|
358
|
+
log.error('Error deleting session:', err);
|
|
355
359
|
throw err;
|
|
356
360
|
}
|
|
357
361
|
},
|
|
@@ -363,7 +367,7 @@ module.exports = ({ strapi }) => ({
|
|
|
363
367
|
*/
|
|
364
368
|
async deleteInactiveSessions() {
|
|
365
369
|
try {
|
|
366
|
-
|
|
370
|
+
log.info('[DELETE] Deleting all inactive sessions...');
|
|
367
371
|
|
|
368
372
|
// Find all inactive sessions (documentId is always included automatically)
|
|
369
373
|
const inactiveSessions = await strapi.documents(SESSION_UID).findMany({
|
|
@@ -378,11 +382,12 @@ module.exports = ({ strapi }) => ({
|
|
|
378
382
|
deletedCount++;
|
|
379
383
|
}
|
|
380
384
|
|
|
381
|
-
|
|
385
|
+
log.info(`[SUCCESS] Deleted ${deletedCount} inactive sessions`);
|
|
382
386
|
return deletedCount;
|
|
383
387
|
} catch (err) {
|
|
384
|
-
|
|
388
|
+
log.error('Error deleting inactive sessions:', err);
|
|
385
389
|
throw err;
|
|
386
390
|
}
|
|
387
391
|
},
|
|
388
|
-
}
|
|
392
|
+
};
|
|
393
|
+
};
|