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.
Files changed (34) hide show
  1. package/README.md +90 -0
  2. package/admin/src/hooks/useLicense.js +1 -1
  3. package/admin/src/index.js +2 -2
  4. package/admin/src/pages/Settings.jsx +0 -1
  5. package/admin/src/utils/parseUserAgent.js +1 -1
  6. package/dist/_chunks/{Analytics-Bi-vcT63.js → Analytics-ioaeEh-E.js} +2 -2
  7. package/dist/_chunks/{Analytics-BM9i88xu.mjs → Analytics-mYu_uGwU.mjs} +2 -2
  8. package/dist/_chunks/{App-DcnJOCL9.mjs → App-BXpIS12l.mjs} +2 -2
  9. package/dist/_chunks/{App-BbiNy_cT.js → App-DdnUYWbC.js} +2 -2
  10. package/dist/_chunks/{License-DsxP-MAL.mjs → License-C03C2j9P.mjs} +1 -1
  11. package/dist/_chunks/{License-kYo8j2yl.js → License-DZYrOgcx.js} +1 -1
  12. package/dist/_chunks/{Settings-C3sW9eBD.mjs → Settings-0ocB3qHk.mjs} +2 -2
  13. package/dist/_chunks/{Settings-jW0TOE_d.js → Settings-C6_CqpCC.js} +2 -2
  14. package/dist/_chunks/{index-DG9XeVSg.mjs → index-DBRS3kt5.mjs} +7 -7
  15. package/dist/_chunks/{index-Dr2HT-Dd.js → index-DC8Y0qxx.js} +7 -7
  16. package/dist/_chunks/{useLicense-DOkJX-tk.mjs → useLicense-DSLL9n3Y.mjs} +2 -2
  17. package/dist/_chunks/{useLicense-BL_3bX9O.js → useLicense-qgGfMvse.js} +2 -2
  18. package/dist/admin/index.js +1 -1
  19. package/dist/admin/index.mjs +1 -1
  20. package/dist/server/index.js +117 -95
  21. package/dist/server/index.mjs +117 -95
  22. package/package.json +1 -1
  23. package/server/src/bootstrap.js +32 -26
  24. package/server/src/controllers/license.js +4 -4
  25. package/server/src/controllers/session.js +10 -6
  26. package/server/src/destroy.js +1 -1
  27. package/server/src/middlewares/last-seen.js +8 -3
  28. package/server/src/register.js +4 -4
  29. package/server/src/services/geolocation.js +4 -2
  30. package/server/src/services/license-guard.js +13 -10
  31. package/server/src/services/notifications.js +10 -10
  32. package/server/src/services/service.js +1 -1
  33. package/server/src/services/session.js +41 -31
  34. package/server/src/utils/encryption.js +1 -1
package/README.md CHANGED
@@ -300,6 +300,96 @@ Add to `config/plugins.ts`:
300
300
 
301
301
  ---
302
302
 
303
+ ## 📧 Email Alerts Setup (Premium)
304
+
305
+ The Session Manager uses **Strapi's Email Plugin** to send notifications. You need to configure an email provider first.
306
+
307
+ ### Step 1: Install Email Provider
308
+
309
+ Choose one of these providers:
310
+
311
+ **Option A: Nodemailer (Recommended)**
312
+ ```bash
313
+ npm install @strapi/provider-email-nodemailer
314
+ ```
315
+
316
+ **Option B: SendGrid**
317
+ ```bash
318
+ npm install @strapi/provider-email-sendgrid
319
+ ```
320
+
321
+ **Option C: Mailgun**
322
+ ```bash
323
+ npm install @strapi/provider-email-mailgun
324
+ ```
325
+
326
+ ### Step 2: Configure Email Plugin
327
+
328
+ Add to `config/plugins.ts`:
329
+
330
+ ```typescript
331
+ export default () => ({
332
+ // Email configuration
333
+ email: {
334
+ config: {
335
+ provider: 'nodemailer',
336
+ providerOptions: {
337
+ host: process.env.SMTP_HOST || 'smtp.gmail.com',
338
+ port: process.env.SMTP_PORT || 587,
339
+ auth: {
340
+ user: process.env.SMTP_USER,
341
+ pass: process.env.SMTP_PASSWORD,
342
+ },
343
+ },
344
+ settings: {
345
+ defaultFrom: process.env.SMTP_DEFAULT_FROM || 'noreply@yourapp.com',
346
+ defaultReplyTo: process.env.SMTP_DEFAULT_REPLY_TO || 'support@yourapp.com',
347
+ },
348
+ },
349
+ },
350
+
351
+ // Session Manager configuration
352
+ 'magic-sessionmanager': {
353
+ enabled: true,
354
+ },
355
+ });
356
+ ```
357
+
358
+ ### Step 3: Add Environment Variables
359
+
360
+ Add to your `.env` file:
361
+
362
+ ```env
363
+ SMTP_HOST=smtp.gmail.com
364
+ SMTP_PORT=587
365
+ SMTP_USER=your-email@gmail.com
366
+ SMTP_PASSWORD=your-app-password
367
+ SMTP_DEFAULT_FROM=noreply@yourapp.com
368
+ SMTP_DEFAULT_REPLY_TO=support@yourapp.com
369
+ ```
370
+
371
+ **For Gmail:**
372
+ - Use an [App Password](https://support.google.com/accounts/answer/185833), not your regular password!
373
+
374
+ ### Step 4: Enable in Admin Panel
375
+
376
+ 1. Go to **Sessions → Settings**
377
+ 2. Scroll to **"Email Notifications"**
378
+ 3. Toggle **"Enable Email Alerts"** to ON
379
+ 4. Customize email templates (optional)
380
+ 5. Click **Save**
381
+
382
+ ### Step 5: Test It
383
+
384
+ Trigger a suspicious login (e.g., use a VPN) and check if the email arrives!
385
+
386
+ **Troubleshooting:**
387
+ - Check Strapi logs for email errors
388
+ - Verify SMTP credentials are correct
389
+ - Test SMTP connection with a tool like [smtp-tester](https://www.npmjs.com/package/smtp-tester)
390
+
391
+ ---
392
+
303
393
  ## 📋 Simple API Guide
304
394
 
305
395
  ### Get Sessions
@@ -60,7 +60,7 @@ export const useLicense = () => {
60
60
  if ((newIsPremium !== isPremium || !silent) && !silent) {
61
61
  console.log(`[magic-sessionmanager/useLicense] Premium Status: ${newIsPremium} (valid: ${isValid}, featurePremium: ${hasPremiumFeature})`);
62
62
  if (!newIsPremium && isValid) {
63
- console.warn('[magic-sessionmanager/useLicense] ⚠️ License is valid but Premium feature is not enabled!');
63
+ console.warn('[magic-sessionmanager/useLicense] [WARN] License is valid but Premium feature is not enabled!');
64
64
  }
65
65
  }
66
66
 
@@ -86,7 +86,7 @@ export default {
86
86
  id: 'online-users-widget',
87
87
  pluginId: pluginId,
88
88
  });
89
- console.log(`[${pluginId}] Online Users Widget registered`);
89
+ console.log(`[${pluginId}] [SUCCESS] Online Users Widget registered`);
90
90
  }
91
91
  },
92
92
 
@@ -99,7 +99,7 @@ export default {
99
99
  if (contentManagerPlugin && contentManagerPlugin.apis) {
100
100
  console.log(`[${pluginId}] Injecting SessionInfoPanel into edit view sidebar...`);
101
101
  contentManagerPlugin.apis.addEditViewSidePanel([SessionInfoPanel]);
102
- console.log(`[${pluginId}] SessionInfoPanel injected successfully`);
102
+ console.log(`[${pluginId}] [SUCCESS] SessionInfoPanel injected successfully`);
103
103
  } else {
104
104
  console.warn(`[${pluginId}] Content Manager plugin or APIs not available`);
105
105
  }
@@ -10,7 +10,6 @@ import {
10
10
  Checkbox,
11
11
  Alert,
12
12
  TextInput,
13
- Textarea,
14
13
  Tabs,
15
14
  Divider,
16
15
  Badge,
@@ -41,7 +41,7 @@ export const parseUserAgent = (userAgent) => {
41
41
  browser = 'Opera';
42
42
  } else if (ua.includes('curl/')) {
43
43
  browser = 'cURL';
44
- deviceIcon = '⚙️';
44
+ deviceIcon = 'gear';
45
45
  device = 'API Client';
46
46
  } else if (ua.includes('postman')) {
47
47
  browser = 'Postman';
@@ -6,8 +6,8 @@ const admin = require("@strapi/strapi/admin");
6
6
  const styled = require("styled-components");
7
7
  const designSystem = require("@strapi/design-system");
8
8
  const icons = require("@strapi/icons");
9
- const index = require("./index-Dr2HT-Dd.js");
10
- const useLicense = require("./useLicense-BL_3bX9O.js");
9
+ const index = require("./index-DC8Y0qxx.js");
10
+ const useLicense = require("./useLicense-qgGfMvse.js");
11
11
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
12
12
  const styled__default = /* @__PURE__ */ _interopDefault(styled);
13
13
  const theme = {
@@ -4,8 +4,8 @@ import { useFetchClient } from "@strapi/strapi/admin";
4
4
  import styled, { css, keyframes } from "styled-components";
5
5
  import { Loader, Typography, Box, Flex, Badge } from "@strapi/design-system";
6
6
  import { ChartBubble, Crown, User, Clock, Monitor } from "@strapi/icons";
7
- import { a as pluginId } from "./index-DG9XeVSg.mjs";
8
- import { u as useLicense } from "./useLicense-DOkJX-tk.mjs";
7
+ import { a as pluginId } from "./index-DBRS3kt5.mjs";
8
+ import { u as useLicense } from "./useLicense-DSLL9n3Y.mjs";
9
9
  const theme = {
10
10
  colors: {
11
11
  primary: { 100: "#E0F2FE", 500: "#0EA5E9", 600: "#0284C7" },
@@ -4,8 +4,8 @@ import { useFetchClient, useNotification } from "@strapi/strapi/admin";
4
4
  import styled, { css, keyframes } from "styled-components";
5
5
  import { Modal, Flex, Box, Typography, Badge, Divider, Button, Loader, SingleSelect, SingleSelectOption, Thead, Tr, Th, Tbody, Td, Table, TextInput } from "@strapi/design-system";
6
6
  import { Check, Information, Monitor, Server, Clock, Cross, Earth, Shield, Crown, Phone, Download, User, Eye, Trash, Search, Key } from "@strapi/icons";
7
- import { p as parseUserAgent, a as pluginId } from "./index-DG9XeVSg.mjs";
8
- import { u as useLicense } from "./useLicense-DOkJX-tk.mjs";
7
+ import { p as parseUserAgent, a as pluginId } from "./index-DBRS3kt5.mjs";
8
+ import { u as useLicense } from "./useLicense-DSLL9n3Y.mjs";
9
9
  import { useNavigate } from "react-router-dom";
10
10
  const TwoColumnGrid = styled.div`
11
11
  display: grid;
@@ -6,8 +6,8 @@ const admin = require("@strapi/strapi/admin");
6
6
  const styled = require("styled-components");
7
7
  const designSystem = require("@strapi/design-system");
8
8
  const icons = require("@strapi/icons");
9
- const index = require("./index-Dr2HT-Dd.js");
10
- const useLicense = require("./useLicense-BL_3bX9O.js");
9
+ const index = require("./index-DC8Y0qxx.js");
10
+ const useLicense = require("./useLicense-qgGfMvse.js");
11
11
  const reactRouterDom = require("react-router-dom");
12
12
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
13
13
  const styled__default = /* @__PURE__ */ _interopDefault(styled);
@@ -4,7 +4,7 @@ import { Loader, Box, Alert, Flex, Typography, Button, Badge, Accordion } from "
4
4
  import { useFetchClient, useNotification } from "@strapi/strapi/admin";
5
5
  import { ArrowClockwise, Duplicate, Download, User, Shield, Sparkle, ChartBubble } from "@strapi/icons";
6
6
  import styled, { css, keyframes } from "styled-components";
7
- import { a as pluginId } from "./index-DG9XeVSg.mjs";
7
+ import { a as pluginId } from "./index-DBRS3kt5.mjs";
8
8
  const theme = {
9
9
  colors: {
10
10
  neutral: { 200: "#E5E7EB" }
@@ -6,7 +6,7 @@ const designSystem = require("@strapi/design-system");
6
6
  const admin = require("@strapi/strapi/admin");
7
7
  const icons = require("@strapi/icons");
8
8
  const styled = require("styled-components");
9
- const index = require("./index-Dr2HT-Dd.js");
9
+ const index = require("./index-DC8Y0qxx.js");
10
10
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
11
11
  const styled__default = /* @__PURE__ */ _interopDefault(styled);
12
12
  const theme = {
@@ -4,8 +4,8 @@ import { Flex, Loader, Typography, Button, Box, Badge, Accordion, Grid, SingleSe
4
4
  import { useFetchClient, useNotification } from "@strapi/strapi/admin";
5
5
  import { Check, Information, Cog, Trash, Shield, Code, Duplicate, Mail } from "@strapi/icons";
6
6
  import styled, { css, keyframes } from "styled-components";
7
- import { a as pluginId } from "./index-DG9XeVSg.mjs";
8
- import { u as useLicense } from "./useLicense-DOkJX-tk.mjs";
7
+ import { a as pluginId } from "./index-DBRS3kt5.mjs";
8
+ import { u as useLicense } from "./useLicense-DSLL9n3Y.mjs";
9
9
  const theme = {
10
10
  colors: {
11
11
  primary: { 600: "#0284C7", 700: "#075985", 100: "#E0F2FE", 50: "#F0F9FF" },
@@ -6,8 +6,8 @@ const designSystem = require("@strapi/design-system");
6
6
  const admin = require("@strapi/strapi/admin");
7
7
  const icons = require("@strapi/icons");
8
8
  const styled = require("styled-components");
9
- const index = require("./index-Dr2HT-Dd.js");
10
- const useLicense = require("./useLicense-BL_3bX9O.js");
9
+ const index = require("./index-DC8Y0qxx.js");
10
+ const useLicense = require("./useLicense-qgGfMvse.js");
11
11
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
12
12
  const styled__default = /* @__PURE__ */ _interopDefault(styled);
13
13
  const theme = {
@@ -50,7 +50,7 @@ const parseUserAgent = (userAgent) => {
50
50
  browser = "Opera";
51
51
  } else if (ua.includes("curl/")) {
52
52
  browser = "cURL";
53
- deviceIcon = "⚙️";
53
+ deviceIcon = "gear";
54
54
  device = "API Client";
55
55
  } else if (ua.includes("postman")) {
56
56
  browser = "Postman";
@@ -403,7 +403,7 @@ const index = {
403
403
  id: `${pluginId}.plugin.name`,
404
404
  defaultMessage: pluginPkg.strapi.displayName
405
405
  },
406
- Component: () => import("./App-DcnJOCL9.mjs")
406
+ Component: () => import("./App-BXpIS12l.mjs")
407
407
  });
408
408
  app.createSettingSection(
409
409
  {
@@ -419,7 +419,7 @@ const index = {
419
419
  },
420
420
  id: "general",
421
421
  to: `/settings/${pluginId}/general`,
422
- Component: () => import("./Settings-C3sW9eBD.mjs")
422
+ Component: () => import("./Settings-0ocB3qHk.mjs")
423
423
  },
424
424
  {
425
425
  intlLabel: {
@@ -428,7 +428,7 @@ const index = {
428
428
  },
429
429
  id: "analytics",
430
430
  to: `/settings/${pluginId}/analytics`,
431
- Component: () => import("./Analytics-BM9i88xu.mjs")
431
+ Component: () => import("./Analytics-mYu_uGwU.mjs")
432
432
  },
433
433
  {
434
434
  intlLabel: {
@@ -437,7 +437,7 @@ const index = {
437
437
  },
438
438
  id: "license",
439
439
  to: `/settings/${pluginId}/license`,
440
- Component: () => import("./License-DsxP-MAL.mjs")
440
+ Component: () => import("./License-C03C2j9P.mjs")
441
441
  }
442
442
  ]
443
443
  );
@@ -461,7 +461,7 @@ const index = {
461
461
  id: "online-users-widget",
462
462
  pluginId
463
463
  });
464
- console.log(`[${pluginId}] Online Users Widget registered`);
464
+ console.log(`[${pluginId}] [SUCCESS] Online Users Widget registered`);
465
465
  }
466
466
  },
467
467
  bootstrap(app) {
@@ -471,7 +471,7 @@ const index = {
471
471
  if (contentManagerPlugin && contentManagerPlugin.apis) {
472
472
  console.log(`[${pluginId}] Injecting SessionInfoPanel into edit view sidebar...`);
473
473
  contentManagerPlugin.apis.addEditViewSidePanel([SessionInfoPanel]);
474
- console.log(`[${pluginId}] SessionInfoPanel injected successfully`);
474
+ console.log(`[${pluginId}] [SUCCESS] SessionInfoPanel injected successfully`);
475
475
  } else {
476
476
  console.warn(`[${pluginId}] Content Manager plugin or APIs not available`);
477
477
  }
@@ -51,7 +51,7 @@ const parseUserAgent = (userAgent) => {
51
51
  browser = "Opera";
52
52
  } else if (ua.includes("curl/")) {
53
53
  browser = "cURL";
54
- deviceIcon = "⚙️";
54
+ deviceIcon = "gear";
55
55
  device = "API Client";
56
56
  } else if (ua.includes("postman")) {
57
57
  browser = "Postman";
@@ -404,7 +404,7 @@ const index = {
404
404
  id: `${pluginId}.plugin.name`,
405
405
  defaultMessage: pluginPkg.strapi.displayName
406
406
  },
407
- Component: () => Promise.resolve().then(() => require("./App-BbiNy_cT.js"))
407
+ Component: () => Promise.resolve().then(() => require("./App-DdnUYWbC.js"))
408
408
  });
409
409
  app.createSettingSection(
410
410
  {
@@ -420,7 +420,7 @@ const index = {
420
420
  },
421
421
  id: "general",
422
422
  to: `/settings/${pluginId}/general`,
423
- Component: () => Promise.resolve().then(() => require("./Settings-jW0TOE_d.js"))
423
+ Component: () => Promise.resolve().then(() => require("./Settings-C6_CqpCC.js"))
424
424
  },
425
425
  {
426
426
  intlLabel: {
@@ -429,7 +429,7 @@ const index = {
429
429
  },
430
430
  id: "analytics",
431
431
  to: `/settings/${pluginId}/analytics`,
432
- Component: () => Promise.resolve().then(() => require("./Analytics-Bi-vcT63.js"))
432
+ Component: () => Promise.resolve().then(() => require("./Analytics-ioaeEh-E.js"))
433
433
  },
434
434
  {
435
435
  intlLabel: {
@@ -438,7 +438,7 @@ const index = {
438
438
  },
439
439
  id: "license",
440
440
  to: `/settings/${pluginId}/license`,
441
- Component: () => Promise.resolve().then(() => require("./License-kYo8j2yl.js"))
441
+ Component: () => Promise.resolve().then(() => require("./License-DZYrOgcx.js"))
442
442
  }
443
443
  ]
444
444
  );
@@ -462,7 +462,7 @@ const index = {
462
462
  id: "online-users-widget",
463
463
  pluginId
464
464
  });
465
- console.log(`[${pluginId}] Online Users Widget registered`);
465
+ console.log(`[${pluginId}] [SUCCESS] Online Users Widget registered`);
466
466
  }
467
467
  },
468
468
  bootstrap(app) {
@@ -472,7 +472,7 @@ const index = {
472
472
  if (contentManagerPlugin && contentManagerPlugin.apis) {
473
473
  console.log(`[${pluginId}] Injecting SessionInfoPanel into edit view sidebar...`);
474
474
  contentManagerPlugin.apis.addEditViewSidePanel([SessionInfoPanel]);
475
- console.log(`[${pluginId}] SessionInfoPanel injected successfully`);
475
+ console.log(`[${pluginId}] [SUCCESS] SessionInfoPanel injected successfully`);
476
476
  } else {
477
477
  console.warn(`[${pluginId}] Content Manager plugin or APIs not available`);
478
478
  }
@@ -1,6 +1,6 @@
1
1
  import { useState, useEffect } from "react";
2
2
  import { useFetchClient } from "@strapi/strapi/admin";
3
- import { a as pluginId } from "./index-DG9XeVSg.mjs";
3
+ import { a as pluginId } from "./index-DBRS3kt5.mjs";
4
4
  const useLicense = () => {
5
5
  const { get } = useFetchClient();
6
6
  const [isPremium, setIsPremium] = useState(false);
@@ -43,7 +43,7 @@ const useLicense = () => {
43
43
  if ((newIsPremium !== isPremium || !silent) && !silent) {
44
44
  console.log(`[magic-sessionmanager/useLicense] Premium Status: ${newIsPremium} (valid: ${isValid}, featurePremium: ${hasPremiumFeature})`);
45
45
  if (!newIsPremium && isValid) {
46
- console.warn("[magic-sessionmanager/useLicense] ⚠️ License is valid but Premium feature is not enabled!");
46
+ console.warn("[magic-sessionmanager/useLicense] [WARN] License is valid but Premium feature is not enabled!");
47
47
  }
48
48
  }
49
49
  setIsPremium(newIsPremium);
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  const react = require("react");
3
3
  const admin = require("@strapi/strapi/admin");
4
- const index = require("./index-Dr2HT-Dd.js");
4
+ const index = require("./index-DC8Y0qxx.js");
5
5
  const useLicense = () => {
6
6
  const { get } = admin.useFetchClient();
7
7
  const [isPremium, setIsPremium] = react.useState(false);
@@ -44,7 +44,7 @@ const useLicense = () => {
44
44
  if ((newIsPremium !== isPremium || !silent) && !silent) {
45
45
  console.log(`[magic-sessionmanager/useLicense] Premium Status: ${newIsPremium} (valid: ${isValid}, featurePremium: ${hasPremiumFeature})`);
46
46
  if (!newIsPremium && isValid) {
47
- console.warn("[magic-sessionmanager/useLicense] ⚠️ License is valid but Premium feature is not enabled!");
47
+ console.warn("[magic-sessionmanager/useLicense] [WARN] License is valid but Premium feature is not enabled!");
48
48
  }
49
49
  }
50
50
  setIsPremium(newIsPremium);
@@ -1,3 +1,3 @@
1
1
  "use strict";
2
- const index = require("../_chunks/index-Dr2HT-Dd.js");
2
+ const index = require("../_chunks/index-DC8Y0qxx.js");
3
3
  module.exports = index.index;
@@ -1,4 +1,4 @@
1
- import { i } from "../_chunks/index-DG9XeVSg.mjs";
1
+ import { i } from "../_chunks/index-DBRS3kt5.mjs";
2
2
  export {
3
3
  i as default
4
4
  };