strapi-plugin-magic-link-v5 5.5.7 → 5.5.9

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/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## [5.5.9](https://github.com/Schero94/strapi-plugin-magic-link-v5/compare/v5.5.8...v5.5.9) (2026-05-03)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * trigger release for plugin always-on refactor ([2ed54eb](https://github.com/Schero94/strapi-plugin-magic-link-v5/commit/2ed54eb228bccc84f1cd013741f98de69edf2268))
7
+
8
+ ## [5.5.8](https://github.com/Schero94/strapi-plugin-magic-link-v5/compare/v5.5.7...v5.5.8) (2026-05-03)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **settings:** declare missing emailTemplates state — closes [#17](https://github.com/Schero94/strapi-plugin-magic-link-v5/issues/17) ([6ee2740](https://github.com/Schero94/strapi-plugin-magic-link-v5/commit/6ee2740c62e7772e5cfa8904416ab64be84bab5e))
14
+
1
15
  ## [5.5.7](https://github.com/Schero94/strapi-plugin-magic-link-v5/compare/v5.5.6...v5.5.7) (2026-04-26)
2
16
 
3
17
 
package/README.md CHANGED
@@ -10,12 +10,12 @@ Secure, modern, and user-friendly authentication using email-based magic links,
10
10
 
11
11
  ## Why Magic Link?
12
12
 
13
- - **Zero Setup Time** - Install, activate license (free), and start using
14
- - **Production Ready** - Battle-tested with rate limiting, IP bans, and session management
15
- - **Multi-Factor Authentication** - Email OTP + TOTP Authenticator support
16
- - **WhatsApp Integration** - Send magic links via WhatsApp (FREE!)
17
- - **Beautiful UI** - Modern, responsive admin interface with German translations
18
- - **Enterprise Security** - License-based feature unlocking with Free, Premium & Advanced tiers
13
+ - **Zero Setup Time** - Install, configure SMTP, and start using.
14
+ - **Production Ready** - Battle-tested with rate limiting, IP bans, and session management.
15
+ - **Multi-Factor Authentication** - Email OTP + TOTP Authenticator support, included.
16
+ - **WhatsApp Integration** - Send magic links via WhatsApp messenger.
17
+ - **Beautiful UI** - Modern, responsive admin interface localized in 5 languages.
18
+ - **Free & Open** - MIT license, no paywall, every feature available out of the box.
19
19
 
20
20
  ## 📚 Quick Links
21
21
 
@@ -45,23 +45,16 @@ Users can switch languages in **Settings → Magic Link → Interface Language**
45
45
 
46
46
  ## 📜 License
47
47
 
48
- This plugin is licensed under the **MIT License** - free for everyone to use!
48
+ MIT-licensed. Free for personal and commercial use. See [LICENSE](./LICENSE).
49
49
 
50
- ### What you CAN do:
51
- - ✅ Use the plugin freely (personal & commercial)
52
- - ✅ View and study the source code
53
- - ✅ Report issues and contribute improvements
54
- - ✅ Deploy in production without fees
55
- - ✅ Integrate in your commercial projects
50
+ ### Optional license-key activation
56
51
 
57
- ### What you CANNOT do:
58
- - ❌ Remove or bypass the license validation system
59
- - ❌ Modify `license-guard.js` or license-related endpoints
60
- - ❌ Disable license activation requirements
52
+ The admin panel offers a "License" tab where you can register an optional
53
+ license key. This is purely cosmetic — it does **not** unlock any
54
+ feature, and the plugin is fully usable without it. Registering a key
55
+ just lets the project track installs and helps us prioritise issues.
61
56
 
62
- **Important:** The license validation system must remain intact and functional. This ensures quality, support, and continued development. Users must activate the plugin (free) through the admin interface.
63
-
64
- 📄 See [LICENSE](./LICENSE) for full terms
57
+ You can ignore the License tab entirely; nothing will be gated.
65
58
 
66
59
  ---
67
60
 
@@ -69,37 +62,25 @@ This plugin is licensed under the **MIT License** - free for everyone to use!
69
62
 
70
63
  ### Authentication Modes
71
64
 
72
- Choose the security level that fits your needs:
65
+ All modes are available in every install — pick whichever fits your security profile:
73
66
 
74
- | Mode | Description | License |
75
- |------|-------------|---------|
76
- | **Magic Link Only** | One-click email login - fast & user-friendly | Free |
77
- | **Magic Link via WhatsApp** | Send magic links via WhatsApp messenger | Free |
78
- | **Magic Link + Email OTP** | 6-digit code after magic link click | Premium |
79
- | **Magic Link + TOTP (MFA)** | Authenticator app (Google Auth, Authy) | Advanced |
80
- | **TOTP-Only Login** | Direct login with email + TOTP code | Advanced |
67
+ | Mode | Description |
68
+ |------|-------------|
69
+ | **Magic Link Only** | One-click email login — fast & user-friendly |
70
+ | **Magic Link via WhatsApp** | Send magic links via the WhatsApp messenger |
71
+ | **Magic Link + Email OTP** | 6-digit code sent after the magic link click |
72
+ | **Magic Link + TOTP (MFA)** | Authenticator app (Google Authenticator, Authy, …) |
73
+ | **TOTP-Only Login** | Direct login with email + TOTP code |
81
74
 
82
75
  ### 🛡️ Security Features
83
76
 
84
- - **Rate Limiting** - 5 requests per 15 minutes (configurable)
85
- - **IP Banning** - Block suspicious addresses with one click
86
- - **Session Management** - Monitor and revoke active JWT sessions
87
- - **Login Tracking** - Store IP addresses and user agents
88
- - **Token Expiration** - Configurable validity periods
89
- - **Brute Force Protection** - Login attempt limiting
90
- - **Security Score** - Real-time configuration assessment
91
-
92
- ### � License Tiers
93
-
94
- | Feature | Free | Premium | Advanced |
95
- |---------|------|---------|----------|
96
- | Magic Link Login | ✅ | ✅ | ✅ |
97
- | Token Management | ✅ | ✅ | ✅ |
98
- | IP Banning | ✅ | ✅ | ✅ |
99
- | Rate Limiting | ✅ | ✅ | ✅ |
100
- | Email OTP | ❌ | ✅ | ✅ |
101
- | TOTP Authenticator | ❌ | ❌ | ✅ |
102
- | TOTP-Only Login | ❌ | ❌ | ✅ |
77
+ - **Rate Limiting** — 5 requests per 15 minutes (configurable)
78
+ - **IP Banning** — Block suspicious addresses with one click
79
+ - **Session Management** — Monitor and revoke active JWT sessions
80
+ - **Login Tracking** — Store IP addresses and user agents
81
+ - **Token Expiration** — Configurable validity periods
82
+ - **Brute Force Protection** — Login attempt limiting
83
+ - **Security Score** — Real-time configuration assessment
103
84
 
104
85
  ### 🎨 Admin Interface
105
86
 
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ const jsxRuntime = require("react/jsx-runtime");
3
+ const react = require("react");
4
+ const reactIntl = require("react-intl");
5
+ const en = require("./en-DnvSpXvu.js");
6
+ const de = require("./de-BSOk5suQ.js");
7
+ const fr = require("./fr-BKo8t7Fx.js");
8
+ const es = require("./es-B-tnwByt.js");
9
+ const pt = require("./pt-CjEkXBAz.js");
10
+ const LanguageContext = react.createContext();
11
+ const usePluginLanguage = () => {
12
+ const context = react.useContext(LanguageContext);
13
+ if (!context) {
14
+ throw new Error("usePluginLanguage must be used within LanguageProvider");
15
+ }
16
+ return context;
17
+ };
18
+ const translations = {
19
+ en: en.default,
20
+ de: de.default,
21
+ fr: fr.default,
22
+ es: es.default,
23
+ pt: pt.default
24
+ };
25
+ const LanguageProvider = ({ children }) => {
26
+ const [currentLanguage, setCurrentLanguage] = react.useState(() => {
27
+ return localStorage.getItem("magic-link-language") || "en";
28
+ });
29
+ const changeLanguage = (newLang) => {
30
+ setCurrentLanguage(newLang);
31
+ localStorage.setItem("magic-link-language", newLang);
32
+ };
33
+ const value = {
34
+ language: currentLanguage,
35
+ changeLanguage,
36
+ t: (key) => {
37
+ const messages = translations[currentLanguage] || translations.en;
38
+ return messages[key] || key;
39
+ }
40
+ };
41
+ return /* @__PURE__ */ jsxRuntime.jsx(LanguageContext.Provider, { value, children: /* @__PURE__ */ jsxRuntime.jsx(
42
+ reactIntl.IntlProvider,
43
+ {
44
+ locale: currentLanguage,
45
+ messages: translations[currentLanguage],
46
+ defaultLocale: "en",
47
+ children
48
+ }
49
+ ) });
50
+ };
51
+ const LicenseGuard = ({ children }) => /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
52
+ exports.LanguageProvider = LanguageProvider;
53
+ exports.LicenseGuard = LicenseGuard;
54
+ exports.usePluginLanguage = usePluginLanguage;
@@ -0,0 +1,55 @@
1
+ import { jsx, Fragment } from "react/jsx-runtime";
2
+ import { useState, createContext, useContext } from "react";
3
+ import { IntlProvider } from "react-intl";
4
+ import enTranslations from "./en-gXXgGDV1.mjs";
5
+ import deTranslations from "./de-CwhYs3O3.mjs";
6
+ import frTranslations from "./fr-BQn1OHOR.mjs";
7
+ import esTranslations from "./es-DG5gW3RZ.mjs";
8
+ import ptTranslations from "./pt-trziAOzT.mjs";
9
+ const LanguageContext = createContext();
10
+ const usePluginLanguage = () => {
11
+ const context = useContext(LanguageContext);
12
+ if (!context) {
13
+ throw new Error("usePluginLanguage must be used within LanguageProvider");
14
+ }
15
+ return context;
16
+ };
17
+ const translations = {
18
+ en: enTranslations,
19
+ de: deTranslations,
20
+ fr: frTranslations,
21
+ es: esTranslations,
22
+ pt: ptTranslations
23
+ };
24
+ const LanguageProvider = ({ children }) => {
25
+ const [currentLanguage, setCurrentLanguage] = useState(() => {
26
+ return localStorage.getItem("magic-link-language") || "en";
27
+ });
28
+ const changeLanguage = (newLang) => {
29
+ setCurrentLanguage(newLang);
30
+ localStorage.setItem("magic-link-language", newLang);
31
+ };
32
+ const value = {
33
+ language: currentLanguage,
34
+ changeLanguage,
35
+ t: (key) => {
36
+ const messages = translations[currentLanguage] || translations.en;
37
+ return messages[key] || key;
38
+ }
39
+ };
40
+ return /* @__PURE__ */ jsx(LanguageContext.Provider, { value, children: /* @__PURE__ */ jsx(
41
+ IntlProvider,
42
+ {
43
+ locale: currentLanguage,
44
+ messages: translations[currentLanguage],
45
+ defaultLocale: "en",
46
+ children
47
+ }
48
+ ) });
49
+ };
50
+ const LicenseGuard = ({ children }) => /* @__PURE__ */ jsx(Fragment, { children });
51
+ export {
52
+ LicenseGuard as L,
53
+ LanguageProvider as a,
54
+ usePluginLanguage as u
55
+ };
@@ -176,8 +176,8 @@ Generated: ${(/* @__PURE__ */ new Date()).toLocaleString()}
176
176
  if (error) {
177
177
  return /* @__PURE__ */ jsxRuntime.jsx(Container, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 8, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Alert, { variant: "danger", title: "Error", children: error }) }) });
178
178
  }
179
- const isValid = licenseData?.valid;
180
- const isDemo = licenseData?.demo;
179
+ const isValid = licenseData?.valid !== false;
180
+ const hasKey = !!licenseData?.hasKey;
181
181
  const data = licenseData?.data || {};
182
182
  return /* @__PURE__ */ jsxRuntime.jsxs(Container, { children: [
183
183
  /* @__PURE__ */ jsxRuntime.jsx(StickySaveBar, { paddingTop: 5, paddingBottom: 5, paddingLeft: 6, paddingRight: 6, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", children: [
@@ -202,7 +202,7 @@ Generated: ${(/* @__PURE__ */ new Date()).toLocaleString()}
202
202
  )
203
203
  ] }) }),
204
204
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { paddingTop: 6, paddingLeft: 6, paddingRight: 6, paddingBottom: 10, children: [
205
- isDemo ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Alert, { variant: "warning", title: "Demo Mode", children: "You're using the demo version. Upgrade to unlock all features." }) : isValid ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Alert, { variant: "success", title: "License Active", children: "Your license is active and all features are unlocked." }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Alert, { variant: "danger", title: "License Issue", children: "There's an issue with your license." }),
205
+ hasKey && isValid ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Alert, { variant: "success", title: "License Active", children: "License key registered. Thanks for supporting the plugin!" }) : hasKey && !isValid ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Alert, { variant: "warning", title: "License Verification", children: "We couldn't reach the license server right now. The plugin keeps working — try Refresh Status later." }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Alert, { variant: "default", title: "No license key registered", children: 'All Magic Link features are available without activation. If you want to register a license key, use the form below or run "Auto-Activate" to generate one for your admin email.' }),
206
206
  data.licenseKey && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 6, children: /* @__PURE__ */ jsxRuntime.jsx(LicenseKeyBanner, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "flex-start", children: [
207
207
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { style: { flex: 1 }, children: [
208
208
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", style: { color: "rgba(255,255,255,0.8)", marginBottom: "12px", textTransform: "uppercase", fontSize: "11px", letterSpacing: "0.5px", display: "block" }, children: "License Key" }),
@@ -287,45 +287,16 @@ Generated: ${(/* @__PURE__ */ new Date()).toLocaleString()}
287
287
  ] })
288
288
  ] }) }) })
289
289
  ] }),
290
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Accordion.Item, { value: "features", children: [
291
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Accordion.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Accordion.Trigger, { icon: icons.Sparkle, children: "Features & Capabilities" }) }),
292
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Accordion.Content, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 6, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 8, wrap: "wrap", children: [
293
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { style: { flex: "1", minWidth: "180px" }, children: [
294
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", textTransform: "uppercase", style: { marginBottom: "8px", display: "block" }, children: "Premium Features" }),
295
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "semiBold", children: data.features?.premium ? "✓ Enabled" : "✗ Disabled" })
296
- ] }),
297
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { style: { flex: "1", minWidth: "180px" }, children: [
298
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", textTransform: "uppercase", style: { marginBottom: "8px", display: "block" }, children: "Advanced Features" }),
299
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "semiBold", children: data.features?.advanced ? "✓ Enabled" : "✗ Disabled" })
300
- ] }),
301
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { style: { flex: "1", minWidth: "180px" }, children: [
302
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", textTransform: "uppercase", style: { marginBottom: "8px", display: "block" }, children: "Enterprise Features" }),
303
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "semiBold", children: data.features?.enterprise ? "✓ Enabled" : "✗ Disabled" })
304
- ] })
305
- ] }) }) })
306
- ] }),
307
290
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Accordion.Item, { value: "status", children: [
308
291
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Accordion.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Accordion.Trigger, { icon: icons.ChartBubble, children: "System Status" }) }),
309
292
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Accordion.Content, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 6, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 8, wrap: "wrap", children: [
310
293
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { style: { flex: "1", minWidth: "150px" }, children: [
311
294
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", textTransform: "uppercase", style: { marginBottom: "8px", display: "block" }, children: "License Status" }),
312
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "semiBold", children: data.isActive ? "Active" : "Inactive" })
313
- ] }),
314
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { style: { flex: "1", minWidth: "150px" }, children: [
315
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", textTransform: "uppercase", style: { marginBottom: "8px", display: "block" }, children: "Connection" }),
316
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "semiBold", children: data.isOnline ? "Online" : "Offline" })
317
- ] }),
318
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { style: { flex: "1", minWidth: "150px" }, children: [
319
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", textTransform: "uppercase", style: { marginBottom: "8px", display: "block" }, children: "Last Sync" }),
320
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "semiBold", children: data.lastPingAt ? new Date(data.lastPingAt).toLocaleTimeString() : "Never" })
295
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "semiBold", children: hasKey ? data.isActive ? "Active" : "Inactive" : "No key registered" })
321
296
  ] }),
322
297
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { style: { flex: "1", minWidth: "150px" }, children: [
323
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", textTransform: "uppercase", style: { marginBottom: "8px", display: "block" }, children: "Device Limit" }),
324
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "omega", fontWeight: "semiBold", children: [
325
- data.currentDevices || 0,
326
- " / ",
327
- data.maxDevices || 1
328
- ] })
298
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", textTransform: "uppercase", style: { marginBottom: "8px", display: "block" }, children: "Plugin Mode" }),
299
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "semiBold", children: "Fully unlocked" })
329
300
  ] })
330
301
  ] }) }) })
331
302
  ] })
@@ -5,7 +5,7 @@ import { useIntl } from "react-intl";
5
5
  import { Flex, Loader, Box, Typography, Button, TextInput, Badge } from "@strapi/design-system";
6
6
  import { Phone, Check, Message, ArrowClockwise } from "@strapi/icons";
7
7
  import { useNotification, useFetchClient } from "@strapi/strapi/admin";
8
- import { g as getTrad } from "./index-34ICAF9_.mjs";
8
+ import { g as getTrad } from "./index-DQUYFsLT.mjs";
9
9
  const theme = {
10
10
  colors: {
11
11
  primary: { 700: "#075985", 100: "#E0F2FE", 50: "#F0F9FF" },
@@ -7,9 +7,9 @@ const styled = require("styled-components");
7
7
  const reactIntl = require("react-intl");
8
8
  const designSystem = require("@strapi/design-system");
9
9
  const icons = require("@strapi/icons");
10
- const index = require("./index-BFzW7Xex.js");
10
+ const index = require("./index-Bj3H_Z4B.js");
11
11
  const admin = require("@strapi/strapi/admin");
12
- const LicenseGuard = require("./LicenseGuard-DqyOwTlf.js");
12
+ const LicenseGuard = require("./LicenseGuard-CiyjFnrw.js");
13
13
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
14
14
  const styled__default = /* @__PURE__ */ _interopDefault(styled);
15
15
  const CreateTokenModal = ({ isOpen, onClose, onSubmit, formData, setFormData }) => {
@@ -61,7 +61,7 @@ const index = {
61
61
  },
62
62
  Component: () => Promise.resolve().then(() => require(
63
63
  /* webpackChunkName: "magic-link-tokens" */
64
- "./index-CddEy_As.js"
64
+ "./index-BWuj-5WE.js"
65
65
  )),
66
66
  permissions: pluginPermissions.access
67
67
  });
@@ -83,7 +83,7 @@ const index = {
83
83
  to: `${PLUGIN_ID}/config`,
84
84
  Component: () => Promise.resolve().then(() => require(
85
85
  /* webpackChunkName: "magic-link-settings" */
86
- "./index-CuXnqVl4.js"
86
+ "./index-DJqXiiP1.js"
87
87
  )),
88
88
  permissions: pluginPermissions.readSettings
89
89
  },
@@ -96,20 +96,7 @@ const index = {
96
96
  to: `${PLUGIN_ID}/license`,
97
97
  Component: () => Promise.resolve().then(() => require(
98
98
  /* webpackChunkName: "magic-link-license" */
99
- "./index-PgHpSdc8.js"
100
- )),
101
- permissions: pluginPermissions.access
102
- },
103
- {
104
- intlLabel: {
105
- id: getTrad("Form.title.Upgrade"),
106
- defaultMessage: "Upgrade"
107
- },
108
- id: "magic-link-upgrade",
109
- to: `${PLUGIN_ID}/upgrade`,
110
- Component: () => Promise.resolve().then(() => require(
111
- /* webpackChunkName: "magic-link-upgrade" */
112
- "./LicensePage-2M-vOJX8.js"
99
+ "./index-01GHNxSr.js"
113
100
  )),
114
101
  permissions: pluginPermissions.access
115
102
  },
@@ -122,7 +109,7 @@ const index = {
122
109
  to: `${PLUGIN_ID}/whatsapp`,
123
110
  Component: () => Promise.resolve().then(() => require(
124
111
  /* webpackChunkName: "magic-link-whatsapp" */
125
- "./index-M5s7QN5m.js"
112
+ "./index-CC4Eu9Dm.js"
126
113
  )),
127
114
  permissions: pluginPermissions.access
128
115
  }
@@ -7,7 +7,7 @@ const reactIntl = require("react-intl");
7
7
  const designSystem = require("@strapi/design-system");
8
8
  const icons = require("@strapi/icons");
9
9
  const admin = require("@strapi/strapi/admin");
10
- const index = require("./index-BFzW7Xex.js");
10
+ const index = require("./index-Bj3H_Z4B.js");
11
11
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
12
12
  const styled__default = /* @__PURE__ */ _interopDefault(styled);
13
13
  const theme = {
@@ -5,8 +5,8 @@ import { useIntl } from "react-intl";
5
5
  import { Box, Typography, Flex, Button, Accordion, SingleSelect, SingleSelectOption, Grid, Switch, NumberInput, TextInput, Divider, Textarea, Badge } from "@strapi/design-system";
6
6
  import { Check, Cog, Lightning, Shield, Mail, CheckCircle, Code, Link, Lock, Key } from "@strapi/icons";
7
7
  import { useNotification, useFetchClient } from "@strapi/strapi/admin";
8
- import { g as getTrad } from "./index-34ICAF9_.mjs";
9
- import { u as usePluginLanguage, L as LicenseGuard, a as LanguageProvider } from "./LicenseGuard-5sMwgS6j.mjs";
8
+ import { g as getTrad } from "./index-DQUYFsLT.mjs";
9
+ import { u as usePluginLanguage, L as LicenseGuard, a as LanguageProvider } from "./LicenseGuard-DJ5fq2UZ.mjs";
10
10
  const EMAIL_TEMPLATES = {
11
11
  modern: {
12
12
  name: "Modern Gradient",
@@ -737,28 +737,18 @@ _Falls du diesen Link nicht angefordert hast, ignoriere diese Nachricht._`,
737
737
  try {
738
738
  const licenseRes = await get("/magic-link/license/status");
739
739
  if (licenseRes?.data) {
740
- let tier = "free";
741
- const licenseData = licenseRes.data.data || licenseRes.data;
742
- if (licenseData.features) {
743
- if (licenseData.features.enterprise) {
744
- tier = "enterprise";
745
- } else if (licenseData.features.advanced) {
746
- tier = "advanced";
747
- } else if (licenseData.features.premium) {
748
- tier = "premium";
749
- }
750
- }
740
+ const licenseData = licenseRes.data.data || {};
751
741
  const enrichedLicenseInfo = {
752
742
  ...licenseData,
753
- tier,
743
+ tier: "enterprise",
754
744
  valid: licenseRes.data.valid !== false,
755
- demo: licenseRes.data.demo === true
745
+ hasKey: licenseRes.data.hasKey === true
756
746
  };
757
747
  setLicenseInfo(enrichedLicenseInfo);
758
- console.log("💎 License Info:", enrichedLicenseInfo);
759
748
  }
760
749
  } catch (error) {
761
750
  console.error("Error loading license info:", error);
751
+ setLicenseInfo({ tier: "enterprise", valid: true, hasKey: false });
762
752
  }
763
753
  } catch (error) {
764
754
  if (error.name !== "AbortError") {
@@ -817,27 +807,6 @@ _Falls du diesen Link nicht angefordert hast, ignoriere diese Nachricht._`,
817
807
  setSelectedTemplateKey(templateEntry.value);
818
808
  }
819
809
  }, [settings.message_html, settings.message_text, selectedTemplateKey]);
820
- useEffect(() => {
821
- if (!licenseInfo) return;
822
- const currentTier = licenseInfo.tier || "free";
823
- let needsUpdate = false;
824
- let newSettings = { ...settings };
825
- if (settings.otp_enabled && !["premium", "advanced", "enterprise"].includes(currentTier)) {
826
- newSettings.otp_enabled = false;
827
- needsUpdate = true;
828
- }
829
- if (settings.mfa_require_totp && !["advanced", "enterprise"].includes(currentTier)) {
830
- newSettings.mfa_require_totp = false;
831
- needsUpdate = true;
832
- }
833
- if (settings.totp_as_primary_auth && !["advanced", "enterprise"].includes(currentTier)) {
834
- newSettings.totp_as_primary_auth = false;
835
- needsUpdate = true;
836
- }
837
- if (needsUpdate) {
838
- setSettings(newSettings);
839
- }
840
- }, [licenseInfo, settings]);
841
810
  const handleSave = async (e) => {
842
811
  e.preventDefault();
843
812
  setIsSaving(true);
@@ -869,31 +838,6 @@ _Falls du diesen Link nicht angefordert hast, ignoriere diese Nachricht._`,
869
838
  const updateSetting = (key, value) => {
870
839
  setSettings({ ...settings, [key]: value });
871
840
  };
872
- const checkLicenseAndSetMode = (mode) => {
873
- const currentTier = licenseInfo?.tier || "free";
874
- if (mode === "otp-email" && !["premium", "advanced", "enterprise"].includes(currentTier)) {
875
- toggleNotification({
876
- type: "warning",
877
- message: "💎 Premium License Required: Email OTP requires at least Premium license. Please upgrade your license."
878
- });
879
- return false;
880
- }
881
- if (mode === "mfa-totp" && !["advanced", "enterprise"].includes(currentTier)) {
882
- toggleNotification({
883
- type: "warning",
884
- message: "⚡ Advanced License Required: MFA with TOTP requires at least Advanced license. Please upgrade your license."
885
- });
886
- return false;
887
- }
888
- if (mode === "totp-primary" && !["advanced", "enterprise"].includes(currentTier)) {
889
- toggleNotification({
890
- type: "warning",
891
- message: "⚡ Advanced License Required: TOTP-only login requires at least Advanced license. Please upgrade your license."
892
- });
893
- return false;
894
- }
895
- return true;
896
- };
897
841
  const handleLanguageChange = (newLang) => {
898
842
  changeLanguage(newLang);
899
843
  };
@@ -1047,19 +991,6 @@ _Falls du diesen Link nicht angefordert hast, ignoriere diese Nachricht._`,
1047
991
  /* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", style: { marginBottom: "8px", display: "block", textAlign: "center", color: "var(--colors-neutral700)" }, children: formatMessage({ id: getTrad("settings.features.title") }) }),
1048
992
  /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { marginBottom: "20px", display: "block", textAlign: "center", fontSize: "12px" }, children: formatMessage({ id: getTrad("settings.features.subtitle") }) }),
1049
993
  /* @__PURE__ */ jsxs(Grid.Root, { gap: 4, children: [
1050
- /* @__PURE__ */ jsx(Grid.Item, { col: 4, s: 6, xs: 12, children: /* @__PURE__ */ jsx(ToggleCard, { $active: settings.enabled, $statusLabel: settings.enabled ? statusActive : statusInactive, children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 3, children: [
1051
- /* @__PURE__ */ jsx(Flex, { justifyContent: "center", alignItems: "center", style: { marginBottom: "8px" }, children: /* @__PURE__ */ jsx(
1052
- Switch,
1053
- {
1054
- checked: settings.enabled,
1055
- onCheckedChange: (checked) => updateSetting("enabled", checked)
1056
- }
1057
- ) }),
1058
- /* @__PURE__ */ jsxs(Box, { children: [
1059
- /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", style: { fontSize: "14px", marginBottom: "6px", display: "block", textAlign: "center" }, children: formatMessage({ id: getTrad("settings.feature.enabled.title") }) }),
1060
- /* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral600", style: { fontSize: "12px", lineHeight: "1.4", textAlign: "center" }, children: formatMessage({ id: getTrad("settings.feature.enabled.description") }) })
1061
- ] })
1062
- ] }) }) }),
1063
994
  /* @__PURE__ */ jsx(Grid.Item, { col: 4, s: 6, xs: 12, children: /* @__PURE__ */ jsx(ToggleCard, { $active: settings.createUserIfNotExists, $statusLabel: settings.createUserIfNotExists ? statusActive : statusInactive, children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 3, children: [
1064
995
  /* @__PURE__ */ jsx(Flex, { justifyContent: "center", alignItems: "center", style: { marginBottom: "8px" }, children: /* @__PURE__ */ jsx(
1065
996
  Switch,
@@ -2233,21 +2164,9 @@ ${language === "de" ? "Der Link läuft in 1 Stunde ab." : "The link expires in 1
2233
2164
  border: "2px solid rgba(128, 128, 128, 0.2)"
2234
2165
  },
2235
2166
  children: [
2236
- /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", style: { marginBottom: "12px" }, children: [
2237
- /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 2, children: [
2238
- /* @__PURE__ */ jsx(Shield, { width: "20px", height: "20px", style: { color: licenseInfo?.tier === "advanced" || licenseInfo?.tier === "enterprise" ? "#16A34A" : "#9CA3AF" } }),
2239
- /* @__PURE__ */ jsxs(Typography, { variant: "pi", fontWeight: "bold", style: { fontSize: "14px" }, children: [
2240
- "Current License: ",
2241
- licenseInfo?.tier ? licenseInfo.tier.charAt(0).toUpperCase() + licenseInfo.tier.slice(1) : "Free"
2242
- ] })
2243
- ] }),
2244
- /* @__PURE__ */ jsx(Badge, { style: {
2245
- backgroundColor: licenseInfo?.tier === "advanced" || licenseInfo?.tier === "enterprise" ? "#16A34A" : licenseInfo?.tier === "premium" ? "#7C3AED" : "#9CA3AF",
2246
- color: "white",
2247
- fontWeight: "600",
2248
- fontSize: "11px",
2249
- padding: "4px 12px"
2250
- }, children: licenseInfo?.tier === "advanced" || licenseInfo?.tier === "enterprise" ? "✓ All Features Unlocked" : licenseInfo?.tier === "premium" ? "Email OTP Available" : "Basic Features Only" })
2167
+ /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 2, style: { marginBottom: "8px" }, children: [
2168
+ /* @__PURE__ */ jsx(Shield, { width: "20px", height: "20px", style: { color: "#16A34A" } }),
2169
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", style: { fontSize: "14px" }, children: "All authentication modes are available" })
2251
2170
  ] }),
2252
2171
  /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "12px", lineHeight: "1.5" }, children: [
2253
2172
  "💡 ",
@@ -2332,7 +2251,6 @@ ${language === "de" ? "Der Link läuft in 1 Stunde ab." : "The link expires in 1
2332
2251
  $active: settings.otp_enabled && !settings.mfa_require_totp && ["premium", "advanced", "enterprise"].includes(licenseInfo?.tier),
2333
2252
  $statusLabel: settings.otp_enabled && !settings.mfa_require_totp && ["premium", "advanced", "enterprise"].includes(licenseInfo?.tier) ? "ACTIVE" : !["premium", "advanced", "enterprise"].includes(licenseInfo?.tier) ? "🔒 LOCKED" : "OFF",
2334
2253
  onClick: () => {
2335
- if (!checkLicenseAndSetMode("otp-email")) return;
2336
2254
  updateSetting("otp_enabled", true);
2337
2255
  updateSetting("mfa_require_totp", false);
2338
2256
  updateSetting("totp_as_primary_auth", false);
@@ -2348,28 +2266,6 @@ ${language === "de" ? "Der Link läuft in 1 Stunde ab." : "The link expires in 1
2348
2266
  position: "relative"
2349
2267
  },
2350
2268
  children: [
2351
- !["premium", "advanced", "enterprise"].includes(licenseInfo?.tier) && /* @__PURE__ */ jsxs(
2352
- "div",
2353
- {
2354
- style: {
2355
- position: "absolute",
2356
- top: 0,
2357
- left: 0,
2358
- right: 0,
2359
- bottom: 0,
2360
- display: "flex",
2361
- alignItems: "center",
2362
- justifyContent: "center",
2363
- zIndex: 10,
2364
- flexDirection: "column",
2365
- gap: "8px"
2366
- },
2367
- children: [
2368
- /* @__PURE__ */ jsx(Lock, { width: "40px", height: "40px", style: { color: "#7C3AED" } }),
2369
- /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", style: { color: "#7C3AED", fontSize: "13px" }, children: "Premium Required" })
2370
- ]
2371
- }
2372
- ),
2373
2269
  /* @__PURE__ */ jsx(IconWrapper, { $bgColor: "rgba(124, 58, 237, 0.1)", $iconColor: "#7C3AED", children: /* @__PURE__ */ jsx(Mail, {}) }),
2374
2270
  /* @__PURE__ */ jsxs(Box, { children: [
2375
2271
  /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: "Magic Link + Email OTP" }),
@@ -2398,7 +2294,6 @@ ${language === "de" ? "Der Link läuft in 1 Stunde ab." : "The link expires in 1
2398
2294
  startIcon: /* @__PURE__ */ jsx(Check, {}),
2399
2295
  onClick: async (e) => {
2400
2296
  e.stopPropagation();
2401
- if (!checkLicenseAndSetMode("otp-email")) return;
2402
2297
  try {
2403
2298
  const newSettings = {
2404
2299
  ...settings,
@@ -2433,7 +2328,6 @@ ${language === "de" ? "Der Link läuft in 1 Stunde ab." : "The link expires in 1
2433
2328
  $active: settings.mfa_require_totp && ["advanced", "enterprise"].includes(licenseInfo?.tier),
2434
2329
  $statusLabel: settings.mfa_require_totp && ["advanced", "enterprise"].includes(licenseInfo?.tier) ? "ACTIVE" : !["advanced", "enterprise"].includes(licenseInfo?.tier) ? "🔒 LOCKED" : "OFF",
2435
2330
  onClick: () => {
2436
- if (!checkLicenseAndSetMode("mfa-totp")) return;
2437
2331
  updateSetting("otp_enabled", false);
2438
2332
  updateSetting("mfa_require_totp", true);
2439
2333
  updateSetting("totp_as_primary_auth", false);
@@ -2449,28 +2343,6 @@ ${language === "de" ? "Der Link läuft in 1 Stunde ab." : "The link expires in 1
2449
2343
  position: "relative"
2450
2344
  },
2451
2345
  children: [
2452
- !["advanced", "enterprise"].includes(licenseInfo?.tier) && /* @__PURE__ */ jsxs(
2453
- "div",
2454
- {
2455
- style: {
2456
- position: "absolute",
2457
- top: 0,
2458
- left: 0,
2459
- right: 0,
2460
- bottom: 0,
2461
- display: "flex",
2462
- alignItems: "center",
2463
- justifyContent: "center",
2464
- zIndex: 10,
2465
- flexDirection: "column",
2466
- gap: "8px"
2467
- },
2468
- children: [
2469
- /* @__PURE__ */ jsx(Lightning, { width: "40px", height: "40px", style: { color: "#D97706" } }),
2470
- /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", style: { color: "#D97706", fontSize: "13px" }, children: "Advanced Required" })
2471
- ]
2472
- }
2473
- ),
2474
2346
  /* @__PURE__ */ jsx(IconWrapper, { $bgColor: "rgba(217, 119, 6, 0.1)", $iconColor: "#D97706", children: /* @__PURE__ */ jsx(Lock, {}) }),
2475
2347
  /* @__PURE__ */ jsxs(Box, { children: [
2476
2348
  /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: "Magic Link + TOTP (MFA)" }),
@@ -2499,7 +2371,6 @@ ${language === "de" ? "Der Link läuft in 1 Stunde ab." : "The link expires in 1
2499
2371
  startIcon: /* @__PURE__ */ jsx(Check, {}),
2500
2372
  onClick: async (e) => {
2501
2373
  e.stopPropagation();
2502
- if (!checkLicenseAndSetMode("mfa-totp")) return;
2503
2374
  try {
2504
2375
  const newSettings = {
2505
2376
  ...settings,
@@ -2679,9 +2550,6 @@ ${language === "de" ? "Der Link läuft in 1 Stunde ab." : "The link expires in 1
2679
2550
  {
2680
2551
  checked: settings.totp_as_primary_auth || false,
2681
2552
  onCheckedChange: (checked) => {
2682
- if (checked && !checkLicenseAndSetMode("totp-primary")) {
2683
- return;
2684
- }
2685
2553
  updateSetting("totp_as_primary_auth", checked);
2686
2554
  }
2687
2555
  }