@forge-connect/react 1.0.1 → 1.0.3
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/dist/index.cjs +1639 -1593
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +1655 -1609
- package/dist/index.js.map +1 -1
- package/package.json +1 -5
package/dist/index.cjs
CHANGED
|
@@ -813,1680 +813,1692 @@ function EmailOtpForm() {
|
|
|
813
813
|
// src/components/tabs/wallet-connect.tsx
|
|
814
814
|
|
|
815
815
|
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
816
|
+
var MOBILE_WALLETS = [
|
|
817
|
+
{
|
|
818
|
+
name: "Phantom",
|
|
819
|
+
icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTA4IiBoZWlnaHQ9IjEwOCIgdmlld0JveD0iMCAwIDEwOCAxMDgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxMDgiIGhlaWdodD0iMTA4IiByeD0iMjYiIGZpbGw9IiNBQjlGRjIiLz4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik00Ni41MjY3IDY5LjkyMjlDNDIuMDA1NCA3Ni44NTA5IDM0LjQyOTIgODUuNjE4MiAyNC4zNDggODUuNjE4MkMxOS41ODI0IDg1LjYxODIgMTUgODMuNjU2MyAxNSA3NS4xMzQyQzE1IDUzLjQzMDUgNDQuNjMyNiAxOS44MzI3IDcyLjEyNjggMTkuODMyN0M4Ny43NjggMTkuODMyNyA5NCAzMC42ODQ2IDk0IDQzLjAwNzlDOTQgNTguODI1OCA4My43MzU1IDc2LjkxMjIgNzMuNTMyMSA3Ni45MTIyQzcwLjI5MzkgNzYuOTEyMiA2OC43MDUzIDc1LjEzNDIgNjguNzA1MyA3Mi4zMTRDNjguNzA1MyA3MS41NzgzIDY4LjgyNzUgNzAuNzgxMiA2OS4wNzE5IDY5LjkyMjlDNjUuNTg5MyA3NS44Njk5IDU4Ljg2ODUgODEuMzg3OCA1Mi41NzU0IDgxLjM4NzhDNDcuOTkzIDgxLjM4NzggNDUuNjcxMyA3OC41MDYzIDQ1LjY3MTMgNzQuNDU5OEM0NS42NzEzIDcyLjk4ODQgNDUuOTc2OCA3MS40NTU2IDQ2LjUyNjcgNjkuOTIyOVpNODMuNjc2MSA0Mi41Nzk0QzgzLjY3NjEgNDYuMTcwNCA4MS41NTc1IDQ3Ljk2NTggNzkuMTg3NSA0Ny45NjU4Qzc2Ljc4MTYgNDcuOTY1OCA3NC42OTg5IDQ2LjE3MDQgNzQuNjk4OSA0Mi41Nzk0Qzc0LjY5ODkgMzguOTg4NSA3Ni43ODE2IDM3LjE5MzEgNzkuMTg3NSAzNy4xOTMxQzgxLjU1NzUgMzcuMTkzMSA4My42NzYxIDM4Ljk4ODUgODMuNjc2MSA0Mi41Nzk0Wk03MC4yMTAzIDQyLjU3OTVDNzAuMjEwMyA0Ni4xNzA0IDY4LjA5MTYgNDcuOTY1OCA2NS43MjE2IDQ3Ljk2NThDNjMuMzE1NyA0Ny45NjU4IDYxLjIzMyA0Ni4xNzA0IDYxLjIzMyA0Mi41Nzk1QzYxLjIzMyAzOC45ODg1IDYzLjMxNTcgMzcuMTkzMSA2NS43MjE2IDM3LjE5MzFDNjguMDkxNiAzNy4xOTMxIDcwLjIxMDMgMzguOTg4NSA3MC4yMTAzIDQyLjU3OTVaIiBmaWxsPSIjRkZGREY4Ii8+Cjwvc3ZnPgo=",
|
|
820
|
+
buildUrl: (url) => `https://phantom.app/ul/browse/${encodeURIComponent(url)}?ref=${encodeURIComponent(url)}`
|
|
821
|
+
},
|
|
822
|
+
{
|
|
823
|
+
name: "Solflare",
|
|
824
|
+
icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIGlkPSJTIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MCA1MCI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOiMwMjA1MGE7c3Ryb2tlOiNmZmVmNDY7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLXdpZHRoOi41cHg7fS5jbHMtMntmaWxsOiNmZmVmNDY7fTwvc3R5bGU+PC9kZWZzPjxyZWN0IGNsYXNzPSJjbHMtMiIgeD0iMCIgd2lkdGg9IjUwIiBoZWlnaHQ9IjUwIiByeD0iMTIiIHJ5PSIxMiIvPjxwYXRoIGNsYXNzPSJjbHMtMSIgZD0iTTI0LjIzLDI2LjQybDIuNDYtMi4zOCw0LjU5LDEuNWMzLjAxLDEsNC41MSwyLjg0LDQuNTEsNS40MywwLDEuOTYtLjc1LDMuMjYtMi4yNSw0LjkzbC0uNDYuNS4xNy0xLjE3Yy42Ny00LjI2LS41OC02LjA5LTQuNzItNy40M2wtNC4zLTEuMzhoMFpNMTguMDUsMTEuODVsMTIuNTIsNC4xNy0yLjcxLDIuNTktNi41MS0yLjE3Yy0yLjI1LS43NS0zLjAxLTEuOTYtMy4zLTQuNTF2LS4wOGgwWk0xNy4zLDMzLjA2bDIuODQtMi43MSw1LjM0LDEuNzVjMi44LjkyLDMuNzYsMi4xMywzLjQ2LDUuMThsLTExLjY1LTQuMjJoMFpNMTMuNzEsMjAuOTVjMC0uNzkuNDItMS41NCwxLjEzLTIuMTcuNzUsMS4wOSwyLjA1LDIuMDUsNC4wOSwyLjcxbDQuNDIsMS40Ni0yLjQ2LDIuMzgtNC4zNC0xLjQyYy0yLS42Ny0yLjg0LTEuNjctMi44NC0yLjk2TTI2LjgyLDQyLjg3YzkuMTgtNi4wOSwxNC4xMS0xMC4yMywxNC4xMS0xNS4zMiwwLTMuMzgtMi01LjI2LTYuNDMtNi43MmwtMy4zNC0xLjEzLDkuMTQtOC43Ny0xLjg0LTEuOTYtMi43MSwyLjM4LTEyLjgxLTQuMjJjLTMuOTcsMS4yOS04Ljk3LDUuMDktOC45Nyw4Ljg5LDAsLjQyLjA0LjgzLjE3LDEuMjktMy4zLDEuODgtNC42MywzLjYzLTQuNjMsNS44LDAsMi4wNSwxLjA5LDQuMDksNC41NSw1LjIybDIuNzUuOTItOS41Miw5LjE0LDEuODQsMS45NiwyLjk2LTIuNzEsMTQuNzMsNS4yMmgwWiIvPjwvc3ZnPg==",
|
|
825
|
+
buildUrl: (url) => `https://solflare.com/ul/v1/browse/${encodeURIComponent(url)}?ref=${encodeURIComponent(url)}`
|
|
826
|
+
},
|
|
827
|
+
{
|
|
828
|
+
name: "Backpack",
|
|
829
|
+
icon: "data:image/webp;base64,UklGRlgCAABXRUJQVlA4WAoAAAAQAAAAOwAAOwAAQUxQSC8AAAABL6CmbQOGP75e/cti0oiIOI0KBto2+a8ACZjAAQ7wL2gCSCL6PwER2t+KmZpFDwBWUDggAgIAAPALAJ0BKjwAPAA+SSCMRKKiIRYKrTQoBISyAGp7nL12mKuwHiZ/pX71XoA8m7rXfQA8q39lfhJ/cL0ZimIeNSGxOaSWtqEDDdJ++ARG5/LVm6OquItoAu4rpz8VksUr1NEDJ0CeZucwAP7+VdYX7J5e8V3cJZ9QoY9vj8KsNGOvZSm+khDZOvwCeiDFjGweq/8KIUmVQk3T/qW3ONyMcepN2uwyEXpZZiidST0x705r7ZnNuWX42r8oi+FEshvXGWm6DabjfrMbiaxJ15irl2Gj3nKWbZ2v3k/jd172plSBejBs7dNt90Re/m+nmv5kNjM/SPfa4EpzvOdu/8BR+hTnR4qe4eWhTsh/oecEfN31OExdi/6AYrsth4nlx/qGEP70b1/TNKmgaB/18+c9ntTfhku9wYpy17/wN3r+B/1geZPzth+AtNsMDXE99PaPLWdFP9MOIMD6ME+MpZu2H7WSfzY7MkWs/N/NNzAZ0P/9vMvxgcdzFHvs/doeUU9WyVv+Ll8QDJbn9NZl86ZZNYtfP4Ol1hiJHWosWyj/66vhMUeFIcDheXIOSRTzvKwj5ffEl7fn/QwflNU556SEjM8MriwSFJ/nrFBrr8O1/pqdrYGqPijG6tjsBVBHp+EDAbtNLL375I2jnG9i3Xb1ZphsFYNjdRaknYdFf4g5iJBoAAA=",
|
|
830
|
+
buildUrl: (url) => `https://backpack.app/ul/browse/${encodeURIComponent(url)}`
|
|
822
831
|
}
|
|
823
|
-
|
|
824
|
-
|
|
832
|
+
];
|
|
833
|
+
function isMobile() {
|
|
834
|
+
if (typeof navigator === "undefined") return false;
|
|
835
|
+
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
|
825
836
|
}
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
const
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
const binary = atob(padded);
|
|
833
|
-
const buffer = new ArrayBuffer(binary.length);
|
|
834
|
-
const bytes = new Uint8Array(buffer);
|
|
835
|
-
for (let i = 0; i < binary.length; i++) {
|
|
836
|
-
bytes[i] = binary.charCodeAt(i);
|
|
837
|
+
function WalletConnectForm() {
|
|
838
|
+
const { walletAdapter, setModalStep, config } = useForgeConnect();
|
|
839
|
+
const methods = resolveLoginMethods(config);
|
|
840
|
+
const showBack = methods.length > 1;
|
|
841
|
+
if (!walletAdapter && isMobile()) {
|
|
842
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, MobileWalletFlow, {});
|
|
837
843
|
}
|
|
838
|
-
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
+
if (walletAdapter) {
|
|
845
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, WalletAdapterFlow, {});
|
|
846
|
+
}
|
|
847
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-tab", children: [
|
|
848
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { className: "fc-tab-title", children: "Connect wallet" }),
|
|
849
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "fc-text", children: [
|
|
850
|
+
"No wallet adapter detected. Pass ",
|
|
851
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "code", { children: "walletAdapter" }),
|
|
852
|
+
" to",
|
|
853
|
+
" ",
|
|
854
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "code", { children: "<ForgeConnectProvider>" }),
|
|
855
|
+
" to enable wallet login."
|
|
856
|
+
] }),
|
|
857
|
+
showBack && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-switch", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "fc-link", onClick: () => setModalStep("method-select"), children: "Back" }) })
|
|
858
|
+
] });
|
|
844
859
|
}
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
const
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
860
|
+
function MobileWalletFlow() {
|
|
861
|
+
const { setModalStep, config } = useForgeConnect();
|
|
862
|
+
const methods = resolveLoginMethods(config);
|
|
863
|
+
const showBack = methods.length > 1;
|
|
864
|
+
const walletConfig = config.walletConfig;
|
|
865
|
+
const preferred = _nullishCoalesce(_optionalChain([walletConfig, 'optionalAccess', _13 => _13.preferredWallets]), () => ( []));
|
|
866
|
+
const onlyPreferred = _nullishCoalesce(_optionalChain([walletConfig, 'optionalAccess', _14 => _14.onlyPreferred]), () => ( false));
|
|
867
|
+
const walletsToShow = _react.useMemo.call(void 0, () => {
|
|
868
|
+
if (preferred.length > 0) {
|
|
869
|
+
const prefList = preferred.map((name) => MOBILE_WALLETS.find((mw) => mw.name === name)).filter(Boolean);
|
|
870
|
+
if (onlyPreferred) return prefList;
|
|
871
|
+
const prefNames = new Set(preferred);
|
|
872
|
+
const others = MOBILE_WALLETS.filter((mw) => !prefNames.has(mw.name));
|
|
873
|
+
return [...prefList, ...others];
|
|
874
|
+
}
|
|
875
|
+
return MOBILE_WALLETS;
|
|
876
|
+
}, [preferred, onlyPreferred]);
|
|
877
|
+
const handleOpen = (mw) => {
|
|
878
|
+
const pageUrl = window.location.href;
|
|
879
|
+
window.location.href = mw.buildUrl(pageUrl);
|
|
861
880
|
};
|
|
881
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-tab", children: [
|
|
882
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-wallet-list", children: walletsToShow.map((mw) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
883
|
+
"button",
|
|
884
|
+
{
|
|
885
|
+
type: "button",
|
|
886
|
+
className: "fc-btn fc-btn-wallet",
|
|
887
|
+
onClick: () => handleOpen(mw),
|
|
888
|
+
children: [
|
|
889
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { style: { position: "relative", display: "inline-flex" }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { src: mw.icon, alt: "", className: "fc-wallet-icon" }) }),
|
|
890
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-wallet-name", children: mw.name }),
|
|
891
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-badge-preferred", children: "Open app" })
|
|
892
|
+
]
|
|
893
|
+
},
|
|
894
|
+
mw.name
|
|
895
|
+
)) }),
|
|
896
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-text", style: { textAlign: "center", fontSize: 12, opacity: 0.6 }, children: "You'll be redirected to the wallet app to sign in." }),
|
|
897
|
+
showBack && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-switch", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "fc-link", onClick: () => setModalStep("method-select"), children: "Back" }) })
|
|
898
|
+
] });
|
|
862
899
|
}
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
);
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
};
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
});
|
|
900
|
+
function WalletAdapterFlow() {
|
|
901
|
+
const { walletAdapter, loginWithWallet, setModalStep, config } = useForgeConnect();
|
|
902
|
+
const wallet = walletAdapter;
|
|
903
|
+
const walletConfig = config.walletConfig;
|
|
904
|
+
const methods = resolveLoginMethods(config);
|
|
905
|
+
const showBack = methods.length > 1;
|
|
906
|
+
const [error, setError] = _react.useState.call(void 0, "");
|
|
907
|
+
const [loading, setLoading] = _react.useState.call(void 0, false);
|
|
908
|
+
const [showOther, setShowOther] = _react.useState.call(void 0, false);
|
|
909
|
+
const [coldWallet, setColdWallet] = _react.useState.call(void 0, false);
|
|
910
|
+
const mobile = _react.useMemo.call(void 0, () => isMobile(), []);
|
|
911
|
+
const coldWalletRef = _react.useRef.call(void 0, coldWallet);
|
|
912
|
+
coldWalletRef.current = coldWallet;
|
|
913
|
+
const buildSignTxFnForAdapter = _react.useCallback.call(void 0, (adapter) => {
|
|
914
|
+
if (!adapter.signTransaction) return void 0;
|
|
915
|
+
const TxClass = _optionalChain([walletConfig, 'optionalAccess', _15 => _15.Transaction]);
|
|
916
|
+
if (!TxClass) return void 0;
|
|
917
|
+
return async (txBase64) => {
|
|
918
|
+
const bytes = Uint8Array.from(atob(txBase64), (c) => c.charCodeAt(0));
|
|
919
|
+
const tx = TxClass.from(bytes);
|
|
920
|
+
const signedTx = await adapter.signTransaction(tx);
|
|
921
|
+
return btoa(String.fromCharCode(...new Uint8Array(signedTx.serialize())));
|
|
922
|
+
};
|
|
923
|
+
}, [_optionalChain([walletConfig, 'optionalAccess', _16 => _16.Transaction])]);
|
|
924
|
+
const handleConnect = async (w) => {
|
|
925
|
+
if (w.readyState !== "Installed") {
|
|
926
|
+
if (mobile) {
|
|
927
|
+
const mw = MOBILE_WALLETS.find((m) => m.name === w.adapter.name);
|
|
928
|
+
if (mw) {
|
|
929
|
+
window.location.href = mw.buildUrl(window.location.href);
|
|
930
|
+
return;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
const url = w.adapter.url;
|
|
934
|
+
if (url) window.open(url, "_blank");
|
|
935
|
+
return;
|
|
900
936
|
}
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
cause: error
|
|
922
|
-
});
|
|
937
|
+
setError("");
|
|
938
|
+
setLoading(true);
|
|
939
|
+
try {
|
|
940
|
+
if (!w.adapter.connected) {
|
|
941
|
+
await w.adapter.connect();
|
|
942
|
+
}
|
|
943
|
+
const pk = w.adapter.publicKey;
|
|
944
|
+
if (!pk) throw new Error("Wallet did not provide a public key.");
|
|
945
|
+
const address = pk.toBase58();
|
|
946
|
+
const useCold = coldWalletRef.current;
|
|
947
|
+
const adapterSignMessage = w.adapter.signMessage ? (msg) => w.adapter.signMessage(msg) : void 0;
|
|
948
|
+
await loginWithWallet(
|
|
949
|
+
address,
|
|
950
|
+
useCold ? void 0 : adapterSignMessage,
|
|
951
|
+
"solana",
|
|
952
|
+
useCold ? buildSignTxFnForAdapter(w.adapter) : void 0
|
|
953
|
+
);
|
|
954
|
+
} catch (err) {
|
|
955
|
+
setError(err instanceof Error ? err.message : "Could not verify your wallet. Please try again.");
|
|
956
|
+
setLoading(false);
|
|
923
957
|
}
|
|
924
|
-
}
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
const validPubKeyCredParams = publicKey.pubKeyCredParams.filter((param) => param.type === "public-key");
|
|
938
|
-
if (validPubKeyCredParams.length === 0) {
|
|
939
|
-
return new WebAuthnError({
|
|
940
|
-
message: 'No entry in pubKeyCredParams was of type "public-key"',
|
|
941
|
-
code: "ERROR_MALFORMED_PUBKEYCREDPARAMS",
|
|
942
|
-
cause: error
|
|
943
|
-
});
|
|
958
|
+
};
|
|
959
|
+
const handleMobileOpen = (mw) => {
|
|
960
|
+
window.location.href = mw.buildUrl(window.location.href);
|
|
961
|
+
};
|
|
962
|
+
const preferred = _nullishCoalesce(_optionalChain([walletConfig, 'optionalAccess', _17 => _17.preferredWallets]), () => ( []));
|
|
963
|
+
const onlyPreferred = _nullishCoalesce(_optionalChain([walletConfig, 'optionalAccess', _18 => _18.onlyPreferred]), () => ( false));
|
|
964
|
+
const preferredSet = new Set(preferred);
|
|
965
|
+
const connectedWalletName = wallet.publicKey ? _nullishCoalesce(_optionalChain([wallet, 'access', _19 => _19.wallets, 'access', _20 => _20.find, 'call', _21 => _21((w) => w.adapter.connected), 'optionalAccess', _22 => _22.adapter, 'access', _23 => _23.name]), () => ( null)) : null;
|
|
966
|
+
const { preferredWallets, otherWallets } = _react.useMemo.call(void 0, () => {
|
|
967
|
+
const all = wallet.wallets;
|
|
968
|
+
const prefList = preferred.map((name) => all.find((w) => w.adapter.name === name)).filter(Boolean);
|
|
969
|
+
if (onlyPreferred && preferred.length > 0) {
|
|
970
|
+
return { preferredWallets: prefList, otherWallets: [] };
|
|
944
971
|
}
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
})
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
972
|
+
const others = all.filter(
|
|
973
|
+
(w) => !preferredSet.has(w.adapter.name) && w.readyState === "Installed"
|
|
974
|
+
);
|
|
975
|
+
return { preferredWallets: prefList, otherWallets: others };
|
|
976
|
+
}, [wallet.wallets, walletConfig]);
|
|
977
|
+
const mobileExtraWallets = _react.useMemo.call(void 0, () => {
|
|
978
|
+
if (!mobile) return [];
|
|
979
|
+
const adapterNames = new Set(wallet.wallets.map((w) => w.adapter.name));
|
|
980
|
+
return MOBILE_WALLETS.filter((mw) => !adapterNames.has(mw.name));
|
|
981
|
+
}, [mobile, wallet.wallets]);
|
|
982
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-tab", children: [
|
|
983
|
+
loading ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: { textAlign: "center", padding: "24px 0" }, children: [
|
|
984
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-tab-title", children: "Connecting..." }),
|
|
985
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-text", children: coldWallet ? "Confirm the transaction on your device" : "Approve the connection, then sign the verification request in your wallet" }),
|
|
986
|
+
error && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
987
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-error", children: error }),
|
|
988
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
989
|
+
"button",
|
|
990
|
+
{
|
|
991
|
+
type: "button",
|
|
992
|
+
className: "fc-btn fc-btn-secondary",
|
|
993
|
+
onClick: () => {
|
|
994
|
+
setLoading(false);
|
|
995
|
+
setError("");
|
|
996
|
+
},
|
|
997
|
+
style: { marginTop: 8 },
|
|
998
|
+
children: "Try again"
|
|
999
|
+
}
|
|
1000
|
+
)
|
|
1001
|
+
] })
|
|
1002
|
+
] }) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
1003
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-wallet-list", children: [
|
|
1004
|
+
preferredWallets.map((w) => {
|
|
1005
|
+
const installed = w.readyState === "Installed";
|
|
1006
|
+
const isConnected = w.adapter.name === connectedWalletName;
|
|
1007
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1008
|
+
"button",
|
|
1009
|
+
{
|
|
1010
|
+
type: "button",
|
|
1011
|
+
className: "fc-btn fc-btn-wallet",
|
|
1012
|
+
onClick: () => handleConnect(w),
|
|
1013
|
+
children: [
|
|
1014
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: installed ? "fc-installed-dot" : "", style: { position: "relative", display: "inline-flex" }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { src: w.adapter.icon, alt: "", className: "fc-wallet-icon" }) }),
|
|
1015
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-wallet-name", children: w.adapter.name }),
|
|
1016
|
+
isConnected ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-badge-preferred", children: "Last used" }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-badge-preferred", children: "Preferred" }),
|
|
1017
|
+
!installed && mobile && MOBILE_WALLETS.some((mw) => mw.name === w.adapter.name) ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-badge-install", children: "Open app" }) : !installed && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-badge-install", children: "Install" })
|
|
1018
|
+
]
|
|
1019
|
+
},
|
|
1020
|
+
w.adapter.name
|
|
1021
|
+
);
|
|
1022
|
+
}),
|
|
1023
|
+
mobileExtraWallets.map((mw) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1024
|
+
"button",
|
|
1025
|
+
{
|
|
1026
|
+
type: "button",
|
|
1027
|
+
className: "fc-btn fc-btn-wallet",
|
|
1028
|
+
onClick: () => handleMobileOpen(mw),
|
|
1029
|
+
children: [
|
|
1030
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { style: { position: "relative", display: "inline-flex" }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { src: mw.icon, alt: "", className: "fc-wallet-icon" }) }),
|
|
1031
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-wallet-name", children: mw.name }),
|
|
1032
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-badge-install", children: "Open app" })
|
|
1033
|
+
]
|
|
1034
|
+
},
|
|
1035
|
+
mw.name
|
|
1036
|
+
)),
|
|
1037
|
+
otherWallets.length > 0 && !showOther && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1038
|
+
"button",
|
|
1039
|
+
{
|
|
1040
|
+
type: "button",
|
|
1041
|
+
className: "fc-btn fc-btn-wallet",
|
|
1042
|
+
onClick: () => setShowOther(true),
|
|
1043
|
+
children: [
|
|
1044
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-other-wallets-icon", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: [
|
|
1045
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "rect", { x: "2", y: "3", width: "16", height: "14", rx: "2", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
1046
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M2 7h16", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
1047
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "rect", { x: "11", y: "10", width: "7", height: "4", rx: "1", stroke: "currentColor", strokeWidth: "1.5" })
|
|
1048
|
+
] }) }),
|
|
1049
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-wallet-name", children: "Other wallets" })
|
|
1050
|
+
]
|
|
1051
|
+
}
|
|
1052
|
+
),
|
|
1053
|
+
showOther && otherWallets.map((w) => {
|
|
1054
|
+
const isConnected = w.adapter.name === connectedWalletName;
|
|
1055
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1056
|
+
"button",
|
|
1057
|
+
{
|
|
1058
|
+
type: "button",
|
|
1059
|
+
className: "fc-btn fc-btn-wallet",
|
|
1060
|
+
onClick: () => handleConnect(w),
|
|
1061
|
+
children: [
|
|
1062
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-installed-dot", style: { position: "relative", display: "inline-flex" }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { src: w.adapter.icon, alt: "", className: "fc-wallet-icon" }) }),
|
|
1063
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-wallet-name", children: w.adapter.name }),
|
|
1064
|
+
isConnected && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-badge-preferred", children: "Last used" })
|
|
1065
|
+
]
|
|
1066
|
+
},
|
|
1067
|
+
w.adapter.name
|
|
1068
|
+
);
|
|
1069
|
+
})
|
|
1070
|
+
] }),
|
|
1071
|
+
preferredWallets.length === 0 && otherWallets.length === 0 && mobileExtraWallets.length === 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-text", children: "No wallet found. Please install a Solana wallet (like Phantom) to continue." }),
|
|
1072
|
+
_optionalChain([walletConfig, 'optionalAccess', _24 => _24.Transaction]) && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { className: "fc-cold-wallet-toggle", children: [
|
|
1073
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1074
|
+
"input",
|
|
1075
|
+
{
|
|
1076
|
+
type: "checkbox",
|
|
1077
|
+
checked: coldWallet,
|
|
1078
|
+
onChange: (e) => setColdWallet(e.target.checked)
|
|
1079
|
+
}
|
|
1080
|
+
),
|
|
1081
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-toggle-track" }),
|
|
1082
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "fc-cold-wallet-label", children: [
|
|
1083
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "Hardware wallet" }),
|
|
1084
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "Ledger, Trezor, Keystone..." })
|
|
1085
|
+
] })
|
|
1086
|
+
] }),
|
|
1087
|
+
error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-error", children: error })
|
|
1088
|
+
] }),
|
|
1089
|
+
showBack && !loading && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-switch", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "fc-link", onClick: () => setModalStep("method-select"), children: "Back" }) })
|
|
1090
|
+
] });
|
|
981
1091
|
}
|
|
982
1092
|
|
|
983
|
-
//
|
|
984
|
-
var BaseWebAuthnAbortService = class {
|
|
985
|
-
constructor() {
|
|
986
|
-
Object.defineProperty(this, "controller", {
|
|
987
|
-
enumerable: true,
|
|
988
|
-
configurable: true,
|
|
989
|
-
writable: true,
|
|
990
|
-
value: void 0
|
|
991
|
-
});
|
|
992
|
-
}
|
|
993
|
-
createNewAbortSignal() {
|
|
994
|
-
if (this.controller) {
|
|
995
|
-
const abortError = new Error("Cancelling existing WebAuthn API call for new one");
|
|
996
|
-
abortError.name = "AbortError";
|
|
997
|
-
this.controller.abort(abortError);
|
|
998
|
-
}
|
|
999
|
-
const newController = new AbortController();
|
|
1000
|
-
this.controller = newController;
|
|
1001
|
-
return newController.signal;
|
|
1002
|
-
}
|
|
1003
|
-
cancelCeremony() {
|
|
1004
|
-
if (this.controller) {
|
|
1005
|
-
const abortError = new Error("Manually cancelling existing WebAuthn API call");
|
|
1006
|
-
abortError.name = "AbortError";
|
|
1007
|
-
this.controller.abort(abortError);
|
|
1008
|
-
this.controller = void 0;
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1011
|
-
};
|
|
1012
|
-
var WebAuthnAbortService = new BaseWebAuthnAbortService();
|
|
1093
|
+
// src/components/tabs/forgot-password.tsx
|
|
1013
1094
|
|
|
1014
|
-
// ../../node_modules/.pnpm/@simplewebauthn+browser@13.2.2/node_modules/@simplewebauthn/browser/esm/helpers/toAuthenticatorAttachment.js
|
|
1015
|
-
var attachments = ["cross-platform", "platform"];
|
|
1016
|
-
function toAuthenticatorAttachment(attachment) {
|
|
1017
|
-
if (!attachment) {
|
|
1018
|
-
return;
|
|
1019
|
-
}
|
|
1020
|
-
if (attachments.indexOf(attachment) < 0) {
|
|
1021
|
-
return;
|
|
1022
|
-
}
|
|
1023
|
-
return attachment;
|
|
1024
|
-
}
|
|
1025
1095
|
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
const
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
challenge: base64URLStringToBuffer(optionsJSON.challenge),
|
|
1039
|
-
user: {
|
|
1040
|
-
...optionsJSON.user,
|
|
1041
|
-
id: base64URLStringToBuffer(optionsJSON.user.id)
|
|
1042
|
-
},
|
|
1043
|
-
excludeCredentials: _optionalChain([optionsJSON, 'access', _20 => _20.excludeCredentials, 'optionalAccess', _21 => _21.map, 'call', _22 => _22(toPublicKeyCredentialDescriptor)])
|
|
1044
|
-
};
|
|
1045
|
-
const createOptions = {};
|
|
1046
|
-
if (useAutoRegister) {
|
|
1047
|
-
createOptions.mediation = "conditional";
|
|
1048
|
-
}
|
|
1049
|
-
createOptions.publicKey = publicKey;
|
|
1050
|
-
createOptions.signal = WebAuthnAbortService.createNewAbortSignal();
|
|
1051
|
-
let credential;
|
|
1052
|
-
try {
|
|
1053
|
-
credential = await navigator.credentials.create(createOptions);
|
|
1054
|
-
} catch (err) {
|
|
1055
|
-
throw identifyRegistrationError({ error: err, options: createOptions });
|
|
1056
|
-
}
|
|
1057
|
-
if (!credential) {
|
|
1058
|
-
throw new Error("Registration was not completed");
|
|
1059
|
-
}
|
|
1060
|
-
const { id, rawId, response, type } = credential;
|
|
1061
|
-
let transports = void 0;
|
|
1062
|
-
if (typeof response.getTransports === "function") {
|
|
1063
|
-
transports = response.getTransports();
|
|
1064
|
-
}
|
|
1065
|
-
let responsePublicKeyAlgorithm = void 0;
|
|
1066
|
-
if (typeof response.getPublicKeyAlgorithm === "function") {
|
|
1067
|
-
try {
|
|
1068
|
-
responsePublicKeyAlgorithm = response.getPublicKeyAlgorithm();
|
|
1069
|
-
} catch (error) {
|
|
1070
|
-
warnOnBrokenImplementation("getPublicKeyAlgorithm()", error);
|
|
1071
|
-
}
|
|
1072
|
-
}
|
|
1073
|
-
let responsePublicKey = void 0;
|
|
1074
|
-
if (typeof response.getPublicKey === "function") {
|
|
1096
|
+
function ForgotPasswordForm() {
|
|
1097
|
+
const { forgotPassword, resetPassword, setModalStep } = useForgeConnect();
|
|
1098
|
+
const [step, setStep] = _react.useState.call(void 0, "email");
|
|
1099
|
+
const [email, setEmail] = _react.useState.call(void 0, "");
|
|
1100
|
+
const [token, setToken] = _react.useState.call(void 0, "");
|
|
1101
|
+
const [password, setPassword] = _react.useState.call(void 0, "");
|
|
1102
|
+
const [error, setError] = _react.useState.call(void 0, "");
|
|
1103
|
+
const [loading, setLoading] = _react.useState.call(void 0, false);
|
|
1104
|
+
const handleSendCode = async (e) => {
|
|
1105
|
+
e.preventDefault();
|
|
1106
|
+
setError("");
|
|
1107
|
+
setLoading(true);
|
|
1075
1108
|
try {
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
}
|
|
1081
|
-
|
|
1109
|
+
await forgotPassword(email);
|
|
1110
|
+
setStep("reset");
|
|
1111
|
+
} catch (err) {
|
|
1112
|
+
setError(err instanceof Error ? err.message : "Could not send the reset code. Please try again.");
|
|
1113
|
+
} finally {
|
|
1114
|
+
setLoading(false);
|
|
1082
1115
|
}
|
|
1083
|
-
}
|
|
1084
|
-
|
|
1085
|
-
|
|
1116
|
+
};
|
|
1117
|
+
const handleReset = async (e) => {
|
|
1118
|
+
e.preventDefault();
|
|
1119
|
+
setError("");
|
|
1120
|
+
setLoading(true);
|
|
1086
1121
|
try {
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1122
|
+
await resetPassword(token.trim(), password);
|
|
1123
|
+
setStep("done");
|
|
1124
|
+
} catch (err) {
|
|
1125
|
+
setError(err instanceof Error ? err.message : "Could not reset your password. Please try again.");
|
|
1126
|
+
} finally {
|
|
1127
|
+
setLoading(false);
|
|
1090
1128
|
}
|
|
1091
|
-
}
|
|
1092
|
-
return {
|
|
1093
|
-
id,
|
|
1094
|
-
rawId: bufferToBase64URLString(rawId),
|
|
1095
|
-
response: {
|
|
1096
|
-
attestationObject: bufferToBase64URLString(response.attestationObject),
|
|
1097
|
-
clientDataJSON: bufferToBase64URLString(response.clientDataJSON),
|
|
1098
|
-
transports,
|
|
1099
|
-
publicKeyAlgorithm: responsePublicKeyAlgorithm,
|
|
1100
|
-
publicKey: responsePublicKey,
|
|
1101
|
-
authenticatorData: responseAuthenticatorData
|
|
1102
|
-
},
|
|
1103
|
-
type,
|
|
1104
|
-
clientExtensionResults: credential.getClientExtensionResults(),
|
|
1105
|
-
authenticatorAttachment: toAuthenticatorAttachment(credential.authenticatorAttachment)
|
|
1106
1129
|
};
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
}
|
|
1112
|
-
|
|
1113
|
-
// ../../node_modules/.pnpm/@simplewebauthn+browser@13.2.2/node_modules/@simplewebauthn/browser/esm/helpers/browserSupportsWebAuthnAutofill.js
|
|
1114
|
-
function browserSupportsWebAuthnAutofill() {
|
|
1115
|
-
if (!browserSupportsWebAuthn()) {
|
|
1116
|
-
return _browserSupportsWebAuthnAutofillInternals.stubThis(new Promise((resolve) => resolve(false)));
|
|
1130
|
+
if (step === "done") {
|
|
1131
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-tab", children: [
|
|
1132
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { className: "fc-tab-title", children: "Password updated" }),
|
|
1133
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-text", children: "Your password has been reset. You can now sign in." }),
|
|
1134
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "fc-btn fc-btn-primary", onClick: () => setModalStep("email-login"), children: "Sign in" })
|
|
1135
|
+
] });
|
|
1117
1136
|
}
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1137
|
+
if (step === "reset") {
|
|
1138
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-tab", children: [
|
|
1139
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { className: "fc-tab-title", children: "Set new password" }),
|
|
1140
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "fc-text", children: [
|
|
1141
|
+
"We sent a reset code to ",
|
|
1142
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "strong", { children: email }),
|
|
1143
|
+
". Paste it below with your new password."
|
|
1144
|
+
] }),
|
|
1145
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { onSubmit: handleReset, className: "fc-form", children: [
|
|
1146
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { className: "fc-label", children: [
|
|
1147
|
+
"Reset code",
|
|
1148
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1149
|
+
"input",
|
|
1150
|
+
{
|
|
1151
|
+
type: "text",
|
|
1152
|
+
className: "fc-input",
|
|
1153
|
+
value: token,
|
|
1154
|
+
onChange: (e) => setToken(e.target.value),
|
|
1155
|
+
placeholder: "Paste the code from your email",
|
|
1156
|
+
required: true,
|
|
1157
|
+
autoComplete: "off"
|
|
1158
|
+
}
|
|
1159
|
+
)
|
|
1160
|
+
] }),
|
|
1161
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { className: "fc-label", children: [
|
|
1162
|
+
"New password",
|
|
1163
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1164
|
+
"input",
|
|
1165
|
+
{
|
|
1166
|
+
type: "password",
|
|
1167
|
+
className: "fc-input",
|
|
1168
|
+
value: password,
|
|
1169
|
+
onChange: (e) => setPassword(e.target.value),
|
|
1170
|
+
placeholder: "8+ characters",
|
|
1171
|
+
required: true,
|
|
1172
|
+
autoComplete: "new-password",
|
|
1173
|
+
minLength: 8
|
|
1174
|
+
}
|
|
1175
|
+
)
|
|
1176
|
+
] }),
|
|
1177
|
+
error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-error", children: error }),
|
|
1178
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "submit", className: "fc-btn fc-btn-primary", disabled: loading, children: loading ? "Resetting..." : "Reset password" })
|
|
1179
|
+
] }),
|
|
1180
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-switch", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "fc-link", onClick: () => setStep("email"), children: "Resend code" }) })
|
|
1181
|
+
] });
|
|
1121
1182
|
}
|
|
1122
|
-
return
|
|
1183
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-tab", children: [
|
|
1184
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { className: "fc-tab-title", children: "Reset your password" }),
|
|
1185
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-text", children: "Enter your email and we'll send you a reset code." }),
|
|
1186
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { onSubmit: handleSendCode, className: "fc-form", children: [
|
|
1187
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { className: "fc-label", children: [
|
|
1188
|
+
"Email",
|
|
1189
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1190
|
+
"input",
|
|
1191
|
+
{
|
|
1192
|
+
type: "email",
|
|
1193
|
+
className: "fc-input",
|
|
1194
|
+
value: email,
|
|
1195
|
+
onChange: (e) => setEmail(e.target.value),
|
|
1196
|
+
placeholder: "you@example.com",
|
|
1197
|
+
required: true,
|
|
1198
|
+
autoComplete: "email"
|
|
1199
|
+
}
|
|
1200
|
+
)
|
|
1201
|
+
] }),
|
|
1202
|
+
error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-error", children: error }),
|
|
1203
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "submit", className: "fc-btn fc-btn-primary", disabled: loading, children: loading ? "Sending..." : "Send reset code" })
|
|
1204
|
+
] }),
|
|
1205
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-switch", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "fc-link", onClick: () => setModalStep("email-login"), children: "Back to sign in" }) })
|
|
1206
|
+
] });
|
|
1123
1207
|
}
|
|
1124
|
-
var _browserSupportsWebAuthnAutofillInternals = {
|
|
1125
|
-
stubThis: (value) => value
|
|
1126
|
-
};
|
|
1127
1208
|
|
|
1128
|
-
//
|
|
1129
|
-
function identifyAuthenticationError({ error, options }) {
|
|
1130
|
-
const { publicKey } = options;
|
|
1131
|
-
if (!publicKey) {
|
|
1132
|
-
throw Error("options was missing required publicKey property");
|
|
1133
|
-
}
|
|
1134
|
-
if (error.name === "AbortError") {
|
|
1135
|
-
if (options.signal instanceof AbortSignal) {
|
|
1136
|
-
return new WebAuthnError({
|
|
1137
|
-
message: "Authentication ceremony was sent an abort signal",
|
|
1138
|
-
code: "ERROR_CEREMONY_ABORTED",
|
|
1139
|
-
cause: error
|
|
1140
|
-
});
|
|
1141
|
-
}
|
|
1142
|
-
} else if (error.name === "NotAllowedError") {
|
|
1143
|
-
return new WebAuthnError({
|
|
1144
|
-
message: error.message,
|
|
1145
|
-
code: "ERROR_PASSTHROUGH_SEE_CAUSE_PROPERTY",
|
|
1146
|
-
cause: error
|
|
1147
|
-
});
|
|
1148
|
-
} else if (error.name === "SecurityError") {
|
|
1149
|
-
const effectiveDomain = globalThis.location.hostname;
|
|
1150
|
-
if (!isValidDomain(effectiveDomain)) {
|
|
1151
|
-
return new WebAuthnError({
|
|
1152
|
-
message: `${globalThis.location.hostname} is an invalid domain`,
|
|
1153
|
-
code: "ERROR_INVALID_DOMAIN",
|
|
1154
|
-
cause: error
|
|
1155
|
-
});
|
|
1156
|
-
} else if (publicKey.rpId !== effectiveDomain) {
|
|
1157
|
-
return new WebAuthnError({
|
|
1158
|
-
message: `The RP ID "${publicKey.rpId}" is invalid for this domain`,
|
|
1159
|
-
code: "ERROR_INVALID_RP_ID",
|
|
1160
|
-
cause: error
|
|
1161
|
-
});
|
|
1162
|
-
}
|
|
1163
|
-
} else if (error.name === "UnknownError") {
|
|
1164
|
-
return new WebAuthnError({
|
|
1165
|
-
message: "The authenticator was unable to process the specified options, or could not create a new assertion signature",
|
|
1166
|
-
code: "ERROR_AUTHENTICATOR_GENERAL_ERROR",
|
|
1167
|
-
cause: error
|
|
1168
|
-
});
|
|
1169
|
-
}
|
|
1170
|
-
return error;
|
|
1171
|
-
}
|
|
1209
|
+
// src/components/tabs/verify-2fa.tsx
|
|
1172
1210
|
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
const
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1211
|
+
|
|
1212
|
+
function Verify2FAForm() {
|
|
1213
|
+
const { verify2FA, verifyRecoveryCode, setModalStep } = useForgeConnect();
|
|
1214
|
+
const [code, setCode] = _react.useState.call(void 0, "");
|
|
1215
|
+
const [loading, setLoading] = _react.useState.call(void 0, false);
|
|
1216
|
+
const [error, setError] = _react.useState.call(void 0, "");
|
|
1217
|
+
const [useRecovery, setUseRecovery] = _react.useState.call(void 0, false);
|
|
1218
|
+
const inputRef = _react.useRef.call(void 0, null);
|
|
1219
|
+
const submittingRef = _react.useRef.call(void 0, false);
|
|
1220
|
+
_react.useEffect.call(void 0, () => {
|
|
1221
|
+
_optionalChain([inputRef, 'access', _25 => _25.current, 'optionalAccess', _26 => _26.focus, 'call', _27 => _27()]);
|
|
1222
|
+
}, [useRecovery]);
|
|
1223
|
+
const submitCode = _react.useCallback.call(void 0, async (codeValue, isRecovery) => {
|
|
1224
|
+
if (submittingRef.current || !codeValue.trim()) return;
|
|
1225
|
+
submittingRef.current = true;
|
|
1226
|
+
setLoading(true);
|
|
1227
|
+
setError("");
|
|
1228
|
+
try {
|
|
1229
|
+
if (isRecovery) {
|
|
1230
|
+
await verifyRecoveryCode(codeValue.trim());
|
|
1231
|
+
} else {
|
|
1232
|
+
await verify2FA(codeValue.trim());
|
|
1233
|
+
}
|
|
1234
|
+
} catch (err) {
|
|
1235
|
+
setError(err instanceof Error ? err.message : "Verification failed. Please try again.");
|
|
1236
|
+
} finally {
|
|
1237
|
+
setLoading(false);
|
|
1238
|
+
submittingRef.current = false;
|
|
1196
1239
|
}
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1240
|
+
}, [verify2FA, verifyRecoveryCode]);
|
|
1241
|
+
const handleSubmit = async (e) => {
|
|
1242
|
+
_optionalChain([e, 'optionalAccess', _28 => _28.preventDefault, 'call', _29 => _29()]);
|
|
1243
|
+
await submitCode(code, useRecovery);
|
|
1244
|
+
};
|
|
1245
|
+
const handleCodeChange = (value) => {
|
|
1246
|
+
setCode(value);
|
|
1247
|
+
if (!useRecovery && value.length === 6 && /^\d{6}$/.test(value)) {
|
|
1248
|
+
submitCode(value, false);
|
|
1200
1249
|
}
|
|
1201
|
-
getOptions.mediation = "conditional";
|
|
1202
|
-
publicKey.allowCredentials = [];
|
|
1203
|
-
}
|
|
1204
|
-
getOptions.publicKey = publicKey;
|
|
1205
|
-
getOptions.signal = WebAuthnAbortService.createNewAbortSignal();
|
|
1206
|
-
let credential;
|
|
1207
|
-
try {
|
|
1208
|
-
credential = await navigator.credentials.get(getOptions);
|
|
1209
|
-
} catch (err) {
|
|
1210
|
-
throw identifyAuthenticationError({ error: err, options: getOptions });
|
|
1211
|
-
}
|
|
1212
|
-
if (!credential) {
|
|
1213
|
-
throw new Error("Authentication was not completed");
|
|
1214
|
-
}
|
|
1215
|
-
const { id, rawId, response, type } = credential;
|
|
1216
|
-
let userHandle = void 0;
|
|
1217
|
-
if (response.userHandle) {
|
|
1218
|
-
userHandle = bufferToBase64URLString(response.userHandle);
|
|
1219
|
-
}
|
|
1220
|
-
return {
|
|
1221
|
-
id,
|
|
1222
|
-
rawId: bufferToBase64URLString(rawId),
|
|
1223
|
-
response: {
|
|
1224
|
-
authenticatorData: bufferToBase64URLString(response.authenticatorData),
|
|
1225
|
-
clientDataJSON: bufferToBase64URLString(response.clientDataJSON),
|
|
1226
|
-
signature: bufferToBase64URLString(response.signature),
|
|
1227
|
-
userHandle
|
|
1228
|
-
},
|
|
1229
|
-
type,
|
|
1230
|
-
clientExtensionResults: credential.getClientExtensionResults(),
|
|
1231
|
-
authenticatorAttachment: toAuthenticatorAttachment(credential.authenticatorAttachment)
|
|
1232
1250
|
};
|
|
1251
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-tab", children: [
|
|
1252
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { type: "button", className: "fc-back", onClick: () => setModalStep("method-select"), children: [
|
|
1253
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M10 12L6 8l4-4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }),
|
|
1254
|
+
"Back"
|
|
1255
|
+
] }),
|
|
1256
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-account-section-desc", style: { marginTop: 8 }, children: useRecovery ? "Enter one of your recovery codes." : "Enter the 6-digit code from your authenticator app." }),
|
|
1257
|
+
error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-error", children: error }),
|
|
1258
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { onSubmit: handleSubmit, className: "fc-form", children: [
|
|
1259
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1260
|
+
"input",
|
|
1261
|
+
{
|
|
1262
|
+
ref: inputRef,
|
|
1263
|
+
className: "fc-input fc-input-code",
|
|
1264
|
+
type: "text",
|
|
1265
|
+
inputMode: useRecovery ? "text" : "numeric",
|
|
1266
|
+
autoComplete: "one-time-code",
|
|
1267
|
+
placeholder: useRecovery ? "Recovery code" : "000000",
|
|
1268
|
+
maxLength: useRecovery ? 20 : 6,
|
|
1269
|
+
value: code,
|
|
1270
|
+
onChange: (e) => handleCodeChange(e.target.value),
|
|
1271
|
+
style: useRecovery ? {} : { textAlign: "center", letterSpacing: "0.3em", fontSize: "1.25rem" }
|
|
1272
|
+
}
|
|
1273
|
+
),
|
|
1274
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "submit", className: "fc-btn fc-btn-primary", disabled: loading || !code.trim(), children: loading ? "Verifying..." : "Verify" })
|
|
1275
|
+
] }),
|
|
1276
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1277
|
+
"button",
|
|
1278
|
+
{
|
|
1279
|
+
type: "button",
|
|
1280
|
+
className: "fc-link",
|
|
1281
|
+
onClick: () => {
|
|
1282
|
+
setUseRecovery(!useRecovery);
|
|
1283
|
+
setCode("");
|
|
1284
|
+
setError("");
|
|
1285
|
+
},
|
|
1286
|
+
style: { marginTop: 12 },
|
|
1287
|
+
children: useRecovery ? "Use authenticator code instead" : "Use a recovery code"
|
|
1288
|
+
}
|
|
1289
|
+
)
|
|
1290
|
+
] });
|
|
1233
1291
|
}
|
|
1234
1292
|
|
|
1235
|
-
// src/
|
|
1236
|
-
var importSolanaWeb3 = () => new Function('return import("@solana/web3.js")')();
|
|
1293
|
+
// src/components/svg-icon.tsx
|
|
1237
1294
|
|
|
1238
|
-
// src/components/tabs/wallet-connect.tsx
|
|
1239
1295
|
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1296
|
+
function SvgIcon({ svg, className }) {
|
|
1297
|
+
const ref = _react.useRef.call(void 0, null);
|
|
1298
|
+
_react.useEffect.call(void 0, () => {
|
|
1299
|
+
if (!ref.current || !svg) return;
|
|
1300
|
+
try {
|
|
1301
|
+
const doc = new DOMParser().parseFromString(svg, "text/html");
|
|
1302
|
+
const svgEl = doc.body.querySelector("svg");
|
|
1303
|
+
if (!svgEl) {
|
|
1304
|
+
ref.current.textContent = "";
|
|
1305
|
+
return;
|
|
1306
|
+
}
|
|
1307
|
+
const dangerous = svgEl.querySelectorAll("script,iframe,object,embed,foreignObject");
|
|
1308
|
+
dangerous.forEach((el) => el.remove());
|
|
1309
|
+
const all = svgEl.querySelectorAll("*");
|
|
1310
|
+
all.forEach((el) => {
|
|
1311
|
+
for (const attr of Array.from(el.attributes)) {
|
|
1312
|
+
if (attr.name.startsWith("on")) {
|
|
1313
|
+
el.removeAttribute(attr.name);
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
});
|
|
1317
|
+
ref.current.textContent = "";
|
|
1318
|
+
ref.current.appendChild(svgEl);
|
|
1319
|
+
} catch (e5) {
|
|
1320
|
+
ref.current.textContent = "";
|
|
1321
|
+
}
|
|
1322
|
+
}, [svg]);
|
|
1323
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { ref, className });
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
// src/components/tabs/oauth-buttons.tsx
|
|
1327
|
+
|
|
1328
|
+
var PROVIDER_INFO = {
|
|
1329
|
+
google: {
|
|
1330
|
+
label: "Google",
|
|
1331
|
+
icon: '<svg viewBox="0 0 24 24" width="20" height="20"><path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 0 1-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z" fill="#4285F4"/><path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" fill="#34A853"/><path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" fill="#FBBC05"/><path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" fill="#EA4335"/></svg>'
|
|
1245
1332
|
},
|
|
1246
|
-
{
|
|
1247
|
-
|
|
1248
|
-
icon: "
|
|
1249
|
-
buildUrl: (url) => `https://solflare.com/ul/v1/browse/${encodeURIComponent(url)}?ref=${encodeURIComponent(url)}`
|
|
1333
|
+
discord: {
|
|
1334
|
+
label: "Discord",
|
|
1335
|
+
icon: '<svg viewBox="0 0 24 24" width="20" height="20"><path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128c.126-.094.252-.192.372-.292a.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03z" fill="#5865F2"/></svg>'
|
|
1250
1336
|
},
|
|
1251
|
-
{
|
|
1252
|
-
|
|
1253
|
-
icon: "
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
const { walletAdapter, setModalStep, config } = useForgeConnect();
|
|
1263
|
-
const methods = resolveLoginMethods(config);
|
|
1264
|
-
const showBack = methods.length > 1;
|
|
1265
|
-
if (!walletAdapter && isMobile()) {
|
|
1266
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, MobileWalletFlow, {});
|
|
1267
|
-
}
|
|
1268
|
-
if (walletAdapter) {
|
|
1269
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, WalletAdapterFlow, {});
|
|
1337
|
+
twitter: {
|
|
1338
|
+
label: "Twitter",
|
|
1339
|
+
icon: '<svg viewBox="0 0 24 24" width="20" height="20"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" fill="currentColor"/></svg>'
|
|
1340
|
+
},
|
|
1341
|
+
apple: {
|
|
1342
|
+
label: "Apple",
|
|
1343
|
+
icon: '<svg viewBox="0 0 24 24" width="20" height="20"><path d="M17.05 20.28c-.98.95-2.05.88-3.08.4-1.09-.5-2.08-.52-3.23 0-1.44.64-2.2.45-3.06-.4C3.79 16.17 4.36 9.02 8.8 8.78c1.27.06 2.15.72 2.91.76.93-.19 1.82-.88 2.83-.8 1.21.1 2.12.58 2.72 1.49-2.46 1.48-1.88 4.73.52 5.64-.42 1.13-.98 2.24-1.73 3.41zM12.03 8.7c-.12-2.35 1.82-4.38 4.04-4.54.29 2.56-2.34 4.68-4.04 4.54z" fill="currentColor"/></svg>'
|
|
1344
|
+
},
|
|
1345
|
+
telegram: {
|
|
1346
|
+
label: "Telegram",
|
|
1347
|
+
icon: '<svg viewBox="0 0 24 24" width="20" height="20"><path d="M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.479.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z" fill="#2AABEE"/></svg>'
|
|
1270
1348
|
}
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
"
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1349
|
+
};
|
|
1350
|
+
function OAuthButton({ provider }) {
|
|
1351
|
+
const { loginWithOAuth } = useForgeConnect();
|
|
1352
|
+
const info = PROVIDER_INFO[provider];
|
|
1353
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1354
|
+
"button",
|
|
1355
|
+
{
|
|
1356
|
+
type: "button",
|
|
1357
|
+
className: "fc-btn fc-btn-oauth",
|
|
1358
|
+
onClick: () => loginWithOAuth(provider),
|
|
1359
|
+
children: [
|
|
1360
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, SvgIcon, { svg: info.icon, className: "fc-oauth-icon" }),
|
|
1361
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-btn-name", children: info.label })
|
|
1362
|
+
]
|
|
1363
|
+
}
|
|
1364
|
+
);
|
|
1283
1365
|
}
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
const
|
|
1289
|
-
const
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1366
|
+
|
|
1367
|
+
// src/components/login-modal.tsx
|
|
1368
|
+
|
|
1369
|
+
function LoginModal() {
|
|
1370
|
+
const { modal, closeModal, config } = useForgeConnect();
|
|
1371
|
+
const renderStep = () => {
|
|
1372
|
+
switch (modal.step) {
|
|
1373
|
+
case "email-login":
|
|
1374
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, EmailLoginForm, {});
|
|
1375
|
+
case "email-register":
|
|
1376
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, EmailRegisterForm, {});
|
|
1377
|
+
case "email-otp":
|
|
1378
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, EmailOtpForm, {});
|
|
1379
|
+
case "wallet-connect":
|
|
1380
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, WalletConnectForm, {});
|
|
1381
|
+
case "forgot-password":
|
|
1382
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ForgotPasswordForm, {});
|
|
1383
|
+
case "verify-2fa":
|
|
1384
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Verify2FAForm, {});
|
|
1385
|
+
case "oauth":
|
|
1386
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, OAuthLoadingView, {});
|
|
1387
|
+
case "success":
|
|
1388
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SuccessView, {});
|
|
1389
|
+
case "method-select":
|
|
1390
|
+
default:
|
|
1391
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, MethodSelect, {});
|
|
1298
1392
|
}
|
|
1299
|
-
return MOBILE_WALLETS;
|
|
1300
|
-
}, [preferred, onlyPreferred]);
|
|
1301
|
-
const handleOpen = (mw) => {
|
|
1302
|
-
const pageUrl = window.location.href;
|
|
1303
|
-
window.location.href = mw.buildUrl(pageUrl);
|
|
1304
1393
|
};
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
"
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1394
|
+
const renderLogo = () => {
|
|
1395
|
+
if (_optionalChain([config, 'access', _30 => _30.appearance, 'optionalAccess', _31 => _31.logoNode])) {
|
|
1396
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-logo", children: config.appearance.logoNode });
|
|
1397
|
+
}
|
|
1398
|
+
if (_optionalChain([config, 'access', _32 => _32.appearance, 'optionalAccess', _33 => _33.logo])) {
|
|
1399
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { src: config.appearance.logo, alt: "", className: "fc-logo" });
|
|
1400
|
+
}
|
|
1401
|
+
return null;
|
|
1402
|
+
};
|
|
1403
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ModalOverlay, { isOpen: modal.isOpen, onClose: closeModal, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1404
|
+
"div",
|
|
1405
|
+
{
|
|
1406
|
+
className: "fc-modal-content",
|
|
1407
|
+
style: {
|
|
1408
|
+
"--fc-accent": _nullishCoalesce(_optionalChain([config, 'access', _34 => _34.appearance, 'optionalAccess', _35 => _35.accentColor]), () => ( "#8b5cf6"))
|
|
1317
1409
|
},
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1410
|
+
"data-theme": _nullishCoalesce(_optionalChain([config, 'access', _36 => _36.appearance, 'optionalAccess', _37 => _37.theme]), () => ( "light")),
|
|
1411
|
+
children: modal.step === "success" || modal.step === "oauth" ? renderStep() : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
1412
|
+
renderLogo(),
|
|
1413
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "fc-modal-title", children: _nullishCoalesce(_optionalChain([config, 'access', _38 => _38.appearance, 'optionalAccess', _39 => _39.title]), () => ( "Log in or sign up")) }),
|
|
1414
|
+
renderStep(),
|
|
1415
|
+
(_optionalChain([config, 'access', _40 => _40.appearance, 'optionalAccess', _41 => _41.termsUrl]) || _optionalChain([config, 'access', _42 => _42.appearance, 'optionalAccess', _43 => _43.privacyUrl])) && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "fc-legal", children: [
|
|
1416
|
+
"By continuing, you agree to our",
|
|
1417
|
+
" ",
|
|
1418
|
+
config.appearance.termsUrl && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "a", { href: config.appearance.termsUrl, target: "_blank", rel: "noopener noreferrer", className: "fc-legal-link", children: "Terms" }),
|
|
1419
|
+
config.appearance.termsUrl && config.appearance.privacyUrl && " and ",
|
|
1420
|
+
config.appearance.privacyUrl && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "a", { href: config.appearance.privacyUrl, target: "_blank", rel: "noopener noreferrer", className: "fc-legal-link", children: "Privacy Policy" })
|
|
1421
|
+
] })
|
|
1422
|
+
] })
|
|
1423
|
+
}
|
|
1424
|
+
) });
|
|
1323
1425
|
}
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1426
|
+
var EmailIcon = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-method-icon-wrap", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", className: "fc-method-icon", children: [
|
|
1427
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "rect", { x: "2", y: "4", width: "16", height: "12", rx: "2", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
1428
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M2 6l8 5 8-5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
|
|
1429
|
+
] }) });
|
|
1430
|
+
var OtpIcon = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-method-icon-wrap", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", className: "fc-method-icon", children: [
|
|
1431
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "rect", { x: "3", y: "6", width: "14", height: "9", rx: "1.5", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
1432
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { cx: "6.5", cy: "10.5", r: "1", fill: "currentColor" }),
|
|
1433
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { cx: "10", cy: "10.5", r: "1", fill: "currentColor" }),
|
|
1434
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { cx: "13.5", cy: "10.5", r: "1", fill: "currentColor" })
|
|
1435
|
+
] }) });
|
|
1436
|
+
var WalletIcon = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-method-icon-wrap", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", className: "fc-method-icon", children: [
|
|
1437
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "rect", { x: "2", y: "5", width: "16", height: "11", rx: "2", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
1438
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "rect", { x: "13", y: "9", width: "5", height: "3", rx: "1", stroke: "currentColor", strokeWidth: "1.5" })
|
|
1439
|
+
] }) });
|
|
1440
|
+
var PasskeyIcon = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-method-icon-wrap", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", className: "fc-method-icon", children: [
|
|
1441
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { cx: "8", cy: "7", r: "3", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
1442
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M13 13.5a5 5 0 0 0-10 0", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }),
|
|
1443
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M15 10v4m0 0l-1.5-1m1.5 1l1.5-1", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
|
|
1444
|
+
] }) });
|
|
1445
|
+
var LoadingSpinner = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-method-icon-wrap", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", className: "fc-method-icon fc-spin", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M10 2a8 8 0 0 1 8 8", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) }) });
|
|
1446
|
+
function MethodSelect() {
|
|
1447
|
+
const { setModalStep, loginWithPasskey, config } = useForgeConnect();
|
|
1328
1448
|
const methods = resolveLoginMethods(config);
|
|
1329
|
-
const
|
|
1330
|
-
const [
|
|
1331
|
-
const
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
const mobile = _react.useMemo.call(void 0, () => isMobile(), []);
|
|
1335
|
-
const coldWalletRef = _react.useRef.call(void 0, coldWallet);
|
|
1336
|
-
coldWalletRef.current = coldWallet;
|
|
1337
|
-
const buildSignTxFnForAdapter = _react.useCallback.call(void 0, (adapter) => {
|
|
1338
|
-
if (!adapter.signTransaction) return void 0;
|
|
1339
|
-
return async (txBase64) => {
|
|
1340
|
-
const { Transaction } = await importSolanaWeb3();
|
|
1341
|
-
const bytes = Uint8Array.from(atob(txBase64), (c) => c.charCodeAt(0));
|
|
1342
|
-
const tx = Transaction.from(bytes);
|
|
1343
|
-
const signedTx = await adapter.signTransaction(tx);
|
|
1344
|
-
return btoa(String.fromCharCode(...new Uint8Array(signedTx.serialize())));
|
|
1345
|
-
};
|
|
1346
|
-
}, []);
|
|
1347
|
-
const handleConnect = async (w) => {
|
|
1348
|
-
if (w.readyState !== "Installed") {
|
|
1349
|
-
if (mobile) {
|
|
1350
|
-
const mw = MOBILE_WALLETS.find((m) => m.name === w.adapter.name);
|
|
1351
|
-
if (mw) {
|
|
1352
|
-
window.location.href = mw.buildUrl(window.location.href);
|
|
1353
|
-
return;
|
|
1354
|
-
}
|
|
1355
|
-
}
|
|
1356
|
-
const url = w.adapter.url;
|
|
1357
|
-
if (url) window.open(url, "_blank");
|
|
1358
|
-
return;
|
|
1359
|
-
}
|
|
1360
|
-
setError("");
|
|
1361
|
-
setLoading(true);
|
|
1449
|
+
const [passkeyLoading, setPasskeyLoading] = _react.useState.call(void 0, false);
|
|
1450
|
+
const [passkeyError, setPasskeyError] = _react.useState.call(void 0, "");
|
|
1451
|
+
const handlePasskey = async () => {
|
|
1452
|
+
setPasskeyLoading(true);
|
|
1453
|
+
setPasskeyError("");
|
|
1362
1454
|
try {
|
|
1363
|
-
|
|
1364
|
-
await w.adapter.connect();
|
|
1365
|
-
}
|
|
1366
|
-
const pk = w.adapter.publicKey;
|
|
1367
|
-
if (!pk) throw new Error("Wallet did not provide a public key.");
|
|
1368
|
-
const address = pk.toBase58();
|
|
1369
|
-
const useCold = coldWalletRef.current;
|
|
1370
|
-
const adapterSignMessage = w.adapter.signMessage ? (msg) => w.adapter.signMessage(msg) : void 0;
|
|
1371
|
-
await loginWithWallet(
|
|
1372
|
-
address,
|
|
1373
|
-
useCold ? void 0 : adapterSignMessage,
|
|
1374
|
-
"solana",
|
|
1375
|
-
useCold ? buildSignTxFnForAdapter(w.adapter) : void 0
|
|
1376
|
-
);
|
|
1455
|
+
await loginWithPasskey();
|
|
1377
1456
|
} catch (err) {
|
|
1378
|
-
|
|
1379
|
-
|
|
1457
|
+
setPasskeyError(err instanceof Error ? err.message : "Passkey authentication failed.");
|
|
1458
|
+
} finally {
|
|
1459
|
+
setPasskeyLoading(false);
|
|
1380
1460
|
}
|
|
1381
1461
|
};
|
|
1382
|
-
const
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
{
|
|
1414
|
-
type: "button",
|
|
1415
|
-
className: "fc-btn fc-btn-secondary",
|
|
1416
|
-
onClick: () => {
|
|
1417
|
-
setLoading(false);
|
|
1418
|
-
setError("");
|
|
1419
|
-
},
|
|
1420
|
-
style: { marginTop: 8 },
|
|
1421
|
-
children: "Try again"
|
|
1422
|
-
}
|
|
1423
|
-
)
|
|
1424
|
-
] })
|
|
1425
|
-
] }) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
1426
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-wallet-list", children: [
|
|
1427
|
-
preferredWallets.map((w) => {
|
|
1428
|
-
const installed = w.readyState === "Installed";
|
|
1429
|
-
const isConnected = w.adapter.name === connectedWalletName;
|
|
1430
|
-
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1431
|
-
"button",
|
|
1432
|
-
{
|
|
1433
|
-
type: "button",
|
|
1434
|
-
className: "fc-btn fc-btn-wallet",
|
|
1435
|
-
onClick: () => handleConnect(w),
|
|
1436
|
-
children: [
|
|
1437
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: installed ? "fc-installed-dot" : "", style: { position: "relative", display: "inline-flex" }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { src: w.adapter.icon, alt: "", className: "fc-wallet-icon" }) }),
|
|
1438
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-wallet-name", children: w.adapter.name }),
|
|
1439
|
-
isConnected ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-badge-preferred", children: "Last used" }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-badge-preferred", children: "Preferred" }),
|
|
1440
|
-
!installed && mobile && MOBILE_WALLETS.some((mw) => mw.name === w.adapter.name) ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-badge-install", children: "Open app" }) : !installed && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-badge-install", children: "Install" })
|
|
1441
|
-
]
|
|
1442
|
-
},
|
|
1443
|
-
w.adapter.name
|
|
1462
|
+
const elements = [];
|
|
1463
|
+
let i = 0;
|
|
1464
|
+
while (i < methods.length) {
|
|
1465
|
+
const method = methods[i];
|
|
1466
|
+
if (isOAuthMethod(method)) {
|
|
1467
|
+
const oauthGroup = [];
|
|
1468
|
+
while (i < methods.length && isOAuthMethod(methods[i])) {
|
|
1469
|
+
oauthGroup.push(methods[i]);
|
|
1470
|
+
i++;
|
|
1471
|
+
}
|
|
1472
|
+
if (elements.length > 0) {
|
|
1473
|
+
elements.push(/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-divider", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "or" }) }, `div-before-${oauthGroup[0]}`));
|
|
1474
|
+
}
|
|
1475
|
+
elements.push(
|
|
1476
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-oauth-group", children: oauthGroup.map((p) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, OAuthButton, { provider: p }, p)) }, `oauth-${oauthGroup.join("-")}`)
|
|
1477
|
+
);
|
|
1478
|
+
} else {
|
|
1479
|
+
if (elements.length > 0) {
|
|
1480
|
+
const prev = methods[i - 1];
|
|
1481
|
+
if (prev && isOAuthMethod(prev)) {
|
|
1482
|
+
elements.push(/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-divider", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "or" }) }, `div-after-${prev}`));
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
switch (method) {
|
|
1486
|
+
case "email":
|
|
1487
|
+
elements.push(
|
|
1488
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { type: "button", className: "fc-btn fc-btn-method", onClick: () => setModalStep("email-login"), children: [
|
|
1489
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, EmailIcon, {}),
|
|
1490
|
+
" ",
|
|
1491
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-btn-name", children: "Password" })
|
|
1492
|
+
] }, "email")
|
|
1444
1493
|
);
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { style: { position: "relative", display: "inline-flex" }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { src: mw.icon, alt: "", className: "fc-wallet-icon" }) }),
|
|
1454
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-wallet-name", children: mw.name }),
|
|
1455
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-badge-install", children: "Open app" })
|
|
1456
|
-
]
|
|
1457
|
-
},
|
|
1458
|
-
mw.name
|
|
1459
|
-
)),
|
|
1460
|
-
otherWallets.length > 0 && !showOther && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1461
|
-
"button",
|
|
1462
|
-
{
|
|
1463
|
-
type: "button",
|
|
1464
|
-
className: "fc-btn fc-btn-wallet",
|
|
1465
|
-
onClick: () => setShowOther(true),
|
|
1466
|
-
children: [
|
|
1467
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-other-wallets-icon", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: [
|
|
1468
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "rect", { x: "2", y: "3", width: "16", height: "14", rx: "2", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
1469
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M2 7h16", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
1470
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "rect", { x: "11", y: "10", width: "7", height: "4", rx: "1", stroke: "currentColor", strokeWidth: "1.5" })
|
|
1471
|
-
] }) }),
|
|
1472
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-wallet-name", children: "Other wallets" })
|
|
1473
|
-
]
|
|
1474
|
-
}
|
|
1475
|
-
),
|
|
1476
|
-
showOther && otherWallets.map((w) => {
|
|
1477
|
-
const isConnected = w.adapter.name === connectedWalletName;
|
|
1478
|
-
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1479
|
-
"button",
|
|
1480
|
-
{
|
|
1481
|
-
type: "button",
|
|
1482
|
-
className: "fc-btn fc-btn-wallet",
|
|
1483
|
-
onClick: () => handleConnect(w),
|
|
1484
|
-
children: [
|
|
1485
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-installed-dot", style: { position: "relative", display: "inline-flex" }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { src: w.adapter.icon, alt: "", className: "fc-wallet-icon" }) }),
|
|
1486
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-wallet-name", children: w.adapter.name }),
|
|
1487
|
-
isConnected && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-badge-preferred", children: "Last used" })
|
|
1488
|
-
]
|
|
1489
|
-
},
|
|
1490
|
-
w.adapter.name
|
|
1494
|
+
break;
|
|
1495
|
+
case "otp":
|
|
1496
|
+
elements.push(
|
|
1497
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { type: "button", className: "fc-btn fc-btn-method", onClick: () => setModalStep("email-otp"), children: [
|
|
1498
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, OtpIcon, {}),
|
|
1499
|
+
" ",
|
|
1500
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-btn-name", children: "Magic code" })
|
|
1501
|
+
] }, "otp")
|
|
1491
1502
|
);
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1503
|
+
break;
|
|
1504
|
+
case "wallet":
|
|
1505
|
+
elements.push(
|
|
1506
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { type: "button", className: "fc-btn fc-btn-method", onClick: () => setModalStep("wallet-connect"), children: [
|
|
1507
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, WalletIcon, {}),
|
|
1508
|
+
" ",
|
|
1509
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-btn-name", children: "Wallet" })
|
|
1510
|
+
] }, "wallet")
|
|
1511
|
+
);
|
|
1512
|
+
break;
|
|
1513
|
+
case "passkey":
|
|
1514
|
+
elements.push(
|
|
1515
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { type: "button", className: "fc-btn fc-btn-method", onClick: handlePasskey, disabled: passkeyLoading, children: [
|
|
1516
|
+
passkeyLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, LoadingSpinner, {}) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, PasskeyIcon, {}),
|
|
1517
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-btn-name", children: passkeyLoading ? "Waiting for passkey..." : "Passkey" })
|
|
1518
|
+
] }, "passkey")
|
|
1519
|
+
);
|
|
1520
|
+
break;
|
|
1521
|
+
}
|
|
1522
|
+
i++;
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-method-select", children: [
|
|
1526
|
+
passkeyError && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-error", children: passkeyError }),
|
|
1527
|
+
elements
|
|
1528
|
+
] });
|
|
1529
|
+
}
|
|
1530
|
+
function OAuthLoadingView() {
|
|
1531
|
+
const { setModalStep } = useForgeConnect();
|
|
1532
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-success", children: [
|
|
1533
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-success-icon", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { width: "52", height: "52", viewBox: "0 0 52 52", className: "fc-spin", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { cx: "26", cy: "26", r: "24", fill: "none", stroke: "var(--fc-accent, #8b5cf6)", strokeWidth: "3", strokeLinecap: "round", strokeDasharray: "100", strokeDashoffset: "30" }) }) }),
|
|
1534
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-success-text", children: "Completing sign in..." }),
|
|
1535
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "fc-btn fc-btn-secondary", style: { marginTop: "16px" }, onClick: () => setModalStep("method-select"), children: "Cancel" })
|
|
1536
|
+
] });
|
|
1537
|
+
}
|
|
1538
|
+
function SuccessView() {
|
|
1539
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-success", children: [
|
|
1540
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-success-icon", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "svg", { viewBox: "0 0 52 52", className: "fc-success-check", children: [
|
|
1541
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { className: "fc-success-circle", cx: "26", cy: "26", r: "24", fill: "none" }),
|
|
1542
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { className: "fc-success-tick", fill: "none", d: "M15 26l7.5 7.5L37 19" })
|
|
1543
|
+
] }) }),
|
|
1544
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-success-text", children: "You're in" })
|
|
1513
1545
|
] });
|
|
1514
1546
|
}
|
|
1515
1547
|
|
|
1516
|
-
// src/components/
|
|
1548
|
+
// src/components/account-modal.tsx
|
|
1517
1549
|
|
|
1518
1550
|
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
const
|
|
1523
|
-
const [
|
|
1524
|
-
const [password, setPassword] = _react.useState.call(void 0, "");
|
|
1525
|
-
const [error, setError] = _react.useState.call(void 0, "");
|
|
1551
|
+
// src/hooks/use-user.ts
|
|
1552
|
+
|
|
1553
|
+
function useUser() {
|
|
1554
|
+
const { auth, api, config, getAccessToken } = useForgeConnect();
|
|
1555
|
+
const [authMethods, setAuthMethods] = _react.useState.call(void 0, null);
|
|
1526
1556
|
const [loading, setLoading] = _react.useState.call(void 0, false);
|
|
1527
|
-
const
|
|
1528
|
-
|
|
1529
|
-
|
|
1557
|
+
const pendingRefreshRef = _react.useRef.call(void 0, false);
|
|
1558
|
+
const updateProfile = _react.useCallback.call(void 0,
|
|
1559
|
+
async (data) => {
|
|
1560
|
+
const token = getAccessToken();
|
|
1561
|
+
if (!token) throw new Error("Please sign in to continue.");
|
|
1562
|
+
return api.updateMe(token, data);
|
|
1563
|
+
},
|
|
1564
|
+
[api, getAccessToken]
|
|
1565
|
+
);
|
|
1566
|
+
const fetchAuthMethods = _react.useCallback.call(void 0, async () => {
|
|
1567
|
+
const token = getAccessToken();
|
|
1568
|
+
if (!token) throw new Error("Please sign in to continue.");
|
|
1530
1569
|
setLoading(true);
|
|
1531
1570
|
try {
|
|
1532
|
-
await
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
setError(err instanceof Error ? err.message : "Could not send the reset code. Please try again.");
|
|
1571
|
+
const methods = await api.getAuthMethods(token);
|
|
1572
|
+
setAuthMethods(methods);
|
|
1573
|
+
return methods;
|
|
1536
1574
|
} finally {
|
|
1537
1575
|
setLoading(false);
|
|
1538
1576
|
}
|
|
1577
|
+
}, [api, getAccessToken]);
|
|
1578
|
+
const linkAuthMethod = _react.useCallback.call(void 0,
|
|
1579
|
+
async (data) => {
|
|
1580
|
+
const token = getAccessToken();
|
|
1581
|
+
if (!token) throw new Error("Please sign in to continue.");
|
|
1582
|
+
await api.linkAuthMethod(token, data);
|
|
1583
|
+
await fetchAuthMethods();
|
|
1584
|
+
},
|
|
1585
|
+
[api, getAccessToken, fetchAuthMethods]
|
|
1586
|
+
);
|
|
1587
|
+
const linkOtpSend = _react.useCallback.call(void 0,
|
|
1588
|
+
async (email) => {
|
|
1589
|
+
const token = getAccessToken();
|
|
1590
|
+
if (!token) throw new Error("Please sign in to continue.");
|
|
1591
|
+
await api.linkOtpSend(token, email);
|
|
1592
|
+
},
|
|
1593
|
+
[api, getAccessToken]
|
|
1594
|
+
);
|
|
1595
|
+
const linkOtpVerify = _react.useCallback.call(void 0,
|
|
1596
|
+
async (email, code) => {
|
|
1597
|
+
const token = getAccessToken();
|
|
1598
|
+
if (!token) throw new Error("Please sign in to continue.");
|
|
1599
|
+
await api.linkOtpVerify(token, email, code);
|
|
1600
|
+
await fetchAuthMethods();
|
|
1601
|
+
},
|
|
1602
|
+
[api, getAccessToken, fetchAuthMethods]
|
|
1603
|
+
);
|
|
1604
|
+
const unlinkAuthMethod = _react.useCallback.call(void 0,
|
|
1605
|
+
async (id) => {
|
|
1606
|
+
const token = getAccessToken();
|
|
1607
|
+
if (!token) throw new Error("Please sign in to continue.");
|
|
1608
|
+
await api.unlinkAuthMethod(token, id);
|
|
1609
|
+
await fetchAuthMethods();
|
|
1610
|
+
},
|
|
1611
|
+
[api, getAccessToken, fetchAuthMethods]
|
|
1612
|
+
);
|
|
1613
|
+
const linkOAuth = _react.useCallback.call(void 0,
|
|
1614
|
+
async (provider) => {
|
|
1615
|
+
const token = getAccessToken();
|
|
1616
|
+
if (!token) throw new Error("Please sign in to continue.");
|
|
1617
|
+
const { intentToken } = await api.createLinkIntent(token);
|
|
1618
|
+
const redirectUri = encodeURIComponent(window.location.origin + "/fc-oauth-callback");
|
|
1619
|
+
const url = `${config.apiUrl}/auth/oauth/${provider}/link?intent=${encodeURIComponent(intentToken)}&redirect_uri=${redirectUri}`;
|
|
1620
|
+
const width = 500;
|
|
1621
|
+
const height = 600;
|
|
1622
|
+
const left = window.screenX + (window.innerWidth - width) / 2;
|
|
1623
|
+
const top = window.screenY + (window.innerHeight - height) / 2;
|
|
1624
|
+
window.open(url, "fc_oauth_link", `width=${width},height=${height},left=${left},top=${top}`);
|
|
1625
|
+
pendingRefreshRef.current = true;
|
|
1626
|
+
},
|
|
1627
|
+
[api, config.apiUrl, getAccessToken]
|
|
1628
|
+
);
|
|
1629
|
+
_react.useEffect.call(void 0, () => {
|
|
1630
|
+
const handleMessage = (event) => {
|
|
1631
|
+
if (event.origin !== window.location.origin) return;
|
|
1632
|
+
if (_optionalChain([event, 'access', _44 => _44.data, 'optionalAccess', _45 => _45.type]) === "fc_oauth_link_success" && pendingRefreshRef.current) {
|
|
1633
|
+
pendingRefreshRef.current = false;
|
|
1634
|
+
fetchAuthMethods().catch(() => {
|
|
1635
|
+
});
|
|
1636
|
+
}
|
|
1637
|
+
};
|
|
1638
|
+
window.addEventListener("message", handleMessage);
|
|
1639
|
+
return () => window.removeEventListener("message", handleMessage);
|
|
1640
|
+
}, [fetchAuthMethods]);
|
|
1641
|
+
return {
|
|
1642
|
+
user: auth.user,
|
|
1643
|
+
authMethods,
|
|
1644
|
+
loading,
|
|
1645
|
+
updateProfile,
|
|
1646
|
+
fetchAuthMethods,
|
|
1647
|
+
linkAuthMethod,
|
|
1648
|
+
linkOtpSend,
|
|
1649
|
+
linkOtpVerify,
|
|
1650
|
+
unlinkAuthMethod,
|
|
1651
|
+
linkOAuth
|
|
1539
1652
|
};
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
// src/hooks/use-wallets.ts
|
|
1656
|
+
|
|
1657
|
+
|
|
1658
|
+
// src/lib/utils.ts
|
|
1659
|
+
var BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
1660
|
+
function uint8ArrayToBase58(bytes) {
|
|
1661
|
+
const digits = [0];
|
|
1662
|
+
for (const byte of bytes) {
|
|
1663
|
+
let carry = byte;
|
|
1664
|
+
for (let j = 0; j < digits.length; j++) {
|
|
1665
|
+
carry += digits[j] << 8;
|
|
1666
|
+
digits[j] = carry % 58;
|
|
1667
|
+
carry = carry / 58 | 0;
|
|
1551
1668
|
}
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
placeholder: "Paste the code from your email",
|
|
1579
|
-
required: true,
|
|
1580
|
-
autoComplete: "off"
|
|
1581
|
-
}
|
|
1582
|
-
)
|
|
1583
|
-
] }),
|
|
1584
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { className: "fc-label", children: [
|
|
1585
|
-
"New password",
|
|
1586
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1587
|
-
"input",
|
|
1588
|
-
{
|
|
1589
|
-
type: "password",
|
|
1590
|
-
className: "fc-input",
|
|
1591
|
-
value: password,
|
|
1592
|
-
onChange: (e) => setPassword(e.target.value),
|
|
1593
|
-
placeholder: "8+ characters",
|
|
1594
|
-
required: true,
|
|
1595
|
-
autoComplete: "new-password",
|
|
1596
|
-
minLength: 8
|
|
1597
|
-
}
|
|
1598
|
-
)
|
|
1599
|
-
] }),
|
|
1600
|
-
error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-error", children: error }),
|
|
1601
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "submit", className: "fc-btn fc-btn-primary", disabled: loading, children: loading ? "Resetting..." : "Reset password" })
|
|
1602
|
-
] }),
|
|
1603
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-switch", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "fc-link", onClick: () => setStep("email"), children: "Resend code" }) })
|
|
1604
|
-
] });
|
|
1605
|
-
}
|
|
1606
|
-
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-tab", children: [
|
|
1607
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { className: "fc-tab-title", children: "Reset your password" }),
|
|
1608
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-text", children: "Enter your email and we'll send you a reset code." }),
|
|
1609
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { onSubmit: handleSendCode, className: "fc-form", children: [
|
|
1610
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { className: "fc-label", children: [
|
|
1611
|
-
"Email",
|
|
1612
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1613
|
-
"input",
|
|
1614
|
-
{
|
|
1615
|
-
type: "email",
|
|
1616
|
-
className: "fc-input",
|
|
1617
|
-
value: email,
|
|
1618
|
-
onChange: (e) => setEmail(e.target.value),
|
|
1619
|
-
placeholder: "you@example.com",
|
|
1620
|
-
required: true,
|
|
1621
|
-
autoComplete: "email"
|
|
1622
|
-
}
|
|
1623
|
-
)
|
|
1624
|
-
] }),
|
|
1625
|
-
error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-error", children: error }),
|
|
1626
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "submit", className: "fc-btn fc-btn-primary", disabled: loading, children: loading ? "Sending..." : "Send reset code" })
|
|
1627
|
-
] }),
|
|
1628
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-switch", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "fc-link", onClick: () => setModalStep("email-login"), children: "Back to sign in" }) })
|
|
1629
|
-
] });
|
|
1669
|
+
while (carry > 0) {
|
|
1670
|
+
digits.push(carry % 58);
|
|
1671
|
+
carry = carry / 58 | 0;
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
let str = "";
|
|
1675
|
+
for (let i = 0; i < bytes.length && bytes[i] === 0; i++) {
|
|
1676
|
+
str += "1";
|
|
1677
|
+
}
|
|
1678
|
+
for (let i = digits.length - 1; i >= 0; i--) {
|
|
1679
|
+
str += BASE58_ALPHABET[digits[i]];
|
|
1680
|
+
}
|
|
1681
|
+
return str;
|
|
1682
|
+
}
|
|
1683
|
+
function timeAgo(dateStr) {
|
|
1684
|
+
const now = Date.now();
|
|
1685
|
+
const then = new Date(dateStr).getTime();
|
|
1686
|
+
const diff = now - then;
|
|
1687
|
+
const mins = Math.floor(diff / 6e4);
|
|
1688
|
+
if (mins < 1) return "just now";
|
|
1689
|
+
if (mins < 60) return `${mins}m ago`;
|
|
1690
|
+
const hours = Math.floor(mins / 60);
|
|
1691
|
+
if (hours < 24) return `${hours}h ago`;
|
|
1692
|
+
const days = Math.floor(hours / 24);
|
|
1693
|
+
if (days < 30) return `${days}d ago`;
|
|
1694
|
+
return new Date(dateStr).toLocaleDateString();
|
|
1630
1695
|
}
|
|
1631
1696
|
|
|
1632
|
-
// src/
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
const { verify2FA, verifyRecoveryCode, setModalStep } = useForgeConnect();
|
|
1637
|
-
const [code, setCode] = _react.useState.call(void 0, "");
|
|
1697
|
+
// src/hooks/use-wallets.ts
|
|
1698
|
+
function useWallets() {
|
|
1699
|
+
const { api, getAccessToken } = useForgeConnect();
|
|
1700
|
+
const [wallets, setWallets] = _react.useState.call(void 0, null);
|
|
1638
1701
|
const [loading, setLoading] = _react.useState.call(void 0, false);
|
|
1639
|
-
const
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
const submittingRef = _react.useRef.call(void 0, false);
|
|
1643
|
-
_react.useEffect.call(void 0, () => {
|
|
1644
|
-
_optionalChain([inputRef, 'access', _38 => _38.current, 'optionalAccess', _39 => _39.focus, 'call', _40 => _40()]);
|
|
1645
|
-
}, [useRecovery]);
|
|
1646
|
-
const submitCode = _react.useCallback.call(void 0, async (codeValue, isRecovery) => {
|
|
1647
|
-
if (submittingRef.current || !codeValue.trim()) return;
|
|
1648
|
-
submittingRef.current = true;
|
|
1702
|
+
const fetchWallets = _react.useCallback.call(void 0, async () => {
|
|
1703
|
+
const token = getAccessToken();
|
|
1704
|
+
if (!token) throw new Error("Please sign in to continue.");
|
|
1649
1705
|
setLoading(true);
|
|
1650
|
-
setError("");
|
|
1651
1706
|
try {
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
await verify2FA(codeValue.trim());
|
|
1656
|
-
}
|
|
1657
|
-
} catch (err) {
|
|
1658
|
-
setError(err instanceof Error ? err.message : "Verification failed. Please try again.");
|
|
1707
|
+
const data = await api.getWallets(token);
|
|
1708
|
+
setWallets(data);
|
|
1709
|
+
return data;
|
|
1659
1710
|
} finally {
|
|
1660
1711
|
setLoading(false);
|
|
1661
|
-
submittingRef.current = false;
|
|
1662
|
-
}
|
|
1663
|
-
}, [verify2FA, verifyRecoveryCode]);
|
|
1664
|
-
const handleSubmit = async (e) => {
|
|
1665
|
-
_optionalChain([e, 'optionalAccess', _41 => _41.preventDefault, 'call', _42 => _42()]);
|
|
1666
|
-
await submitCode(code, useRecovery);
|
|
1667
|
-
};
|
|
1668
|
-
const handleCodeChange = (value) => {
|
|
1669
|
-
setCode(value);
|
|
1670
|
-
if (!useRecovery && value.length === 6 && /^\d{6}$/.test(value)) {
|
|
1671
|
-
submitCode(value, false);
|
|
1672
1712
|
}
|
|
1673
|
-
};
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
"
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1713
|
+
}, [api, getAccessToken]);
|
|
1714
|
+
const updateWallet = _react.useCallback.call(void 0,
|
|
1715
|
+
async (id, data) => {
|
|
1716
|
+
const token = getAccessToken();
|
|
1717
|
+
if (!token) throw new Error("Please sign in to continue.");
|
|
1718
|
+
await api.updateWallet(token, id, data);
|
|
1719
|
+
await fetchWallets();
|
|
1720
|
+
},
|
|
1721
|
+
[api, getAccessToken, fetchWallets]
|
|
1722
|
+
);
|
|
1723
|
+
const linkWallet = _react.useCallback.call(void 0,
|
|
1724
|
+
async (walletAddress, signMessage, chain = "solana", signTransaction) => {
|
|
1725
|
+
const token = getAccessToken();
|
|
1726
|
+
if (!token) throw new Error("Please sign in to continue.");
|
|
1727
|
+
if (signMessage) {
|
|
1728
|
+
const { challengeId, message: challengeMessage } = await api.walletChallenge(walletAddress, chain);
|
|
1729
|
+
const encoded = new TextEncoder().encode(challengeMessage);
|
|
1730
|
+
const signatureBytes = await signMessage(encoded);
|
|
1731
|
+
const signature = chain === "solana" ? uint8ArrayToBase58(signatureBytes) : Array.from(signatureBytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1732
|
+
await api.linkAuthMethod(token, {
|
|
1733
|
+
provider: `${chain}_wallet`,
|
|
1734
|
+
challengeId,
|
|
1735
|
+
signature,
|
|
1736
|
+
walletAddress
|
|
1737
|
+
});
|
|
1738
|
+
} else {
|
|
1739
|
+
if (!signTransaction) {
|
|
1740
|
+
throw new Error("Wallet does not support message signing or transaction signing.");
|
|
1695
1741
|
}
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
onClick: () => {
|
|
1705
|
-
setUseRecovery(!useRecovery);
|
|
1706
|
-
setCode("");
|
|
1707
|
-
setError("");
|
|
1708
|
-
},
|
|
1709
|
-
style: { marginTop: 12 },
|
|
1710
|
-
children: useRecovery ? "Use authenticator code instead" : "Use a recovery code"
|
|
1742
|
+
const { challengeId, transaction: txBase64 } = await api.walletChallengeTx(walletAddress, chain);
|
|
1743
|
+
const signedTxBase64 = await signTransaction(txBase64);
|
|
1744
|
+
await api.linkAuthMethod(token, {
|
|
1745
|
+
provider: `${chain}_wallet_tx`,
|
|
1746
|
+
challengeId,
|
|
1747
|
+
signedTransaction: signedTxBase64,
|
|
1748
|
+
walletAddress
|
|
1749
|
+
});
|
|
1711
1750
|
}
|
|
1712
|
-
|
|
1713
|
-
|
|
1751
|
+
await fetchWallets();
|
|
1752
|
+
},
|
|
1753
|
+
[api, getAccessToken, fetchWallets]
|
|
1754
|
+
);
|
|
1755
|
+
return {
|
|
1756
|
+
wallets,
|
|
1757
|
+
loading,
|
|
1758
|
+
fetchWallets,
|
|
1759
|
+
updateWallet,
|
|
1760
|
+
linkWallet
|
|
1761
|
+
};
|
|
1714
1762
|
}
|
|
1715
1763
|
|
|
1716
|
-
// src/
|
|
1717
|
-
|
|
1764
|
+
// src/hooks/use-sessions.ts
|
|
1718
1765
|
|
|
1719
|
-
function
|
|
1720
|
-
const
|
|
1721
|
-
_react.
|
|
1722
|
-
|
|
1766
|
+
function useSessions() {
|
|
1767
|
+
const { api, getAccessToken } = useForgeConnect();
|
|
1768
|
+
const [sessions, setSessions] = _react.useState.call(void 0, null);
|
|
1769
|
+
const [loading, setLoading] = _react.useState.call(void 0, false);
|
|
1770
|
+
const fetchSessions = _react.useCallback.call(void 0, async () => {
|
|
1771
|
+
const token = getAccessToken();
|
|
1772
|
+
if (!token) throw new Error("Please sign in to continue.");
|
|
1773
|
+
setLoading(true);
|
|
1723
1774
|
try {
|
|
1724
|
-
const
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
}
|
|
1730
|
-
const dangerous = svgEl.querySelectorAll("script,iframe,object,embed,foreignObject");
|
|
1731
|
-
dangerous.forEach((el) => el.remove());
|
|
1732
|
-
const all = svgEl.querySelectorAll("*");
|
|
1733
|
-
all.forEach((el) => {
|
|
1734
|
-
for (const attr of Array.from(el.attributes)) {
|
|
1735
|
-
if (attr.name.startsWith("on")) {
|
|
1736
|
-
el.removeAttribute(attr.name);
|
|
1737
|
-
}
|
|
1738
|
-
}
|
|
1739
|
-
});
|
|
1740
|
-
ref.current.textContent = "";
|
|
1741
|
-
ref.current.appendChild(svgEl);
|
|
1742
|
-
} catch (e5) {
|
|
1743
|
-
ref.current.textContent = "";
|
|
1775
|
+
const data = await api.getSessions(token);
|
|
1776
|
+
setSessions(data);
|
|
1777
|
+
return data;
|
|
1778
|
+
} finally {
|
|
1779
|
+
setLoading(false);
|
|
1744
1780
|
}
|
|
1745
|
-
}, [
|
|
1746
|
-
|
|
1781
|
+
}, [api, getAccessToken]);
|
|
1782
|
+
const revokeSession = _react.useCallback.call(void 0,
|
|
1783
|
+
async (id) => {
|
|
1784
|
+
const token = getAccessToken();
|
|
1785
|
+
if (!token) throw new Error("Please sign in to continue.");
|
|
1786
|
+
await api.revokeSession(token, id);
|
|
1787
|
+
await fetchSessions();
|
|
1788
|
+
},
|
|
1789
|
+
[api, getAccessToken, fetchSessions]
|
|
1790
|
+
);
|
|
1791
|
+
return {
|
|
1792
|
+
sessions,
|
|
1793
|
+
loading,
|
|
1794
|
+
fetchSessions,
|
|
1795
|
+
revokeSession
|
|
1796
|
+
};
|
|
1747
1797
|
}
|
|
1748
1798
|
|
|
1749
|
-
// src/components/
|
|
1799
|
+
// src/components/two-factor-modal.tsx
|
|
1750
1800
|
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, SvgIcon, { svg: info.icon, className: "fc-oauth-icon" }),
|
|
1784
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-btn-name", children: info.label })
|
|
1785
|
-
]
|
|
1801
|
+
|
|
1802
|
+
function TwoFactorModal({ isOpen, onClose, initialEnabled, onStatusChange }) {
|
|
1803
|
+
const { api, getAccessToken, config } = useForgeConnect();
|
|
1804
|
+
const theme = _nullishCoalesce(_optionalChain([config, 'access', _46 => _46.appearance, 'optionalAccess', _47 => _47.theme]), () => ( "light"));
|
|
1805
|
+
const [step, setStep] = _react.useState.call(void 0, initialEnabled ? "manage" : "setup");
|
|
1806
|
+
const [setupData, setSetupData] = _react.useState.call(void 0, null);
|
|
1807
|
+
const [code, setCode] = _react.useState.call(void 0, "");
|
|
1808
|
+
const [loading, setLoading] = _react.useState.call(void 0, false);
|
|
1809
|
+
const [msg, setMsg] = _react.useState.call(void 0, null);
|
|
1810
|
+
const [showSecret, setShowSecret] = _react.useState.call(void 0, false);
|
|
1811
|
+
const [recoveryCodes, setRecoveryCodes] = _react.useState.call(void 0, []);
|
|
1812
|
+
_react.useEffect.call(void 0, () => {
|
|
1813
|
+
if (isOpen) {
|
|
1814
|
+
setStep(initialEnabled ? "manage" : "setup");
|
|
1815
|
+
setSetupData(null);
|
|
1816
|
+
setCode("");
|
|
1817
|
+
setMsg(null);
|
|
1818
|
+
setLoading(false);
|
|
1819
|
+
setShowSecret(false);
|
|
1820
|
+
setRecoveryCodes([]);
|
|
1821
|
+
if (!initialEnabled) {
|
|
1822
|
+
const token = getAccessToken();
|
|
1823
|
+
if (token) {
|
|
1824
|
+
setLoading(true);
|
|
1825
|
+
api.setup2FA(token).then((data) => {
|
|
1826
|
+
setSetupData(data);
|
|
1827
|
+
setRecoveryCodes(data.recoveryCodes);
|
|
1828
|
+
}).catch((err) => {
|
|
1829
|
+
setMsg({ text: err instanceof Error ? err.message : "Could not set up 2FA.", ok: false });
|
|
1830
|
+
}).finally(() => setLoading(false));
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1786
1833
|
}
|
|
1787
|
-
);
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
case "wallet-connect":
|
|
1803
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, WalletConnectForm, {});
|
|
1804
|
-
case "forgot-password":
|
|
1805
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ForgotPasswordForm, {});
|
|
1806
|
-
case "verify-2fa":
|
|
1807
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Verify2FAForm, {});
|
|
1808
|
-
case "oauth":
|
|
1809
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, OAuthLoadingView, {});
|
|
1810
|
-
case "success":
|
|
1811
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SuccessView, {});
|
|
1812
|
-
case "method-select":
|
|
1813
|
-
default:
|
|
1814
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, MethodSelect, {});
|
|
1834
|
+
}, [isOpen, initialEnabled, api, getAccessToken]);
|
|
1835
|
+
const handleEnable = async () => {
|
|
1836
|
+
const token = getAccessToken();
|
|
1837
|
+
if (!token || !code) return;
|
|
1838
|
+
setLoading(true);
|
|
1839
|
+
setMsg(null);
|
|
1840
|
+
try {
|
|
1841
|
+
await api.enable2FA(token, code);
|
|
1842
|
+
onStatusChange(true);
|
|
1843
|
+
setStep("recovery-codes");
|
|
1844
|
+
setCode("");
|
|
1845
|
+
} catch (err) {
|
|
1846
|
+
setMsg({ text: err instanceof Error ? err.message : "Invalid code.", ok: false });
|
|
1847
|
+
} finally {
|
|
1848
|
+
setLoading(false);
|
|
1815
1849
|
}
|
|
1816
1850
|
};
|
|
1817
|
-
const
|
|
1818
|
-
|
|
1819
|
-
|
|
1851
|
+
const handleDisable = async () => {
|
|
1852
|
+
const token = getAccessToken();
|
|
1853
|
+
if (!token || !code) return;
|
|
1854
|
+
setLoading(true);
|
|
1855
|
+
setMsg(null);
|
|
1856
|
+
try {
|
|
1857
|
+
await api.disable2FA(token, code);
|
|
1858
|
+
onStatusChange(false);
|
|
1859
|
+
setCode("");
|
|
1860
|
+
onClose();
|
|
1861
|
+
} catch (err) {
|
|
1862
|
+
setMsg({ text: err instanceof Error ? err.message : "Invalid code.", ok: false });
|
|
1863
|
+
} finally {
|
|
1864
|
+
setLoading(false);
|
|
1820
1865
|
}
|
|
1821
|
-
|
|
1822
|
-
|
|
1866
|
+
};
|
|
1867
|
+
const handleRegenerate = async () => {
|
|
1868
|
+
const token = getAccessToken();
|
|
1869
|
+
if (!token || !code) return;
|
|
1870
|
+
setLoading(true);
|
|
1871
|
+
setMsg(null);
|
|
1872
|
+
try {
|
|
1873
|
+
const { recoveryCodes: codes } = await api.regenerateRecoveryCodes(token, code);
|
|
1874
|
+
setRecoveryCodes(codes);
|
|
1875
|
+
setStep("recovery-codes");
|
|
1876
|
+
setCode("");
|
|
1877
|
+
} catch (err) {
|
|
1878
|
+
setMsg({ text: err instanceof Error ? err.message : "Invalid code.", ok: false });
|
|
1879
|
+
} finally {
|
|
1880
|
+
setLoading(false);
|
|
1823
1881
|
}
|
|
1824
|
-
return null;
|
|
1825
1882
|
};
|
|
1826
|
-
|
|
1883
|
+
const handleCopyAll = () => {
|
|
1884
|
+
navigator.clipboard.writeText(recoveryCodes.join("\n")).catch(() => {
|
|
1885
|
+
});
|
|
1886
|
+
};
|
|
1887
|
+
const goBack = () => {
|
|
1888
|
+
setCode("");
|
|
1889
|
+
setMsg(null);
|
|
1890
|
+
setStep("manage");
|
|
1891
|
+
};
|
|
1892
|
+
if (!isOpen) return null;
|
|
1893
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ModalOverlay, { isOpen, onClose, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1827
1894
|
"div",
|
|
1828
1895
|
{
|
|
1829
1896
|
className: "fc-modal-content",
|
|
1830
|
-
style: {
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1897
|
+
style: { "--fc-accent": _nullishCoalesce(_optionalChain([config, 'access', _48 => _48.appearance, 'optionalAccess', _49 => _49.accentColor]), () => ( "#8b5cf6")) },
|
|
1898
|
+
"data-theme": theme,
|
|
1899
|
+
children: [
|
|
1900
|
+
step === "setup" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
1901
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "fc-modal-title", children: "Set up 2FA" }),
|
|
1902
|
+
msg && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: msg.ok ? "fc-text" : "fc-error", children: msg.text }),
|
|
1903
|
+
loading && !setupData && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-text", children: "Loading..." }),
|
|
1904
|
+
setupData && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-tab", children: [
|
|
1905
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-account-section-desc", style: { textAlign: "center" }, children: "Scan this QR code with your authenticator app" }),
|
|
1906
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: { display: "flex", justifyContent: "center", margin: "12px 0" }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1907
|
+
"img",
|
|
1908
|
+
{
|
|
1909
|
+
src: setupData.qrCodeDataUrl,
|
|
1910
|
+
alt: "TOTP QR code",
|
|
1911
|
+
style: { width: 180, height: 180, borderRadius: 12 }
|
|
1912
|
+
}
|
|
1913
|
+
) }),
|
|
1914
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: { textAlign: "center", marginBottom: 12 }, children: [
|
|
1915
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "fc-link", onClick: () => setShowSecret(!showSecret), children: showSecret ? "Hide code" : "Can't scan? Enter manually" }),
|
|
1916
|
+
showSecret && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { style: { margin: "8px 0 0", fontFamily: "monospace", fontSize: 12, opacity: 0.7, wordBreak: "break-all" }, children: setupData.secret })
|
|
1917
|
+
] }),
|
|
1918
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1919
|
+
"input",
|
|
1920
|
+
{
|
|
1921
|
+
className: "fc-input",
|
|
1922
|
+
type: "text",
|
|
1923
|
+
inputMode: "numeric",
|
|
1924
|
+
placeholder: "Enter 6-digit code",
|
|
1925
|
+
maxLength: 6,
|
|
1926
|
+
value: code,
|
|
1927
|
+
onChange: (e) => setCode(e.target.value.replace(/\D/g, "")),
|
|
1928
|
+
style: { textAlign: "center", letterSpacing: "0.2em" },
|
|
1929
|
+
autoFocus: true
|
|
1930
|
+
}
|
|
1931
|
+
),
|
|
1932
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1933
|
+
"button",
|
|
1934
|
+
{
|
|
1935
|
+
type: "button",
|
|
1936
|
+
className: "fc-btn fc-btn-primary",
|
|
1937
|
+
onClick: handleEnable,
|
|
1938
|
+
disabled: loading || code.length !== 6,
|
|
1939
|
+
style: { marginTop: 10 },
|
|
1940
|
+
children: loading ? "Verifying..." : "Verify & Enable"
|
|
1941
|
+
}
|
|
1942
|
+
)
|
|
1943
|
+
] })
|
|
1944
|
+
] }),
|
|
1945
|
+
step === "manage" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
1946
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "fc-modal-title", children: "Two-factor authentication" }),
|
|
1947
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: { textAlign: "center", marginBottom: 20 }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-badge-verified", style: { fontSize: 12, padding: "4px 12px" }, children: "Enabled" }) }),
|
|
1948
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-tab", children: [
|
|
1949
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1950
|
+
"button",
|
|
1951
|
+
{
|
|
1952
|
+
type: "button",
|
|
1953
|
+
className: "fc-security-card",
|
|
1954
|
+
onClick: () => {
|
|
1955
|
+
setCode("");
|
|
1956
|
+
setMsg(null);
|
|
1957
|
+
setStep("confirm-regenerate");
|
|
1958
|
+
},
|
|
1959
|
+
children: [
|
|
1960
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-security-card-icon", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "svg", { viewBox: "0 0 20 20", fill: "none", children: [
|
|
1961
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M3 10a7 7 0 0 1 7-7m0 14a7 7 0 0 1-7-7m14 0a7 7 0 0 1-7 7m0-14a7 7 0 0 1 7 7", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }),
|
|
1962
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M14 3l-1 3h3", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
|
|
1963
|
+
] }) }),
|
|
1964
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "fc-security-card-info", children: [
|
|
1965
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-security-card-label", children: "Regenerate recovery codes" }),
|
|
1966
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-security-card-detail", children: "Get new backup codes" })
|
|
1967
|
+
] }),
|
|
1968
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-security-card-chevron", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M6 4l4 4-4 4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }) })
|
|
1969
|
+
]
|
|
1970
|
+
}
|
|
1971
|
+
),
|
|
1972
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1973
|
+
"button",
|
|
1974
|
+
{
|
|
1975
|
+
type: "button",
|
|
1976
|
+
className: "fc-security-card",
|
|
1977
|
+
onClick: () => {
|
|
1978
|
+
setCode("");
|
|
1979
|
+
setMsg(null);
|
|
1980
|
+
setStep("confirm-disable");
|
|
1981
|
+
},
|
|
1982
|
+
children: [
|
|
1983
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-security-card-icon", style: { color: "#dc2626" }, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "svg", { viewBox: "0 0 20 20", fill: "none", children: [
|
|
1984
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M10 2l6 3v4c0 4.42-2.56 8.22-6 9.5C6.56 17.22 4 13.42 4 9V5l6-3z", stroke: "currentColor", strokeWidth: "1.5", strokeLinejoin: "round" }),
|
|
1985
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M7.5 7.5l5 5M12.5 7.5l-5 5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
|
|
1986
|
+
] }) }),
|
|
1987
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "fc-security-card-info", children: [
|
|
1988
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-security-card-label", style: { color: "#dc2626" }, children: "Disable 2FA" }),
|
|
1989
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-security-card-detail", children: "Remove two-factor authentication" })
|
|
1990
|
+
] }),
|
|
1991
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-security-card-chevron", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M6 4l4 4-4 4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }) })
|
|
1992
|
+
]
|
|
1993
|
+
}
|
|
1994
|
+
)
|
|
1995
|
+
] })
|
|
1996
|
+
] }),
|
|
1997
|
+
step === "confirm-regenerate" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
1998
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "fc-modal-title", children: "Regenerate recovery codes" }),
|
|
1999
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-account-section-desc", style: { textAlign: "center" }, children: "Enter your 2FA code to generate new recovery codes. Your old codes will stop working." }),
|
|
2000
|
+
msg && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: msg.ok ? "fc-text" : "fc-error", children: msg.text }),
|
|
2001
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-tab", children: [
|
|
2002
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2003
|
+
"input",
|
|
2004
|
+
{
|
|
2005
|
+
className: "fc-input",
|
|
2006
|
+
type: "text",
|
|
2007
|
+
inputMode: "numeric",
|
|
2008
|
+
placeholder: "Enter 6-digit code",
|
|
2009
|
+
maxLength: 6,
|
|
2010
|
+
value: code,
|
|
2011
|
+
onChange: (e) => setCode(e.target.value.replace(/\D/g, "")),
|
|
2012
|
+
style: { textAlign: "center", letterSpacing: "0.2em" },
|
|
2013
|
+
autoFocus: true
|
|
2014
|
+
}
|
|
2015
|
+
),
|
|
2016
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2017
|
+
"button",
|
|
2018
|
+
{
|
|
2019
|
+
type: "button",
|
|
2020
|
+
className: "fc-btn fc-btn-primary",
|
|
2021
|
+
onClick: handleRegenerate,
|
|
2022
|
+
disabled: loading || code.length !== 6,
|
|
2023
|
+
style: { marginTop: 10 },
|
|
2024
|
+
children: loading ? "Generating..." : "Regenerate codes"
|
|
2025
|
+
}
|
|
2026
|
+
),
|
|
2027
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-switch", style: { marginTop: 12 }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "fc-link", onClick: goBack, children: "Back" }) })
|
|
2028
|
+
] })
|
|
2029
|
+
] }),
|
|
2030
|
+
step === "confirm-disable" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
2031
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "fc-modal-title", children: "Disable 2FA" }),
|
|
2032
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-account-section-desc", style: { textAlign: "center" }, children: "Enter your 2FA code to disable two-factor authentication." }),
|
|
2033
|
+
msg && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: msg.ok ? "fc-text" : "fc-error", children: msg.text }),
|
|
2034
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-tab", children: [
|
|
2035
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2036
|
+
"input",
|
|
2037
|
+
{
|
|
2038
|
+
className: "fc-input",
|
|
2039
|
+
type: "text",
|
|
2040
|
+
inputMode: "numeric",
|
|
2041
|
+
placeholder: "Enter 6-digit code",
|
|
2042
|
+
maxLength: 6,
|
|
2043
|
+
value: code,
|
|
2044
|
+
onChange: (e) => setCode(e.target.value.replace(/\D/g, "")),
|
|
2045
|
+
style: { textAlign: "center", letterSpacing: "0.2em" },
|
|
2046
|
+
autoFocus: true
|
|
2047
|
+
}
|
|
2048
|
+
),
|
|
2049
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2050
|
+
"button",
|
|
2051
|
+
{
|
|
2052
|
+
type: "button",
|
|
2053
|
+
className: "fc-btn fc-btn-secondary",
|
|
2054
|
+
onClick: handleDisable,
|
|
2055
|
+
disabled: loading || code.length !== 6,
|
|
2056
|
+
style: { marginTop: 10, background: "rgba(220, 38, 38, 0.1)", color: "#dc2626", borderColor: "rgba(220, 38, 38, 0.2)" },
|
|
2057
|
+
children: loading ? "Disabling..." : "Disable 2FA"
|
|
2058
|
+
}
|
|
2059
|
+
),
|
|
2060
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-switch", style: { marginTop: 12 }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "fc-link", onClick: goBack, children: "Back" }) })
|
|
2061
|
+
] })
|
|
2062
|
+
] }),
|
|
2063
|
+
step === "recovery-codes" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
2064
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "fc-modal-title", children: "Save your recovery codes" }),
|
|
2065
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-account-section-desc", style: { textAlign: "center" }, children: "Store these codes somewhere safe. Each code can only be used once." }),
|
|
2066
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-recovery-grid", children: recoveryCodes.map((c, i) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-recovery-code", children: c }, i)) }),
|
|
2067
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: { textAlign: "center", margin: "8px 0 12px" }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "fc-link", onClick: handleCopyAll, children: "Copy all" }) }),
|
|
2068
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "fc-btn fc-btn-primary", onClick: onClose, children: "Done" })
|
|
1844
2069
|
] })
|
|
1845
|
-
]
|
|
2070
|
+
]
|
|
1846
2071
|
}
|
|
1847
2072
|
) });
|
|
1848
2073
|
}
|
|
1849
|
-
var EmailIcon = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-method-icon-wrap", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", className: "fc-method-icon", children: [
|
|
1850
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "rect", { x: "2", y: "4", width: "16", height: "12", rx: "2", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
1851
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M2 6l8 5 8-5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
|
|
1852
|
-
] }) });
|
|
1853
|
-
var OtpIcon = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-method-icon-wrap", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", className: "fc-method-icon", children: [
|
|
1854
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "rect", { x: "3", y: "6", width: "14", height: "9", rx: "1.5", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
1855
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { cx: "6.5", cy: "10.5", r: "1", fill: "currentColor" }),
|
|
1856
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { cx: "10", cy: "10.5", r: "1", fill: "currentColor" }),
|
|
1857
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { cx: "13.5", cy: "10.5", r: "1", fill: "currentColor" })
|
|
1858
|
-
] }) });
|
|
1859
|
-
var WalletIcon = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-method-icon-wrap", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", className: "fc-method-icon", children: [
|
|
1860
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "rect", { x: "2", y: "5", width: "16", height: "11", rx: "2", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
1861
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "rect", { x: "13", y: "9", width: "5", height: "3", rx: "1", stroke: "currentColor", strokeWidth: "1.5" })
|
|
1862
|
-
] }) });
|
|
1863
|
-
var PasskeyIcon = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-method-icon-wrap", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", className: "fc-method-icon", children: [
|
|
1864
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { cx: "8", cy: "7", r: "3", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
1865
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M13 13.5a5 5 0 0 0-10 0", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }),
|
|
1866
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M15 10v4m0 0l-1.5-1m1.5 1l1.5-1", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
|
|
1867
|
-
] }) });
|
|
1868
|
-
var LoadingSpinner = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-method-icon-wrap", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", className: "fc-method-icon fc-spin", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M10 2a8 8 0 0 1 8 8", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) }) });
|
|
1869
|
-
function MethodSelect() {
|
|
1870
|
-
const { setModalStep, loginWithPasskey, config } = useForgeConnect();
|
|
1871
|
-
const methods = resolveLoginMethods(config);
|
|
1872
|
-
const [passkeyLoading, setPasskeyLoading] = _react.useState.call(void 0, false);
|
|
1873
|
-
const [passkeyError, setPasskeyError] = _react.useState.call(void 0, "");
|
|
1874
|
-
const handlePasskey = async () => {
|
|
1875
|
-
setPasskeyLoading(true);
|
|
1876
|
-
setPasskeyError("");
|
|
1877
|
-
try {
|
|
1878
|
-
await loginWithPasskey();
|
|
1879
|
-
} catch (err) {
|
|
1880
|
-
setPasskeyError(err instanceof Error ? err.message : "Passkey authentication failed.");
|
|
1881
|
-
} finally {
|
|
1882
|
-
setPasskeyLoading(false);
|
|
1883
|
-
}
|
|
1884
|
-
};
|
|
1885
|
-
const elements = [];
|
|
1886
|
-
let i = 0;
|
|
1887
|
-
while (i < methods.length) {
|
|
1888
|
-
const method = methods[i];
|
|
1889
|
-
if (isOAuthMethod(method)) {
|
|
1890
|
-
const oauthGroup = [];
|
|
1891
|
-
while (i < methods.length && isOAuthMethod(methods[i])) {
|
|
1892
|
-
oauthGroup.push(methods[i]);
|
|
1893
|
-
i++;
|
|
1894
|
-
}
|
|
1895
|
-
if (elements.length > 0) {
|
|
1896
|
-
elements.push(/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-divider", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "or" }) }, `div-before-${oauthGroup[0]}`));
|
|
1897
|
-
}
|
|
1898
|
-
elements.push(
|
|
1899
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-oauth-group", children: oauthGroup.map((p) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, OAuthButton, { provider: p }, p)) }, `oauth-${oauthGroup.join("-")}`)
|
|
1900
|
-
);
|
|
1901
|
-
} else {
|
|
1902
|
-
if (elements.length > 0) {
|
|
1903
|
-
const prev = methods[i - 1];
|
|
1904
|
-
if (prev && isOAuthMethod(prev)) {
|
|
1905
|
-
elements.push(/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-divider", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "or" }) }, `div-after-${prev}`));
|
|
1906
|
-
}
|
|
1907
|
-
}
|
|
1908
|
-
switch (method) {
|
|
1909
|
-
case "email":
|
|
1910
|
-
elements.push(
|
|
1911
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { type: "button", className: "fc-btn fc-btn-method", onClick: () => setModalStep("email-login"), children: [
|
|
1912
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, EmailIcon, {}),
|
|
1913
|
-
" ",
|
|
1914
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-btn-name", children: "Password" })
|
|
1915
|
-
] }, "email")
|
|
1916
|
-
);
|
|
1917
|
-
break;
|
|
1918
|
-
case "otp":
|
|
1919
|
-
elements.push(
|
|
1920
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { type: "button", className: "fc-btn fc-btn-method", onClick: () => setModalStep("email-otp"), children: [
|
|
1921
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, OtpIcon, {}),
|
|
1922
|
-
" ",
|
|
1923
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-btn-name", children: "Magic code" })
|
|
1924
|
-
] }, "otp")
|
|
1925
|
-
);
|
|
1926
|
-
break;
|
|
1927
|
-
case "wallet":
|
|
1928
|
-
elements.push(
|
|
1929
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { type: "button", className: "fc-btn fc-btn-method", onClick: () => setModalStep("wallet-connect"), children: [
|
|
1930
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, WalletIcon, {}),
|
|
1931
|
-
" ",
|
|
1932
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-btn-name", children: "Wallet" })
|
|
1933
|
-
] }, "wallet")
|
|
1934
|
-
);
|
|
1935
|
-
break;
|
|
1936
|
-
case "passkey":
|
|
1937
|
-
elements.push(
|
|
1938
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { type: "button", className: "fc-btn fc-btn-method", onClick: handlePasskey, disabled: passkeyLoading, children: [
|
|
1939
|
-
passkeyLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, LoadingSpinner, {}) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, PasskeyIcon, {}),
|
|
1940
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-btn-name", children: passkeyLoading ? "Waiting for passkey..." : "Passkey" })
|
|
1941
|
-
] }, "passkey")
|
|
1942
|
-
);
|
|
1943
|
-
break;
|
|
1944
|
-
}
|
|
1945
|
-
i++;
|
|
1946
|
-
}
|
|
1947
|
-
}
|
|
1948
|
-
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-method-select", children: [
|
|
1949
|
-
passkeyError && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-error", children: passkeyError }),
|
|
1950
|
-
elements
|
|
1951
|
-
] });
|
|
1952
|
-
}
|
|
1953
|
-
function OAuthLoadingView() {
|
|
1954
|
-
const { setModalStep } = useForgeConnect();
|
|
1955
|
-
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-success", children: [
|
|
1956
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-success-icon", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { width: "52", height: "52", viewBox: "0 0 52 52", className: "fc-spin", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { cx: "26", cy: "26", r: "24", fill: "none", stroke: "var(--fc-accent, #8b5cf6)", strokeWidth: "3", strokeLinecap: "round", strokeDasharray: "100", strokeDashoffset: "30" }) }) }),
|
|
1957
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-success-text", children: "Completing sign in..." }),
|
|
1958
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "fc-btn fc-btn-secondary", style: { marginTop: "16px" }, onClick: () => setModalStep("method-select"), children: "Cancel" })
|
|
1959
|
-
] });
|
|
1960
|
-
}
|
|
1961
|
-
function SuccessView() {
|
|
1962
|
-
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-success", children: [
|
|
1963
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-success-icon", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "svg", { viewBox: "0 0 52 52", className: "fc-success-check", children: [
|
|
1964
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { className: "fc-success-circle", cx: "26", cy: "26", r: "24", fill: "none" }),
|
|
1965
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { className: "fc-success-tick", fill: "none", d: "M15 26l7.5 7.5L37 19" })
|
|
1966
|
-
] }) }),
|
|
1967
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-success-text", children: "You're in" })
|
|
1968
|
-
] });
|
|
1969
|
-
}
|
|
1970
2074
|
|
|
1971
|
-
// src/components/
|
|
2075
|
+
// src/components/passkeys-modal.tsx
|
|
1972
2076
|
|
|
1973
2077
|
|
|
1974
|
-
//
|
|
2078
|
+
// ../../node_modules/.pnpm/@simplewebauthn+browser@13.2.2/node_modules/@simplewebauthn/browser/esm/helpers/bufferToBase64URLString.js
|
|
2079
|
+
function bufferToBase64URLString(buffer) {
|
|
2080
|
+
const bytes = new Uint8Array(buffer);
|
|
2081
|
+
let str = "";
|
|
2082
|
+
for (const charCode of bytes) {
|
|
2083
|
+
str += String.fromCharCode(charCode);
|
|
2084
|
+
}
|
|
2085
|
+
const base64String = btoa(str);
|
|
2086
|
+
return base64String.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
2087
|
+
}
|
|
1975
2088
|
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
const
|
|
1979
|
-
const
|
|
1980
|
-
const
|
|
1981
|
-
const
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
}
|
|
2001
|
-
const linkAuthMethod = _react.useCallback.call(void 0,
|
|
2002
|
-
async (data) => {
|
|
2003
|
-
const token = getAccessToken();
|
|
2004
|
-
if (!token) throw new Error("Please sign in to continue.");
|
|
2005
|
-
await api.linkAuthMethod(token, data);
|
|
2006
|
-
await fetchAuthMethods();
|
|
2007
|
-
},
|
|
2008
|
-
[api, getAccessToken, fetchAuthMethods]
|
|
2009
|
-
);
|
|
2010
|
-
const linkOtpSend = _react.useCallback.call(void 0,
|
|
2011
|
-
async (email) => {
|
|
2012
|
-
const token = getAccessToken();
|
|
2013
|
-
if (!token) throw new Error("Please sign in to continue.");
|
|
2014
|
-
await api.linkOtpSend(token, email);
|
|
2015
|
-
},
|
|
2016
|
-
[api, getAccessToken]
|
|
2017
|
-
);
|
|
2018
|
-
const linkOtpVerify = _react.useCallback.call(void 0,
|
|
2019
|
-
async (email, code) => {
|
|
2020
|
-
const token = getAccessToken();
|
|
2021
|
-
if (!token) throw new Error("Please sign in to continue.");
|
|
2022
|
-
await api.linkOtpVerify(token, email, code);
|
|
2023
|
-
await fetchAuthMethods();
|
|
2024
|
-
},
|
|
2025
|
-
[api, getAccessToken, fetchAuthMethods]
|
|
2026
|
-
);
|
|
2027
|
-
const unlinkAuthMethod = _react.useCallback.call(void 0,
|
|
2028
|
-
async (id) => {
|
|
2029
|
-
const token = getAccessToken();
|
|
2030
|
-
if (!token) throw new Error("Please sign in to continue.");
|
|
2031
|
-
await api.unlinkAuthMethod(token, id);
|
|
2032
|
-
await fetchAuthMethods();
|
|
2033
|
-
},
|
|
2034
|
-
[api, getAccessToken, fetchAuthMethods]
|
|
2035
|
-
);
|
|
2036
|
-
const linkOAuth = _react.useCallback.call(void 0,
|
|
2037
|
-
async (provider) => {
|
|
2038
|
-
const token = getAccessToken();
|
|
2039
|
-
if (!token) throw new Error("Please sign in to continue.");
|
|
2040
|
-
const { intentToken } = await api.createLinkIntent(token);
|
|
2041
|
-
const redirectUri = encodeURIComponent(window.location.origin + "/fc-oauth-callback");
|
|
2042
|
-
const url = `${config.apiUrl}/auth/oauth/${provider}/link?intent=${encodeURIComponent(intentToken)}&redirect_uri=${redirectUri}`;
|
|
2043
|
-
const width = 500;
|
|
2044
|
-
const height = 600;
|
|
2045
|
-
const left = window.screenX + (window.innerWidth - width) / 2;
|
|
2046
|
-
const top = window.screenY + (window.innerHeight - height) / 2;
|
|
2047
|
-
window.open(url, "fc_oauth_link", `width=${width},height=${height},left=${left},top=${top}`);
|
|
2048
|
-
pendingRefreshRef.current = true;
|
|
2049
|
-
},
|
|
2050
|
-
[api, config.apiUrl, getAccessToken]
|
|
2051
|
-
);
|
|
2052
|
-
_react.useEffect.call(void 0, () => {
|
|
2053
|
-
const handleMessage = (event) => {
|
|
2054
|
-
if (event.origin !== window.location.origin) return;
|
|
2055
|
-
if (_optionalChain([event, 'access', _57 => _57.data, 'optionalAccess', _58 => _58.type]) === "fc_oauth_link_success" && pendingRefreshRef.current) {
|
|
2056
|
-
pendingRefreshRef.current = false;
|
|
2057
|
-
fetchAuthMethods().catch(() => {
|
|
2058
|
-
});
|
|
2059
|
-
}
|
|
2060
|
-
};
|
|
2061
|
-
window.addEventListener("message", handleMessage);
|
|
2062
|
-
return () => window.removeEventListener("message", handleMessage);
|
|
2063
|
-
}, [fetchAuthMethods]);
|
|
2089
|
+
// ../../node_modules/.pnpm/@simplewebauthn+browser@13.2.2/node_modules/@simplewebauthn/browser/esm/helpers/base64URLStringToBuffer.js
|
|
2090
|
+
function base64URLStringToBuffer(base64URLString) {
|
|
2091
|
+
const base64 = base64URLString.replace(/-/g, "+").replace(/_/g, "/");
|
|
2092
|
+
const padLength = (4 - base64.length % 4) % 4;
|
|
2093
|
+
const padded = base64.padEnd(base64.length + padLength, "=");
|
|
2094
|
+
const binary = atob(padded);
|
|
2095
|
+
const buffer = new ArrayBuffer(binary.length);
|
|
2096
|
+
const bytes = new Uint8Array(buffer);
|
|
2097
|
+
for (let i = 0; i < binary.length; i++) {
|
|
2098
|
+
bytes[i] = binary.charCodeAt(i);
|
|
2099
|
+
}
|
|
2100
|
+
return buffer;
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2103
|
+
// ../../node_modules/.pnpm/@simplewebauthn+browser@13.2.2/node_modules/@simplewebauthn/browser/esm/helpers/browserSupportsWebAuthn.js
|
|
2104
|
+
function browserSupportsWebAuthn() {
|
|
2105
|
+
return _browserSupportsWebAuthnInternals.stubThis(_optionalChain([globalThis, 'optionalAccess', _50 => _50.PublicKeyCredential]) !== void 0 && typeof globalThis.PublicKeyCredential === "function");
|
|
2106
|
+
}
|
|
2107
|
+
var _browserSupportsWebAuthnInternals = {
|
|
2108
|
+
stubThis: (value) => value
|
|
2109
|
+
};
|
|
2110
|
+
|
|
2111
|
+
// ../../node_modules/.pnpm/@simplewebauthn+browser@13.2.2/node_modules/@simplewebauthn/browser/esm/helpers/toPublicKeyCredentialDescriptor.js
|
|
2112
|
+
function toPublicKeyCredentialDescriptor(descriptor) {
|
|
2113
|
+
const { id } = descriptor;
|
|
2064
2114
|
return {
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
unlinkAuthMethod,
|
|
2074
|
-
linkOAuth
|
|
2115
|
+
...descriptor,
|
|
2116
|
+
id: base64URLStringToBuffer(id),
|
|
2117
|
+
/**
|
|
2118
|
+
* `descriptor.transports` is an array of our `AuthenticatorTransportFuture` that includes newer
|
|
2119
|
+
* transports that TypeScript's DOM lib is ignorant of. Convince TS that our list of transports
|
|
2120
|
+
* are fine to pass to WebAuthn since browsers will recognize the new value.
|
|
2121
|
+
*/
|
|
2122
|
+
transports: descriptor.transports
|
|
2075
2123
|
};
|
|
2076
2124
|
}
|
|
2077
2125
|
|
|
2078
|
-
//
|
|
2126
|
+
// ../../node_modules/.pnpm/@simplewebauthn+browser@13.2.2/node_modules/@simplewebauthn/browser/esm/helpers/isValidDomain.js
|
|
2127
|
+
function isValidDomain(hostname) {
|
|
2128
|
+
return (
|
|
2129
|
+
// Consider localhost valid as well since it's okay wrt Secure Contexts
|
|
2130
|
+
hostname === "localhost" || /^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/i.test(hostname)
|
|
2131
|
+
);
|
|
2132
|
+
}
|
|
2079
2133
|
|
|
2134
|
+
// ../../node_modules/.pnpm/@simplewebauthn+browser@13.2.2/node_modules/@simplewebauthn/browser/esm/helpers/webAuthnError.js
|
|
2135
|
+
var WebAuthnError = class extends Error {
|
|
2136
|
+
constructor({ message, code, cause, name }) {
|
|
2137
|
+
super(message, { cause });
|
|
2138
|
+
Object.defineProperty(this, "code", {
|
|
2139
|
+
enumerable: true,
|
|
2140
|
+
configurable: true,
|
|
2141
|
+
writable: true,
|
|
2142
|
+
value: void 0
|
|
2143
|
+
});
|
|
2144
|
+
this.name = _nullishCoalesce(name, () => ( cause.name));
|
|
2145
|
+
this.code = code;
|
|
2146
|
+
}
|
|
2147
|
+
};
|
|
2080
2148
|
|
|
2081
|
-
//
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2149
|
+
// ../../node_modules/.pnpm/@simplewebauthn+browser@13.2.2/node_modules/@simplewebauthn/browser/esm/helpers/identifyRegistrationError.js
|
|
2150
|
+
function identifyRegistrationError({ error, options }) {
|
|
2151
|
+
const { publicKey } = options;
|
|
2152
|
+
if (!publicKey) {
|
|
2153
|
+
throw Error("options was missing required publicKey property");
|
|
2154
|
+
}
|
|
2155
|
+
if (error.name === "AbortError") {
|
|
2156
|
+
if (options.signal instanceof AbortSignal) {
|
|
2157
|
+
return new WebAuthnError({
|
|
2158
|
+
message: "Registration ceremony was sent an abort signal",
|
|
2159
|
+
code: "ERROR_CEREMONY_ABORTED",
|
|
2160
|
+
cause: error
|
|
2161
|
+
});
|
|
2091
2162
|
}
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2163
|
+
} else if (error.name === "ConstraintError") {
|
|
2164
|
+
if (_optionalChain([publicKey, 'access', _51 => _51.authenticatorSelection, 'optionalAccess', _52 => _52.requireResidentKey]) === true) {
|
|
2165
|
+
return new WebAuthnError({
|
|
2166
|
+
message: "Discoverable credentials were required but no available authenticator supported it",
|
|
2167
|
+
code: "ERROR_AUTHENTICATOR_MISSING_DISCOVERABLE_CREDENTIAL_SUPPORT",
|
|
2168
|
+
cause: error
|
|
2169
|
+
});
|
|
2170
|
+
} else if (
|
|
2171
|
+
// @ts-ignore: `mediation` doesn't yet exist on CredentialCreationOptions but it's possible as of Sept 2024
|
|
2172
|
+
options.mediation === "conditional" && _optionalChain([publicKey, 'access', _53 => _53.authenticatorSelection, 'optionalAccess', _54 => _54.userVerification]) === "required"
|
|
2173
|
+
) {
|
|
2174
|
+
return new WebAuthnError({
|
|
2175
|
+
message: "User verification was required during automatic registration but it could not be performed",
|
|
2176
|
+
code: "ERROR_AUTO_REGISTER_USER_VERIFICATION_FAILURE",
|
|
2177
|
+
cause: error
|
|
2178
|
+
});
|
|
2179
|
+
} else if (_optionalChain([publicKey, 'access', _55 => _55.authenticatorSelection, 'optionalAccess', _56 => _56.userVerification]) === "required") {
|
|
2180
|
+
return new WebAuthnError({
|
|
2181
|
+
message: "User verification was required but no available authenticator supported it",
|
|
2182
|
+
code: "ERROR_AUTHENTICATOR_MISSING_USER_VERIFICATION_SUPPORT",
|
|
2183
|
+
cause: error
|
|
2184
|
+
});
|
|
2185
|
+
}
|
|
2186
|
+
} else if (error.name === "InvalidStateError") {
|
|
2187
|
+
return new WebAuthnError({
|
|
2188
|
+
message: "The authenticator was previously registered",
|
|
2189
|
+
code: "ERROR_AUTHENTICATOR_PREVIOUSLY_REGISTERED",
|
|
2190
|
+
cause: error
|
|
2191
|
+
});
|
|
2192
|
+
} else if (error.name === "NotAllowedError") {
|
|
2193
|
+
return new WebAuthnError({
|
|
2194
|
+
message: error.message,
|
|
2195
|
+
code: "ERROR_PASSTHROUGH_SEE_CAUSE_PROPERTY",
|
|
2196
|
+
cause: error
|
|
2197
|
+
});
|
|
2198
|
+
} else if (error.name === "NotSupportedError") {
|
|
2199
|
+
const validPubKeyCredParams = publicKey.pubKeyCredParams.filter((param) => param.type === "public-key");
|
|
2200
|
+
if (validPubKeyCredParams.length === 0) {
|
|
2201
|
+
return new WebAuthnError({
|
|
2202
|
+
message: 'No entry in pubKeyCredParams was of type "public-key"',
|
|
2203
|
+
code: "ERROR_MALFORMED_PUBKEYCREDPARAMS",
|
|
2204
|
+
cause: error
|
|
2205
|
+
});
|
|
2206
|
+
}
|
|
2207
|
+
return new WebAuthnError({
|
|
2208
|
+
message: "No available authenticator supported any of the specified pubKeyCredParams algorithms",
|
|
2209
|
+
code: "ERROR_AUTHENTICATOR_NO_SUPPORTED_PUBKEYCREDPARAMS_ALG",
|
|
2210
|
+
cause: error
|
|
2211
|
+
});
|
|
2212
|
+
} else if (error.name === "SecurityError") {
|
|
2213
|
+
const effectiveDomain = globalThis.location.hostname;
|
|
2214
|
+
if (!isValidDomain(effectiveDomain)) {
|
|
2215
|
+
return new WebAuthnError({
|
|
2216
|
+
message: `${globalThis.location.hostname} is an invalid domain`,
|
|
2217
|
+
code: "ERROR_INVALID_DOMAIN",
|
|
2218
|
+
cause: error
|
|
2219
|
+
});
|
|
2220
|
+
} else if (publicKey.rp.id !== effectiveDomain) {
|
|
2221
|
+
return new WebAuthnError({
|
|
2222
|
+
message: `The RP ID "${publicKey.rp.id}" is invalid for this domain`,
|
|
2223
|
+
code: "ERROR_INVALID_RP_ID",
|
|
2224
|
+
cause: error
|
|
2225
|
+
});
|
|
2226
|
+
}
|
|
2227
|
+
} else if (error.name === "TypeError") {
|
|
2228
|
+
if (publicKey.user.id.byteLength < 1 || publicKey.user.id.byteLength > 64) {
|
|
2229
|
+
return new WebAuthnError({
|
|
2230
|
+
message: "User ID was not between 1 and 64 characters",
|
|
2231
|
+
code: "ERROR_INVALID_USER_ID_LENGTH",
|
|
2232
|
+
cause: error
|
|
2233
|
+
});
|
|
2095
2234
|
}
|
|
2235
|
+
} else if (error.name === "UnknownError") {
|
|
2236
|
+
return new WebAuthnError({
|
|
2237
|
+
message: "The authenticator was unable to process the specified options, or could not create a new credential",
|
|
2238
|
+
code: "ERROR_AUTHENTICATOR_GENERAL_ERROR",
|
|
2239
|
+
cause: error
|
|
2240
|
+
});
|
|
2096
2241
|
}
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2242
|
+
return error;
|
|
2243
|
+
}
|
|
2244
|
+
|
|
2245
|
+
// ../../node_modules/.pnpm/@simplewebauthn+browser@13.2.2/node_modules/@simplewebauthn/browser/esm/helpers/webAuthnAbortService.js
|
|
2246
|
+
var BaseWebAuthnAbortService = class {
|
|
2247
|
+
constructor() {
|
|
2248
|
+
Object.defineProperty(this, "controller", {
|
|
2249
|
+
enumerable: true,
|
|
2250
|
+
configurable: true,
|
|
2251
|
+
writable: true,
|
|
2252
|
+
value: void 0
|
|
2253
|
+
});
|
|
2100
2254
|
}
|
|
2101
|
-
|
|
2102
|
-
|
|
2255
|
+
createNewAbortSignal() {
|
|
2256
|
+
if (this.controller) {
|
|
2257
|
+
const abortError = new Error("Cancelling existing WebAuthn API call for new one");
|
|
2258
|
+
abortError.name = "AbortError";
|
|
2259
|
+
this.controller.abort(abortError);
|
|
2260
|
+
}
|
|
2261
|
+
const newController = new AbortController();
|
|
2262
|
+
this.controller = newController;
|
|
2263
|
+
return newController.signal;
|
|
2103
2264
|
}
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2265
|
+
cancelCeremony() {
|
|
2266
|
+
if (this.controller) {
|
|
2267
|
+
const abortError = new Error("Manually cancelling existing WebAuthn API call");
|
|
2268
|
+
abortError.name = "AbortError";
|
|
2269
|
+
this.controller.abort(abortError);
|
|
2270
|
+
this.controller = void 0;
|
|
2271
|
+
}
|
|
2272
|
+
}
|
|
2273
|
+
};
|
|
2274
|
+
var WebAuthnAbortService = new BaseWebAuthnAbortService();
|
|
2275
|
+
|
|
2276
|
+
// ../../node_modules/.pnpm/@simplewebauthn+browser@13.2.2/node_modules/@simplewebauthn/browser/esm/helpers/toAuthenticatorAttachment.js
|
|
2277
|
+
var attachments = ["cross-platform", "platform"];
|
|
2278
|
+
function toAuthenticatorAttachment(attachment) {
|
|
2279
|
+
if (!attachment) {
|
|
2280
|
+
return;
|
|
2281
|
+
}
|
|
2282
|
+
if (attachments.indexOf(attachment) < 0) {
|
|
2283
|
+
return;
|
|
2284
|
+
}
|
|
2285
|
+
return attachment;
|
|
2118
2286
|
}
|
|
2119
2287
|
|
|
2120
|
-
//
|
|
2121
|
-
function
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
}, [api, getAccessToken]);
|
|
2137
|
-
const updateWallet = _react.useCallback.call(void 0,
|
|
2138
|
-
async (id, data) => {
|
|
2139
|
-
const token = getAccessToken();
|
|
2140
|
-
if (!token) throw new Error("Please sign in to continue.");
|
|
2141
|
-
await api.updateWallet(token, id, data);
|
|
2142
|
-
await fetchWallets();
|
|
2143
|
-
},
|
|
2144
|
-
[api, getAccessToken, fetchWallets]
|
|
2145
|
-
);
|
|
2146
|
-
const linkWallet = _react.useCallback.call(void 0,
|
|
2147
|
-
async (walletAddress, signMessage, chain = "solana") => {
|
|
2148
|
-
const token = getAccessToken();
|
|
2149
|
-
if (!token) throw new Error("Please sign in to continue.");
|
|
2150
|
-
const { challengeId, message: challengeMessage } = await api.walletChallenge(walletAddress, chain);
|
|
2151
|
-
const encoded = new TextEncoder().encode(challengeMessage);
|
|
2152
|
-
const signatureBytes = await signMessage(encoded);
|
|
2153
|
-
const signature = chain === "solana" ? uint8ArrayToBase58(signatureBytes) : Array.from(signatureBytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
2154
|
-
await api.linkAuthMethod(token, {
|
|
2155
|
-
provider: `${chain}_wallet`,
|
|
2156
|
-
challengeId,
|
|
2157
|
-
signature,
|
|
2158
|
-
walletAddress
|
|
2159
|
-
});
|
|
2160
|
-
await fetchWallets();
|
|
2288
|
+
// ../../node_modules/.pnpm/@simplewebauthn+browser@13.2.2/node_modules/@simplewebauthn/browser/esm/methods/startRegistration.js
|
|
2289
|
+
async function startRegistration(options) {
|
|
2290
|
+
if (!options.optionsJSON && options.challenge) {
|
|
2291
|
+
console.warn("startRegistration() was not called correctly. It will try to continue with the provided options, but this call should be refactored to use the expected call structure instead. See https://simplewebauthn.dev/docs/packages/browser#typeerror-cannot-read-properties-of-undefined-reading-challenge for more information.");
|
|
2292
|
+
options = { optionsJSON: options };
|
|
2293
|
+
}
|
|
2294
|
+
const { optionsJSON, useAutoRegister = false } = options;
|
|
2295
|
+
if (!browserSupportsWebAuthn()) {
|
|
2296
|
+
throw new Error("WebAuthn is not supported in this browser");
|
|
2297
|
+
}
|
|
2298
|
+
const publicKey = {
|
|
2299
|
+
...optionsJSON,
|
|
2300
|
+
challenge: base64URLStringToBuffer(optionsJSON.challenge),
|
|
2301
|
+
user: {
|
|
2302
|
+
...optionsJSON.user,
|
|
2303
|
+
id: base64URLStringToBuffer(optionsJSON.user.id)
|
|
2161
2304
|
},
|
|
2162
|
-
[
|
|
2163
|
-
);
|
|
2164
|
-
return {
|
|
2165
|
-
wallets,
|
|
2166
|
-
loading,
|
|
2167
|
-
fetchWallets,
|
|
2168
|
-
updateWallet,
|
|
2169
|
-
linkWallet
|
|
2305
|
+
excludeCredentials: _optionalChain([optionsJSON, 'access', _57 => _57.excludeCredentials, 'optionalAccess', _58 => _58.map, 'call', _59 => _59(toPublicKeyCredentialDescriptor)])
|
|
2170
2306
|
};
|
|
2171
|
-
}
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2307
|
+
const createOptions = {};
|
|
2308
|
+
if (useAutoRegister) {
|
|
2309
|
+
createOptions.mediation = "conditional";
|
|
2310
|
+
}
|
|
2311
|
+
createOptions.publicKey = publicKey;
|
|
2312
|
+
createOptions.signal = WebAuthnAbortService.createNewAbortSignal();
|
|
2313
|
+
let credential;
|
|
2314
|
+
try {
|
|
2315
|
+
credential = await navigator.credentials.create(createOptions);
|
|
2316
|
+
} catch (err) {
|
|
2317
|
+
throw identifyRegistrationError({ error: err, options: createOptions });
|
|
2318
|
+
}
|
|
2319
|
+
if (!credential) {
|
|
2320
|
+
throw new Error("Registration was not completed");
|
|
2321
|
+
}
|
|
2322
|
+
const { id, rawId, response, type } = credential;
|
|
2323
|
+
let transports = void 0;
|
|
2324
|
+
if (typeof response.getTransports === "function") {
|
|
2325
|
+
transports = response.getTransports();
|
|
2326
|
+
}
|
|
2327
|
+
let responsePublicKeyAlgorithm = void 0;
|
|
2328
|
+
if (typeof response.getPublicKeyAlgorithm === "function") {
|
|
2183
2329
|
try {
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
} finally {
|
|
2188
|
-
setLoading(false);
|
|
2330
|
+
responsePublicKeyAlgorithm = response.getPublicKeyAlgorithm();
|
|
2331
|
+
} catch (error) {
|
|
2332
|
+
warnOnBrokenImplementation("getPublicKeyAlgorithm()", error);
|
|
2189
2333
|
}
|
|
2190
|
-
}
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
},
|
|
2198
|
-
[api, getAccessToken, fetchSessions]
|
|
2199
|
-
);
|
|
2200
|
-
return {
|
|
2201
|
-
sessions,
|
|
2202
|
-
loading,
|
|
2203
|
-
fetchSessions,
|
|
2204
|
-
revokeSession
|
|
2205
|
-
};
|
|
2206
|
-
}
|
|
2207
|
-
|
|
2208
|
-
// src/components/two-factor-modal.tsx
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
function TwoFactorModal({ isOpen, onClose, initialEnabled, onStatusChange }) {
|
|
2212
|
-
const { api, getAccessToken, config } = useForgeConnect();
|
|
2213
|
-
const theme = _nullishCoalesce(_optionalChain([config, 'access', _59 => _59.appearance, 'optionalAccess', _60 => _60.theme]), () => ( "light"));
|
|
2214
|
-
const [step, setStep] = _react.useState.call(void 0, initialEnabled ? "manage" : "setup");
|
|
2215
|
-
const [setupData, setSetupData] = _react.useState.call(void 0, null);
|
|
2216
|
-
const [code, setCode] = _react.useState.call(void 0, "");
|
|
2217
|
-
const [loading, setLoading] = _react.useState.call(void 0, false);
|
|
2218
|
-
const [msg, setMsg] = _react.useState.call(void 0, null);
|
|
2219
|
-
const [showSecret, setShowSecret] = _react.useState.call(void 0, false);
|
|
2220
|
-
const [recoveryCodes, setRecoveryCodes] = _react.useState.call(void 0, []);
|
|
2221
|
-
_react.useEffect.call(void 0, () => {
|
|
2222
|
-
if (isOpen) {
|
|
2223
|
-
setStep(initialEnabled ? "manage" : "setup");
|
|
2224
|
-
setSetupData(null);
|
|
2225
|
-
setCode("");
|
|
2226
|
-
setMsg(null);
|
|
2227
|
-
setLoading(false);
|
|
2228
|
-
setShowSecret(false);
|
|
2229
|
-
setRecoveryCodes([]);
|
|
2230
|
-
if (!initialEnabled) {
|
|
2231
|
-
const token = getAccessToken();
|
|
2232
|
-
if (token) {
|
|
2233
|
-
setLoading(true);
|
|
2234
|
-
api.setup2FA(token).then((data) => {
|
|
2235
|
-
setSetupData(data);
|
|
2236
|
-
setRecoveryCodes(data.recoveryCodes);
|
|
2237
|
-
}).catch((err) => {
|
|
2238
|
-
setMsg({ text: err instanceof Error ? err.message : "Could not set up 2FA.", ok: false });
|
|
2239
|
-
}).finally(() => setLoading(false));
|
|
2240
|
-
}
|
|
2334
|
+
}
|
|
2335
|
+
let responsePublicKey = void 0;
|
|
2336
|
+
if (typeof response.getPublicKey === "function") {
|
|
2337
|
+
try {
|
|
2338
|
+
const _publicKey = response.getPublicKey();
|
|
2339
|
+
if (_publicKey !== null) {
|
|
2340
|
+
responsePublicKey = bufferToBase64URLString(_publicKey);
|
|
2241
2341
|
}
|
|
2342
|
+
} catch (error) {
|
|
2343
|
+
warnOnBrokenImplementation("getPublicKey()", error);
|
|
2242
2344
|
}
|
|
2243
|
-
}
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
if (!token || !code) return;
|
|
2247
|
-
setLoading(true);
|
|
2248
|
-
setMsg(null);
|
|
2345
|
+
}
|
|
2346
|
+
let responseAuthenticatorData;
|
|
2347
|
+
if (typeof response.getAuthenticatorData === "function") {
|
|
2249
2348
|
try {
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
setCode("");
|
|
2254
|
-
} catch (err) {
|
|
2255
|
-
setMsg({ text: err instanceof Error ? err.message : "Invalid code.", ok: false });
|
|
2256
|
-
} finally {
|
|
2257
|
-
setLoading(false);
|
|
2349
|
+
responseAuthenticatorData = bufferToBase64URLString(response.getAuthenticatorData());
|
|
2350
|
+
} catch (error) {
|
|
2351
|
+
warnOnBrokenImplementation("getAuthenticatorData()", error);
|
|
2258
2352
|
}
|
|
2353
|
+
}
|
|
2354
|
+
return {
|
|
2355
|
+
id,
|
|
2356
|
+
rawId: bufferToBase64URLString(rawId),
|
|
2357
|
+
response: {
|
|
2358
|
+
attestationObject: bufferToBase64URLString(response.attestationObject),
|
|
2359
|
+
clientDataJSON: bufferToBase64URLString(response.clientDataJSON),
|
|
2360
|
+
transports,
|
|
2361
|
+
publicKeyAlgorithm: responsePublicKeyAlgorithm,
|
|
2362
|
+
publicKey: responsePublicKey,
|
|
2363
|
+
authenticatorData: responseAuthenticatorData
|
|
2364
|
+
},
|
|
2365
|
+
type,
|
|
2366
|
+
clientExtensionResults: credential.getClientExtensionResults(),
|
|
2367
|
+
authenticatorAttachment: toAuthenticatorAttachment(credential.authenticatorAttachment)
|
|
2259
2368
|
};
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2369
|
+
}
|
|
2370
|
+
function warnOnBrokenImplementation(methodName, cause) {
|
|
2371
|
+
console.warn(`The browser extension that intercepted this WebAuthn API call incorrectly implemented ${methodName}. You should report this error to them.
|
|
2372
|
+
`, cause);
|
|
2373
|
+
}
|
|
2374
|
+
|
|
2375
|
+
// ../../node_modules/.pnpm/@simplewebauthn+browser@13.2.2/node_modules/@simplewebauthn/browser/esm/helpers/browserSupportsWebAuthnAutofill.js
|
|
2376
|
+
function browserSupportsWebAuthnAutofill() {
|
|
2377
|
+
if (!browserSupportsWebAuthn()) {
|
|
2378
|
+
return _browserSupportsWebAuthnAutofillInternals.stubThis(new Promise((resolve) => resolve(false)));
|
|
2379
|
+
}
|
|
2380
|
+
const globalPublicKeyCredential = globalThis.PublicKeyCredential;
|
|
2381
|
+
if (_optionalChain([globalPublicKeyCredential, 'optionalAccess', _60 => _60.isConditionalMediationAvailable]) === void 0) {
|
|
2382
|
+
return _browserSupportsWebAuthnAutofillInternals.stubThis(new Promise((resolve) => resolve(false)));
|
|
2383
|
+
}
|
|
2384
|
+
return _browserSupportsWebAuthnAutofillInternals.stubThis(globalPublicKeyCredential.isConditionalMediationAvailable());
|
|
2385
|
+
}
|
|
2386
|
+
var _browserSupportsWebAuthnAutofillInternals = {
|
|
2387
|
+
stubThis: (value) => value
|
|
2388
|
+
};
|
|
2389
|
+
|
|
2390
|
+
// ../../node_modules/.pnpm/@simplewebauthn+browser@13.2.2/node_modules/@simplewebauthn/browser/esm/helpers/identifyAuthenticationError.js
|
|
2391
|
+
function identifyAuthenticationError({ error, options }) {
|
|
2392
|
+
const { publicKey } = options;
|
|
2393
|
+
if (!publicKey) {
|
|
2394
|
+
throw Error("options was missing required publicKey property");
|
|
2395
|
+
}
|
|
2396
|
+
if (error.name === "AbortError") {
|
|
2397
|
+
if (options.signal instanceof AbortSignal) {
|
|
2398
|
+
return new WebAuthnError({
|
|
2399
|
+
message: "Authentication ceremony was sent an abort signal",
|
|
2400
|
+
code: "ERROR_CEREMONY_ABORTED",
|
|
2401
|
+
cause: error
|
|
2402
|
+
});
|
|
2274
2403
|
}
|
|
2275
|
-
}
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2404
|
+
} else if (error.name === "NotAllowedError") {
|
|
2405
|
+
return new WebAuthnError({
|
|
2406
|
+
message: error.message,
|
|
2407
|
+
code: "ERROR_PASSTHROUGH_SEE_CAUSE_PROPERTY",
|
|
2408
|
+
cause: error
|
|
2409
|
+
});
|
|
2410
|
+
} else if (error.name === "SecurityError") {
|
|
2411
|
+
const effectiveDomain = globalThis.location.hostname;
|
|
2412
|
+
if (!isValidDomain(effectiveDomain)) {
|
|
2413
|
+
return new WebAuthnError({
|
|
2414
|
+
message: `${globalThis.location.hostname} is an invalid domain`,
|
|
2415
|
+
code: "ERROR_INVALID_DOMAIN",
|
|
2416
|
+
cause: error
|
|
2417
|
+
});
|
|
2418
|
+
} else if (publicKey.rpId !== effectiveDomain) {
|
|
2419
|
+
return new WebAuthnError({
|
|
2420
|
+
message: `The RP ID "${publicKey.rpId}" is invalid for this domain`,
|
|
2421
|
+
code: "ERROR_INVALID_RP_ID",
|
|
2422
|
+
cause: error
|
|
2423
|
+
});
|
|
2290
2424
|
}
|
|
2291
|
-
}
|
|
2292
|
-
|
|
2293
|
-
|
|
2425
|
+
} else if (error.name === "UnknownError") {
|
|
2426
|
+
return new WebAuthnError({
|
|
2427
|
+
message: "The authenticator was unable to process the specified options, or could not create a new assertion signature",
|
|
2428
|
+
code: "ERROR_AUTHENTICATOR_GENERAL_ERROR",
|
|
2429
|
+
cause: error
|
|
2294
2430
|
});
|
|
2431
|
+
}
|
|
2432
|
+
return error;
|
|
2433
|
+
}
|
|
2434
|
+
|
|
2435
|
+
// ../../node_modules/.pnpm/@simplewebauthn+browser@13.2.2/node_modules/@simplewebauthn/browser/esm/methods/startAuthentication.js
|
|
2436
|
+
async function startAuthentication(options) {
|
|
2437
|
+
if (!options.optionsJSON && options.challenge) {
|
|
2438
|
+
console.warn("startAuthentication() was not called correctly. It will try to continue with the provided options, but this call should be refactored to use the expected call structure instead. See https://simplewebauthn.dev/docs/packages/browser#typeerror-cannot-read-properties-of-undefined-reading-challenge for more information.");
|
|
2439
|
+
options = { optionsJSON: options };
|
|
2440
|
+
}
|
|
2441
|
+
const { optionsJSON, useBrowserAutofill = false, verifyBrowserAutofillInput = true } = options;
|
|
2442
|
+
if (!browserSupportsWebAuthn()) {
|
|
2443
|
+
throw new Error("WebAuthn is not supported in this browser");
|
|
2444
|
+
}
|
|
2445
|
+
let allowCredentials;
|
|
2446
|
+
if (_optionalChain([optionsJSON, 'access', _61 => _61.allowCredentials, 'optionalAccess', _62 => _62.length]) !== 0) {
|
|
2447
|
+
allowCredentials = _optionalChain([optionsJSON, 'access', _63 => _63.allowCredentials, 'optionalAccess', _64 => _64.map, 'call', _65 => _65(toPublicKeyCredentialDescriptor)]);
|
|
2448
|
+
}
|
|
2449
|
+
const publicKey = {
|
|
2450
|
+
...optionsJSON,
|
|
2451
|
+
challenge: base64URLStringToBuffer(optionsJSON.challenge),
|
|
2452
|
+
allowCredentials
|
|
2295
2453
|
};
|
|
2296
|
-
const
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
};
|
|
2301
|
-
if (!isOpen) return null;
|
|
2302
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ModalOverlay, { isOpen, onClose, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
2303
|
-
"div",
|
|
2304
|
-
{
|
|
2305
|
-
className: "fc-modal-content",
|
|
2306
|
-
style: { "--fc-accent": _nullishCoalesce(_optionalChain([config, 'access', _61 => _61.appearance, 'optionalAccess', _62 => _62.accentColor]), () => ( "#8b5cf6")) },
|
|
2307
|
-
"data-theme": theme,
|
|
2308
|
-
children: [
|
|
2309
|
-
step === "setup" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
2310
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "fc-modal-title", children: "Set up 2FA" }),
|
|
2311
|
-
msg && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: msg.ok ? "fc-text" : "fc-error", children: msg.text }),
|
|
2312
|
-
loading && !setupData && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-text", children: "Loading..." }),
|
|
2313
|
-
setupData && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-tab", children: [
|
|
2314
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-account-section-desc", style: { textAlign: "center" }, children: "Scan this QR code with your authenticator app" }),
|
|
2315
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: { display: "flex", justifyContent: "center", margin: "12px 0" }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2316
|
-
"img",
|
|
2317
|
-
{
|
|
2318
|
-
src: setupData.qrCodeDataUrl,
|
|
2319
|
-
alt: "TOTP QR code",
|
|
2320
|
-
style: { width: 180, height: 180, borderRadius: 12 }
|
|
2321
|
-
}
|
|
2322
|
-
) }),
|
|
2323
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: { textAlign: "center", marginBottom: 12 }, children: [
|
|
2324
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "fc-link", onClick: () => setShowSecret(!showSecret), children: showSecret ? "Hide code" : "Can't scan? Enter manually" }),
|
|
2325
|
-
showSecret && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { style: { margin: "8px 0 0", fontFamily: "monospace", fontSize: 12, opacity: 0.7, wordBreak: "break-all" }, children: setupData.secret })
|
|
2326
|
-
] }),
|
|
2327
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2328
|
-
"input",
|
|
2329
|
-
{
|
|
2330
|
-
className: "fc-input",
|
|
2331
|
-
type: "text",
|
|
2332
|
-
inputMode: "numeric",
|
|
2333
|
-
placeholder: "Enter 6-digit code",
|
|
2334
|
-
maxLength: 6,
|
|
2335
|
-
value: code,
|
|
2336
|
-
onChange: (e) => setCode(e.target.value.replace(/\D/g, "")),
|
|
2337
|
-
style: { textAlign: "center", letterSpacing: "0.2em" },
|
|
2338
|
-
autoFocus: true
|
|
2339
|
-
}
|
|
2340
|
-
),
|
|
2341
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2342
|
-
"button",
|
|
2343
|
-
{
|
|
2344
|
-
type: "button",
|
|
2345
|
-
className: "fc-btn fc-btn-primary",
|
|
2346
|
-
onClick: handleEnable,
|
|
2347
|
-
disabled: loading || code.length !== 6,
|
|
2348
|
-
style: { marginTop: 10 },
|
|
2349
|
-
children: loading ? "Verifying..." : "Verify & Enable"
|
|
2350
|
-
}
|
|
2351
|
-
)
|
|
2352
|
-
] })
|
|
2353
|
-
] }),
|
|
2354
|
-
step === "manage" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
2355
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "fc-modal-title", children: "Two-factor authentication" }),
|
|
2356
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: { textAlign: "center", marginBottom: 20 }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-badge-verified", style: { fontSize: 12, padding: "4px 12px" }, children: "Enabled" }) }),
|
|
2357
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-tab", children: [
|
|
2358
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
2359
|
-
"button",
|
|
2360
|
-
{
|
|
2361
|
-
type: "button",
|
|
2362
|
-
className: "fc-security-card",
|
|
2363
|
-
onClick: () => {
|
|
2364
|
-
setCode("");
|
|
2365
|
-
setMsg(null);
|
|
2366
|
-
setStep("confirm-regenerate");
|
|
2367
|
-
},
|
|
2368
|
-
children: [
|
|
2369
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-security-card-icon", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "svg", { viewBox: "0 0 20 20", fill: "none", children: [
|
|
2370
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M3 10a7 7 0 0 1 7-7m0 14a7 7 0 0 1-7-7m14 0a7 7 0 0 1-7 7m0-14a7 7 0 0 1 7 7", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }),
|
|
2371
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M14 3l-1 3h3", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
|
|
2372
|
-
] }) }),
|
|
2373
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "fc-security-card-info", children: [
|
|
2374
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-security-card-label", children: "Regenerate recovery codes" }),
|
|
2375
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-security-card-detail", children: "Get new backup codes" })
|
|
2376
|
-
] }),
|
|
2377
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-security-card-chevron", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M6 4l4 4-4 4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }) })
|
|
2378
|
-
]
|
|
2379
|
-
}
|
|
2380
|
-
),
|
|
2381
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
2382
|
-
"button",
|
|
2383
|
-
{
|
|
2384
|
-
type: "button",
|
|
2385
|
-
className: "fc-security-card",
|
|
2386
|
-
onClick: () => {
|
|
2387
|
-
setCode("");
|
|
2388
|
-
setMsg(null);
|
|
2389
|
-
setStep("confirm-disable");
|
|
2390
|
-
},
|
|
2391
|
-
children: [
|
|
2392
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-security-card-icon", style: { color: "#dc2626" }, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "svg", { viewBox: "0 0 20 20", fill: "none", children: [
|
|
2393
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M10 2l6 3v4c0 4.42-2.56 8.22-6 9.5C6.56 17.22 4 13.42 4 9V5l6-3z", stroke: "currentColor", strokeWidth: "1.5", strokeLinejoin: "round" }),
|
|
2394
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M7.5 7.5l5 5M12.5 7.5l-5 5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
|
|
2395
|
-
] }) }),
|
|
2396
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "fc-security-card-info", children: [
|
|
2397
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-security-card-label", style: { color: "#dc2626" }, children: "Disable 2FA" }),
|
|
2398
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-security-card-detail", children: "Remove two-factor authentication" })
|
|
2399
|
-
] }),
|
|
2400
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-security-card-chevron", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M6 4l4 4-4 4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }) })
|
|
2401
|
-
]
|
|
2402
|
-
}
|
|
2403
|
-
)
|
|
2404
|
-
] })
|
|
2405
|
-
] }),
|
|
2406
|
-
step === "confirm-regenerate" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
2407
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "fc-modal-title", children: "Regenerate recovery codes" }),
|
|
2408
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-account-section-desc", style: { textAlign: "center" }, children: "Enter your 2FA code to generate new recovery codes. Your old codes will stop working." }),
|
|
2409
|
-
msg && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: msg.ok ? "fc-text" : "fc-error", children: msg.text }),
|
|
2410
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-tab", children: [
|
|
2411
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2412
|
-
"input",
|
|
2413
|
-
{
|
|
2414
|
-
className: "fc-input",
|
|
2415
|
-
type: "text",
|
|
2416
|
-
inputMode: "numeric",
|
|
2417
|
-
placeholder: "Enter 6-digit code",
|
|
2418
|
-
maxLength: 6,
|
|
2419
|
-
value: code,
|
|
2420
|
-
onChange: (e) => setCode(e.target.value.replace(/\D/g, "")),
|
|
2421
|
-
style: { textAlign: "center", letterSpacing: "0.2em" },
|
|
2422
|
-
autoFocus: true
|
|
2423
|
-
}
|
|
2424
|
-
),
|
|
2425
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2426
|
-
"button",
|
|
2427
|
-
{
|
|
2428
|
-
type: "button",
|
|
2429
|
-
className: "fc-btn fc-btn-primary",
|
|
2430
|
-
onClick: handleRegenerate,
|
|
2431
|
-
disabled: loading || code.length !== 6,
|
|
2432
|
-
style: { marginTop: 10 },
|
|
2433
|
-
children: loading ? "Generating..." : "Regenerate codes"
|
|
2434
|
-
}
|
|
2435
|
-
),
|
|
2436
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-switch", style: { marginTop: 12 }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "fc-link", onClick: goBack, children: "Back" }) })
|
|
2437
|
-
] })
|
|
2438
|
-
] }),
|
|
2439
|
-
step === "confirm-disable" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
2440
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "fc-modal-title", children: "Disable 2FA" }),
|
|
2441
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-account-section-desc", style: { textAlign: "center" }, children: "Enter your 2FA code to disable two-factor authentication." }),
|
|
2442
|
-
msg && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: msg.ok ? "fc-text" : "fc-error", children: msg.text }),
|
|
2443
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-tab", children: [
|
|
2444
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2445
|
-
"input",
|
|
2446
|
-
{
|
|
2447
|
-
className: "fc-input",
|
|
2448
|
-
type: "text",
|
|
2449
|
-
inputMode: "numeric",
|
|
2450
|
-
placeholder: "Enter 6-digit code",
|
|
2451
|
-
maxLength: 6,
|
|
2452
|
-
value: code,
|
|
2453
|
-
onChange: (e) => setCode(e.target.value.replace(/\D/g, "")),
|
|
2454
|
-
style: { textAlign: "center", letterSpacing: "0.2em" },
|
|
2455
|
-
autoFocus: true
|
|
2456
|
-
}
|
|
2457
|
-
),
|
|
2458
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2459
|
-
"button",
|
|
2460
|
-
{
|
|
2461
|
-
type: "button",
|
|
2462
|
-
className: "fc-btn fc-btn-secondary",
|
|
2463
|
-
onClick: handleDisable,
|
|
2464
|
-
disabled: loading || code.length !== 6,
|
|
2465
|
-
style: { marginTop: 10, background: "rgba(220, 38, 38, 0.1)", color: "#dc2626", borderColor: "rgba(220, 38, 38, 0.2)" },
|
|
2466
|
-
children: loading ? "Disabling..." : "Disable 2FA"
|
|
2467
|
-
}
|
|
2468
|
-
),
|
|
2469
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-switch", style: { marginTop: 12 }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "fc-link", onClick: goBack, children: "Back" }) })
|
|
2470
|
-
] })
|
|
2471
|
-
] }),
|
|
2472
|
-
step === "recovery-codes" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
2473
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "fc-modal-title", children: "Save your recovery codes" }),
|
|
2474
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-account-section-desc", style: { textAlign: "center" }, children: "Store these codes somewhere safe. Each code can only be used once." }),
|
|
2475
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-recovery-grid", children: recoveryCodes.map((c, i) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-recovery-code", children: c }, i)) }),
|
|
2476
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: { textAlign: "center", margin: "8px 0 12px" }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "fc-link", onClick: handleCopyAll, children: "Copy all" }) }),
|
|
2477
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "fc-btn fc-btn-primary", onClick: onClose, children: "Done" })
|
|
2478
|
-
] })
|
|
2479
|
-
]
|
|
2454
|
+
const getOptions = {};
|
|
2455
|
+
if (useBrowserAutofill) {
|
|
2456
|
+
if (!await browserSupportsWebAuthnAutofill()) {
|
|
2457
|
+
throw Error("Browser does not support WebAuthn autofill");
|
|
2480
2458
|
}
|
|
2481
|
-
|
|
2459
|
+
const eligibleInputs = document.querySelectorAll("input[autocomplete$='webauthn']");
|
|
2460
|
+
if (eligibleInputs.length < 1 && verifyBrowserAutofillInput) {
|
|
2461
|
+
throw Error('No <input> with "webauthn" as the only or last value in its `autocomplete` attribute was detected');
|
|
2462
|
+
}
|
|
2463
|
+
getOptions.mediation = "conditional";
|
|
2464
|
+
publicKey.allowCredentials = [];
|
|
2465
|
+
}
|
|
2466
|
+
getOptions.publicKey = publicKey;
|
|
2467
|
+
getOptions.signal = WebAuthnAbortService.createNewAbortSignal();
|
|
2468
|
+
let credential;
|
|
2469
|
+
try {
|
|
2470
|
+
credential = await navigator.credentials.get(getOptions);
|
|
2471
|
+
} catch (err) {
|
|
2472
|
+
throw identifyAuthenticationError({ error: err, options: getOptions });
|
|
2473
|
+
}
|
|
2474
|
+
if (!credential) {
|
|
2475
|
+
throw new Error("Authentication was not completed");
|
|
2476
|
+
}
|
|
2477
|
+
const { id, rawId, response, type } = credential;
|
|
2478
|
+
let userHandle = void 0;
|
|
2479
|
+
if (response.userHandle) {
|
|
2480
|
+
userHandle = bufferToBase64URLString(response.userHandle);
|
|
2481
|
+
}
|
|
2482
|
+
return {
|
|
2483
|
+
id,
|
|
2484
|
+
rawId: bufferToBase64URLString(rawId),
|
|
2485
|
+
response: {
|
|
2486
|
+
authenticatorData: bufferToBase64URLString(response.authenticatorData),
|
|
2487
|
+
clientDataJSON: bufferToBase64URLString(response.clientDataJSON),
|
|
2488
|
+
signature: bufferToBase64URLString(response.signature),
|
|
2489
|
+
userHandle
|
|
2490
|
+
},
|
|
2491
|
+
type,
|
|
2492
|
+
clientExtensionResults: credential.getClientExtensionResults(),
|
|
2493
|
+
authenticatorAttachment: toAuthenticatorAttachment(credential.authenticatorAttachment)
|
|
2494
|
+
};
|
|
2482
2495
|
}
|
|
2483
2496
|
|
|
2484
2497
|
// src/components/passkeys-modal.tsx
|
|
2485
2498
|
|
|
2486
|
-
|
|
2487
2499
|
function PasskeysModal({ isOpen, onClose, onCountChange }) {
|
|
2488
2500
|
const { api, getAccessToken, config } = useForgeConnect();
|
|
2489
|
-
const theme = _nullishCoalesce(_optionalChain([config, 'access',
|
|
2501
|
+
const theme = _nullishCoalesce(_optionalChain([config, 'access', _66 => _66.appearance, 'optionalAccess', _67 => _67.theme]), () => ( "light"));
|
|
2490
2502
|
const [passkeys, setPasskeys] = _react.useState.call(void 0, []);
|
|
2491
2503
|
const [loading, setLoading] = _react.useState.call(void 0, false);
|
|
2492
2504
|
const [addLoading, setAddLoading] = _react.useState.call(void 0, false);
|
|
@@ -2546,7 +2558,7 @@ function PasskeysModal({ isOpen, onClose, onCountChange }) {
|
|
|
2546
2558
|
"div",
|
|
2547
2559
|
{
|
|
2548
2560
|
className: "fc-modal-content",
|
|
2549
|
-
style: { "--fc-accent": _nullishCoalesce(_optionalChain([config, 'access',
|
|
2561
|
+
style: { "--fc-accent": _nullishCoalesce(_optionalChain([config, 'access', _68 => _68.appearance, 'optionalAccess', _69 => _69.accentColor]), () => ( "#8b5cf6")) },
|
|
2550
2562
|
"data-theme": theme,
|
|
2551
2563
|
children: [
|
|
2552
2564
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "fc-modal-title", children: "Passkeys" }),
|
|
@@ -2620,7 +2632,7 @@ function ErrorView({
|
|
|
2620
2632
|
|
|
2621
2633
|
function PasswordModal({ isOpen, onClose, hasPassword }) {
|
|
2622
2634
|
const { api, getAccessToken, config } = useForgeConnect();
|
|
2623
|
-
const theme = _nullishCoalesce(_optionalChain([config, 'access',
|
|
2635
|
+
const theme = _nullishCoalesce(_optionalChain([config, 'access', _70 => _70.appearance, 'optionalAccess', _71 => _71.theme]), () => ( "light"));
|
|
2624
2636
|
const [step, setStep] = _react.useState.call(void 0, "form");
|
|
2625
2637
|
const [currentPassword, setCurrentPassword] = _react.useState.call(void 0, "");
|
|
2626
2638
|
const [newPassword, setNewPassword] = _react.useState.call(void 0, "");
|
|
@@ -2657,7 +2669,7 @@ function PasswordModal({ isOpen, onClose, hasPassword }) {
|
|
|
2657
2669
|
"div",
|
|
2658
2670
|
{
|
|
2659
2671
|
className: "fc-modal-content",
|
|
2660
|
-
style: { "--fc-accent": _nullishCoalesce(_optionalChain([config, 'access',
|
|
2672
|
+
style: { "--fc-accent": _nullishCoalesce(_optionalChain([config, 'access', _72 => _72.appearance, 'optionalAccess', _73 => _73.accentColor]), () => ( "#8b5cf6")) },
|
|
2661
2673
|
"data-theme": theme,
|
|
2662
2674
|
children: step === "done" ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-tab", style: { textAlign: "center", padding: "24px 0" }, children: [
|
|
2663
2675
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-success", children: [
|
|
@@ -2726,7 +2738,7 @@ function PasswordModal({ isOpen, onClose, hasPassword }) {
|
|
|
2726
2738
|
|
|
2727
2739
|
function DeleteAccountModal({ isOpen, onClose, onDeleted }) {
|
|
2728
2740
|
const { api, getAccessToken, config, logout } = useForgeConnect();
|
|
2729
|
-
const theme = _nullishCoalesce(_optionalChain([config, 'access',
|
|
2741
|
+
const theme = _nullishCoalesce(_optionalChain([config, 'access', _74 => _74.appearance, 'optionalAccess', _75 => _75.theme]), () => ( "light"));
|
|
2730
2742
|
const [step, setStep] = _react.useState.call(void 0, "confirm");
|
|
2731
2743
|
const [code, setCode] = _react.useState.call(void 0, "");
|
|
2732
2744
|
const [loading, setLoading] = _react.useState.call(void 0, false);
|
|
@@ -2786,7 +2798,7 @@ function DeleteAccountModal({ isOpen, onClose, onDeleted }) {
|
|
|
2786
2798
|
"div",
|
|
2787
2799
|
{
|
|
2788
2800
|
className: "fc-modal-content",
|
|
2789
|
-
style: { "--fc-accent": _nullishCoalesce(_optionalChain([config, 'access',
|
|
2801
|
+
style: { "--fc-accent": _nullishCoalesce(_optionalChain([config, 'access', _76 => _76.appearance, 'optionalAccess', _77 => _77.accentColor]), () => ( "#8b5cf6")) },
|
|
2790
2802
|
"data-theme": theme,
|
|
2791
2803
|
children: [
|
|
2792
2804
|
step === "confirm" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
@@ -2913,20 +2925,20 @@ function AccountModal() {
|
|
|
2913
2925
|
prevLinkOpen.current = linkModal.isOpen;
|
|
2914
2926
|
}, [linkModal.isOpen]);
|
|
2915
2927
|
if (!accountModal.isOpen) return null;
|
|
2916
|
-
const theme = _nullishCoalesce(_optionalChain([config, 'access',
|
|
2917
|
-
const initial = (_nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess',
|
|
2928
|
+
const theme = _nullishCoalesce(_optionalChain([config, 'access', _78 => _78.appearance, 'optionalAccess', _79 => _79.theme]), () => ( "light"));
|
|
2929
|
+
const initial = (_nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess', _80 => _80.displayName]), () => ( _optionalChain([user, 'optionalAccess', _81 => _81.primaryEmail]))), () => ( "?"))).charAt(0).toUpperCase();
|
|
2918
2930
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ModalOverlay, { isOpen: accountModal.isOpen, onClose: closeAccountModal, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
2919
2931
|
"div",
|
|
2920
2932
|
{
|
|
2921
2933
|
className: "fc-modal-content",
|
|
2922
|
-
style: { "--fc-accent": _nullishCoalesce(_optionalChain([config, 'access',
|
|
2934
|
+
style: { "--fc-accent": _nullishCoalesce(_optionalChain([config, 'access', _82 => _82.appearance, 'optionalAccess', _83 => _83.accentColor]), () => ( "#8b5cf6")) },
|
|
2923
2935
|
"data-theme": theme,
|
|
2924
2936
|
children: [
|
|
2925
2937
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-account-hero", children: [
|
|
2926
|
-
_optionalChain([user, 'optionalAccess',
|
|
2938
|
+
_optionalChain([user, 'optionalAccess', _84 => _84.avatarUrl]) ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { src: user.avatarUrl, alt: "", className: "fc-account-hero-avatar" }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-account-hero-avatar fc-account-hero-avatar-placeholder", children: initial }),
|
|
2927
2939
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-account-hero-info", children: [
|
|
2928
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-account-hero-name", children: _nullishCoalesce(_optionalChain([user, 'optionalAccess',
|
|
2929
|
-
_optionalChain([user, 'optionalAccess',
|
|
2940
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-account-hero-name", children: _nullishCoalesce(_optionalChain([user, 'optionalAccess', _85 => _85.displayName]), () => ( "Your account")) }),
|
|
2941
|
+
_optionalChain([user, 'optionalAccess', _86 => _86.primaryEmail]) && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-account-hero-email", children: user.primaryEmail })
|
|
2930
2942
|
] })
|
|
2931
2943
|
] }),
|
|
2932
2944
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-account-tabs", children: TABS.map((tab) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
@@ -2964,13 +2976,13 @@ function AccountModal() {
|
|
|
2964
2976
|
}
|
|
2965
2977
|
function ProfileTab() {
|
|
2966
2978
|
const { user, updateProfile } = useUser();
|
|
2967
|
-
const [displayName, setDisplayName] = _react.useState.call(void 0, _nullishCoalesce(_optionalChain([user, 'optionalAccess',
|
|
2968
|
-
const [avatarUrl, setAvatarUrl] = _react.useState.call(void 0, _nullishCoalesce(_optionalChain([user, 'optionalAccess',
|
|
2979
|
+
const [displayName, setDisplayName] = _react.useState.call(void 0, _nullishCoalesce(_optionalChain([user, 'optionalAccess', _87 => _87.displayName]), () => ( "")));
|
|
2980
|
+
const [avatarUrl, setAvatarUrl] = _react.useState.call(void 0, _nullishCoalesce(_optionalChain([user, 'optionalAccess', _88 => _88.avatarUrl]), () => ( "")));
|
|
2969
2981
|
const [loading, setLoading] = _react.useState.call(void 0, false);
|
|
2970
2982
|
const [msg, setMsg] = _react.useState.call(void 0, null);
|
|
2971
2983
|
_react.useEffect.call(void 0, () => {
|
|
2972
|
-
setDisplayName(_nullishCoalesce(_optionalChain([user, 'optionalAccess',
|
|
2973
|
-
setAvatarUrl(_nullishCoalesce(_optionalChain([user, 'optionalAccess',
|
|
2984
|
+
setDisplayName(_nullishCoalesce(_optionalChain([user, 'optionalAccess', _89 => _89.displayName]), () => ( "")));
|
|
2985
|
+
setAvatarUrl(_nullishCoalesce(_optionalChain([user, 'optionalAccess', _90 => _90.avatarUrl]), () => ( "")));
|
|
2974
2986
|
}, [user]);
|
|
2975
2987
|
const handleSave = async () => {
|
|
2976
2988
|
setLoading(true);
|
|
@@ -3035,7 +3047,7 @@ function LoginsTab({ onLink, refreshKey }) {
|
|
|
3035
3047
|
msg && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-error", children: msg }),
|
|
3036
3048
|
loading && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-text", children: "Loading..." }),
|
|
3037
3049
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-account-section-desc", children: "Ways you can sign in to your account." }),
|
|
3038
|
-
_optionalChain([authMethods, 'optionalAccess',
|
|
3050
|
+
_optionalChain([authMethods, 'optionalAccess', _91 => _91.map, 'call', _92 => _92((m) => {
|
|
3039
3051
|
const display = getMethodDisplay(m.provider);
|
|
3040
3052
|
const detail = m.provider === "email" ? m.providerId : m.provider.endsWith("_wallet") ? truncate(m.providerId) : m.providerId;
|
|
3041
3053
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-account-item", children: [
|
|
@@ -3050,7 +3062,7 @@ function LoginsTab({ onLink, refreshKey }) {
|
|
|
3050
3062
|
] })
|
|
3051
3063
|
] }, m.id);
|
|
3052
3064
|
})]),
|
|
3053
|
-
_optionalChain([authMethods, 'optionalAccess',
|
|
3065
|
+
_optionalChain([authMethods, 'optionalAccess', _93 => _93.length]) === 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-account-empty", children: "No login methods yet" }),
|
|
3054
3066
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "fc-btn fc-btn-secondary", onClick: onLink, style: { marginTop: 8 }, children: "+ Add login method" })
|
|
3055
3067
|
] });
|
|
3056
3068
|
}
|
|
@@ -3073,8 +3085,8 @@ function WalletsTab({ onLink, refreshKey }) {
|
|
|
3073
3085
|
msg && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-error", children: msg }),
|
|
3074
3086
|
loading && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-text", children: "Loading..." }),
|
|
3075
3087
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-account-section-desc", children: "Crypto wallets connected to your account." }),
|
|
3076
|
-
_optionalChain([wallets, 'optionalAccess',
|
|
3077
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, SvgIcon, { svg: _nullishCoalesce(_optionalChain([METHOD_DISPLAY, 'access',
|
|
3088
|
+
_optionalChain([wallets, 'optionalAccess', _94 => _94.map, 'call', _95 => _95((w) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-account-item", children: [
|
|
3089
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, SvgIcon, { svg: _nullishCoalesce(_optionalChain([METHOD_DISPLAY, 'access', _96 => _96[`${w.chain}_wallet`], 'optionalAccess', _97 => _97.iconHtml]), () => ( "")), className: "fc-account-item-icon" }),
|
|
3078
3090
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-account-item-info", children: [
|
|
3079
3091
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "fc-account-item-label", children: [
|
|
3080
3092
|
w.chain.charAt(0).toUpperCase() + w.chain.slice(1),
|
|
@@ -3084,7 +3096,7 @@ function WalletsTab({ onLink, refreshKey }) {
|
|
|
3084
3096
|
] }),
|
|
3085
3097
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-account-item-actions", children: !w.isPrimary && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "fc-btn-primary-sm", onClick: () => handleSetPrimary(w.id), children: "Make primary" }) })
|
|
3086
3098
|
] }, w.id))]),
|
|
3087
|
-
_optionalChain([wallets, 'optionalAccess',
|
|
3099
|
+
_optionalChain([wallets, 'optionalAccess', _98 => _98.length]) === 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-account-empty", children: "No wallets connected" }),
|
|
3088
3100
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "fc-btn fc-btn-secondary", onClick: onLink, style: { marginTop: 8 }, children: "+ Connect wallet" })
|
|
3089
3101
|
] });
|
|
3090
3102
|
}
|
|
@@ -3119,7 +3131,7 @@ function SecurityTab() {
|
|
|
3119
3131
|
refreshStatus();
|
|
3120
3132
|
refreshPasskeyCount();
|
|
3121
3133
|
}, [fetchSessions, fetchAuthMethods, refreshStatus, refreshPasskeyCount]);
|
|
3122
|
-
const hasPassword = _optionalChain([userAuthMethods, 'optionalAccess',
|
|
3134
|
+
const hasPassword = _optionalChain([userAuthMethods, 'optionalAccess', _99 => _99.some, 'call', _100 => _100((m) => m.provider === "email")]);
|
|
3123
3135
|
const handleRevoke = async (id) => {
|
|
3124
3136
|
setMsg("");
|
|
3125
3137
|
try {
|
|
@@ -3153,7 +3165,7 @@ function SecurityTab() {
|
|
|
3153
3165
|
] }),
|
|
3154
3166
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, ChevronRight, {})
|
|
3155
3167
|
] }),
|
|
3156
|
-
_optionalChain([user, 'optionalAccess',
|
|
3168
|
+
_optionalChain([user, 'optionalAccess', _101 => _101.primaryEmail]) && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
3157
3169
|
"button",
|
|
3158
3170
|
{
|
|
3159
3171
|
type: "button",
|
|
@@ -3174,7 +3186,7 @@ function SecurityTab() {
|
|
|
3174
3186
|
),
|
|
3175
3187
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-divider", style: { margin: "16px 0" }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "active sessions" }) }),
|
|
3176
3188
|
loading && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-text", children: "Loading..." }),
|
|
3177
|
-
_optionalChain([sessions, 'optionalAccess',
|
|
3189
|
+
_optionalChain([sessions, 'optionalAccess', _102 => _102.map, 'call', _103 => _103((s) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-account-item", children: [
|
|
3178
3190
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-account-item-icon", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "svg", { width: "16", height: "16", viewBox: "0 0 20 20", fill: "none", children: [
|
|
3179
3191
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "rect", { x: "2", y: "3", width: "16", height: "11", rx: "2", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
3180
3192
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M7 17h6M10 14v3", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
|
|
@@ -3190,7 +3202,7 @@ function SecurityTab() {
|
|
|
3190
3202
|
] }),
|
|
3191
3203
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-account-item-actions", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "fc-btn-danger-sm", onClick: () => handleRevoke(s.id), children: "Sign out" }) })
|
|
3192
3204
|
] }, s.id))]),
|
|
3193
|
-
_optionalChain([sessions, 'optionalAccess',
|
|
3205
|
+
_optionalChain([sessions, 'optionalAccess', _104 => _104.length]) === 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-account-empty", children: "No active sessions" }),
|
|
3194
3206
|
sessions && sessions.length > 1 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3195
3207
|
"button",
|
|
3196
3208
|
{
|
|
@@ -3237,7 +3249,7 @@ function SecurityTab() {
|
|
|
3237
3249
|
onCountChange: (count) => setPasskeyCount(count)
|
|
3238
3250
|
}
|
|
3239
3251
|
),
|
|
3240
|
-
_optionalChain([user, 'optionalAccess',
|
|
3252
|
+
_optionalChain([user, 'optionalAccess', _105 => _105.primaryEmail]) && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3241
3253
|
PasswordModal,
|
|
3242
3254
|
{
|
|
3243
3255
|
isOpen: showPasswordModal,
|
|
@@ -3282,7 +3294,7 @@ function LinkAuthModal() {
|
|
|
3282
3294
|
if (!linkModal.isOpen) return;
|
|
3283
3295
|
const handleMessage = (event) => {
|
|
3284
3296
|
if (event.origin !== window.location.origin) return;
|
|
3285
|
-
if (_optionalChain([event, 'access',
|
|
3297
|
+
if (_optionalChain([event, 'access', _106 => _106.data, 'optionalAccess', _107 => _107.type]) === "fc_oauth_link_success") {
|
|
3286
3298
|
setStep("success");
|
|
3287
3299
|
setTimeout(() => {
|
|
3288
3300
|
handleClose();
|
|
@@ -3293,7 +3305,7 @@ function LinkAuthModal() {
|
|
|
3293
3305
|
return () => window.removeEventListener("message", handleMessage);
|
|
3294
3306
|
}, [linkModal.isOpen]);
|
|
3295
3307
|
if (!linkModal.isOpen) return null;
|
|
3296
|
-
const theme = _nullishCoalesce(_optionalChain([config, 'access',
|
|
3308
|
+
const theme = _nullishCoalesce(_optionalChain([config, 'access', _108 => _108.appearance, 'optionalAccess', _109 => _109.theme]), () => ( "light"));
|
|
3297
3309
|
const handleClose = () => {
|
|
3298
3310
|
setStep("method-select");
|
|
3299
3311
|
closeLinkModal();
|
|
@@ -3316,7 +3328,7 @@ function LinkAuthModal() {
|
|
|
3316
3328
|
"div",
|
|
3317
3329
|
{
|
|
3318
3330
|
className: "fc-modal-content",
|
|
3319
|
-
style: { "--fc-accent": _nullishCoalesce(_optionalChain([config, 'access',
|
|
3331
|
+
style: { "--fc-accent": _nullishCoalesce(_optionalChain([config, 'access', _110 => _110.appearance, 'optionalAccess', _111 => _111.accentColor]), () => ( "#8b5cf6")) },
|
|
3320
3332
|
"data-theme": theme,
|
|
3321
3333
|
children: step === "success" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SuccessView2, {}) : step === "error" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3322
3334
|
ErrorView,
|
|
@@ -3332,7 +3344,7 @@ function LinkAuthModal() {
|
|
|
3332
3344
|
AuthMethodSelectStep,
|
|
3333
3345
|
{
|
|
3334
3346
|
config,
|
|
3335
|
-
connectedProviders: _nullishCoalesce(_optionalChain([authMethods, 'optionalAccess',
|
|
3347
|
+
connectedProviders: _nullishCoalesce(_optionalChain([authMethods, 'optionalAccess', _112 => _112.map, 'call', _113 => _113((m) => m.provider)]), () => ( [])),
|
|
3336
3348
|
onSelectEmail: () => setStep("email"),
|
|
3337
3349
|
onSelectOtp: () => setStep("otp"),
|
|
3338
3350
|
onOAuth: handleOAuthDirect
|
|
@@ -3548,10 +3560,24 @@ function WalletLinkStep({ onBack, onSuccess, onFatalError }) {
|
|
|
3548
3560
|
const [loading, setLoading] = _react.useState.call(void 0, false);
|
|
3549
3561
|
const [error, setError] = _react.useState.call(void 0, "");
|
|
3550
3562
|
const [showOther, setShowOther] = _react.useState.call(void 0, false);
|
|
3563
|
+
const [coldWallet, setColdWallet] = _react.useState.call(void 0, false);
|
|
3551
3564
|
const mobile = _react.useMemo.call(void 0, () => isMobile(), []);
|
|
3552
3565
|
const walletConfig = config.walletConfig;
|
|
3553
|
-
const preferred = _nullishCoalesce(_optionalChain([walletConfig, 'optionalAccess',
|
|
3554
|
-
const onlyPreferred = _nullishCoalesce(_optionalChain([walletConfig, 'optionalAccess',
|
|
3566
|
+
const preferred = _nullishCoalesce(_optionalChain([walletConfig, 'optionalAccess', _114 => _114.preferredWallets]), () => ( []));
|
|
3567
|
+
const onlyPreferred = _nullishCoalesce(_optionalChain([walletConfig, 'optionalAccess', _115 => _115.onlyPreferred]), () => ( false));
|
|
3568
|
+
const coldWalletRef = _react.useRef.call(void 0, coldWallet);
|
|
3569
|
+
coldWalletRef.current = coldWallet;
|
|
3570
|
+
const buildSignTxFnForAdapter = _react.useCallback.call(void 0, (adapter) => {
|
|
3571
|
+
if (!adapter.signTransaction) return void 0;
|
|
3572
|
+
const TxClass = _optionalChain([walletConfig, 'optionalAccess', _116 => _116.Transaction]);
|
|
3573
|
+
if (!TxClass) return void 0;
|
|
3574
|
+
return async (txBase64) => {
|
|
3575
|
+
const bytes = Uint8Array.from(atob(txBase64), (c) => c.charCodeAt(0));
|
|
3576
|
+
const tx = TxClass.from(bytes);
|
|
3577
|
+
const signedTx = await adapter.signTransaction(tx);
|
|
3578
|
+
return btoa(String.fromCharCode(...new Uint8Array(signedTx.serialize())));
|
|
3579
|
+
};
|
|
3580
|
+
}, [_optionalChain([walletConfig, 'optionalAccess', _117 => _117.Transaction])]);
|
|
3555
3581
|
const handleConnect = async (w) => {
|
|
3556
3582
|
if (w.readyState !== "Installed") {
|
|
3557
3583
|
if (mobile) {
|
|
@@ -3571,9 +3597,14 @@ function WalletLinkStep({ onBack, onSuccess, onFatalError }) {
|
|
|
3571
3597
|
if (!w.adapter.connected) await w.adapter.connect();
|
|
3572
3598
|
const pk = w.adapter.publicKey;
|
|
3573
3599
|
if (!pk) throw new Error("Wallet did not provide a public key.");
|
|
3600
|
+
const useCold = coldWalletRef.current;
|
|
3574
3601
|
const adapterSignMessage = w.adapter.signMessage ? (msg) => w.adapter.signMessage(msg) : void 0;
|
|
3575
|
-
|
|
3576
|
-
|
|
3602
|
+
await linkWallet(
|
|
3603
|
+
pk.toBase58(),
|
|
3604
|
+
useCold ? void 0 : adapterSignMessage,
|
|
3605
|
+
"solana",
|
|
3606
|
+
useCold ? buildSignTxFnForAdapter(w.adapter) : void 0
|
|
3607
|
+
);
|
|
3577
3608
|
onSuccess();
|
|
3578
3609
|
} catch (err) {
|
|
3579
3610
|
onFatalError(err instanceof Error ? err.message : "Could not link this wallet. Please try again.");
|
|
@@ -3587,12 +3618,12 @@ function WalletLinkStep({ onBack, onSuccess, onFatalError }) {
|
|
|
3587
3618
|
const prefSet = new Set(preferred);
|
|
3588
3619
|
const others = all.filter((w) => !prefSet.has(w.adapter.name) && w.readyState === "Installed");
|
|
3589
3620
|
return { preferredWallets: prefList, otherWallets: others };
|
|
3590
|
-
}, [_optionalChain([walletAdapter, 'optionalAccess',
|
|
3621
|
+
}, [_optionalChain([walletAdapter, 'optionalAccess', _118 => _118.wallets]), walletConfig]);
|
|
3591
3622
|
const mobileExtraWallets = _react.useMemo.call(void 0, () => {
|
|
3592
3623
|
if (!mobile || !walletAdapter) return [];
|
|
3593
3624
|
const adapterNames = new Set(walletAdapter.wallets.map((w) => w.adapter.name));
|
|
3594
3625
|
return MOBILE_WALLETS.filter((mw) => !adapterNames.has(mw.name));
|
|
3595
|
-
}, [mobile, _optionalChain([walletAdapter, 'optionalAccess',
|
|
3626
|
+
}, [mobile, _optionalChain([walletAdapter, 'optionalAccess', _119 => _119.wallets])]);
|
|
3596
3627
|
if (!walletAdapter && mobile) {
|
|
3597
3628
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-tab", children: [
|
|
3598
3629
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-wallet-list", children: MOBILE_WALLETS.map((mw) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
@@ -3630,7 +3661,7 @@ function WalletLinkStep({ onBack, onSuccess, onFatalError }) {
|
|
|
3630
3661
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-tab", children: [
|
|
3631
3662
|
loading ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: { textAlign: "center", padding: "24px 0" }, children: [
|
|
3632
3663
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-tab-title", children: "Connecting..." }),
|
|
3633
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-text", children: "Approve the connection, then sign the verification request in your wallet" }),
|
|
3664
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-text", children: coldWallet ? "Confirm the transaction on your device" : "Approve the connection, then sign the verification request in your wallet" }),
|
|
3634
3665
|
error && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
3635
3666
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-error", children: error }),
|
|
3636
3667
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
@@ -3688,6 +3719,21 @@ function WalletLinkStep({ onBack, onSuccess, onFatalError }) {
|
|
|
3688
3719
|
] }, w.adapter.name))
|
|
3689
3720
|
] }),
|
|
3690
3721
|
preferredWallets.length === 0 && otherWallets.length === 0 && mobileExtraWallets.length === 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-text", children: "No wallet found. Please install a Solana wallet (like Phantom) to continue." }),
|
|
3722
|
+
_optionalChain([walletConfig, 'optionalAccess', _120 => _120.Transaction]) && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { className: "fc-cold-wallet-toggle", children: [
|
|
3723
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3724
|
+
"input",
|
|
3725
|
+
{
|
|
3726
|
+
type: "checkbox",
|
|
3727
|
+
checked: coldWallet,
|
|
3728
|
+
onChange: (e) => setColdWallet(e.target.checked)
|
|
3729
|
+
}
|
|
3730
|
+
),
|
|
3731
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-toggle-track" }),
|
|
3732
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "fc-cold-wallet-label", children: [
|
|
3733
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "Hardware wallet" }),
|
|
3734
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "Ledger, Trezor, Keystone..." })
|
|
3735
|
+
] })
|
|
3736
|
+
] }),
|
|
3691
3737
|
error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-error", children: error })
|
|
3692
3738
|
] }),
|
|
3693
3739
|
!loading && onBack && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-switch", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "fc-link", onClick: onBack, children: "Back" }) })
|
|
@@ -3774,7 +3820,7 @@ function ForgeConnectProvider({ config, children, onLogin, onLogout, walletAdapt
|
|
|
3774
3820
|
}
|
|
3775
3821
|
const handleMessage = async (event) => {
|
|
3776
3822
|
if (event.origin !== window.location.origin) return;
|
|
3777
|
-
if (_optionalChain([event, 'access',
|
|
3823
|
+
if (_optionalChain([event, 'access', _121 => _121.data, 'optionalAccess', _122 => _122.type]) !== "fc_oauth_code") return;
|
|
3778
3824
|
const code = event.data.code;
|
|
3779
3825
|
if (!code) return;
|
|
3780
3826
|
try {
|
|
@@ -3790,7 +3836,7 @@ function ForgeConnectProvider({ config, children, onLogin, onLogout, walletAdapt
|
|
|
3790
3836
|
const user = await api.getMe(token);
|
|
3791
3837
|
setAuth({ status: "authenticated", user, accessToken: token });
|
|
3792
3838
|
scheduleRefresh(token);
|
|
3793
|
-
_optionalChain([onLogin, 'optionalCall',
|
|
3839
|
+
_optionalChain([onLogin, 'optionalCall', _123 => _123(user)]);
|
|
3794
3840
|
setTimeout(() => {
|
|
3795
3841
|
setModal({ isOpen: false, step: "method-select" });
|
|
3796
3842
|
}, 1500);
|
|
@@ -3816,7 +3862,7 @@ function ForgeConnectProvider({ config, children, onLogin, onLogout, walletAdapt
|
|
|
3816
3862
|
setAuth({ status: "authenticated", user, accessToken: token });
|
|
3817
3863
|
scheduleRefresh(token);
|
|
3818
3864
|
setModal({ isOpen: true, step: "success" });
|
|
3819
|
-
_optionalChain([onLogin, 'optionalCall',
|
|
3865
|
+
_optionalChain([onLogin, 'optionalCall', _124 => _124(user)]);
|
|
3820
3866
|
setTimeout(() => {
|
|
3821
3867
|
setModal({ isOpen: false, step: "method-select" });
|
|
3822
3868
|
}, 1500);
|
|
@@ -3916,7 +3962,7 @@ function ForgeConnectProvider({ config, children, onLogin, onLogout, walletAdapt
|
|
|
3916
3962
|
const token = auth.accessToken;
|
|
3917
3963
|
if (refreshTimerRef.current) clearTimeout(refreshTimerRef.current);
|
|
3918
3964
|
setAuth({ status: "unauthenticated", user: null, accessToken: null });
|
|
3919
|
-
_optionalChain([onLogout, 'optionalCall',
|
|
3965
|
+
_optionalChain([onLogout, 'optionalCall', _125 => _125()]);
|
|
3920
3966
|
if (token) {
|
|
3921
3967
|
try {
|
|
3922
3968
|
await api.logout(token);
|
|
@@ -3970,7 +4016,7 @@ function ForgeConnectProvider({ config, children, onLogin, onLogout, walletAdapt
|
|
|
3970
4016
|
const token = auth.accessToken;
|
|
3971
4017
|
if (refreshTimerRef.current) clearTimeout(refreshTimerRef.current);
|
|
3972
4018
|
setAuth({ status: "unauthenticated", user: null, accessToken: null });
|
|
3973
|
-
_optionalChain([onLogout, 'optionalCall',
|
|
4019
|
+
_optionalChain([onLogout, 'optionalCall', _126 => _126()]);
|
|
3974
4020
|
if (token) {
|
|
3975
4021
|
try {
|
|
3976
4022
|
await api.logoutAll(token);
|
|
@@ -4155,11 +4201,11 @@ function useAdmin() {
|
|
|
4155
4201
|
const token = getAccessToken();
|
|
4156
4202
|
if (!token) throw new Error("Please sign in to continue.");
|
|
4157
4203
|
await api.adminUpdateUserStatus(token, id, status);
|
|
4158
|
-
if (_optionalChain([selectedUser, 'optionalAccess',
|
|
4204
|
+
if (_optionalChain([selectedUser, 'optionalAccess', _127 => _127.id]) === id) {
|
|
4159
4205
|
await getUser(id);
|
|
4160
4206
|
}
|
|
4161
4207
|
},
|
|
4162
|
-
[api, getAccessToken, _optionalChain([selectedUser, 'optionalAccess',
|
|
4208
|
+
[api, getAccessToken, _optionalChain([selectedUser, 'optionalAccess', _128 => _128.id]), getUser]
|
|
4163
4209
|
);
|
|
4164
4210
|
const getUserSessions = _react.useCallback.call(void 0,
|
|
4165
4211
|
async (id) => {
|
|
@@ -4275,9 +4321,9 @@ function useRoles() {
|
|
|
4275
4321
|
const token = getAccessToken();
|
|
4276
4322
|
if (!token) throw new Error("Please sign in to continue.");
|
|
4277
4323
|
await api.adminDeleteRole(token, id);
|
|
4278
|
-
if (_optionalChain([selectedRole, 'optionalAccess',
|
|
4324
|
+
if (_optionalChain([selectedRole, 'optionalAccess', _129 => _129.id]) === id) setSelectedRole(null);
|
|
4279
4325
|
},
|
|
4280
|
-
[api, getAccessToken, _optionalChain([selectedRole, 'optionalAccess',
|
|
4326
|
+
[api, getAccessToken, _optionalChain([selectedRole, 'optionalAccess', _130 => _130.id])]
|
|
4281
4327
|
);
|
|
4282
4328
|
const getPermissions = _react.useCallback.call(void 0,
|
|
4283
4329
|
async () => {
|