shogun-button-react 6.4.0 β 6.4.2
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/README.md +17 -0
- package/dist/components/ShogunButton.d.ts +1 -0
- package/dist/components/ShogunButton.js +205 -12
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/dist/118.index.js +0 -2
- package/dist/118.index.js.LICENSE.txt +0 -3
- package/dist/18.index.js +0 -1
- package/dist/195.index.js +0 -2
- package/dist/195.index.js.LICENSE.txt +0 -1
- package/dist/452.index.js +0 -2
- package/dist/452.index.js.LICENSE.txt +0 -1
- package/dist/508.index.js +0 -2
- package/dist/508.index.js.LICENSE.txt +0 -1
- package/dist/604.index.js +0 -2
- package/dist/604.index.js.LICENSE.txt +0 -7
- package/dist/619.index.js +0 -2
- package/dist/619.index.js.LICENSE.txt +0 -1
- package/dist/639.index.js +0 -2
- package/dist/639.index.js.LICENSE.txt +0 -1
- package/dist/695.index.js +0 -1
- package/dist/725.index.js +0 -2
- package/dist/725.index.js.LICENSE.txt +0 -1
- package/dist/732.index.js +0 -1
- package/dist/766.index.js +0 -2
- package/dist/766.index.js.LICENSE.txt +0 -1
- package/dist/841.index.js +0 -2
- package/dist/841.index.js.LICENSE.txt +0 -1
package/README.md
CHANGED
|
@@ -9,7 +9,9 @@ A comprehensive React component library for seamless integration of Shogun authe
|
|
|
9
9
|
- π **Easy Integration** - Simple setup with minimal configuration
|
|
10
10
|
- π¨ **Customizable UI** - Modern, responsive design with dark mode support
|
|
11
11
|
- π **Multi-Authentication** - Support for Password, MetaMask, WebAuthn, Nostr, and ZK-Proof
|
|
12
|
+
- π‘οΈ **WebAuthn Recovery** - Restore hardware credentials on new devices with saved seed phrases
|
|
12
13
|
- π **Account Management** - Export/import Gun pairs for account backup and recovery
|
|
14
|
+
- π΅οΈ **ZK-Proof Trapdoor Handoff** - Display and copy the generated trapdoor during signup to keep anonymous identities portable
|
|
13
15
|
- π± **Responsive Design** - Works seamlessly across all device sizes
|
|
14
16
|
- π **TypeScript Support** - Full type safety and IntelliSense support
|
|
15
17
|
- π **Plugin System** - Advanced Gun operations with custom hooks
|
|
@@ -170,6 +172,21 @@ const { core, options } = shogunConnector({
|
|
|
170
172
|
});
|
|
171
173
|
```
|
|
172
174
|
|
|
175
|
+
## π Recovery Flows
|
|
176
|
+
|
|
177
|
+
### WebAuthn Multi-Device Restore
|
|
178
|
+
|
|
179
|
+
- Users now see a **Restore with Recovery Code** option when choosing WebAuthn login.
|
|
180
|
+
- Enter the username plus the stored seed phrase to recreate the credential on a new browser.
|
|
181
|
+
- The button calls `webauthnPlugin.signUp(username, { seedPhrase, generateSeedPhrase: false })` behind the scenes, leveraging the core pluginβs `importFromSeed` flow.
|
|
182
|
+
- After a successful restore the seed phrase is shown one more time so the user can double-check or re-copy it before the modal closes.
|
|
183
|
+
|
|
184
|
+
### ZK-Proof Trapdoor Delivery
|
|
185
|
+
|
|
186
|
+
- Upon successful `zkproof` signup, the modal switches to a confirmation screen that displays the generated trapdoor (also returned as `seedPhrase`).
|
|
187
|
+
- A **Copy Trapdoor** helper copies the phrase to the clipboard, with inline feedback when the copy succeeds.
|
|
188
|
+
- The user must acknowledge with **I Saved My Trapdoor** before returning to the main UI, reducing the risk of losing the anonymous identity.
|
|
189
|
+
|
|
173
190
|
## π― API Reference
|
|
174
191
|
|
|
175
192
|
### ShogunButtonProvider
|
|
@@ -23,6 +23,7 @@ type ShogunContextType = {
|
|
|
23
23
|
remove: (path: string) => Promise<void>;
|
|
24
24
|
completePendingSignup: () => void;
|
|
25
25
|
hasPendingSignup: boolean;
|
|
26
|
+
setHasPendingSignup: (value: boolean) => void;
|
|
26
27
|
};
|
|
27
28
|
export declare const useShogun: () => ShogunContextType;
|
|
28
29
|
type ShogunButtonProviderProps = {
|
|
@@ -27,6 +27,7 @@ const defaultShogunContext = {
|
|
|
27
27
|
remove: async () => { },
|
|
28
28
|
completePendingSignup: () => { },
|
|
29
29
|
hasPendingSignup: false,
|
|
30
|
+
setHasPendingSignup: (_value) => { },
|
|
30
31
|
};
|
|
31
32
|
// Create context using React's createContext directly
|
|
32
33
|
const ShogunContext = createContext(defaultShogunContext);
|
|
@@ -38,6 +39,7 @@ export function ShogunButtonProvider({ children, core, options, onLoginSuccess,
|
|
|
38
39
|
const [isLoggedIn, setIsLoggedIn] = useState(false);
|
|
39
40
|
const [userPub, setUserPub] = useState(null);
|
|
40
41
|
const [username, setUsername] = useState(null);
|
|
42
|
+
const [hasPendingSignup, setHasPendingSignup] = useState(false);
|
|
41
43
|
// Effetto per gestire l'inizializzazione e pulizia
|
|
42
44
|
useEffect(() => {
|
|
43
45
|
var _a, _b;
|
|
@@ -220,7 +222,7 @@ export function ShogunButtonProvider({ children, core, options, onLoginSuccess,
|
|
|
220
222
|
};
|
|
221
223
|
// Unified signup
|
|
222
224
|
const signUp = async (method, ...args) => {
|
|
223
|
-
var _a, _b;
|
|
225
|
+
var _a, _b, _c;
|
|
224
226
|
try {
|
|
225
227
|
if (!core) {
|
|
226
228
|
throw new Error("SDK not initialized");
|
|
@@ -252,18 +254,39 @@ export function ShogunButtonProvider({ children, core, options, onLoginSuccess,
|
|
|
252
254
|
throw error;
|
|
253
255
|
}
|
|
254
256
|
break;
|
|
255
|
-
case "webauthn":
|
|
256
|
-
username = args[0];
|
|
257
|
+
case "webauthn": {
|
|
258
|
+
username = typeof args[0] === "string" ? args[0].trim() : "";
|
|
259
|
+
const webauthnOptions = args.length > 1 && typeof args[1] === "object" && args[1] !== null
|
|
260
|
+
? args[1]
|
|
261
|
+
: {};
|
|
262
|
+
if (!username) {
|
|
263
|
+
throw new Error("Username is required for WebAuthn registration");
|
|
264
|
+
}
|
|
257
265
|
if (isShogunCore(core)) {
|
|
258
266
|
const webauthn = core.getPlugin("webauthn");
|
|
259
267
|
if (!webauthn)
|
|
260
268
|
throw new Error("WebAuthn plugin not available");
|
|
261
|
-
|
|
269
|
+
const pluginOptions = {};
|
|
270
|
+
if (webauthnOptions.seedPhrase) {
|
|
271
|
+
pluginOptions.seedPhrase = webauthnOptions.seedPhrase.trim();
|
|
272
|
+
pluginOptions.generateSeedPhrase =
|
|
273
|
+
(_a = webauthnOptions.generateSeedPhrase) !== null && _a !== void 0 ? _a : false;
|
|
274
|
+
}
|
|
275
|
+
else if (typeof webauthnOptions.generateSeedPhrase === "boolean") {
|
|
276
|
+
pluginOptions.generateSeedPhrase =
|
|
277
|
+
webauthnOptions.generateSeedPhrase;
|
|
278
|
+
}
|
|
279
|
+
if (pluginOptions.generateSeedPhrase === undefined &&
|
|
280
|
+
!pluginOptions.seedPhrase) {
|
|
281
|
+
pluginOptions.generateSeedPhrase = true;
|
|
282
|
+
}
|
|
283
|
+
result = await webauthn.signUp(username, pluginOptions);
|
|
262
284
|
}
|
|
263
285
|
else {
|
|
264
286
|
throw new Error("WebAuthn requires ShogunCore");
|
|
265
287
|
}
|
|
266
288
|
break;
|
|
289
|
+
}
|
|
267
290
|
case "web3":
|
|
268
291
|
if (isShogunCore(core)) {
|
|
269
292
|
const web3 = core.getPlugin("web3");
|
|
@@ -320,7 +343,7 @@ export function ShogunButtonProvider({ children, core, options, onLoginSuccess,
|
|
|
320
343
|
if (result.success) {
|
|
321
344
|
let userPub = result.userPub || "";
|
|
322
345
|
if (!userPub && isShogunCore(core)) {
|
|
323
|
-
userPub = ((
|
|
346
|
+
userPub = ((_c = (_b = core.gun.user()) === null || _b === void 0 ? void 0 : _b.is) === null || _c === void 0 ? void 0 : _c.pub) || "";
|
|
324
347
|
}
|
|
325
348
|
const displayName = result.alias || username || userPub.slice(0, 8) + "...";
|
|
326
349
|
setIsLoggedIn(true);
|
|
@@ -332,6 +355,8 @@ export function ShogunButtonProvider({ children, core, options, onLoginSuccess,
|
|
|
332
355
|
seedPhrase: result.seedPhrase,
|
|
333
356
|
authMethod: authMethod,
|
|
334
357
|
};
|
|
358
|
+
const pendingBackup = Boolean(result.seedPhrase || result.trapdoor);
|
|
359
|
+
setHasPendingSignup(pendingBackup);
|
|
335
360
|
onSignupSuccess === null || onSignupSuccess === void 0 ? void 0 : onSignupSuccess(signupPayload);
|
|
336
361
|
}
|
|
337
362
|
else {
|
|
@@ -465,8 +490,9 @@ export function ShogunButtonProvider({ children, core, options, onLoginSuccess,
|
|
|
465
490
|
const gunPlugin = null;
|
|
466
491
|
// Plugin hooks removed - GunAdvancedPlugin no longer available
|
|
467
492
|
const pluginHooks = {};
|
|
468
|
-
const completePendingSignup = React.useCallback(() => {
|
|
469
|
-
|
|
493
|
+
const completePendingSignup = React.useCallback(() => {
|
|
494
|
+
setHasPendingSignup(false);
|
|
495
|
+
}, [setHasPendingSignup]);
|
|
470
496
|
// Create a properly typed context value
|
|
471
497
|
const contextValue = React.useMemo(() => ({
|
|
472
498
|
core,
|
|
@@ -486,6 +512,7 @@ export function ShogunButtonProvider({ children, core, options, onLoginSuccess,
|
|
|
486
512
|
gunPlugin,
|
|
487
513
|
completePendingSignup,
|
|
488
514
|
hasPendingSignup,
|
|
515
|
+
setHasPendingSignup,
|
|
489
516
|
put: async (path, data) => {
|
|
490
517
|
if (isShogunCore(core)) {
|
|
491
518
|
if (!core.gun)
|
|
@@ -545,6 +572,8 @@ export function ShogunButtonProvider({ children, core, options, onLoginSuccess,
|
|
|
545
572
|
gunPlugin,
|
|
546
573
|
pluginHooks,
|
|
547
574
|
completePendingSignup,
|
|
575
|
+
hasPendingSignup,
|
|
576
|
+
setHasPendingSignup,
|
|
548
577
|
]);
|
|
549
578
|
// Provide the context value to children
|
|
550
579
|
return (React.createElement(ShogunContext.Provider, { value: contextValue }, children));
|
|
@@ -594,7 +623,7 @@ const ExportIcon = () => (React.createElement("svg", { xmlns: "http://www.w3.org
|
|
|
594
623
|
// Component for Shogun login button
|
|
595
624
|
export const ShogunButton = (() => {
|
|
596
625
|
const Button = () => {
|
|
597
|
-
const { isLoggedIn, username, logout, login, signUp, core, options, exportGunPair, importGunPair, hasPlugin, } = useShogun();
|
|
626
|
+
const { isLoggedIn, username, logout, login, signUp, core, options, exportGunPair, importGunPair, hasPlugin, hasPendingSignup, setHasPendingSignup, } = useShogun();
|
|
598
627
|
// Form states
|
|
599
628
|
const [modalIsOpen, setModalIsOpen] = useState(false);
|
|
600
629
|
const [formUsername, setFormUsername] = useState("");
|
|
@@ -616,7 +645,10 @@ export const ShogunButton = (() => {
|
|
|
616
645
|
const [showCopySuccess, setShowCopySuccess] = useState(false);
|
|
617
646
|
const [showImportSuccess, setShowImportSuccess] = useState(false);
|
|
618
647
|
const [zkTrapdoor, setZkTrapdoor] = useState("");
|
|
648
|
+
const [zkSignupTrapdoor, setZkSignupTrapdoor] = useState("");
|
|
649
|
+
const [showZkTrapdoorCopySuccess, setShowZkTrapdoorCopySuccess] = useState(false);
|
|
619
650
|
const [webauthnSeedPhrase, setWebauthnSeedPhrase] = useState("");
|
|
651
|
+
const [webauthnRecoverySeed, setWebauthnRecoverySeed] = useState("");
|
|
620
652
|
const dropdownRef = useRef(null);
|
|
621
653
|
// Handle click outside to close dropdown
|
|
622
654
|
useEffect(() => {
|
|
@@ -633,6 +665,20 @@ export const ShogunButton = (() => {
|
|
|
633
665
|
};
|
|
634
666
|
}
|
|
635
667
|
}, [dropdownOpen]);
|
|
668
|
+
useEffect(() => {
|
|
669
|
+
if (hasPendingSignup) {
|
|
670
|
+
setModalIsOpen(true);
|
|
671
|
+
if (authView !== "webauthn-signup-result" &&
|
|
672
|
+
authView !== "zkproof-signup-result") {
|
|
673
|
+
if (webauthnSeedPhrase) {
|
|
674
|
+
setAuthView("webauthn-signup-result");
|
|
675
|
+
}
|
|
676
|
+
else if (zkSignupTrapdoor) {
|
|
677
|
+
setAuthView("zkproof-signup-result");
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
}, [hasPendingSignup, authView, webauthnSeedPhrase, zkSignupTrapdoor]);
|
|
636
682
|
// If already logged in, show only logout button
|
|
637
683
|
if (isLoggedIn && username && !modalIsOpen) {
|
|
638
684
|
return (React.createElement("div", { className: "shogun-logged-in-container" },
|
|
@@ -753,6 +799,41 @@ export const ShogunButton = (() => {
|
|
|
753
799
|
}
|
|
754
800
|
setAuthView("webauthn-username");
|
|
755
801
|
};
|
|
802
|
+
const handleWebauthnImport = async () => {
|
|
803
|
+
setError("");
|
|
804
|
+
setLoading(true);
|
|
805
|
+
try {
|
|
806
|
+
const username = formUsername.trim();
|
|
807
|
+
const recoveryCode = webauthnRecoverySeed.trim();
|
|
808
|
+
if (!username) {
|
|
809
|
+
throw new Error("Please enter your username");
|
|
810
|
+
}
|
|
811
|
+
if (!recoveryCode) {
|
|
812
|
+
throw new Error("Please enter your recovery code");
|
|
813
|
+
}
|
|
814
|
+
if (!isShogunCore(core)) {
|
|
815
|
+
throw new Error("WebAuthn recovery requires ShogunCore");
|
|
816
|
+
}
|
|
817
|
+
const result = await signUp("webauthn", username, {
|
|
818
|
+
seedPhrase: recoveryCode,
|
|
819
|
+
generateSeedPhrase: false,
|
|
820
|
+
});
|
|
821
|
+
if (!result || !result.success) {
|
|
822
|
+
throw new Error((result === null || result === void 0 ? void 0 : result.error) || "Failed to restore account");
|
|
823
|
+
}
|
|
824
|
+
const seedToDisplay = result.seedPhrase || recoveryCode;
|
|
825
|
+
setWebauthnSeedPhrase(seedToDisplay);
|
|
826
|
+
setWebauthnRecoverySeed("");
|
|
827
|
+
setShowCopySuccess(false);
|
|
828
|
+
setAuthView("webauthn-signup-result");
|
|
829
|
+
}
|
|
830
|
+
catch (e) {
|
|
831
|
+
setError(e.message || "Failed to restore WebAuthn account");
|
|
832
|
+
}
|
|
833
|
+
finally {
|
|
834
|
+
setLoading(false);
|
|
835
|
+
}
|
|
836
|
+
};
|
|
756
837
|
const handleZkProofAuth = () => {
|
|
757
838
|
if (!hasPlugin("zkproof")) {
|
|
758
839
|
setError("ZK-Proof plugin not available");
|
|
@@ -791,8 +872,17 @@ export const ShogunButton = (() => {
|
|
|
791
872
|
if (!result || !result.success) {
|
|
792
873
|
throw new Error((result === null || result === void 0 ? void 0 : result.error) || "ZK-Proof signup failed");
|
|
793
874
|
}
|
|
794
|
-
|
|
795
|
-
|
|
875
|
+
const trapdoorValue = result.seedPhrase || result.trapdoor || "";
|
|
876
|
+
if (trapdoorValue) {
|
|
877
|
+
setZkSignupTrapdoor(trapdoorValue);
|
|
878
|
+
setShowZkTrapdoorCopySuccess(false);
|
|
879
|
+
setAuthView("zkproof-signup-result");
|
|
880
|
+
setHasPendingSignup(true);
|
|
881
|
+
}
|
|
882
|
+
else {
|
|
883
|
+
setAuthView("options");
|
|
884
|
+
setModalIsOpen(false);
|
|
885
|
+
}
|
|
796
886
|
}
|
|
797
887
|
catch (e) {
|
|
798
888
|
setError(e.message || "ZK-Proof signup failed");
|
|
@@ -911,7 +1001,10 @@ export const ShogunButton = (() => {
|
|
|
911
1001
|
setShowImportSuccess(false);
|
|
912
1002
|
setRecoveredHint("");
|
|
913
1003
|
setZkTrapdoor("");
|
|
1004
|
+
setZkSignupTrapdoor("");
|
|
1005
|
+
setShowZkTrapdoorCopySuccess(false);
|
|
914
1006
|
setWebauthnSeedPhrase("");
|
|
1007
|
+
setWebauthnRecoverySeed("");
|
|
915
1008
|
};
|
|
916
1009
|
const openModal = () => {
|
|
917
1010
|
resetForm();
|
|
@@ -921,11 +1014,13 @@ export const ShogunButton = (() => {
|
|
|
921
1014
|
const closeModal = () => {
|
|
922
1015
|
setError("");
|
|
923
1016
|
setModalIsOpen(false);
|
|
1017
|
+
setHasPendingSignup(false);
|
|
924
1018
|
};
|
|
925
1019
|
const finalizeZkProofSignup = () => {
|
|
926
1020
|
setError("");
|
|
927
1021
|
resetForm();
|
|
928
1022
|
setModalIsOpen(false);
|
|
1023
|
+
setHasPendingSignup(false);
|
|
929
1024
|
};
|
|
930
1025
|
const toggleMode = () => {
|
|
931
1026
|
resetForm();
|
|
@@ -1037,7 +1132,52 @@ export const ShogunButton = (() => {
|
|
|
1037
1132
|
React.createElement("input", { type: "text", id: "username", value: formUsername, onChange: (e) => setFormUsername(e.target.value), disabled: loading, required: true, placeholder: "Enter your username", autoFocus: true })),
|
|
1038
1133
|
React.createElement("button", { type: "button", className: "shogun-submit-button", onClick: () => handleAuth("webauthn", formUsername), disabled: loading || !formUsername.trim() }, loading ? "Processing..." : `Continue with WebAuthn`),
|
|
1039
1134
|
React.createElement("div", { className: "shogun-form-footer" },
|
|
1040
|
-
React.createElement("button", { type: "button", className: "shogun-back-button", onClick: () => setAuthView("options"), disabled: loading }, "\u2190 Back to Options")
|
|
1135
|
+
React.createElement("button", { type: "button", className: "shogun-back-button", onClick: () => setAuthView("options"), disabled: loading }, "\u2190 Back to Options"),
|
|
1136
|
+
formMode === "login" && (React.createElement("button", { type: "button", className: "shogun-toggle-mode", onClick: () => setAuthView("webauthn-recovery"), disabled: loading }, "Restore with Recovery Code")))));
|
|
1137
|
+
const renderWebauthnRecoveryForm = () => (React.createElement("div", { className: "shogun-auth-form" },
|
|
1138
|
+
React.createElement("h3", null, "Restore WebAuthn Account"),
|
|
1139
|
+
React.createElement("div", { style: {
|
|
1140
|
+
backgroundColor: "#fef3c7",
|
|
1141
|
+
padding: "12px",
|
|
1142
|
+
borderRadius: "8px",
|
|
1143
|
+
marginBottom: "16px",
|
|
1144
|
+
border: "1px solid #f59e0b",
|
|
1145
|
+
} },
|
|
1146
|
+
React.createElement("p", { style: {
|
|
1147
|
+
fontSize: "14px",
|
|
1148
|
+
color: "#92400e",
|
|
1149
|
+
margin: "0",
|
|
1150
|
+
fontWeight: "500",
|
|
1151
|
+
} }, "\u26A0\uFE0F Recovery Required"),
|
|
1152
|
+
React.createElement("p", { style: {
|
|
1153
|
+
fontSize: "13px",
|
|
1154
|
+
color: "#a16207",
|
|
1155
|
+
margin: "4px 0 0 0",
|
|
1156
|
+
} }, "Enter the username and recovery code saved during signup to restore access on this device.")),
|
|
1157
|
+
React.createElement("div", { className: "shogun-form-group" },
|
|
1158
|
+
React.createElement("label", { htmlFor: "recoveryUsername" },
|
|
1159
|
+
React.createElement(UserIcon, null),
|
|
1160
|
+
React.createElement("span", null, "Username")),
|
|
1161
|
+
React.createElement("input", { type: "text", id: "recoveryUsername", value: formUsername, onChange: (e) => setFormUsername(e.target.value), disabled: loading, placeholder: "Enter your username", autoFocus: true })),
|
|
1162
|
+
React.createElement("div", { className: "shogun-form-group" },
|
|
1163
|
+
React.createElement("label", { htmlFor: "recoverySeed" },
|
|
1164
|
+
React.createElement(KeyIcon, null),
|
|
1165
|
+
React.createElement("span", null, "Recovery Code")),
|
|
1166
|
+
React.createElement("textarea", { id: "recoverySeed", value: webauthnRecoverySeed, onChange: (e) => setWebauthnRecoverySeed(e.target.value), disabled: loading, placeholder: "Enter your WebAuthn seed phrase...", rows: 4, style: {
|
|
1167
|
+
fontFamily: "monospace",
|
|
1168
|
+
fontSize: "12px",
|
|
1169
|
+
width: "100%",
|
|
1170
|
+
padding: "8px",
|
|
1171
|
+
border: "1px solid #f59e0b",
|
|
1172
|
+
borderRadius: "4px",
|
|
1173
|
+
backgroundColor: "#fffbeb",
|
|
1174
|
+
} })),
|
|
1175
|
+
React.createElement("button", { type: "button", className: "shogun-submit-button", onClick: handleWebauthnImport, disabled: loading }, loading ? "Restoring..." : "Restore Account"),
|
|
1176
|
+
React.createElement("div", { className: "shogun-form-footer" },
|
|
1177
|
+
React.createElement("button", { type: "button", className: "shogun-back-button", onClick: () => {
|
|
1178
|
+
setError("");
|
|
1179
|
+
setAuthView("webauthn-username");
|
|
1180
|
+
}, disabled: loading }, "\u2190 Back to WebAuthn"))));
|
|
1041
1181
|
const renderRecoveryForm = () => (React.createElement("div", { className: "shogun-auth-form" },
|
|
1042
1182
|
React.createElement("div", { className: "shogun-form-group" },
|
|
1043
1183
|
React.createElement("label", { htmlFor: "username" },
|
|
@@ -1150,6 +1290,55 @@ export const ShogunButton = (() => {
|
|
|
1150
1290
|
React.createElement("button", { type: "button", className: "shogun-submit-button", onClick: handleZkProofLogin, disabled: loading || !zkTrapdoor.trim() }, loading ? "Processing..." : "Login Anonymously"),
|
|
1151
1291
|
React.createElement("div", { className: "shogun-form-footer" },
|
|
1152
1292
|
React.createElement("button", { className: "shogun-toggle-mode", onClick: () => setAuthView("options"), disabled: loading }, "Back to Login Options"))));
|
|
1293
|
+
const renderZkProofSignupResult = () => (React.createElement("div", { className: "shogun-auth-form" },
|
|
1294
|
+
React.createElement("h3", null, "ZK-Proof Account Created!"),
|
|
1295
|
+
React.createElement("div", { style: {
|
|
1296
|
+
backgroundColor: "#fef3c7",
|
|
1297
|
+
padding: "12px",
|
|
1298
|
+
borderRadius: "8px",
|
|
1299
|
+
marginBottom: "16px",
|
|
1300
|
+
border: "1px solid #f59e0b",
|
|
1301
|
+
} },
|
|
1302
|
+
React.createElement("p", { style: {
|
|
1303
|
+
fontSize: "14px",
|
|
1304
|
+
color: "#92400e",
|
|
1305
|
+
margin: "0",
|
|
1306
|
+
fontWeight: "500",
|
|
1307
|
+
} }, "\u26A0\uFE0F Important: Save Your Trapdoor"),
|
|
1308
|
+
React.createElement("p", { style: { fontSize: "13px", color: "#a16207", margin: "4px 0 0 0" } }, "This trapdoor lets you restore your anonymous identity on new devices. Store it securely and never share it.")),
|
|
1309
|
+
React.createElement("div", { className: "shogun-form-group" },
|
|
1310
|
+
React.createElement("label", null, "Your Trapdoor (Recovery Phrase):"),
|
|
1311
|
+
React.createElement("textarea", { value: zkSignupTrapdoor, readOnly: true, rows: 4, style: {
|
|
1312
|
+
fontFamily: "monospace",
|
|
1313
|
+
fontSize: "12px",
|
|
1314
|
+
width: "100%",
|
|
1315
|
+
padding: "8px",
|
|
1316
|
+
border: "2px solid #f59e0b",
|
|
1317
|
+
borderRadius: "4px",
|
|
1318
|
+
backgroundColor: "#fffbeb",
|
|
1319
|
+
} }),
|
|
1320
|
+
React.createElement("button", { type: "button", className: "shogun-submit-button", style: { marginTop: "8px" }, onClick: async () => {
|
|
1321
|
+
if (!zkSignupTrapdoor) {
|
|
1322
|
+
return;
|
|
1323
|
+
}
|
|
1324
|
+
try {
|
|
1325
|
+
if (navigator.clipboard) {
|
|
1326
|
+
await navigator.clipboard.writeText(zkSignupTrapdoor);
|
|
1327
|
+
setShowZkTrapdoorCopySuccess(true);
|
|
1328
|
+
setTimeout(() => setShowZkTrapdoorCopySuccess(false), 3000);
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
catch (copyError) {
|
|
1332
|
+
console.warn("Failed to copy trapdoor:", copyError);
|
|
1333
|
+
}
|
|
1334
|
+
}, disabled: !zkSignupTrapdoor }, "Copy Trapdoor"),
|
|
1335
|
+
showZkTrapdoorCopySuccess && (React.createElement("p", { style: {
|
|
1336
|
+
color: "#047857",
|
|
1337
|
+
fontSize: "12px",
|
|
1338
|
+
marginTop: "6px",
|
|
1339
|
+
} }, "Trapdoor copied to clipboard!"))),
|
|
1340
|
+
React.createElement("div", { className: "shogun-form-footer" },
|
|
1341
|
+
React.createElement("button", { type: "button", className: "shogun-submit-button", onClick: finalizeZkProofSignup }, "I Saved My Trapdoor"))));
|
|
1153
1342
|
const renderWebauthnSignupResult = () => (React.createElement("div", { className: "shogun-auth-form" },
|
|
1154
1343
|
React.createElement("h3", null, "WebAuthn Account Created!"),
|
|
1155
1344
|
React.createElement("div", { style: {
|
|
@@ -1292,9 +1481,13 @@ export const ShogunButton = (() => {
|
|
|
1292
1481
|
authView === "import" && renderImportForm(),
|
|
1293
1482
|
authView === "webauthn-username" &&
|
|
1294
1483
|
renderWebAuthnUsernameForm(),
|
|
1484
|
+
authView === "webauthn-recovery" &&
|
|
1485
|
+
renderWebauthnRecoveryForm(),
|
|
1295
1486
|
authView === "webauthn-signup-result" &&
|
|
1296
1487
|
renderWebauthnSignupResult(),
|
|
1297
|
-
authView === "zkproof-login" && renderZkProofLoginForm()
|
|
1488
|
+
authView === "zkproof-login" && renderZkProofLoginForm(),
|
|
1489
|
+
authView === "zkproof-signup-result" &&
|
|
1490
|
+
renderZkProofSignupResult()))))));
|
|
1298
1491
|
};
|
|
1299
1492
|
Button.displayName = "ShogunButton";
|
|
1300
1493
|
return Object.assign(Button, {
|