strapi-identity 0.2.0 → 0.4.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 (84) hide show
  1. package/README.md +5 -2
  2. package/dist/admin/{AdminReset-CqHhVBS_.js → AdminReset-BiWQDTRv.js} +3 -4
  3. package/dist/admin/{AdminReset-B-WGECOX.mjs → AdminReset-DOmsyqwQ.mjs} +1 -2
  4. package/dist/admin/{ProfileToggle-BRYjt5Lu.js → ProfileToggle-BUqs_hxZ.js} +8 -218
  5. package/dist/admin/{ProfileToggle-BCtCsOvj.mjs → ProfileToggle-k0d-caPC.mjs} +2 -210
  6. package/dist/admin/{SettingsPage-DAxGIv_E.js → SettingsPage-DVVkN1xw.js} +3 -6
  7. package/dist/admin/{SettingsPage-7Ytl01jH.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-D03zlFnm.js → index-B9P8S4CX.js} +428 -9
  37. package/dist/admin/{index-BfC6z9N5.mjs → index-DpIJdETG.mjs} +439 -20
  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 +3 -3
  83. package/dist/admin/tokenHelpers-DagDzpso.mjs +0 -22
  84. package/dist/admin/tokenHelpers-jtoRu0q5.js +0 -21
@@ -1,12 +1,13 @@
1
1
  import * as React from "react";
2
2
  import React__default, { useRef, useEffect, useContext, useCallback, useDebugValue, useState } from "react";
3
- import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
4
4
  import "react-dom";
5
5
  import styled, { keyframes } from "styled-components";
6
6
  import { OTPInput, OTPInputContext } from "input-otp";
7
- import { Box, Flex, Main, Typography, TextInput, Button, SingleSelect, SingleSelectOption } from "@strapi/design-system";
8
- import { useAuth, RESPONSIVE_DEFAULT_SPACING } from "@strapi/strapi/admin";
7
+ import { Box, Flex, Main, Typography, TextInput, Button, SingleSelect, SingleSelectOption, Modal, Grid } from "@strapi/design-system";
8
+ import { useAuth, RESPONSIVE_DEFAULT_SPACING, Page, Layouts } from "@strapi/strapi/admin";
9
9
  import { useIntl } from "react-intl";
10
+ import { QRCodeCanvas } from "qrcode.react";
10
11
  import { initialiseInjections } from "strapi-admin-portal";
11
12
  const __variableDynamicImportRuntimeHelper = (glob, path, segs) => {
12
13
  const v = glob[path];
@@ -637,7 +638,7 @@ function requireReactIs_development$1() {
637
638
  var ContextProvider = REACT_PROVIDER_TYPE;
638
639
  var Element = REACT_ELEMENT_TYPE;
639
640
  var ForwardRef = REACT_FORWARD_REF_TYPE;
640
- var Fragment = REACT_FRAGMENT_TYPE;
641
+ var Fragment2 = REACT_FRAGMENT_TYPE;
641
642
  var Lazy = REACT_LAZY_TYPE;
642
643
  var Memo = REACT_MEMO_TYPE;
643
644
  var Portal = REACT_PORTAL_TYPE;
@@ -696,7 +697,7 @@ function requireReactIs_development$1() {
696
697
  reactIs_development$1.ContextProvider = ContextProvider;
697
698
  reactIs_development$1.Element = Element;
698
699
  reactIs_development$1.ForwardRef = ForwardRef;
699
- reactIs_development$1.Fragment = Fragment;
700
+ reactIs_development$1.Fragment = Fragment2;
700
701
  reactIs_development$1.Lazy = Lazy;
701
702
  reactIs_development$1.Memo = Memo;
702
703
  reactIs_development$1.Portal = Portal;
@@ -1023,7 +1024,7 @@ function requireReactIs_development() {
1023
1024
  var ContextProvider = REACT_PROVIDER_TYPE;
1024
1025
  var Element = REACT_ELEMENT_TYPE;
1025
1026
  var ForwardRef = REACT_FORWARD_REF_TYPE;
1026
- var Fragment = REACT_FRAGMENT_TYPE;
1027
+ var Fragment2 = REACT_FRAGMENT_TYPE;
1027
1028
  var Lazy = REACT_LAZY_TYPE;
1028
1029
  var Memo = REACT_MEMO_TYPE;
1029
1030
  var Portal = REACT_PORTAL_TYPE;
@@ -1091,7 +1092,7 @@ function requireReactIs_development() {
1091
1092
  reactIs_development.ContextProvider = ContextProvider;
1092
1093
  reactIs_development.Element = Element;
1093
1094
  reactIs_development.ForwardRef = ForwardRef;
1094
- reactIs_development.Fragment = Fragment;
1095
+ reactIs_development.Fragment = Fragment2;
1095
1096
  reactIs_development.Lazy = Lazy;
1096
1097
  reactIs_development.Memo = Memo;
1097
1098
  reactIs_development.Portal = Portal;
@@ -1506,6 +1507,422 @@ const VerifyPage = ({ fallbackIcon }) => {
1506
1507
  )
1507
1508
  ] });
1508
1509
  };
1510
+ function ConfirmModal({
1511
+ open,
1512
+ onOpenChange,
1513
+ onSubmit,
1514
+ qrCodeUri,
1515
+ secret,
1516
+ passcodes
1517
+ }) {
1518
+ const { formatMessage } = useIntl();
1519
+ return /* @__PURE__ */ jsx(Modal.Root, { open, onOpenChange, children: /* @__PURE__ */ jsx(Modal.Content, { children: /* @__PURE__ */ jsxs("form", { onSubmit, children: [
1520
+ /* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: formatMessage({
1521
+ id: getTranslation("profile.setup"),
1522
+ defaultMessage: "Set up Two-Factor Authentication"
1523
+ }) }) }),
1524
+ /* @__PURE__ */ jsx(Modal.Body, { children: passcodes ? /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "center", gap: 4, marginTop: 4, marginBottom: 4, children: [
1525
+ /* @__PURE__ */ jsx(Typography, { textAlign: "center", children: formatMessage({
1526
+ id: getTranslation("profile.recovery_codes"),
1527
+ 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."
1528
+ }) }),
1529
+ /* @__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)) }),
1530
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textAlign: "center", children: formatMessage({
1531
+ id: getTranslation("profile.recovery_codes_warning"),
1532
+ 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."
1533
+ }) })
1534
+ ] }) : /* @__PURE__ */ jsxs(Flex, { direction: "column", children: [
1535
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "center", gap: 4, marginTop: 4, marginBottom: 4, children: [
1536
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
1537
+ id: getTranslation("profile.scan_qr"),
1538
+ defaultMessage: "You will need an authenticator app to scan the QR code below."
1539
+ }) }),
1540
+ qrCodeUri && /* @__PURE__ */ jsx(QRCodeCanvas, { value: qrCodeUri, size: 256 }),
1541
+ secret && /* @__PURE__ */ jsx(Typography, { variant: "pi", children: secret || "" })
1542
+ ] }),
1543
+ /* @__PURE__ */ jsx(Rule, {}),
1544
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "center", gap: 4, marginTop: 4, marginBottom: 4, children: [
1545
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
1546
+ id: getTranslation("profile.enter_otp"),
1547
+ defaultMessage: "Enter the 6-digit code from your authenticator app to confirm."
1548
+ }) }),
1549
+ /* @__PURE__ */ jsxs(InputOTP, { maxLength: 6, name: "otp", id: "otp", autoFocus: true, children: [
1550
+ /* @__PURE__ */ jsxs(InputOTPGroup, { children: [
1551
+ /* @__PURE__ */ jsx(InputOTPSlot, { index: 0 }),
1552
+ /* @__PURE__ */ jsx(InputOTPSlot, { index: 1 }),
1553
+ /* @__PURE__ */ jsx(InputOTPSlot, { index: 2 })
1554
+ ] }),
1555
+ /* @__PURE__ */ jsx(InputOTPSeparator, {}),
1556
+ /* @__PURE__ */ jsxs(InputOTPGroup, { children: [
1557
+ /* @__PURE__ */ jsx(InputOTPSlot, { index: 3 }),
1558
+ /* @__PURE__ */ jsx(InputOTPSlot, { index: 4 }),
1559
+ /* @__PURE__ */ jsx(InputOTPSlot, { index: 5 })
1560
+ ] })
1561
+ ] })
1562
+ ] })
1563
+ ] }) }),
1564
+ /* @__PURE__ */ jsxs(Modal.Footer, { children: [
1565
+ passcodes && /* @__PURE__ */ jsx("span", {}),
1566
+ /* @__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" }) }) }),
1567
+ !passcodes && /* @__PURE__ */ jsx(Button, { type: "submit", children: formatMessage({ id: "app.components.Button.confirm", defaultMessage: "Confirm" }) })
1568
+ ] })
1569
+ ] }) }) });
1570
+ }
1571
+ const Rule = styled.hr`
1572
+ height: 1px;
1573
+ border: 0;
1574
+ background-color: #e5e5e5;
1575
+ `;
1576
+ const getCookieValue = (name) => {
1577
+ const cookieArray = document.cookie.split(";");
1578
+ return cookieArray.reduce((result, cookie) => {
1579
+ const [key, value] = cookie.split("=").map((item) => item.trim());
1580
+ return key === name ? decodeURIComponent(value) : result;
1581
+ }, null);
1582
+ };
1583
+ const getToken = () => {
1584
+ const fromLocalStorage = localStorage.getItem("jwtToken");
1585
+ if (fromLocalStorage) return JSON.parse(fromLocalStorage);
1586
+ const fromCookie = getCookieValue("jwtToken");
1587
+ return fromCookie ?? null;
1588
+ };
1589
+ function EmailOTPModal({
1590
+ mode,
1591
+ open,
1592
+ email,
1593
+ onOpenChange,
1594
+ onSuccess
1595
+ }) {
1596
+ const { formatMessage } = useIntl();
1597
+ const [step, setStep] = useState("send");
1598
+ const [loading, setLoading] = useState(false);
1599
+ const [error, setError] = useState(null);
1600
+ const handleOpenChange = (nextOpen) => {
1601
+ if (!nextOpen) {
1602
+ setStep("send");
1603
+ setError(null);
1604
+ }
1605
+ onOpenChange(nextOpen);
1606
+ };
1607
+ const handleSend = async () => {
1608
+ const token = getToken();
1609
+ setLoading(true);
1610
+ setError(null);
1611
+ try {
1612
+ const endpoint = mode === "setup" ? "/strapi-identity/enable-email" : "/strapi-identity/disable-email/request";
1613
+ const response = await fetch(endpoint, {
1614
+ method: "POST",
1615
+ headers: { "Content-Type": "application/json", authorization: `Bearer ${token}` }
1616
+ });
1617
+ const body = await response.json();
1618
+ if (!response.ok) {
1619
+ throw new Error(body.error || "Failed to send verification email");
1620
+ }
1621
+ setStep("confirm");
1622
+ } catch (err) {
1623
+ setError(err.message);
1624
+ } finally {
1625
+ setLoading(false);
1626
+ }
1627
+ };
1628
+ const handleConfirm = async (e) => {
1629
+ e.preventDefault();
1630
+ const token = getToken();
1631
+ const formData = new FormData(e.target);
1632
+ const code = formData.get("otp");
1633
+ setLoading(true);
1634
+ setError(null);
1635
+ try {
1636
+ const endpoint = mode === "setup" ? "/strapi-identity/setup-email" : "/strapi-identity/disable";
1637
+ const response = await fetch(endpoint, {
1638
+ method: "POST",
1639
+ headers: { "Content-Type": "application/json", authorization: `Bearer ${token}` },
1640
+ body: JSON.stringify({ code })
1641
+ });
1642
+ const body = await response.json();
1643
+ if (!response.ok) {
1644
+ throw new Error(body.error || "Invalid or expired code");
1645
+ }
1646
+ handleOpenChange(false);
1647
+ onSuccess();
1648
+ } catch (err) {
1649
+ setError(err.message);
1650
+ } finally {
1651
+ setLoading(false);
1652
+ }
1653
+ };
1654
+ const title = mode === "setup" ? formatMessage({
1655
+ id: getTranslation("email_otp.setup_title"),
1656
+ defaultMessage: "Enable Email OTP"
1657
+ }) : formatMessage({
1658
+ id: getTranslation("email_otp.disable_title"),
1659
+ defaultMessage: "Disable Email OTP"
1660
+ });
1661
+ return /* @__PURE__ */ jsx(Modal.Root, { open, onOpenChange: handleOpenChange, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
1662
+ /* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
1663
+ step === "send" ? /* @__PURE__ */ jsxs(Fragment, { children: [
1664
+ /* @__PURE__ */ jsx(Modal.Body, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "center", gap: 4, marginTop: 4, marginBottom: 4, children: [
1665
+ /* @__PURE__ */ jsx(Typography, { textAlign: "center", children: mode === "setup" ? formatMessage(
1666
+ {
1667
+ id: getTranslation("email_otp.setup_description"),
1668
+ defaultMessage: "We'll send a 6-digit verification code to {email}. Enter it to enable Email OTP."
1669
+ },
1670
+ { email: /* @__PURE__ */ jsx("strong", { children: email }) }
1671
+ ) : formatMessage(
1672
+ {
1673
+ id: getTranslation("email_otp.disable_description"),
1674
+ defaultMessage: "We'll send a 6-digit verification code to {email}. Enter it to disable Email OTP."
1675
+ },
1676
+ { email: /* @__PURE__ */ jsx("strong", { children: email }) }
1677
+ ) }),
1678
+ error ? /* @__PURE__ */ jsx(Typography, { role: "alert", textColor: "danger600", textAlign: "center", children: error }) : null
1679
+ ] }) }),
1680
+ /* @__PURE__ */ jsxs(Modal.Footer, { children: [
1681
+ /* @__PURE__ */ jsx(Modal.Close, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({ id: "app.components.Button.cancel", defaultMessage: "Cancel" }) }) }),
1682
+ /* @__PURE__ */ jsx(Button, { onClick: handleSend, loading, children: formatMessage({
1683
+ id: getTranslation("email_otp.send_code"),
1684
+ defaultMessage: "Send verification email"
1685
+ }) })
1686
+ ] })
1687
+ ] }) : /* @__PURE__ */ jsxs("form", { onSubmit: handleConfirm, children: [
1688
+ /* @__PURE__ */ jsx(Modal.Body, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "center", gap: 4, marginTop: 4, marginBottom: 4, children: [
1689
+ /* @__PURE__ */ jsx(Typography, { textAlign: "center", children: formatMessage(
1690
+ {
1691
+ id: getTranslation("email_otp.confirm_description"),
1692
+ defaultMessage: "Enter the 6-digit code sent to {email}."
1693
+ },
1694
+ { email: /* @__PURE__ */ jsx("strong", { children: email }) }
1695
+ ) }),
1696
+ /* @__PURE__ */ jsxs(InputOTP, { maxLength: 6, name: "otp", id: "otp", autoFocus: true, children: [
1697
+ /* @__PURE__ */ jsxs(InputOTPGroup, { children: [
1698
+ /* @__PURE__ */ jsx(InputOTPSlot, { index: 0 }),
1699
+ /* @__PURE__ */ jsx(InputOTPSlot, { index: 1 }),
1700
+ /* @__PURE__ */ jsx(InputOTPSlot, { index: 2 })
1701
+ ] }),
1702
+ /* @__PURE__ */ jsx(InputOTPSeparator, {}),
1703
+ /* @__PURE__ */ jsxs(InputOTPGroup, { children: [
1704
+ /* @__PURE__ */ jsx(InputOTPSlot, { index: 3 }),
1705
+ /* @__PURE__ */ jsx(InputOTPSlot, { index: 4 }),
1706
+ /* @__PURE__ */ jsx(InputOTPSlot, { index: 5 })
1707
+ ] })
1708
+ ] }),
1709
+ error ? /* @__PURE__ */ jsx(Typography, { role: "alert", textColor: "danger600", textAlign: "center", children: error }) : null,
1710
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", type: "button", onClick: () => handleSend(), children: formatMessage({
1711
+ id: getTranslation("email_otp.resend_code"),
1712
+ defaultMessage: "Resend code"
1713
+ }) })
1714
+ ] }) }),
1715
+ /* @__PURE__ */ jsxs(Modal.Footer, { children: [
1716
+ /* @__PURE__ */ jsx(Modal.Close, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
1717
+ id: "app.components.Button.cancel",
1718
+ defaultMessage: "Cancel"
1719
+ }) }) }),
1720
+ /* @__PURE__ */ jsx(Button, { type: "submit", loading, children: formatMessage({
1721
+ id: "app.components.Button.confirm",
1722
+ defaultMessage: "Confirm"
1723
+ }) })
1724
+ ] })
1725
+ ] })
1726
+ ] }) });
1727
+ }
1728
+ const InjectEnforced = async (app) => {
1729
+ const _router = app.router;
1730
+ while (!_router.router) await new Promise((resolve) => setTimeout(resolve, 10));
1731
+ _router.router.routes?.[0].children?.push({
1732
+ path: "strapi-identity/enforced",
1733
+ element: /* @__PURE__ */ jsx(EnforcedPage, {})
1734
+ });
1735
+ };
1736
+ const EnforcedPage = () => {
1737
+ const { formatMessage } = useIntl();
1738
+ const [loading, setLoading] = useState(true);
1739
+ const [emailConfigured, setEmailConfigured] = useState(false);
1740
+ const [userEmail, setUserEmail] = useState("");
1741
+ const [totpModalOpen, setTotpModalOpen] = useState(false);
1742
+ const [uri, setUri] = useState(null);
1743
+ const [secret, setSecret] = useState(null);
1744
+ const [passcodes, setPasscodes] = useState(null);
1745
+ const [emailModalOpen, setEmailModalOpen] = useState(false);
1746
+ useEffect(() => {
1747
+ const ac = new AbortController();
1748
+ (async () => {
1749
+ const token = getToken();
1750
+ try {
1751
+ const [statusRes, configRes, meRes] = await Promise.all([
1752
+ fetch("/strapi-identity/status", {
1753
+ headers: { authorization: `Bearer ${token}` },
1754
+ signal: ac.signal
1755
+ }),
1756
+ fetch("/strapi-identity/config", {
1757
+ headers: { authorization: `Bearer ${token}` },
1758
+ signal: ac.signal
1759
+ }),
1760
+ fetch("/admin/users/me", {
1761
+ headers: { authorization: `Bearer ${token}` },
1762
+ signal: ac.signal
1763
+ })
1764
+ ]);
1765
+ if (statusRes.ok) {
1766
+ const statusBody = await statusRes.json();
1767
+ if (statusBody.data?.status === "full") {
1768
+ window.location.replace("/admin");
1769
+ return;
1770
+ }
1771
+ }
1772
+ if (configRes.ok) {
1773
+ const configBody = await configRes.json();
1774
+ setEmailConfigured(!!configBody.data?.email_enabled);
1775
+ }
1776
+ if (meRes.ok) {
1777
+ const meBody = await meRes.json();
1778
+ setUserEmail(meBody.data?.email || "");
1779
+ }
1780
+ } catch (error) {
1781
+ if (error.name === "AbortError") return;
1782
+ console.error("Failed to check MFA status:", error);
1783
+ } finally {
1784
+ setLoading(false);
1785
+ }
1786
+ })();
1787
+ return () => ac.abort();
1788
+ }, []);
1789
+ const handleEnableTOTP = async () => {
1790
+ const token = getToken();
1791
+ try {
1792
+ const response = await fetch("/strapi-identity/enable", {
1793
+ method: "POST",
1794
+ headers: { "Content-Type": "application/json", authorization: `Bearer ${token}` },
1795
+ body: JSON.stringify({ enable: true })
1796
+ });
1797
+ const body = await response.json();
1798
+ if (!response.ok) {
1799
+ throw new Error(body.error || "Failed to initiate TOTP setup");
1800
+ }
1801
+ setUri(body.data?.uri || null);
1802
+ setSecret(body.data?.secret || null);
1803
+ setTotpModalOpen(true);
1804
+ } catch (error) {
1805
+ console.error(error);
1806
+ }
1807
+ };
1808
+ const handleConfirmTOTP = async (e) => {
1809
+ e.preventDefault();
1810
+ const formData = new FormData(e.target);
1811
+ const code = formData.get("otp");
1812
+ const token = getToken();
1813
+ try {
1814
+ const response = await fetch("/strapi-identity/setup", {
1815
+ method: "POST",
1816
+ headers: { "Content-Type": "application/json", authorization: `Bearer ${token}` },
1817
+ body: JSON.stringify({ code })
1818
+ });
1819
+ const body = await response.json();
1820
+ if (!response.ok) {
1821
+ throw new Error(body.error || "Failed to set up MFA");
1822
+ }
1823
+ if (body.data?.recoveryCodes) {
1824
+ setPasscodes(body.data.recoveryCodes);
1825
+ } else {
1826
+ window.location.replace("/admin");
1827
+ }
1828
+ setUri(null);
1829
+ setSecret(null);
1830
+ } catch (error) {
1831
+ console.error(error);
1832
+ }
1833
+ };
1834
+ const handleCloseTOTP = () => {
1835
+ if (passcodes) {
1836
+ window.location.replace("/admin");
1837
+ return;
1838
+ }
1839
+ setTotpModalOpen(false);
1840
+ setUri(null);
1841
+ setSecret(null);
1842
+ setPasscodes(null);
1843
+ };
1844
+ if (loading) return null;
1845
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1846
+ /* @__PURE__ */ jsx(Page.Title, { children: formatMessage({
1847
+ id: getTranslation("enforced.page_title"),
1848
+ defaultMessage: "MFA Required"
1849
+ }) }),
1850
+ /* @__PURE__ */ jsxs(Page.Main, { children: [
1851
+ /* @__PURE__ */ jsx(
1852
+ Layouts.Header,
1853
+ {
1854
+ title: formatMessage({
1855
+ id: getTranslation("enforced.title"),
1856
+ defaultMessage: "Multi-Factor Authentication Required"
1857
+ }),
1858
+ subtitle: formatMessage({
1859
+ id: getTranslation("enforced.subtitle"),
1860
+ defaultMessage: "Your administrator requires MFA to be configured before you can access the CMS."
1861
+ })
1862
+ }
1863
+ ),
1864
+ /* @__PURE__ */ jsx(Layouts.Content, { children: /* @__PURE__ */ jsx(
1865
+ Box,
1866
+ {
1867
+ background: "neutral0",
1868
+ hasRadius: true,
1869
+ shadow: "tableShadow",
1870
+ paddingTop: 6,
1871
+ paddingBottom: 6,
1872
+ paddingLeft: 7,
1873
+ paddingRight: 7,
1874
+ children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
1875
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 1, children: [
1876
+ /* @__PURE__ */ jsx(Typography, { variant: "delta", tag: "h2", children: formatMessage({
1877
+ id: getTranslation("enforced.card_title"),
1878
+ defaultMessage: "Set Up Two-Factor Authentication"
1879
+ }) }),
1880
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
1881
+ id: getTranslation("enforced.description"),
1882
+ defaultMessage: "To continue using the CMS, you must enable at least one Multi-Factor Authentication method. Choose an option below to get started."
1883
+ }) })
1884
+ ] }),
1885
+ /* @__PURE__ */ jsxs(Flex, { gap: 3, wrap: "wrap", children: [
1886
+ /* @__PURE__ */ jsx(Button, { size: "L", onClick: handleEnableTOTP, children: formatMessage({
1887
+ id: getTranslation("enforced.setup_totp"),
1888
+ defaultMessage: "Set up Authenticator App"
1889
+ }) }),
1890
+ emailConfigured && /* @__PURE__ */ jsx(Button, { size: "L", variant: "secondary", onClick: () => setEmailModalOpen(true), children: formatMessage({
1891
+ id: getTranslation("enforced.setup_email"),
1892
+ defaultMessage: "Set up Email OTP"
1893
+ }) })
1894
+ ] })
1895
+ ] })
1896
+ }
1897
+ ) })
1898
+ ] }),
1899
+ /* @__PURE__ */ jsx(
1900
+ ConfirmModal,
1901
+ {
1902
+ open: totpModalOpen,
1903
+ onOpenChange: handleCloseTOTP,
1904
+ qrCodeUri: uri,
1905
+ secret,
1906
+ passcodes,
1907
+ onSubmit: handleConfirmTOTP
1908
+ }
1909
+ ),
1910
+ /* @__PURE__ */ jsx(
1911
+ EmailOTPModal,
1912
+ {
1913
+ mode: "setup",
1914
+ open: emailModalOpen,
1915
+ email: userEmail,
1916
+ onOpenChange: (open) => {
1917
+ if (!open) setEmailModalOpen(false);
1918
+ },
1919
+ onSuccess: () => {
1920
+ window.location.replace("/admin");
1921
+ }
1922
+ }
1923
+ )
1924
+ ] });
1925
+ };
1509
1926
  const plugin = {
1510
1927
  register(app) {
1511
1928
  app.registerPlugin({
@@ -1520,12 +1937,9 @@ const plugin = {
1520
1937
  defaultMessage: "Strapi Identity Settings"
1521
1938
  },
1522
1939
  id: "strapi-identity-settings",
1523
- to: `/settings/${PLUGIN_ID}`,
1524
- Component: async () => import("./SettingsPage-7Ytl01jH.mjs"),
1525
- permissions: [
1526
- { action: "plugin::strapi-identity.settings.read" },
1527
- { action: "plugin::strapi-identity.settings.read" }
1528
- ]
1940
+ to: `/${PLUGIN_ID}`,
1941
+ Component: () => import("./SettingsPage-Dm_llkYv.mjs"),
1942
+ permissions: [{ action: "plugin::strapi-identity.settings.update" }]
1529
1943
  });
1530
1944
  app.addMiddlewares([mfaRedirect]);
1531
1945
  const injections = initialiseInjections(app);
@@ -1533,21 +1947,23 @@ const plugin = {
1533
1947
  id: "profile-toggle",
1534
1948
  route: "/admin/me",
1535
1949
  selector: '#main-content form[method="put"] > :nth-child(2) > div > div > div:nth-child(2)',
1536
- Component: async () => import("./ProfileToggle-BCtCsOvj.mjs")
1950
+ Component: () => import("./ProfileToggle-k0d-caPC.mjs")
1537
1951
  });
1538
1952
  injections.registerRoute({
1539
1953
  id: "admin-reset",
1540
1954
  route: "/admin/settings/users/:id",
1541
1955
  selector: '#main-content form[method="put"] > :nth-child(2) > div > div:nth-child(2)',
1542
- Component: async () => import("./AdminReset-B-WGECOX.mjs")
1956
+ permissions: [{ action: "plugin::strapi-identity.settings.update" }],
1957
+ Component: () => import("./AdminReset-DOmsyqwQ.mjs")
1543
1958
  });
1544
1959
  InjectVerify(app);
1960
+ InjectEnforced(app);
1545
1961
  },
1546
1962
  registerTrads({ locales }) {
1547
1963
  return Promise.all(
1548
1964
  locales.map(async (locale) => {
1549
1965
  try {
1550
- const { default: data } = await __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-DwZqj0qM.mjs"), "./translations/ca.json": () => import("./ca-aKVVc8iQ.mjs"), "./translations/cs.json": () => import("./cs--prflMHS.mjs"), "./translations/de.json": () => import("./de-BT25lv_6.mjs"), "./translations/dk.json": () => import("./dk-Ck3AQYU7.mjs"), "./translations/en.json": () => import("./en-9qzlpde0.mjs"), "./translations/es.json": () => import("./es-lh6XoPb7.mjs"), "./translations/eu.json": () => import("./eu-Cuz6ijBX.mjs"), "./translations/fr.json": () => import("./fr-ChlDcZsG.mjs"), "./translations/gu.json": () => import("./gu-B6zyD1bW.mjs"), "./translations/he.json": () => import("./he-C5V-qZCX.mjs"), "./translations/hi.json": () => import("./hi-czhOWo6-.mjs"), "./translations/hu.json": () => import("./hu-NbZ3aiYV.mjs"), "./translations/id.json": () => import("./id-NH9PvcR5.mjs"), "./translations/it.json": () => import("./it-Cmrey6tg.mjs"), "./translations/ja.json": () => import("./ja-DH3KMqOL.mjs"), "./translations/ko.json": () => import("./ko-DPN28RE8.mjs"), "./translations/ml.json": () => import("./ml-MsHNacm6.mjs"), "./translations/ms.json": () => import("./ms-TjHAaxTd.mjs"), "./translations/nl.json": () => import("./nl-BLILZU8-.mjs"), "./translations/no.json": () => import("./no-BtVZ-siy.mjs"), "./translations/pl.json": () => import("./pl-DCSB6LwZ.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-CeLqmj88.mjs"), "./translations/pt.json": () => import("./pt-fgjdOyW5.mjs"), "./translations/ru.json": () => import("./ru-B_hlpAyP.mjs"), "./translations/sa.json": () => import("./sa-BtuJ_I1t.mjs"), "./translations/sk.json": () => import("./sk-mmuTFlCK.mjs"), "./translations/sv.json": () => import("./sv-BlaHc5ax.mjs"), "./translations/th.json": () => import("./th-BwyhFaeE.mjs"), "./translations/tr.json": () => import("./tr-BLocNlbZ.mjs"), "./translations/uk.json": () => import("./uk-CyZ10xtq.mjs"), "./translations/vi.json": () => import("./vi-Bx_UJ8up.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-s7G2GUHU.mjs"), "./translations/zh.json": () => import("./zh-CjJdRa3l.mjs") }), `./translations/${locale}.json`, 3);
1966
+ const { default: data } = await __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-B4yBU4m7.mjs"), "./translations/ca.json": () => import("./ca-DLE8GCgI.mjs"), "./translations/cs.json": () => import("./cs-3kxvJ5GN.mjs"), "./translations/de.json": () => import("./de-BTldhzPN.mjs"), "./translations/dk.json": () => import("./dk-CCNCrmIK.mjs"), "./translations/en.json": () => import("./en-1anycEwN.mjs"), "./translations/es.json": () => import("./es-DMANTUCL.mjs"), "./translations/eu.json": () => import("./eu-BITeCOIE.mjs"), "./translations/fr.json": () => import("./fr-C81x3RP3.mjs"), "./translations/gu.json": () => import("./gu-DDR6O_Dp.mjs"), "./translations/he.json": () => import("./he-TPBr5x3o.mjs"), "./translations/hi.json": () => import("./hi-Pwt1EMiO.mjs"), "./translations/hu.json": () => import("./hu-CTKkJzwl.mjs"), "./translations/id.json": () => import("./id-Bq3jNpUL.mjs"), "./translations/it.json": () => import("./it-CgRQVAPr.mjs"), "./translations/ja.json": () => import("./ja-2xaH1Qf2.mjs"), "./translations/ko.json": () => import("./ko-CGgmfI4W.mjs"), "./translations/ml.json": () => import("./ml-aXIja392.mjs"), "./translations/ms.json": () => import("./ms-CLGR4CKx.mjs"), "./translations/nl.json": () => import("./nl-CGFOqn_t.mjs"), "./translations/no.json": () => import("./no-BIbR3s2A.mjs"), "./translations/pl.json": () => import("./pl-BBEIjPVT.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C0S_4PYn.mjs"), "./translations/pt.json": () => import("./pt-DwDWDT_T.mjs"), "./translations/ru.json": () => import("./ru-DuxM9hFK.mjs"), "./translations/sa.json": () => import("./sa-DfqNZDgh.mjs"), "./translations/sk.json": () => import("./sk-BcYzeG4F.mjs"), "./translations/sv.json": () => import("./sv-CkoFHi6o.mjs"), "./translations/th.json": () => import("./th-C4FBlfLA.mjs"), "./translations/tr.json": () => import("./tr-Djsa55Fh.mjs"), "./translations/uk.json": () => import("./uk-BDoDjhO2.mjs"), "./translations/vi.json": () => import("./vi-D977KjlZ.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-DNgRcEC-.mjs"), "./translations/zh.json": () => import("./zh-CKYKCaVd.mjs") }), `./translations/${locale}.json`, 3);
1551
1967
  const newData = {};
1552
1968
  const keys = Object.keys(data);
1553
1969
  for (const key of keys) {
@@ -1571,10 +1987,13 @@ const mfaRedirect = () => {
1571
1987
  };
1572
1988
  };
1573
1989
  export {
1990
+ ConfirmModal as C,
1991
+ EmailOTPModal as E,
1574
1992
  InputOTP as I,
1575
- InputOTPGroup as a,
1576
- InputOTPSlot as b,
1577
- InputOTPSeparator as c,
1578
- getTranslation as g,
1993
+ getTranslation as a,
1994
+ InputOTPGroup as b,
1995
+ InputOTPSlot as c,
1996
+ InputOTPSeparator as d,
1997
+ getToken as g,
1579
1998
  plugin as p
1580
1999
  };
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
- const index = require("./index-D03zlFnm.js");
3
+ const index = require("./index-B9P8S4CX.js");
4
4
  require("strapi-admin-portal");
5
5
  exports.default = index.plugin;
@@ -1,4 +1,4 @@
1
- import { p } from "./index-BfC6z9N5.mjs";
1
+ import { p } from "./index-DpIJdETG.mjs";
2
2
  import "strapi-admin-portal";
3
3
  export {
4
4
  p as default
@@ -4,6 +4,13 @@ const it = {
4
4
  "admin.title": "Autenticazione a due fattori",
5
5
  "admin.warn-title": "Reimpostare la 2FA per questo utente?",
6
6
  "admin.warning": "La reimpostazione dell'autenticazione a due fattori consentirà all'utente di configurarla nuovamente con un nuovo dispositivo. Questa azione non può essere annullata.",
7
+ "enforced.card_title": "Configura autenticazione a due fattori",
8
+ "enforced.description": "Per continuare a utilizzare il CMS, è necessario abilitare almeno un metodo di autenticazione a più fattori. Scegli un'opzione qui sotto per iniziare.",
9
+ "enforced.page_title": "MFA richiesto",
10
+ "enforced.setup_email": "Configura OTP via email",
11
+ "enforced.setup_totp": "Configura l'app di autenticazione",
12
+ "enforced.subtitle": "L'amministratore richiede che MFA sia configurato prima di poter accedere al CMS.",
13
+ "enforced.title": "Autenticazione a più fattori richiesta",
7
14
  "email_otp.confirm_description": "Inserisci il codice a 6 cifre inviato a {email}.",
8
15
  "email_otp.disable_description": "Invieremo un codice di verifica a 6 cifre a {email}. Inseriscilo per disabilitare Email OTP.",
9
16
  "email_otp.disable_title": "Disabilita Email OTP",
@@ -6,6 +6,13 @@ const it = {
6
6
  "admin.title": "Autenticazione a due fattori",
7
7
  "admin.warn-title": "Reimpostare la 2FA per questo utente?",
8
8
  "admin.warning": "La reimpostazione dell'autenticazione a due fattori consentirà all'utente di configurarla nuovamente con un nuovo dispositivo. Questa azione non può essere annullata.",
9
+ "enforced.card_title": "Configura autenticazione a due fattori",
10
+ "enforced.description": "Per continuare a utilizzare il CMS, è necessario abilitare almeno un metodo di autenticazione a più fattori. Scegli un'opzione qui sotto per iniziare.",
11
+ "enforced.page_title": "MFA richiesto",
12
+ "enforced.setup_email": "Configura OTP via email",
13
+ "enforced.setup_totp": "Configura l'app di autenticazione",
14
+ "enforced.subtitle": "L'amministratore richiede che MFA sia configurato prima di poter accedere al CMS.",
15
+ "enforced.title": "Autenticazione a più fattori richiesta",
9
16
  "email_otp.confirm_description": "Inserisci il codice a 6 cifre inviato a {email}.",
10
17
  "email_otp.disable_description": "Invieremo un codice di verifica a 6 cifre a {email}. Inseriscilo per disabilitare Email OTP.",
11
18
  "email_otp.disable_title": "Disabilita Email OTP",
@@ -6,6 +6,13 @@ const ja = {
6
6
  "admin.title": "二要素認証",
7
7
  "admin.warn-title": "このユーザーの2FAをリセットしますか?",
8
8
  "admin.warning": "二要素認証をリセットすると、ユーザーは新しいデバイスで再設定できるようになります。この操作は元に戻せません。",
9
+ "enforced.card_title": "二要素認証を設定する",
10
+ "enforced.description": "CMSの使用を続けるには、少なくとも1つの多要素認証方法を有効にする必要があります。開始するには以下のオプションを選択してください。",
11
+ "enforced.page_title": "MFAが必要です",
12
+ "enforced.setup_email": "メールOTPを設定する",
13
+ "enforced.setup_totp": "認証アプリを設定する",
14
+ "enforced.subtitle": "CMSにアクセスするには、管理者がMFAを設定するよう求めています。",
15
+ "enforced.title": "多要素認証が必要です",
9
16
  "email_otp.confirm_description": "{email} に送信された6桁のコードを入力してください。",
10
17
  "email_otp.disable_description": "{email} に6桁の確認コードを送信します。Email OTPを無効にするには入力してください。",
11
18
  "email_otp.disable_title": "Email OTPを無効にする",
@@ -4,6 +4,13 @@ const ja = {
4
4
  "admin.title": "二要素認証",
5
5
  "admin.warn-title": "このユーザーの2FAをリセットしますか?",
6
6
  "admin.warning": "二要素認証をリセットすると、ユーザーは新しいデバイスで再設定できるようになります。この操作は元に戻せません。",
7
+ "enforced.card_title": "二要素認証を設定する",
8
+ "enforced.description": "CMSの使用を続けるには、少なくとも1つの多要素認証方法を有効にする必要があります。開始するには以下のオプションを選択してください。",
9
+ "enforced.page_title": "MFAが必要です",
10
+ "enforced.setup_email": "メールOTPを設定する",
11
+ "enforced.setup_totp": "認証アプリを設定する",
12
+ "enforced.subtitle": "CMSにアクセスするには、管理者がMFAを設定するよう求めています。",
13
+ "enforced.title": "多要素認証が必要です",
7
14
  "email_otp.confirm_description": "{email} に送信された6桁のコードを入力してください。",
8
15
  "email_otp.disable_description": "{email} に6桁の確認コードを送信します。Email OTPを無効にするには入力してください。",
9
16
  "email_otp.disable_title": "Email OTPを無効にする",
@@ -4,6 +4,13 @@ const ko = {
4
4
  "admin.title": "2단계 인증",
5
5
  "admin.warn-title": "이 사용자의 2FA를 초기화하시겠습니까?",
6
6
  "admin.warning": "2단계 인증을 초기화하면 사용자가 새 기기로 다시 설정할 수 있습니다. 이 작업은 되돌릴 수 없습니다.",
7
+ "enforced.card_title": "2단계 인증 설정",
8
+ "enforced.description": "CMS를 계속 사용하려면 적어도 하나의 다중 요소 인증 방법을 활성화해야 합니다. 시작하려면 아래에서 옵션을 선택하세요.",
9
+ "enforced.page_title": "MFA 필요",
10
+ "enforced.setup_email": "이메일 OTP 설정",
11
+ "enforced.setup_totp": "인증 앱 설정",
12
+ "enforced.subtitle": "관리자는 CMS에 액세스하기 전에 MFA를 설정하도록 요구합니다.",
13
+ "enforced.title": "다중 요소 인증 필요",
7
14
  "email_otp.confirm_description": "{email}로 전송된 6자리 코드를 입력하세요.",
8
15
  "email_otp.disable_description": "{email}로 6자리 인증 코드를 전송합니다. Email OTP를 비활성화하려면 입력하세요.",
9
16
  "email_otp.disable_title": "Email OTP 비활성화",
@@ -6,6 +6,13 @@ const ko = {
6
6
  "admin.title": "2단계 인증",
7
7
  "admin.warn-title": "이 사용자의 2FA를 초기화하시겠습니까?",
8
8
  "admin.warning": "2단계 인증을 초기화하면 사용자가 새 기기로 다시 설정할 수 있습니다. 이 작업은 되돌릴 수 없습니다.",
9
+ "enforced.card_title": "2단계 인증 설정",
10
+ "enforced.description": "CMS를 계속 사용하려면 적어도 하나의 다중 요소 인증 방법을 활성화해야 합니다. 시작하려면 아래에서 옵션을 선택하세요.",
11
+ "enforced.page_title": "MFA 필요",
12
+ "enforced.setup_email": "이메일 OTP 설정",
13
+ "enforced.setup_totp": "인증 앱 설정",
14
+ "enforced.subtitle": "관리자는 CMS에 액세스하기 전에 MFA를 설정하도록 요구합니다.",
15
+ "enforced.title": "다중 요소 인증 필요",
9
16
  "email_otp.confirm_description": "{email}로 전송된 6자리 코드를 입력하세요.",
10
17
  "email_otp.disable_description": "{email}로 6자리 인증 코드를 전송합니다. Email OTP를 비활성화하려면 입력하세요.",
11
18
  "email_otp.disable_title": "Email OTP 비활성화",