strapi-plugin-magic-sessionmanager 4.2.3 → 4.2.5

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.
Files changed (61) hide show
  1. package/dist/server/index.js +1 -1
  2. package/dist/server/index.mjs +1 -1
  3. package/package.json +1 -3
  4. package/admin/jsconfig.json +0 -10
  5. package/admin/src/components/Initializer.jsx +0 -11
  6. package/admin/src/components/LicenseGuard.jsx +0 -591
  7. package/admin/src/components/OnlineUsersWidget.jsx +0 -212
  8. package/admin/src/components/PluginIcon.jsx +0 -8
  9. package/admin/src/components/SessionDetailModal.jsx +0 -449
  10. package/admin/src/components/SessionInfoCard.jsx +0 -151
  11. package/admin/src/components/SessionInfoPanel.jsx +0 -385
  12. package/admin/src/components/index.jsx +0 -5
  13. package/admin/src/hooks/useLicense.js +0 -103
  14. package/admin/src/index.js +0 -149
  15. package/admin/src/pages/ActiveSessions.jsx +0 -12
  16. package/admin/src/pages/Analytics.jsx +0 -735
  17. package/admin/src/pages/App.jsx +0 -12
  18. package/admin/src/pages/HomePage.jsx +0 -1212
  19. package/admin/src/pages/License.jsx +0 -603
  20. package/admin/src/pages/Settings.jsx +0 -1646
  21. package/admin/src/pages/SettingsNew.jsx +0 -1204
  22. package/admin/src/pages/UpgradePage.jsx +0 -448
  23. package/admin/src/pages/index.jsx +0 -3
  24. package/admin/src/pluginId.js +0 -4
  25. package/admin/src/translations/de.json +0 -299
  26. package/admin/src/translations/en.json +0 -299
  27. package/admin/src/translations/es.json +0 -287
  28. package/admin/src/translations/fr.json +0 -287
  29. package/admin/src/translations/pt.json +0 -287
  30. package/admin/src/utils/getTranslation.js +0 -5
  31. package/admin/src/utils/index.js +0 -2
  32. package/admin/src/utils/parseUserAgent.js +0 -79
  33. package/admin/src/utils/theme.js +0 -85
  34. package/server/jsconfig.json +0 -10
  35. package/server/src/bootstrap.js +0 -492
  36. package/server/src/config/index.js +0 -23
  37. package/server/src/content-types/index.js +0 -9
  38. package/server/src/content-types/session/schema.json +0 -84
  39. package/server/src/controllers/controller.js +0 -11
  40. package/server/src/controllers/index.js +0 -11
  41. package/server/src/controllers/license.js +0 -266
  42. package/server/src/controllers/session.js +0 -433
  43. package/server/src/controllers/settings.js +0 -122
  44. package/server/src/destroy.js +0 -22
  45. package/server/src/index.js +0 -23
  46. package/server/src/middlewares/index.js +0 -5
  47. package/server/src/middlewares/last-seen.js +0 -62
  48. package/server/src/policies/index.js +0 -3
  49. package/server/src/register.js +0 -36
  50. package/server/src/routes/admin.js +0 -149
  51. package/server/src/routes/content-api.js +0 -60
  52. package/server/src/routes/index.js +0 -9
  53. package/server/src/services/geolocation.js +0 -182
  54. package/server/src/services/index.js +0 -13
  55. package/server/src/services/license-guard.js +0 -316
  56. package/server/src/services/notifications.js +0 -319
  57. package/server/src/services/service.js +0 -7
  58. package/server/src/services/session.js +0 -393
  59. package/server/src/utils/encryption.js +0 -121
  60. package/server/src/utils/getClientIp.js +0 -118
  61. package/server/src/utils/logger.js +0 -84
@@ -1,316 +0,0 @@
1
- /**
2
- * License Guard Service for Magic Session Manager
3
- * Handles license creation, verification, and ping tracking
4
- */
5
-
6
- const crypto = require('crypto');
7
- const os = require('os');
8
- const pluginPkg = require('../../../package.json');
9
- const { createLogger } = require('../utils/logger');
10
-
11
- // FIXED LICENSE SERVER URL
12
- const LICENSE_SERVER_URL = 'https://magicapi.fitlex.me';
13
-
14
- module.exports = ({ strapi }) => {
15
- const log = createLogger(strapi);
16
-
17
- return {
18
- /**
19
- * Get license server URL
20
- */
21
- getLicenseServerUrl() {
22
- return LICENSE_SERVER_URL;
23
- },
24
-
25
- /**
26
- * Generate device ID
27
- */
28
- generateDeviceId() {
29
- try {
30
- const networkInterfaces = os.networkInterfaces();
31
- const macAddresses = [];
32
-
33
- Object.values(networkInterfaces).forEach(interfaces => {
34
- interfaces?.forEach(iface => {
35
- if (iface.mac && iface.mac !== '00:00:00:00:00:00') {
36
- macAddresses.push(iface.mac);
37
- }
38
- });
39
- });
40
-
41
- const identifier = `${macAddresses.join('-')}-${os.hostname()}`;
42
- return crypto.createHash('sha256').update(identifier).digest('hex').substring(0, 32);
43
- } catch (error) {
44
- return crypto.randomBytes(16).toString('hex');
45
- }
46
- },
47
-
48
- getDeviceName() {
49
- try {
50
- return os.hostname() || 'Unknown Device';
51
- } catch (error) {
52
- return 'Unknown Device';
53
- }
54
- },
55
-
56
- getIpAddress() {
57
- try {
58
- const networkInterfaces = os.networkInterfaces();
59
- for (const name of Object.keys(networkInterfaces)) {
60
- const interfaces = networkInterfaces[name];
61
- if (interfaces) {
62
- for (const iface of interfaces) {
63
- if (iface.family === 'IPv4' && !iface.internal) {
64
- return iface.address;
65
- }
66
- }
67
- }
68
- }
69
- return '127.0.0.1';
70
- } catch (error) {
71
- return '127.0.0.1';
72
- }
73
- },
74
-
75
- getUserAgent() {
76
- const pluginVersion = pluginPkg.version || '1.0.0';
77
- const strapiVersion = strapi.config.get('info.strapi') || '5.0.0';
78
- return `MagicSessionManager/${pluginVersion} Strapi/${strapiVersion} Node/${process.version} ${os.platform()}/${os.release()}`;
79
- },
80
-
81
- async createLicense({ email, firstName, lastName }) {
82
- try {
83
- const deviceId = this.generateDeviceId();
84
- const deviceName = this.getDeviceName();
85
- const ipAddress = this.getIpAddress();
86
- const userAgent = this.getUserAgent();
87
-
88
- const licenseServerUrl = this.getLicenseServerUrl();
89
- const response = await fetch(`${licenseServerUrl}/api/licenses/create`, {
90
- method: 'POST',
91
- headers: { 'Content-Type': 'application/json' },
92
- body: JSON.stringify({
93
- email,
94
- firstName,
95
- lastName,
96
- deviceName,
97
- deviceId,
98
- ipAddress,
99
- userAgent,
100
- pluginName: 'magic-sessionmanager',
101
- productName: 'Magic Session Manager - Premium Session Tracking',
102
- }),
103
- });
104
-
105
- const data = await response.json();
106
-
107
- if (data.success) {
108
- log.info('[SUCCESS] License created:', data.data.licenseKey);
109
- return data.data;
110
- } else {
111
- log.error('[ERROR] License creation failed:', data);
112
- return null;
113
- }
114
- } catch (error) {
115
- log.error('[ERROR] Error creating license:', error);
116
- return null;
117
- }
118
- },
119
-
120
- async verifyLicense(licenseKey, allowGracePeriod = false) {
121
- try {
122
- const controller = new AbortController();
123
- const timeoutId = setTimeout(() => controller.abort(), 5000);
124
-
125
- const licenseServerUrl = this.getLicenseServerUrl();
126
- const response = await fetch(`${licenseServerUrl}/api/licenses/verify`, {
127
- method: 'POST',
128
- headers: { 'Content-Type': 'application/json' },
129
- body: JSON.stringify({
130
- licenseKey,
131
- pluginName: 'magic-sessionmanager',
132
- productName: 'Magic Session Manager - Premium Session Tracking',
133
- }),
134
- signal: controller.signal,
135
- });
136
-
137
- clearTimeout(timeoutId);
138
- const data = await response.json();
139
-
140
- if (data.success && data.data) {
141
- return { valid: true, data: data.data, gracePeriod: false };
142
- } else {
143
- return { valid: false, data: null };
144
- }
145
- } catch (error) {
146
- if (allowGracePeriod) {
147
- return { valid: true, data: null, gracePeriod: true };
148
- }
149
- return { valid: false, data: null };
150
- }
151
- },
152
-
153
- async getLicenseByKey(licenseKey) {
154
- try {
155
- const licenseServerUrl = this.getLicenseServerUrl();
156
- const url = `${licenseServerUrl}/api/licenses/key/${licenseKey}`;
157
-
158
- log.debug(`[magic-sessionmanager/license-guard] Fetching license from: ${url}`);
159
-
160
- const response = await fetch(url, {
161
- method: 'GET',
162
- headers: { 'Content-Type': 'application/json' },
163
- });
164
-
165
- const data = await response.json();
166
-
167
- if (data.success && data.data) {
168
- log.debug(`[magic-sessionmanager/license-guard] License fetched: ${data.data.email}, featurePremium: ${data.data.featurePremium}`);
169
- return data.data;
170
- }
171
-
172
- log.warn(`[magic-sessionmanager/license-guard] License API returned no data`);
173
- return null;
174
- } catch (error) {
175
- log.error('[magic-sessionmanager/license-guard] Error fetching license by key:', error);
176
- return null;
177
- }
178
- },
179
-
180
- async pingLicense(licenseKey) {
181
- try {
182
- const deviceId = this.generateDeviceId();
183
- const deviceName = this.getDeviceName();
184
- const ipAddress = this.getIpAddress();
185
- const userAgent = this.getUserAgent();
186
-
187
- const licenseServerUrl = this.getLicenseServerUrl();
188
- const response = await fetch(`${licenseServerUrl}/api/licenses/ping`, {
189
- method: 'POST',
190
- headers: { 'Content-Type': 'application/json' },
191
- body: JSON.stringify({
192
- licenseKey,
193
- deviceId,
194
- deviceName,
195
- ipAddress,
196
- userAgent,
197
- pluginName: 'magic-sessionmanager',
198
- }),
199
- });
200
-
201
- const data = await response.json();
202
- return data.success ? data.data : null;
203
- } catch (error) {
204
- return null;
205
- }
206
- },
207
-
208
- async storeLicenseKey(licenseKey) {
209
- const pluginStore = strapi.store({
210
- type: 'plugin',
211
- name: 'magic-sessionmanager'
212
- });
213
- await pluginStore.set({ key: 'licenseKey', value: licenseKey });
214
- log.info(`[SUCCESS] License key stored: ${licenseKey.substring(0, 8)}...`);
215
- },
216
-
217
- startPinging(licenseKey, intervalMinutes = 15) {
218
- log.info(`[TIME] Starting license pings every ${intervalMinutes} minutes`);
219
-
220
- // Immediate ping
221
- this.pingLicense(licenseKey);
222
-
223
- const interval = setInterval(async () => {
224
- try {
225
- await this.pingLicense(licenseKey);
226
- } catch (error) {
227
- log.error('Ping error:', error);
228
- }
229
- }, intervalMinutes * 60 * 1000);
230
-
231
- return interval;
232
- },
233
-
234
- /**
235
- * Initialize license guard
236
- * Checks for existing license and starts pinging
237
- */
238
- async initialize() {
239
- try {
240
- log.info('[SECURE] Initializing License Guard...');
241
-
242
- // Check if license key exists in plugin store
243
- const pluginStore = strapi.store({
244
- type: 'plugin',
245
- name: 'magic-sessionmanager'
246
- });
247
- const licenseKey = await pluginStore.get({ key: 'licenseKey' });
248
-
249
- if (!licenseKey) {
250
- log.info('[INFO] No license found - Running in demo mode');
251
- return {
252
- valid: false,
253
- demo: true,
254
- data: null,
255
- };
256
- }
257
-
258
- // Check last validation timestamp for grace period
259
- const lastValidated = await pluginStore.get({ key: 'lastValidated' });
260
- const now = new Date();
261
- const gracePeriodHours = 24;
262
- let withinGracePeriod = false;
263
-
264
- if (lastValidated) {
265
- const lastValidatedDate = new Date(lastValidated);
266
- const hoursSinceValidation = (now.getTime() - lastValidatedDate.getTime()) / (1000 * 60 * 60);
267
- withinGracePeriod = hoursSinceValidation < gracePeriodHours;
268
- }
269
-
270
- // Verify license (allow grace period if we have a last validation)
271
- const verification = await this.verifyLicense(licenseKey, withinGracePeriod);
272
-
273
- if (verification.valid) {
274
- // Update last validated timestamp
275
- await pluginStore.set({
276
- key: 'lastValidated',
277
- value: now.toISOString()
278
- });
279
-
280
- // Start automatic pinging
281
- const pingInterval = this.startPinging(licenseKey, 15);
282
-
283
- // Store interval globally so we can clean it up
284
- strapi.licenseGuard = {
285
- licenseKey,
286
- pingInterval,
287
- data: verification.data,
288
- };
289
-
290
- return {
291
- valid: true,
292
- demo: false,
293
- data: verification.data,
294
- gracePeriod: verification.gracePeriod || false,
295
- };
296
- } else {
297
- log.error('[ERROR] License validation failed');
298
- return {
299
- valid: false,
300
- demo: true,
301
- error: 'Invalid or expired license',
302
- data: null,
303
- };
304
- }
305
- } catch (error) {
306
- log.error('[ERROR] Error initializing License Guard:', error);
307
- return {
308
- valid: false,
309
- demo: true,
310
- error: error.message,
311
- data: null,
312
- };
313
- }
314
- },
315
- };
316
- };
@@ -1,319 +0,0 @@
1
- /**
2
- * Notifications Service (ADVANCED Feature)
3
- * Send email alerts for session events
4
- */
5
-
6
- module.exports = ({ strapi }) => ({
7
- /**
8
- * Get email templates from database settings
9
- * Falls back to default hardcoded templates if not found
10
- */
11
- async getEmailTemplates() {
12
- try {
13
- // Try to load templates from database
14
- const pluginStore = strapi.store({
15
- type: 'plugin',
16
- name: 'magic-sessionmanager',
17
- });
18
-
19
- const settings = await pluginStore.get({ key: 'settings' });
20
-
21
- if (settings?.emailTemplates && Object.keys(settings.emailTemplates).length > 0) {
22
- // Check if templates have content
23
- const hasContent = Object.values(settings.emailTemplates).some(
24
- template => template.html || template.text
25
- );
26
-
27
- if (hasContent) {
28
- strapi.log.debug('[magic-sessionmanager/notifications] Using templates from database');
29
- return settings.emailTemplates;
30
- }
31
- }
32
- } catch (err) {
33
- strapi.log.warn('[magic-sessionmanager/notifications] Could not load templates from DB, using defaults:', err.message);
34
- }
35
-
36
- // Default fallback templates
37
- strapi.log.debug('[magic-sessionmanager/notifications] Using default fallback templates');
38
- return {
39
- suspiciousLogin: {
40
- subject: '[ALERT] Suspicious Login Alert - Session Manager',
41
- html: `
42
- <html>
43
- <body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333;">
44
- <div style="max-width: 600px; margin: 0 auto; padding: 20px; background-color: #f9fafb; border-radius: 10px;">
45
- <h2 style="color: #dc2626;">[ALERT] Suspicious Login Detected</h2>
46
- <p>A potentially suspicious login was detected for your account.</p>
47
-
48
- <div style="background: white; padding: 15px; border-radius: 8px; margin: 20px 0;">
49
- <h3 style="margin-top: 0;">Account Information:</h3>
50
- <ul>
51
- <li><strong>Email:</strong> {{user.email}}</li>
52
- <li><strong>Username:</strong> {{user.username}}</li>
53
- </ul>
54
-
55
- <h3>Login Details:</h3>
56
- <ul>
57
- <li><strong>Time:</strong> {{session.loginTime}}</li>
58
- <li><strong>IP Address:</strong> {{session.ipAddress}}</li>
59
- <li><strong>Location:</strong> {{geo.city}}, {{geo.country}}</li>
60
- <li><strong>Timezone:</strong> {{geo.timezone}}</li>
61
- <li><strong>Device:</strong> {{session.userAgent}}</li>
62
- </ul>
63
-
64
- <h3 style="color: #dc2626;">Security Alert:</h3>
65
- <ul>
66
- <li>VPN Detected: {{reason.isVpn}}</li>
67
- <li>Proxy Detected: {{reason.isProxy}}</li>
68
- <li>Threat Detected: {{reason.isThreat}}</li>
69
- <li>Security Score: {{reason.securityScore}}/100</li>
70
- </ul>
71
- </div>
72
-
73
- <p>If this was you, you can safely ignore this email. If you don't recognize this activity, please secure your account immediately.</p>
74
-
75
- <hr style="border: none; border-top: 1px solid #e5e7eb; margin: 20px 0;"/>
76
- <p style="color: #666; font-size: 12px;">This is an automated security notification from Magic Session Manager.</p>
77
- </div>
78
- </body>
79
- </html>`,
80
- text: `[ALERT] Suspicious Login Detected\n\nA potentially suspicious login was detected for your account.\n\nAccount: {{user.email}}\nUsername: {{user.username}}\n\nLogin Details:\n- Time: {{session.loginTime}}\n- IP: {{session.ipAddress}}\n- Location: {{geo.city}}, {{geo.country}}\n\nSecurity: VPN={{reason.isVpn}}, Proxy={{reason.isProxy}}, Threat={{reason.isThreat}}, Score={{reason.securityScore}}/100`,
81
- },
82
- newLocation: {
83
- subject: '[LOCATION] New Location Login Detected',
84
- 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>`,
85
- text: `[LOCATION] New Location Login\n\nAccount: {{user.email}}\nTime: {{session.loginTime}}\nLocation: {{geo.city}}, {{geo.country}}\nIP: {{session.ipAddress}}`,
86
- },
87
- vpnProxy: {
88
- subject: '[WARNING] VPN/Proxy Login Detected',
89
- 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>`,
90
- text: `[WARNING] VPN/Proxy Detected\n\nAccount: {{user.email}}\nTime: {{session.loginTime}}\nIP: {{session.ipAddress}}\nVPN: {{reason.isVpn}}, Proxy: {{reason.isProxy}}`,
91
- },
92
- };
93
- },
94
-
95
- /**
96
- * Replace template variables with actual values
97
- */
98
- replaceVariables(template, data) {
99
- let result = template;
100
-
101
- // User variables
102
- result = result.replace(/\{\{user\.email\}\}/g, data.user?.email || 'N/A');
103
- result = result.replace(/\{\{user\.username\}\}/g, data.user?.username || 'N/A');
104
-
105
- // Session variables
106
- result = result.replace(/\{\{session\.loginTime\}\}/g,
107
- data.session?.loginTime ? new Date(data.session.loginTime).toLocaleString() : 'N/A');
108
- result = result.replace(/\{\{session\.ipAddress\}\}/g, data.session?.ipAddress || 'N/A');
109
- result = result.replace(/\{\{session\.userAgent\}\}/g, data.session?.userAgent || 'N/A');
110
-
111
- // Geo variables
112
- result = result.replace(/\{\{geo\.city\}\}/g, data.geoData?.city || 'Unknown');
113
- result = result.replace(/\{\{geo\.country\}\}/g, data.geoData?.country || 'Unknown');
114
- result = result.replace(/\{\{geo\.timezone\}\}/g, data.geoData?.timezone || 'Unknown');
115
-
116
- // Reason variables
117
- result = result.replace(/\{\{reason\.isVpn\}\}/g, data.reason?.isVpn ? 'Yes' : 'No');
118
- result = result.replace(/\{\{reason\.isProxy\}\}/g, data.reason?.isProxy ? 'Yes' : 'No');
119
- result = result.replace(/\{\{reason\.isThreat\}\}/g, data.reason?.isThreat ? 'Yes' : 'No');
120
- result = result.replace(/\{\{reason\.securityScore\}\}/g, data.reason?.securityScore || '0');
121
-
122
- return result;
123
- },
124
-
125
- /**
126
- * Send suspicious login alert
127
- * @param {Object} params - { user, session, reason, geoData }
128
- */
129
- async sendSuspiciousLoginAlert({ user, session, reason, geoData }) {
130
- try {
131
- // Get templates from database (or defaults)
132
- const templates = await this.getEmailTemplates();
133
- const template = templates.suspiciousLogin;
134
-
135
- // Prepare data for variable replacement
136
- const data = { user, session, reason, geoData };
137
-
138
- // Replace variables in template
139
- const htmlContent = this.replaceVariables(template.html, data);
140
- const textContent = this.replaceVariables(template.text, data);
141
-
142
- await strapi.plugins['email'].services.email.send({
143
- to: user.email,
144
- subject: template.subject,
145
- html: htmlContent,
146
- text: textContent,
147
- });
148
-
149
- strapi.log.info(`[magic-sessionmanager/notifications] Suspicious login alert sent to ${user.email}`);
150
- return true;
151
- } catch (err) {
152
- strapi.log.error('[magic-sessionmanager/notifications] Error sending email:', err);
153
- return false;
154
- }
155
- },
156
-
157
- /**
158
- * Send new location login alert
159
- * @param {Object} params - { user, session, geoData }
160
- */
161
- async sendNewLocationAlert({ user, session, geoData }) {
162
- try {
163
- // Get templates from database (or defaults)
164
- const templates = await this.getEmailTemplates();
165
- const template = templates.newLocation;
166
-
167
- // Prepare data for variable replacement
168
- const data = { user, session, geoData, reason: {} };
169
-
170
- // Replace variables in template
171
- const htmlContent = this.replaceVariables(template.html, data);
172
- const textContent = this.replaceVariables(template.text, data);
173
-
174
- await strapi.plugins['email'].services.email.send({
175
- to: user.email,
176
- subject: template.subject,
177
- html: htmlContent,
178
- text: textContent,
179
- });
180
-
181
- strapi.log.info(`[magic-sessionmanager/notifications] New location alert sent to ${user.email}`);
182
- return true;
183
- } catch (err) {
184
- strapi.log.error('[magic-sessionmanager/notifications] Error sending new location email:', err);
185
- return false;
186
- }
187
- },
188
-
189
- /**
190
- * Send VPN/Proxy login alert
191
- * @param {Object} params - { user, session, reason, geoData }
192
- */
193
- async sendVpnProxyAlert({ user, session, reason, geoData }) {
194
- try {
195
- // Get templates from database (or defaults)
196
- const templates = await this.getEmailTemplates();
197
- const template = templates.vpnProxy;
198
-
199
- // Prepare data for variable replacement
200
- const data = { user, session, reason, geoData };
201
-
202
- // Replace variables in template
203
- const htmlContent = this.replaceVariables(template.html, data);
204
- const textContent = this.replaceVariables(template.text, data);
205
-
206
- await strapi.plugins['email'].services.email.send({
207
- to: user.email,
208
- subject: template.subject,
209
- html: htmlContent,
210
- text: textContent,
211
- });
212
-
213
- strapi.log.info(`[magic-sessionmanager/notifications] VPN/Proxy alert sent to ${user.email}`);
214
- return true;
215
- } catch (err) {
216
- strapi.log.error('[magic-sessionmanager/notifications] Error sending VPN/Proxy email:', err);
217
- return false;
218
- }
219
- },
220
-
221
- /**
222
- * Send webhook notification
223
- * @param {Object} params - { event, data, webhookUrl }
224
- */
225
- async sendWebhook({ event, data, webhookUrl }) {
226
- try {
227
- const payload = {
228
- event,
229
- timestamp: new Date().toISOString(),
230
- data,
231
- source: 'magic-sessionmanager',
232
- };
233
-
234
- const response = await fetch(webhookUrl, {
235
- method: 'POST',
236
- headers: {
237
- 'Content-Type': 'application/json',
238
- 'User-Agent': 'Strapi-Magic-SessionManager-Webhook/1.0',
239
- },
240
- body: JSON.stringify(payload),
241
- });
242
-
243
- if (response.ok) {
244
- strapi.log.info(`[magic-sessionmanager/notifications] Webhook sent: ${event}`);
245
- return true;
246
- } else {
247
- strapi.log.warn(`[magic-sessionmanager/notifications] Webhook failed: ${response.status}`);
248
- return false;
249
- }
250
- } catch (err) {
251
- strapi.log.error('[magic-sessionmanager/notifications] Webhook error:', err);
252
- return false;
253
- }
254
- },
255
-
256
- /**
257
- * Format webhook for Discord
258
- * @param {Object} params - { event, session, user, geoData }
259
- */
260
- formatDiscordWebhook({ event, session, user, geoData }) {
261
- const embed = {
262
- title: this.getEventTitle(event),
263
- color: this.getEventColor(event),
264
- fields: [
265
- { name: 'User', value: `${user.email}\n${user.username || 'N/A'}`, inline: true },
266
- { name: 'IP', value: session.ipAddress, inline: true },
267
- { name: 'Time', value: new Date(session.loginTime).toLocaleString(), inline: false },
268
- ],
269
- timestamp: new Date().toISOString(),
270
- footer: { text: 'Magic Session Manager' },
271
- };
272
-
273
- if (geoData) {
274
- embed.fields.push({
275
- name: '[LOCATION] Location',
276
- value: `${geoData.country_flag} ${geoData.city}, ${geoData.country}`,
277
- inline: true,
278
- });
279
-
280
- if (geoData.isVpn || geoData.isProxy || geoData.isThreat) {
281
- const warnings = [];
282
- if (geoData.isVpn) warnings.push('VPN');
283
- if (geoData.isProxy) warnings.push('Proxy');
284
- if (geoData.isThreat) warnings.push('Threat');
285
-
286
- embed.fields.push({
287
- name: '[WARNING] Security',
288
- value: `${warnings.join(', ')} detected\nScore: ${geoData.securityScore}/100`,
289
- inline: true,
290
- });
291
- }
292
- }
293
-
294
- return { embeds: [embed] };
295
- },
296
-
297
- getEventTitle(event) {
298
- const titles = {
299
- 'login.suspicious': '[ALERT] Suspicious Login',
300
- 'login.new_location': '[LOCATION] New Location Login',
301
- 'login.vpn': '[WARNING] VPN Login Detected',
302
- 'login.threat': '[THREAT] Threat IP Login',
303
- 'session.terminated': '[INFO] Session Terminated',
304
- };
305
- return titles[event] || '[STATS] Session Event';
306
- },
307
-
308
- getEventColor(event) {
309
- const colors = {
310
- 'login.suspicious': 0xFF0000, // Red
311
- 'login.new_location': 0xFFA500, // Orange
312
- 'login.vpn': 0xFF6B6B, // Light Red
313
- 'login.threat': 0x8B0000, // Dark Red
314
- 'session.terminated': 0x808080, // Gray
315
- };
316
- return colors[event] || 0x5865F2; // Discord Blue
317
- },
318
- });
319
-
@@ -1,7 +0,0 @@
1
- const service = ({ strapi }) => ({
2
- getWelcomeMessage() {
3
- return 'Welcome to Strapi [START]';
4
- },
5
- });
6
-
7
- export default service;