strapi-identity 0.3.0 → 0.4.1

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 (84) hide show
  1. package/README.md +5 -2
  2. package/dist/admin/{AdminReset-QClQP2Il.js → AdminReset-BiWQDTRv.js} +3 -4
  3. package/dist/admin/{AdminReset-CCGgw-0k.mjs → AdminReset-DOmsyqwQ.mjs} +1 -2
  4. package/dist/admin/{ProfileToggle-H31GHNDA.js → ProfileToggle-BUqs_hxZ.js} +8 -218
  5. package/dist/admin/{ProfileToggle-gPuH6dGP.mjs → ProfileToggle-k0d-caPC.mjs} +2 -210
  6. package/dist/admin/{SettingsPage-DulEjadb.js → SettingsPage-DVVkN1xw.js} +3 -6
  7. package/dist/admin/{SettingsPage-DgPikS3m.mjs → SettingsPage-Dm_llkYv.mjs} +1 -4
  8. package/dist/admin/{ar-DwZqj0qM.mjs → ar-B4yBU4m7.mjs} +7 -0
  9. package/dist/admin/{ar-BYnI7Tsa.js → ar-wjkCnUTi.js} +7 -0
  10. package/dist/admin/{ca-sBRHuaFU.js → ca-BHz1SCoK.js} +7 -0
  11. package/dist/admin/{ca-aKVVc8iQ.mjs → ca-DLE8GCgI.mjs} +7 -0
  12. package/dist/admin/{cs--prflMHS.mjs → cs-3kxvJ5GN.mjs} +7 -0
  13. package/dist/admin/{cs-gU7KP3Lx.js → cs-Echs10hb.js} +7 -0
  14. package/dist/admin/{de-BT25lv_6.mjs → de-BTldhzPN.mjs} +7 -0
  15. package/dist/admin/{de-CrlCAUuf.js → de-p5oK0g4T.js} +7 -0
  16. package/dist/admin/{dk-Ck3AQYU7.mjs → dk-CCNCrmIK.mjs} +7 -0
  17. package/dist/admin/{dk-BNC3WUzY.js → dk-Z6BhrTeh.js} +7 -0
  18. package/dist/admin/{en-9qzlpde0.mjs → en-1anycEwN.mjs} +7 -0
  19. package/dist/admin/{en-DBj0AD5g.js → en-CLnZaoOA.js} +7 -0
  20. package/dist/admin/{es-D5Sn41_H.js → es-C-4sXZ_R.js} +7 -0
  21. package/dist/admin/{es-lh6XoPb7.mjs → es-DMANTUCL.mjs} +7 -0
  22. package/dist/admin/{eu-Cuz6ijBX.mjs → eu-BITeCOIE.mjs} +7 -0
  23. package/dist/admin/{eu-Qr3RvDPW.js → eu-CHWReAeU.js} +7 -0
  24. package/dist/admin/{fr-ChlDcZsG.mjs → fr-C81x3RP3.mjs} +7 -0
  25. package/dist/admin/{fr-C4pmkPYn.js → fr-DH-kRY27.js} +7 -0
  26. package/dist/admin/{gu-BMZL76zM.js → gu-CDocz32V.js} +7 -0
  27. package/dist/admin/{gu-B6zyD1bW.mjs → gu-DDR6O_Dp.mjs} +7 -0
  28. package/dist/admin/{he-H6iBa45A.js → he-CKFM5685.js} +7 -0
  29. package/dist/admin/{he-C5V-qZCX.mjs → he-TPBr5x3o.mjs} +7 -0
  30. package/dist/admin/{hi-Be8rPk7I.js → hi-DqJ11ApQ.js} +7 -0
  31. package/dist/admin/{hi-czhOWo6-.mjs → hi-Pwt1EMiO.mjs} +7 -0
  32. package/dist/admin/{hu-NbZ3aiYV.mjs → hu-CTKkJzwl.mjs} +7 -0
  33. package/dist/admin/{hu-DKp6kOmc.js → hu-DFGcSNo0.js} +7 -0
  34. package/dist/admin/{id-NH9PvcR5.mjs → id-Bq3jNpUL.mjs} +7 -0
  35. package/dist/admin/{id-DO0bwFgY.js → id-ChXHR8aw.js} +7 -0
  36. package/dist/admin/{index-C9K2h5UC.js → index-B9P8S4CX.js} +425 -4
  37. package/dist/admin/{index-C_4USMnn.mjs → index-DpIJdETG.mjs} +436 -15
  38. package/dist/admin/index.js +1 -1
  39. package/dist/admin/index.mjs +1 -1
  40. package/dist/admin/{it-Cmrey6tg.mjs → it-CgRQVAPr.mjs} +7 -0
  41. package/dist/admin/{it-Df6-7-M7.js → it-r0rbu0x0.js} +7 -0
  42. package/dist/admin/{ja-HuAq9ZwT.js → ja-27vNq46V.js} +7 -0
  43. package/dist/admin/{ja-DH3KMqOL.mjs → ja-2xaH1Qf2.mjs} +7 -0
  44. package/dist/admin/{ko-DPN28RE8.mjs → ko-CGgmfI4W.mjs} +7 -0
  45. package/dist/admin/{ko-S9k8KA8K.js → ko-Ci0l5h1b.js} +7 -0
  46. package/dist/admin/{ml-Bh9GGqcW.js → ml-Augll2or.js} +7 -0
  47. package/dist/admin/{ml-MsHNacm6.mjs → ml-aXIja392.mjs} +7 -0
  48. package/dist/admin/{ms-hO5YeEg4.js → ms-B8pBYl9n.js} +7 -0
  49. package/dist/admin/{ms-TjHAaxTd.mjs → ms-CLGR4CKx.mjs} +7 -0
  50. package/dist/admin/{nl-BLILZU8-.mjs → nl-CGFOqn_t.mjs} +7 -0
  51. package/dist/admin/{nl-BF98NBwL.js → nl-Cqn_nYD8.js} +7 -0
  52. package/dist/admin/{no-BtVZ-siy.mjs → no-BIbR3s2A.mjs} +7 -0
  53. package/dist/admin/{no-bl1OXlfa.js → no-DPF_xI-b.js} +7 -0
  54. package/dist/admin/{pl-DCSB6LwZ.mjs → pl-BBEIjPVT.mjs} +7 -0
  55. package/dist/admin/{pl-DCnOWIDw.js → pl-BjIa9TiI.js} +7 -0
  56. package/dist/admin/{pt-BR-D2_UrxTp.js → pt-BR-BbPay13q.js} +7 -0
  57. package/dist/admin/{pt-BR-CeLqmj88.mjs → pt-BR-C0S_4PYn.mjs} +7 -0
  58. package/dist/admin/{pt-DIu8RT_X.js → pt-DDhcHCz6.js} +7 -0
  59. package/dist/admin/{pt-fgjdOyW5.mjs → pt-DwDWDT_T.mjs} +7 -0
  60. package/dist/admin/{ru-BccMCf0l.js → ru-BzQ0SoFG.js} +7 -0
  61. package/dist/admin/{ru-B_hlpAyP.mjs → ru-DuxM9hFK.mjs} +7 -0
  62. package/dist/admin/{sa-D3A-fo85.js → sa-Cwsmxq_x.js} +7 -0
  63. package/dist/admin/{sa-BtuJ_I1t.mjs → sa-DfqNZDgh.mjs} +7 -0
  64. package/dist/admin/{sk-mmuTFlCK.mjs → sk-BcYzeG4F.mjs} +7 -0
  65. package/dist/admin/{sk-uSLC6KhO.js → sk-Coqlt4Kq.js} +7 -0
  66. package/dist/admin/{sv-CuKk5tE-.js → sv-9zwaCIfo.js} +7 -0
  67. package/dist/admin/{sv-BlaHc5ax.mjs → sv-CkoFHi6o.mjs} +7 -0
  68. package/dist/admin/{th-BwyhFaeE.mjs → th-C4FBlfLA.mjs} +7 -0
  69. package/dist/admin/{th-Bv3NKkYO.js → th-CFkjhGd6.js} +7 -0
  70. package/dist/admin/{tr-Bmvs-Hx-.js → tr-D0g7vqL1.js} +7 -0
  71. package/dist/admin/{tr-BLocNlbZ.mjs → tr-Djsa55Fh.mjs} +7 -0
  72. package/dist/admin/{uk-CyZ10xtq.mjs → uk-BDoDjhO2.mjs} +7 -0
  73. package/dist/admin/{uk-BDxn-EZU.js → uk-Dw1MGmom.js} +7 -0
  74. package/dist/admin/{vi-Bx_UJ8up.mjs → vi-D977KjlZ.mjs} +7 -0
  75. package/dist/admin/{vi-F_mqQCme.js → vi-DNZKFaOu.js} +7 -0
  76. package/dist/admin/{zh-CFZJPG5N.js → zh-C2aozMiZ.js} +7 -0
  77. package/dist/admin/{zh-CjJdRa3l.mjs → zh-CKYKCaVd.mjs} +7 -0
  78. package/dist/admin/{zh-Hans-s7G2GUHU.mjs → zh-Hans-DNgRcEC-.mjs} +7 -0
  79. package/dist/admin/{zh-Hans-4BhSwSQw.js → zh-Hans-ellQkyo7.js} +7 -0
  80. package/dist/server/index.js +88 -16
  81. package/dist/server/index.mjs +88 -16
  82. package/package.json +1 -1
  83. package/dist/admin/tokenHelpers-B54WRTn1.js +0 -15
  84. package/dist/admin/tokenHelpers-CKVyT1sz.mjs +0 -16
package/README.md CHANGED
@@ -2,12 +2,15 @@
2
2
 
3
3
  Detailed Multi-Factor Authentication (MFA) plugin for Strapi v5+. Secure your Strapi Admin panel with TOTP-based 2FA, fully integrated into the Strapi interface.
4
4
 
5
+ ![verification screen](./screenshots/login-verification.webp)
6
+
5
7
  ## Features
6
8
 
7
9
  - **MFA Login Interception**: Seamlessly integrates with the default Strapi login flow.
8
10
  - **TOTP Compatibility**: Works with all major authenticator apps (Google Authenticator, Authy, 1Password, etc.).
9
11
  - **Recovery Codes**: Generates secure recovery codes for emergency access.
10
12
  - **Email Passcode**: Option to receive a one-time passcode via email as an alternative MFA method.
13
+ - **Enforced mode**: Prevent a user from accessing the CMS until 2FA is setup on their account.
11
14
  - **Native UI Integration**:
12
15
  - Matches Strapi's design system.
13
16
  - Profile integration for easy setup.
@@ -62,7 +65,7 @@ Access the global settings via the admin panel:
62
65
  | Option | Description |
63
66
  | ----------- | ------------------------------------------------------------------------------------------ |
64
67
  | **Enabled** | Master switch to enable or disable the MFA interception logic globally. |
65
- | **Enforce** | _(Coming Soon)_ Force all users to set up MFA before accessing the dashboard. |
68
+ | **Enforce** | Force all users to set up MFA before accessing the dashboard. |
66
69
  | **Issuer** | The name that appears in the authenticator app (e.g., "My Project"). Defaults to "Strapi". |
67
70
 
68
71
  ### Permissions
@@ -116,4 +119,4 @@ Below is the implementation status of planned features.
116
119
  - [x] **Multi-language Support**: i18n ready.
117
120
  - [x] **Admin Reset**: Allow super-admins to reset MFA for other users who lost access.
118
121
  - [x] **Email Passcode**: Alternative MFA method via Email.
119
- - [ ] **Enforced Mode**: Mandatory MFA for specific roles or all users.
122
+ - [x] **Enforced Mode**: Mandatory MFA for all users.
@@ -4,8 +4,7 @@ const jsxRuntime = require("react/jsx-runtime");
4
4
  const React = require("react");
5
5
  const WarningAlert = require("./WarningAlert-DFE5euMk.js");
6
6
  const designSystem = require("@strapi/design-system");
7
- const index = require("./index-C9K2h5UC.js");
8
- const tokenHelpers = require("./tokenHelpers-B54WRTn1.js");
7
+ const index = require("./index-B9P8S4CX.js");
9
8
  const reactIntl = require("react-intl");
10
9
  const AdminReset = ({ id }) => {
11
10
  const { formatMessage } = reactIntl.useIntl();
@@ -13,7 +12,7 @@ const AdminReset = ({ id }) => {
13
12
  const [warningOpen, setWarningOpen] = React.useState(false);
14
13
  const [loading, setLoading] = React.useState(false);
15
14
  const handleReset = async () => {
16
- const token = tokenHelpers.getToken();
15
+ const token = index.getToken();
17
16
  setLoading(true);
18
17
  try {
19
18
  const response = await fetch(`/strapi-identity/admin/user/${id}`, {
@@ -32,7 +31,7 @@ const AdminReset = ({ id }) => {
32
31
  React.useEffect(() => {
33
32
  if (!id) return;
34
33
  const ac = new AbortController();
35
- const token = tokenHelpers.getToken();
34
+ const token = index.getToken();
36
35
  (async () => {
37
36
  try {
38
37
  const response = await fetch(`/strapi-identity/admin/user/${id}`, {
@@ -2,8 +2,7 @@ import { jsxs, Fragment, jsx } from "react/jsx-runtime";
2
2
  import { useState, useEffect } from "react";
3
3
  import { W as WarningAlert } from "./WarningAlert-VU011LVF.mjs";
4
4
  import { Box, Flex, Typography, Grid, Button } from "@strapi/design-system";
5
- import { g as getTranslation } from "./index-C_4USMnn.mjs";
6
- import { g as getToken } from "./tokenHelpers-CKVyT1sz.mjs";
5
+ import { g as getToken, a as getTranslation } from "./index-DpIJdETG.mjs";
7
6
  import { useIntl } from "react-intl";
8
7
  const AdminReset = ({ id }) => {
9
8
  const { formatMessage } = useIntl();
@@ -3,79 +3,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const jsxRuntime = require("react/jsx-runtime");
4
4
  const React = require("react");
5
5
  const designSystem = require("@strapi/design-system");
6
- const styled = require("styled-components");
7
- const index = require("./index-C9K2h5UC.js");
8
- const qrcode_react = require("qrcode.react");
6
+ const index = require("./index-B9P8S4CX.js");
9
7
  const reactIntl = require("react-intl");
10
- const tokenHelpers = require("./tokenHelpers-B54WRTn1.js");
11
- const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
12
- const styled__default = /* @__PURE__ */ _interopDefault(styled);
13
- function ConfirmModal({
14
- open,
15
- onOpenChange,
16
- onSubmit,
17
- qrCodeUri,
18
- secret,
19
- passcodes
20
- }) {
21
- const { formatMessage } = reactIntl.useIntl();
22
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Root, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Content, { children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit, children: [
23
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Title, { children: formatMessage({
24
- id: index.getTranslation("profile.setup"),
25
- defaultMessage: "Set up Two-Factor Authentication"
26
- }) }) }),
27
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Body, { children: passcodes ? /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "center", gap: 4, marginTop: 4, marginBottom: 4, children: [
28
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textAlign: "center", children: formatMessage({
29
- id: index.getTranslation("profile.recovery_codes"),
30
- defaultMessage: "Please save the following recovery codes in a safe place. Each code can only be used once to access your account if you lose access to your authenticator app."
31
- }) }),
32
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Root, { gap: 4, marginTop: 4, marginBottom: 4, children: passcodes.map((code) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 6, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: code }) }, code)) }),
33
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textAlign: "center", children: formatMessage({
34
- id: index.getTranslation("profile.recovery_codes_warning"),
35
- defaultMessage: "If you lose both your authenticator app and your recovery codes, you will need to contact an administrator to regain access to your account."
36
- }) })
37
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", children: [
38
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "center", gap: 4, marginTop: 4, marginBottom: 4, children: [
39
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
40
- id: index.getTranslation("profile.scan_qr"),
41
- defaultMessage: "You will need an authenticator app to scan the QR code below."
42
- }) }),
43
- qrCodeUri && /* @__PURE__ */ jsxRuntime.jsx(qrcode_react.QRCodeCanvas, { value: qrCodeUri, size: 256 }),
44
- secret && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: secret || "" })
45
- ] }),
46
- /* @__PURE__ */ jsxRuntime.jsx(Rule, {}),
47
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "center", gap: 4, marginTop: 4, marginBottom: 4, children: [
48
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
49
- id: index.getTranslation("profile.enter_otp"),
50
- defaultMessage: "Enter the 6-digit code from your authenticator app to confirm."
51
- }) }),
52
- /* @__PURE__ */ jsxRuntime.jsxs(index.InputOTP, { maxLength: 6, name: "otp", id: "otp", autoFocus: true, children: [
53
- /* @__PURE__ */ jsxRuntime.jsxs(index.InputOTPGroup, { children: [
54
- /* @__PURE__ */ jsxRuntime.jsx(index.InputOTPSlot, { index: 0 }),
55
- /* @__PURE__ */ jsxRuntime.jsx(index.InputOTPSlot, { index: 1 }),
56
- /* @__PURE__ */ jsxRuntime.jsx(index.InputOTPSlot, { index: 2 })
57
- ] }),
58
- /* @__PURE__ */ jsxRuntime.jsx(index.InputOTPSeparator, {}),
59
- /* @__PURE__ */ jsxRuntime.jsxs(index.InputOTPGroup, { children: [
60
- /* @__PURE__ */ jsxRuntime.jsx(index.InputOTPSlot, { index: 3 }),
61
- /* @__PURE__ */ jsxRuntime.jsx(index.InputOTPSlot, { index: 4 }),
62
- /* @__PURE__ */ jsxRuntime.jsx(index.InputOTPSlot, { index: 5 })
63
- ] })
64
- ] })
65
- ] })
66
- ] }) }),
67
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
68
- passcodes && /* @__PURE__ */ jsxRuntime.jsx("span", {}),
69
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Close, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: passcodes ? void 0 : "tertiary", children: passcodes ? formatMessage({ id: "global.close", defaultMessage: "Close" }) : formatMessage({ id: "app.components.Button.cancel", defaultMessage: "Cancel" }) }) }),
70
- !passcodes && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { type: "submit", children: formatMessage({ id: "app.components.Button.confirm", defaultMessage: "Confirm" }) })
71
- ] })
72
- ] }) }) });
73
- }
74
- const Rule = styled__default.default.hr`
75
- height: 1px;
76
- border: 0;
77
- background-color: #e5e5e5;
78
- `;
79
8
  function RemoveModal({ open, onOpenChange, onSubmit }) {
80
9
  const { formatMessage } = reactIntl.useIntl();
81
10
  const [showRecovery, setShowRecovery] = React.useState(false);
@@ -124,145 +53,6 @@ function RemoveModal({ open, onOpenChange, onSubmit }) {
124
53
  ] })
125
54
  ] }) }) });
126
55
  }
127
- function EmailOTPModal({
128
- mode,
129
- open,
130
- email,
131
- onOpenChange,
132
- onSuccess
133
- }) {
134
- const { formatMessage } = reactIntl.useIntl();
135
- const [step, setStep] = React.useState("send");
136
- const [loading, setLoading] = React.useState(false);
137
- const [error, setError] = React.useState(null);
138
- const handleOpenChange = (nextOpen) => {
139
- if (!nextOpen) {
140
- setStep("send");
141
- setError(null);
142
- }
143
- onOpenChange(nextOpen);
144
- };
145
- const handleSend = async () => {
146
- const token = tokenHelpers.getToken();
147
- setLoading(true);
148
- setError(null);
149
- try {
150
- const endpoint = mode === "setup" ? "/strapi-identity/enable-email" : "/strapi-identity/disable-email/request";
151
- const response = await fetch(endpoint, {
152
- method: "POST",
153
- headers: { "Content-Type": "application/json", authorization: `Bearer ${token}` }
154
- });
155
- const body = await response.json();
156
- if (!response.ok) {
157
- throw new Error(body.error || "Failed to send verification email");
158
- }
159
- setStep("confirm");
160
- } catch (err) {
161
- setError(err.message);
162
- } finally {
163
- setLoading(false);
164
- }
165
- };
166
- const handleConfirm = async (e) => {
167
- e.preventDefault();
168
- const token = tokenHelpers.getToken();
169
- const formData = new FormData(e.target);
170
- const code = formData.get("otp");
171
- setLoading(true);
172
- setError(null);
173
- try {
174
- const endpoint = mode === "setup" ? "/strapi-identity/setup-email" : "/strapi-identity/disable";
175
- const response = await fetch(endpoint, {
176
- method: "POST",
177
- headers: { "Content-Type": "application/json", authorization: `Bearer ${token}` },
178
- body: JSON.stringify({ code })
179
- });
180
- const body = await response.json();
181
- if (!response.ok) {
182
- throw new Error(body.error || "Invalid or expired code");
183
- }
184
- handleOpenChange(false);
185
- onSuccess();
186
- } catch (err) {
187
- setError(err.message);
188
- } finally {
189
- setLoading(false);
190
- }
191
- };
192
- const title = mode === "setup" ? formatMessage({
193
- id: index.getTranslation("email_otp.setup_title"),
194
- defaultMessage: "Enable Email OTP"
195
- }) : formatMessage({
196
- id: index.getTranslation("email_otp.disable_title"),
197
- defaultMessage: "Disable Email OTP"
198
- });
199
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Root, { open, onOpenChange: handleOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Content, { children: [
200
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Title, { children: title }) }),
201
- step === "send" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
202
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "center", gap: 4, marginTop: 4, marginBottom: 4, children: [
203
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textAlign: "center", children: mode === "setup" ? formatMessage(
204
- {
205
- id: index.getTranslation("email_otp.setup_description"),
206
- defaultMessage: "We'll send a 6-digit verification code to {email}. Enter it to enable Email OTP."
207
- },
208
- { email: /* @__PURE__ */ jsxRuntime.jsx("strong", { children: email }) }
209
- ) : formatMessage(
210
- {
211
- id: index.getTranslation("email_otp.disable_description"),
212
- defaultMessage: "We'll send a 6-digit verification code to {email}. Enter it to disable Email OTP."
213
- },
214
- { email: /* @__PURE__ */ jsxRuntime.jsx("strong", { children: email }) }
215
- ) }),
216
- error ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { role: "alert", textColor: "danger600", textAlign: "center", children: error }) : null
217
- ] }) }),
218
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
219
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Close, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", children: formatMessage({ id: "app.components.Button.cancel", defaultMessage: "Cancel" }) }) }),
220
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleSend, loading, children: formatMessage({
221
- id: index.getTranslation("email_otp.send_code"),
222
- defaultMessage: "Send verification email"
223
- }) })
224
- ] })
225
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleConfirm, children: [
226
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "center", gap: 4, marginTop: 4, marginBottom: 4, children: [
227
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textAlign: "center", children: formatMessage(
228
- {
229
- id: index.getTranslation("email_otp.confirm_description"),
230
- defaultMessage: "Enter the 6-digit code sent to {email}."
231
- },
232
- { email: /* @__PURE__ */ jsxRuntime.jsx("strong", { children: email }) }
233
- ) }),
234
- /* @__PURE__ */ jsxRuntime.jsxs(index.InputOTP, { maxLength: 6, name: "otp", id: "otp", autoFocus: true, children: [
235
- /* @__PURE__ */ jsxRuntime.jsxs(index.InputOTPGroup, { children: [
236
- /* @__PURE__ */ jsxRuntime.jsx(index.InputOTPSlot, { index: 0 }),
237
- /* @__PURE__ */ jsxRuntime.jsx(index.InputOTPSlot, { index: 1 }),
238
- /* @__PURE__ */ jsxRuntime.jsx(index.InputOTPSlot, { index: 2 })
239
- ] }),
240
- /* @__PURE__ */ jsxRuntime.jsx(index.InputOTPSeparator, {}),
241
- /* @__PURE__ */ jsxRuntime.jsxs(index.InputOTPGroup, { children: [
242
- /* @__PURE__ */ jsxRuntime.jsx(index.InputOTPSlot, { index: 3 }),
243
- /* @__PURE__ */ jsxRuntime.jsx(index.InputOTPSlot, { index: 4 }),
244
- /* @__PURE__ */ jsxRuntime.jsx(index.InputOTPSlot, { index: 5 })
245
- ] })
246
- ] }),
247
- error ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { role: "alert", textColor: "danger600", textAlign: "center", children: error }) : null,
248
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "ghost", type: "button", onClick: () => handleSend(), children: formatMessage({
249
- id: index.getTranslation("email_otp.resend_code"),
250
- defaultMessage: "Resend code"
251
- }) })
252
- ] }) }),
253
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
254
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Close, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", children: formatMessage({
255
- id: "app.components.Button.cancel",
256
- defaultMessage: "Cancel"
257
- }) }) }),
258
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { type: "submit", loading, children: formatMessage({
259
- id: "app.components.Button.confirm",
260
- defaultMessage: "Confirm"
261
- }) })
262
- ] })
263
- ] })
264
- ] }) });
265
- }
266
56
  const ProfileToggle = () => {
267
57
  const { formatMessage } = reactIntl.useIntl();
268
58
  const [enabled, setEnabled] = React.useState(null);
@@ -278,7 +68,7 @@ const ProfileToggle = () => {
278
68
  const [secret, setSecret] = React.useState(null);
279
69
  const [passcodes, setPasscodes] = React.useState(null);
280
70
  const handleToggle = async ({ target }) => {
281
- const token = tokenHelpers.getToken();
71
+ const token = index.getToken();
282
72
  const enable = target?.checked || false;
283
73
  if (!enable && enabled === "full") {
284
74
  setDisableDialogOpen(true);
@@ -329,7 +119,7 @@ const ProfileToggle = () => {
329
119
  const form = e.target;
330
120
  const formData = new FormData(form);
331
121
  const code = formData.get("otp");
332
- const token = tokenHelpers.getToken();
122
+ const token = index.getToken();
333
123
  try {
334
124
  const response = await fetch("/strapi-identity/setup", {
335
125
  method: "POST",
@@ -365,7 +155,7 @@ const ProfileToggle = () => {
365
155
  const form = e.target;
366
156
  const formData = new FormData(form);
367
157
  const code = formData.get("otp");
368
- const token = tokenHelpers.getToken();
158
+ const token = index.getToken();
369
159
  try {
370
160
  const response = await fetch("/strapi-identity/disable", {
371
161
  method: "POST",
@@ -388,7 +178,7 @@ const ProfileToggle = () => {
388
178
  React.useEffect(() => {
389
179
  const ac = new AbortController();
390
180
  (async () => {
391
- const token = tokenHelpers.getToken();
181
+ const token = index.getToken();
392
182
  try {
393
183
  const [statusRes, enabledRes, meRes] = await Promise.all([
394
184
  fetch("/strapi-identity/status", {
@@ -541,7 +331,7 @@ const ProfileToggle = () => {
541
331
  }
542
332
  ),
543
333
  /* @__PURE__ */ jsxRuntime.jsx(
544
- ConfirmModal,
334
+ index.ConfirmModal,
545
335
  {
546
336
  open: modalOpen,
547
337
  onOpenChange: handleClose,
@@ -560,7 +350,7 @@ const ProfileToggle = () => {
560
350
  }
561
351
  ),
562
352
  /* @__PURE__ */ jsxRuntime.jsx(
563
- EmailOTPModal,
353
+ index.EmailOTPModal,
564
354
  {
565
355
  mode: "setup",
566
356
  open: emailSetupOpen,
@@ -576,7 +366,7 @@ const ProfileToggle = () => {
576
366
  }
577
367
  ),
578
368
  /* @__PURE__ */ jsxRuntime.jsx(
579
- EmailOTPModal,
369
+ index.EmailOTPModal,
580
370
  {
581
371
  mode: "disable",
582
372
  open: emailDisableOpen,
@@ -1,77 +1,8 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import { useState, useEffect } from "react";
3
- import { Modal, Flex, Typography, Grid, Button, TextInput, Box, Field, Toggle } from "@strapi/design-system";
4
- import styled from "styled-components";
5
- import { g as getTranslation, I as InputOTP, a as InputOTPGroup, b as InputOTPSlot, c as InputOTPSeparator } from "./index-C_4USMnn.mjs";
6
- import { QRCodeCanvas } from "qrcode.react";
3
+ import { Modal, Flex, Typography, TextInput, Button, Box, Grid, Field, Toggle } from "@strapi/design-system";
4
+ import { a as getTranslation, I as InputOTP, b as InputOTPGroup, c as InputOTPSlot, d as InputOTPSeparator, g as getToken, C as ConfirmModal, E as EmailOTPModal } from "./index-DpIJdETG.mjs";
7
5
  import { useIntl } from "react-intl";
8
- import { g as getToken } from "./tokenHelpers-CKVyT1sz.mjs";
9
- function ConfirmModal({
10
- open,
11
- onOpenChange,
12
- onSubmit,
13
- qrCodeUri,
14
- secret,
15
- passcodes
16
- }) {
17
- const { formatMessage } = useIntl();
18
- return /* @__PURE__ */ jsx(Modal.Root, { open, onOpenChange, children: /* @__PURE__ */ jsx(Modal.Content, { children: /* @__PURE__ */ jsxs("form", { onSubmit, children: [
19
- /* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: formatMessage({
20
- id: getTranslation("profile.setup"),
21
- defaultMessage: "Set up Two-Factor Authentication"
22
- }) }) }),
23
- /* @__PURE__ */ jsx(Modal.Body, { children: passcodes ? /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "center", gap: 4, marginTop: 4, marginBottom: 4, children: [
24
- /* @__PURE__ */ jsx(Typography, { textAlign: "center", children: formatMessage({
25
- id: getTranslation("profile.recovery_codes"),
26
- defaultMessage: "Please save the following recovery codes in a safe place. Each code can only be used once to access your account if you lose access to your authenticator app."
27
- }) }),
28
- /* @__PURE__ */ jsx(Grid.Root, { gap: 4, marginTop: 4, marginBottom: 4, children: passcodes.map((code) => /* @__PURE__ */ jsx(Grid.Item, { col: 6, children: /* @__PURE__ */ jsx(Typography, { variant: "pi", children: code }) }, code)) }),
29
- /* @__PURE__ */ jsx(Typography, { variant: "pi", textAlign: "center", children: formatMessage({
30
- id: getTranslation("profile.recovery_codes_warning"),
31
- defaultMessage: "If you lose both your authenticator app and your recovery codes, you will need to contact an administrator to regain access to your account."
32
- }) })
33
- ] }) : /* @__PURE__ */ jsxs(Flex, { direction: "column", children: [
34
- /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "center", gap: 4, marginTop: 4, marginBottom: 4, children: [
35
- /* @__PURE__ */ jsx(Typography, { children: formatMessage({
36
- id: getTranslation("profile.scan_qr"),
37
- defaultMessage: "You will need an authenticator app to scan the QR code below."
38
- }) }),
39
- qrCodeUri && /* @__PURE__ */ jsx(QRCodeCanvas, { value: qrCodeUri, size: 256 }),
40
- secret && /* @__PURE__ */ jsx(Typography, { variant: "pi", children: secret || "" })
41
- ] }),
42
- /* @__PURE__ */ jsx(Rule, {}),
43
- /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "center", gap: 4, marginTop: 4, marginBottom: 4, children: [
44
- /* @__PURE__ */ jsx(Typography, { children: formatMessage({
45
- id: getTranslation("profile.enter_otp"),
46
- defaultMessage: "Enter the 6-digit code from your authenticator app to confirm."
47
- }) }),
48
- /* @__PURE__ */ jsxs(InputOTP, { maxLength: 6, name: "otp", id: "otp", autoFocus: true, children: [
49
- /* @__PURE__ */ jsxs(InputOTPGroup, { children: [
50
- /* @__PURE__ */ jsx(InputOTPSlot, { index: 0 }),
51
- /* @__PURE__ */ jsx(InputOTPSlot, { index: 1 }),
52
- /* @__PURE__ */ jsx(InputOTPSlot, { index: 2 })
53
- ] }),
54
- /* @__PURE__ */ jsx(InputOTPSeparator, {}),
55
- /* @__PURE__ */ jsxs(InputOTPGroup, { children: [
56
- /* @__PURE__ */ jsx(InputOTPSlot, { index: 3 }),
57
- /* @__PURE__ */ jsx(InputOTPSlot, { index: 4 }),
58
- /* @__PURE__ */ jsx(InputOTPSlot, { index: 5 })
59
- ] })
60
- ] })
61
- ] })
62
- ] }) }),
63
- /* @__PURE__ */ jsxs(Modal.Footer, { children: [
64
- passcodes && /* @__PURE__ */ jsx("span", {}),
65
- /* @__PURE__ */ jsx(Modal.Close, { children: /* @__PURE__ */ jsx(Button, { variant: passcodes ? void 0 : "tertiary", children: passcodes ? formatMessage({ id: "global.close", defaultMessage: "Close" }) : formatMessage({ id: "app.components.Button.cancel", defaultMessage: "Cancel" }) }) }),
66
- !passcodes && /* @__PURE__ */ jsx(Button, { type: "submit", children: formatMessage({ id: "app.components.Button.confirm", defaultMessage: "Confirm" }) })
67
- ] })
68
- ] }) }) });
69
- }
70
- const Rule = styled.hr`
71
- height: 1px;
72
- border: 0;
73
- background-color: #e5e5e5;
74
- `;
75
6
  function RemoveModal({ open, onOpenChange, onSubmit }) {
76
7
  const { formatMessage } = useIntl();
77
8
  const [showRecovery, setShowRecovery] = useState(false);
@@ -120,145 +51,6 @@ function RemoveModal({ open, onOpenChange, onSubmit }) {
120
51
  ] })
121
52
  ] }) }) });
122
53
  }
123
- function EmailOTPModal({
124
- mode,
125
- open,
126
- email,
127
- onOpenChange,
128
- onSuccess
129
- }) {
130
- const { formatMessage } = useIntl();
131
- const [step, setStep] = useState("send");
132
- const [loading, setLoading] = useState(false);
133
- const [error, setError] = useState(null);
134
- const handleOpenChange = (nextOpen) => {
135
- if (!nextOpen) {
136
- setStep("send");
137
- setError(null);
138
- }
139
- onOpenChange(nextOpen);
140
- };
141
- const handleSend = async () => {
142
- const token = getToken();
143
- setLoading(true);
144
- setError(null);
145
- try {
146
- const endpoint = mode === "setup" ? "/strapi-identity/enable-email" : "/strapi-identity/disable-email/request";
147
- const response = await fetch(endpoint, {
148
- method: "POST",
149
- headers: { "Content-Type": "application/json", authorization: `Bearer ${token}` }
150
- });
151
- const body = await response.json();
152
- if (!response.ok) {
153
- throw new Error(body.error || "Failed to send verification email");
154
- }
155
- setStep("confirm");
156
- } catch (err) {
157
- setError(err.message);
158
- } finally {
159
- setLoading(false);
160
- }
161
- };
162
- const handleConfirm = async (e) => {
163
- e.preventDefault();
164
- const token = getToken();
165
- const formData = new FormData(e.target);
166
- const code = formData.get("otp");
167
- setLoading(true);
168
- setError(null);
169
- try {
170
- const endpoint = mode === "setup" ? "/strapi-identity/setup-email" : "/strapi-identity/disable";
171
- const response = await fetch(endpoint, {
172
- method: "POST",
173
- headers: { "Content-Type": "application/json", authorization: `Bearer ${token}` },
174
- body: JSON.stringify({ code })
175
- });
176
- const body = await response.json();
177
- if (!response.ok) {
178
- throw new Error(body.error || "Invalid or expired code");
179
- }
180
- handleOpenChange(false);
181
- onSuccess();
182
- } catch (err) {
183
- setError(err.message);
184
- } finally {
185
- setLoading(false);
186
- }
187
- };
188
- const title = mode === "setup" ? formatMessage({
189
- id: getTranslation("email_otp.setup_title"),
190
- defaultMessage: "Enable Email OTP"
191
- }) : formatMessage({
192
- id: getTranslation("email_otp.disable_title"),
193
- defaultMessage: "Disable Email OTP"
194
- });
195
- return /* @__PURE__ */ jsx(Modal.Root, { open, onOpenChange: handleOpenChange, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
196
- /* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
197
- step === "send" ? /* @__PURE__ */ jsxs(Fragment, { children: [
198
- /* @__PURE__ */ jsx(Modal.Body, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "center", gap: 4, marginTop: 4, marginBottom: 4, children: [
199
- /* @__PURE__ */ jsx(Typography, { textAlign: "center", children: mode === "setup" ? formatMessage(
200
- {
201
- id: getTranslation("email_otp.setup_description"),
202
- defaultMessage: "We'll send a 6-digit verification code to {email}. Enter it to enable Email OTP."
203
- },
204
- { email: /* @__PURE__ */ jsx("strong", { children: email }) }
205
- ) : formatMessage(
206
- {
207
- id: getTranslation("email_otp.disable_description"),
208
- defaultMessage: "We'll send a 6-digit verification code to {email}. Enter it to disable Email OTP."
209
- },
210
- { email: /* @__PURE__ */ jsx("strong", { children: email }) }
211
- ) }),
212
- error ? /* @__PURE__ */ jsx(Typography, { role: "alert", textColor: "danger600", textAlign: "center", children: error }) : null
213
- ] }) }),
214
- /* @__PURE__ */ jsxs(Modal.Footer, { children: [
215
- /* @__PURE__ */ jsx(Modal.Close, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({ id: "app.components.Button.cancel", defaultMessage: "Cancel" }) }) }),
216
- /* @__PURE__ */ jsx(Button, { onClick: handleSend, loading, children: formatMessage({
217
- id: getTranslation("email_otp.send_code"),
218
- defaultMessage: "Send verification email"
219
- }) })
220
- ] })
221
- ] }) : /* @__PURE__ */ jsxs("form", { onSubmit: handleConfirm, children: [
222
- /* @__PURE__ */ jsx(Modal.Body, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "center", gap: 4, marginTop: 4, marginBottom: 4, children: [
223
- /* @__PURE__ */ jsx(Typography, { textAlign: "center", children: formatMessage(
224
- {
225
- id: getTranslation("email_otp.confirm_description"),
226
- defaultMessage: "Enter the 6-digit code sent to {email}."
227
- },
228
- { email: /* @__PURE__ */ jsx("strong", { children: email }) }
229
- ) }),
230
- /* @__PURE__ */ jsxs(InputOTP, { maxLength: 6, name: "otp", id: "otp", autoFocus: true, children: [
231
- /* @__PURE__ */ jsxs(InputOTPGroup, { children: [
232
- /* @__PURE__ */ jsx(InputOTPSlot, { index: 0 }),
233
- /* @__PURE__ */ jsx(InputOTPSlot, { index: 1 }),
234
- /* @__PURE__ */ jsx(InputOTPSlot, { index: 2 })
235
- ] }),
236
- /* @__PURE__ */ jsx(InputOTPSeparator, {}),
237
- /* @__PURE__ */ jsxs(InputOTPGroup, { children: [
238
- /* @__PURE__ */ jsx(InputOTPSlot, { index: 3 }),
239
- /* @__PURE__ */ jsx(InputOTPSlot, { index: 4 }),
240
- /* @__PURE__ */ jsx(InputOTPSlot, { index: 5 })
241
- ] })
242
- ] }),
243
- error ? /* @__PURE__ */ jsx(Typography, { role: "alert", textColor: "danger600", textAlign: "center", children: error }) : null,
244
- /* @__PURE__ */ jsx(Button, { variant: "ghost", type: "button", onClick: () => handleSend(), children: formatMessage({
245
- id: getTranslation("email_otp.resend_code"),
246
- defaultMessage: "Resend code"
247
- }) })
248
- ] }) }),
249
- /* @__PURE__ */ jsxs(Modal.Footer, { children: [
250
- /* @__PURE__ */ jsx(Modal.Close, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
251
- id: "app.components.Button.cancel",
252
- defaultMessage: "Cancel"
253
- }) }) }),
254
- /* @__PURE__ */ jsx(Button, { type: "submit", loading, children: formatMessage({
255
- id: "app.components.Button.confirm",
256
- defaultMessage: "Confirm"
257
- }) })
258
- ] })
259
- ] })
260
- ] }) });
261
- }
262
54
  const ProfileToggle = () => {
263
55
  const { formatMessage } = useIntl();
264
56
  const [enabled, setEnabled] = useState(null);
@@ -6,8 +6,7 @@ const WarningAlert = require("./WarningAlert-DFE5euMk.js");
6
6
  const admin = require("@strapi/strapi/admin");
7
7
  const designSystem = require("@strapi/design-system");
8
8
  const icons = require("@strapi/icons");
9
- const index = require("./index-C9K2h5UC.js");
10
- const tokenHelpers = require("./tokenHelpers-B54WRTn1.js");
9
+ const index = require("./index-B9P8S4CX.js");
11
10
  const reactIntl = require("react-intl");
12
11
  var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
13
12
  var lodash$1 = { exports: {} };
@@ -5611,7 +5610,6 @@ function SettingsPage() {
5611
5610
  setSaving(true);
5612
5611
  const formData = new FormData(event.currentTarget);
5613
5612
  const values = getConfigFromForm(formData);
5614
- console.log(formData, values);
5615
5613
  if (initialConfig?.enabled && !values.enabled && !confirmed) {
5616
5614
  setShowWarning(true);
5617
5615
  setSaving(false);
@@ -5623,7 +5621,7 @@ function SettingsPage() {
5623
5621
  return;
5624
5622
  }
5625
5623
  try {
5626
- const token = tokenHelpers.getToken();
5624
+ const token = index.getToken();
5627
5625
  const response = await fetch("/strapi-identity/config", {
5628
5626
  method: "PUT",
5629
5627
  headers: {
@@ -5659,7 +5657,7 @@ function SettingsPage() {
5659
5657
  };
5660
5658
  React.useEffect(() => {
5661
5659
  const ac = new AbortController();
5662
- const token = tokenHelpers.getToken();
5660
+ const token = index.getToken();
5663
5661
  (async () => {
5664
5662
  try {
5665
5663
  const response = await fetch("/strapi-identity/config", {
@@ -5775,7 +5773,6 @@ function SettingsPage() {
5775
5773
  designSystem.Toggle,
5776
5774
  {
5777
5775
  name: "enforce",
5778
- disabled: true,
5779
5776
  checked: enforce,
5780
5777
  onChange: ({ target }) => setEnforce(target.checked),
5781
5778
  offLabel: formatMessage({
@@ -4,8 +4,7 @@ import { W as WarningAlert } from "./WarningAlert-VU011LVF.mjs";
4
4
  import { useNotification, Page, Layouts } from "@strapi/strapi/admin";
5
5
  import { Button, Flex, Typography, Grid, Field, Toggle, TextInput, Textarea } from "@strapi/design-system";
6
6
  import { Check } from "@strapi/icons";
7
- import { g as getTranslation } from "./index-C_4USMnn.mjs";
8
- import { g as getToken } from "./tokenHelpers-CKVyT1sz.mjs";
7
+ import { g as getToken, a as getTranslation } from "./index-DpIJdETG.mjs";
9
8
  import { useIntl } from "react-intl";
10
9
  var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
11
10
  var lodash$1 = { exports: {} };
@@ -5609,7 +5608,6 @@ function SettingsPage() {
5609
5608
  setSaving(true);
5610
5609
  const formData = new FormData(event.currentTarget);
5611
5610
  const values = getConfigFromForm(formData);
5612
- console.log(formData, values);
5613
5611
  if (initialConfig?.enabled && !values.enabled && !confirmed) {
5614
5612
  setShowWarning(true);
5615
5613
  setSaving(false);
@@ -5773,7 +5771,6 @@ function SettingsPage() {
5773
5771
  Toggle,
5774
5772
  {
5775
5773
  name: "enforce",
5776
- disabled: true,
5777
5774
  checked: enforce,
5778
5775
  onChange: ({ target }) => setEnforce(target.checked),
5779
5776
  offLabel: formatMessage({