shogun-button-react 6.3.7 β 6.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -0
- package/dist/components/ShogunButton.js +174 -88
- package/dist/index.js +1 -1
- package/dist/index.js.LICENSE.txt +0 -2
- 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
|
|
@@ -38,7 +38,6 @@ export function ShogunButtonProvider({ children, core, options, onLoginSuccess,
|
|
|
38
38
|
const [isLoggedIn, setIsLoggedIn] = useState(false);
|
|
39
39
|
const [userPub, setUserPub] = useState(null);
|
|
40
40
|
const [username, setUsername] = useState(null);
|
|
41
|
-
const [pendingSignupData, setPendingSignupData] = useState(null);
|
|
42
41
|
// Effetto per gestire l'inizializzazione e pulizia
|
|
43
42
|
useEffect(() => {
|
|
44
43
|
var _a, _b;
|
|
@@ -221,7 +220,7 @@ export function ShogunButtonProvider({ children, core, options, onLoginSuccess,
|
|
|
221
220
|
};
|
|
222
221
|
// Unified signup
|
|
223
222
|
const signUp = async (method, ...args) => {
|
|
224
|
-
var _a, _b;
|
|
223
|
+
var _a, _b, _c;
|
|
225
224
|
try {
|
|
226
225
|
if (!core) {
|
|
227
226
|
throw new Error("SDK not initialized");
|
|
@@ -253,18 +252,39 @@ export function ShogunButtonProvider({ children, core, options, onLoginSuccess,
|
|
|
253
252
|
throw error;
|
|
254
253
|
}
|
|
255
254
|
break;
|
|
256
|
-
case "webauthn":
|
|
257
|
-
username = args[0];
|
|
255
|
+
case "webauthn": {
|
|
256
|
+
username = typeof args[0] === "string" ? args[0].trim() : "";
|
|
257
|
+
const webauthnOptions = args.length > 1 && typeof args[1] === "object" && args[1] !== null
|
|
258
|
+
? args[1]
|
|
259
|
+
: {};
|
|
260
|
+
if (!username) {
|
|
261
|
+
throw new Error("Username is required for WebAuthn registration");
|
|
262
|
+
}
|
|
258
263
|
if (isShogunCore(core)) {
|
|
259
264
|
const webauthn = core.getPlugin("webauthn");
|
|
260
265
|
if (!webauthn)
|
|
261
266
|
throw new Error("WebAuthn plugin not available");
|
|
262
|
-
|
|
267
|
+
const pluginOptions = {};
|
|
268
|
+
if (webauthnOptions.seedPhrase) {
|
|
269
|
+
pluginOptions.seedPhrase = webauthnOptions.seedPhrase.trim();
|
|
270
|
+
pluginOptions.generateSeedPhrase =
|
|
271
|
+
(_a = webauthnOptions.generateSeedPhrase) !== null && _a !== void 0 ? _a : false;
|
|
272
|
+
}
|
|
273
|
+
else if (typeof webauthnOptions.generateSeedPhrase === "boolean") {
|
|
274
|
+
pluginOptions.generateSeedPhrase =
|
|
275
|
+
webauthnOptions.generateSeedPhrase;
|
|
276
|
+
}
|
|
277
|
+
if (pluginOptions.generateSeedPhrase === undefined &&
|
|
278
|
+
!pluginOptions.seedPhrase) {
|
|
279
|
+
pluginOptions.generateSeedPhrase = true;
|
|
280
|
+
}
|
|
281
|
+
result = await webauthn.signUp(username, pluginOptions);
|
|
263
282
|
}
|
|
264
283
|
else {
|
|
265
284
|
throw new Error("WebAuthn requires ShogunCore");
|
|
266
285
|
}
|
|
267
286
|
break;
|
|
287
|
+
}
|
|
268
288
|
case "web3":
|
|
269
289
|
if (isShogunCore(core)) {
|
|
270
290
|
const web3 = core.getPlugin("web3");
|
|
@@ -321,7 +341,7 @@ export function ShogunButtonProvider({ children, core, options, onLoginSuccess,
|
|
|
321
341
|
if (result.success) {
|
|
322
342
|
let userPub = result.userPub || "";
|
|
323
343
|
if (!userPub && isShogunCore(core)) {
|
|
324
|
-
userPub = ((
|
|
344
|
+
userPub = ((_c = (_b = core.gun.user()) === null || _b === void 0 ? void 0 : _b.is) === null || _c === void 0 ? void 0 : _c.pub) || "";
|
|
325
345
|
}
|
|
326
346
|
const displayName = result.alias || username || userPub.slice(0, 8) + "...";
|
|
327
347
|
setIsLoggedIn(true);
|
|
@@ -333,12 +353,7 @@ export function ShogunButtonProvider({ children, core, options, onLoginSuccess,
|
|
|
333
353
|
seedPhrase: result.seedPhrase,
|
|
334
354
|
authMethod: authMethod,
|
|
335
355
|
};
|
|
336
|
-
|
|
337
|
-
setPendingSignupData(signupPayload);
|
|
338
|
-
}
|
|
339
|
-
else {
|
|
340
|
-
onSignupSuccess === null || onSignupSuccess === void 0 ? void 0 : onSignupSuccess(signupPayload);
|
|
341
|
-
}
|
|
356
|
+
onSignupSuccess === null || onSignupSuccess === void 0 ? void 0 : onSignupSuccess(signupPayload);
|
|
342
357
|
}
|
|
343
358
|
else {
|
|
344
359
|
onError === null || onError === void 0 ? void 0 : onError(result.error);
|
|
@@ -358,7 +373,6 @@ export function ShogunButtonProvider({ children, core, options, onLoginSuccess,
|
|
|
358
373
|
setIsLoggedIn(false);
|
|
359
374
|
setUserPub(null);
|
|
360
375
|
setUsername(null);
|
|
361
|
-
setPendingSignupData(null);
|
|
362
376
|
};
|
|
363
377
|
// Implementazione del metodo setProvider
|
|
364
378
|
const setProvider = (provider) => {
|
|
@@ -472,13 +486,8 @@ export function ShogunButtonProvider({ children, core, options, onLoginSuccess,
|
|
|
472
486
|
const gunPlugin = null;
|
|
473
487
|
// Plugin hooks removed - GunAdvancedPlugin no longer available
|
|
474
488
|
const pluginHooks = {};
|
|
475
|
-
const completePendingSignup = React.useCallback(() => {
|
|
476
|
-
|
|
477
|
-
const dataToEmit = pendingSignupData;
|
|
478
|
-
setPendingSignupData(null);
|
|
479
|
-
onSignupSuccess === null || onSignupSuccess === void 0 ? void 0 : onSignupSuccess(dataToEmit);
|
|
480
|
-
}
|
|
481
|
-
}, [pendingSignupData, onSignupSuccess]);
|
|
489
|
+
const completePendingSignup = React.useCallback(() => { }, []);
|
|
490
|
+
const hasPendingSignup = false;
|
|
482
491
|
// Create a properly typed context value
|
|
483
492
|
const contextValue = React.useMemo(() => ({
|
|
484
493
|
core,
|
|
@@ -497,7 +506,7 @@ export function ShogunButtonProvider({ children, core, options, onLoginSuccess,
|
|
|
497
506
|
setProvider,
|
|
498
507
|
gunPlugin,
|
|
499
508
|
completePendingSignup,
|
|
500
|
-
hasPendingSignup
|
|
509
|
+
hasPendingSignup,
|
|
501
510
|
put: async (path, data) => {
|
|
502
511
|
if (isShogunCore(core)) {
|
|
503
512
|
if (!core.gun)
|
|
@@ -556,7 +565,6 @@ export function ShogunButtonProvider({ children, core, options, onLoginSuccess,
|
|
|
556
565
|
importGunPair,
|
|
557
566
|
gunPlugin,
|
|
558
567
|
pluginHooks,
|
|
559
|
-
pendingSignupData,
|
|
560
568
|
completePendingSignup,
|
|
561
569
|
]);
|
|
562
570
|
// Provide the context value to children
|
|
@@ -607,7 +615,7 @@ const ExportIcon = () => (React.createElement("svg", { xmlns: "http://www.w3.org
|
|
|
607
615
|
// Component for Shogun login button
|
|
608
616
|
export const ShogunButton = (() => {
|
|
609
617
|
const Button = () => {
|
|
610
|
-
const { isLoggedIn, username, logout, login, signUp, core, options, exportGunPair, importGunPair, hasPlugin,
|
|
618
|
+
const { isLoggedIn, username, logout, login, signUp, core, options, exportGunPair, importGunPair, hasPlugin, } = useShogun();
|
|
611
619
|
// Form states
|
|
612
620
|
const [modalIsOpen, setModalIsOpen] = useState(false);
|
|
613
621
|
const [formUsername, setFormUsername] = useState("");
|
|
@@ -629,10 +637,11 @@ export const ShogunButton = (() => {
|
|
|
629
637
|
const [showCopySuccess, setShowCopySuccess] = useState(false);
|
|
630
638
|
const [showImportSuccess, setShowImportSuccess] = useState(false);
|
|
631
639
|
const [zkTrapdoor, setZkTrapdoor] = useState("");
|
|
632
|
-
const [
|
|
640
|
+
const [zkSignupTrapdoor, setZkSignupTrapdoor] = useState("");
|
|
641
|
+
const [showZkTrapdoorCopySuccess, setShowZkTrapdoorCopySuccess] = useState(false);
|
|
633
642
|
const [webauthnSeedPhrase, setWebauthnSeedPhrase] = useState("");
|
|
643
|
+
const [webauthnRecoverySeed, setWebauthnRecoverySeed] = useState("");
|
|
634
644
|
const dropdownRef = useRef(null);
|
|
635
|
-
const [pendingZkConfirmation, setPendingZkConfirmation] = useState(false);
|
|
636
645
|
// Handle click outside to close dropdown
|
|
637
646
|
useEffect(() => {
|
|
638
647
|
const handleClickOutside = (event) => {
|
|
@@ -768,6 +777,41 @@ export const ShogunButton = (() => {
|
|
|
768
777
|
}
|
|
769
778
|
setAuthView("webauthn-username");
|
|
770
779
|
};
|
|
780
|
+
const handleWebauthnImport = async () => {
|
|
781
|
+
setError("");
|
|
782
|
+
setLoading(true);
|
|
783
|
+
try {
|
|
784
|
+
const username = formUsername.trim();
|
|
785
|
+
const recoveryCode = webauthnRecoverySeed.trim();
|
|
786
|
+
if (!username) {
|
|
787
|
+
throw new Error("Please enter your username");
|
|
788
|
+
}
|
|
789
|
+
if (!recoveryCode) {
|
|
790
|
+
throw new Error("Please enter your recovery code");
|
|
791
|
+
}
|
|
792
|
+
if (!isShogunCore(core)) {
|
|
793
|
+
throw new Error("WebAuthn recovery requires ShogunCore");
|
|
794
|
+
}
|
|
795
|
+
const result = await signUp("webauthn", username, {
|
|
796
|
+
seedPhrase: recoveryCode,
|
|
797
|
+
generateSeedPhrase: false,
|
|
798
|
+
});
|
|
799
|
+
if (!result || !result.success) {
|
|
800
|
+
throw new Error((result === null || result === void 0 ? void 0 : result.error) || "Failed to restore account");
|
|
801
|
+
}
|
|
802
|
+
const seedToDisplay = result.seedPhrase || recoveryCode;
|
|
803
|
+
setWebauthnSeedPhrase(seedToDisplay);
|
|
804
|
+
setWebauthnRecoverySeed("");
|
|
805
|
+
setShowCopySuccess(false);
|
|
806
|
+
setAuthView("webauthn-signup-result");
|
|
807
|
+
}
|
|
808
|
+
catch (e) {
|
|
809
|
+
setError(e.message || "Failed to restore WebAuthn account");
|
|
810
|
+
}
|
|
811
|
+
finally {
|
|
812
|
+
setLoading(false);
|
|
813
|
+
}
|
|
814
|
+
};
|
|
771
815
|
const handleZkProofAuth = () => {
|
|
772
816
|
if (!hasPlugin("zkproof")) {
|
|
773
817
|
setError("ZK-Proof plugin not available");
|
|
@@ -803,14 +847,18 @@ export const ShogunButton = (() => {
|
|
|
803
847
|
setLoading(true);
|
|
804
848
|
try {
|
|
805
849
|
const result = await signUp("zkproof");
|
|
806
|
-
if (result
|
|
807
|
-
|
|
808
|
-
|
|
850
|
+
if (!result || !result.success) {
|
|
851
|
+
throw new Error((result === null || result === void 0 ? void 0 : result.error) || "ZK-Proof signup failed");
|
|
852
|
+
}
|
|
853
|
+
const trapdoorValue = result.seedPhrase || result.trapdoor || "";
|
|
854
|
+
if (trapdoorValue) {
|
|
855
|
+
setZkSignupTrapdoor(trapdoorValue);
|
|
856
|
+
setShowZkTrapdoorCopySuccess(false);
|
|
809
857
|
setAuthView("zkproof-signup-result");
|
|
810
|
-
setPendingZkConfirmation(true);
|
|
811
858
|
}
|
|
812
|
-
else
|
|
813
|
-
|
|
859
|
+
else {
|
|
860
|
+
setAuthView("options");
|
|
861
|
+
setModalIsOpen(false);
|
|
814
862
|
}
|
|
815
863
|
}
|
|
816
864
|
catch (e) {
|
|
@@ -930,9 +978,10 @@ export const ShogunButton = (() => {
|
|
|
930
978
|
setShowImportSuccess(false);
|
|
931
979
|
setRecoveredHint("");
|
|
932
980
|
setZkTrapdoor("");
|
|
933
|
-
|
|
981
|
+
setZkSignupTrapdoor("");
|
|
982
|
+
setShowZkTrapdoorCopySuccess(false);
|
|
934
983
|
setWebauthnSeedPhrase("");
|
|
935
|
-
|
|
984
|
+
setWebauthnRecoverySeed("");
|
|
936
985
|
};
|
|
937
986
|
const openModal = () => {
|
|
938
987
|
resetForm();
|
|
@@ -940,17 +989,12 @@ export const ShogunButton = (() => {
|
|
|
940
989
|
setModalIsOpen(true);
|
|
941
990
|
};
|
|
942
991
|
const closeModal = () => {
|
|
943
|
-
|
|
944
|
-
setError("Please save your trapdoor and confirm before leaving this screen.");
|
|
945
|
-
return;
|
|
946
|
-
}
|
|
992
|
+
setError("");
|
|
947
993
|
setModalIsOpen(false);
|
|
948
994
|
};
|
|
949
995
|
const finalizeZkProofSignup = () => {
|
|
950
|
-
completePendingSignup();
|
|
951
996
|
setError("");
|
|
952
|
-
|
|
953
|
-
setAuthView("options");
|
|
997
|
+
resetForm();
|
|
954
998
|
setModalIsOpen(false);
|
|
955
999
|
};
|
|
956
1000
|
const toggleMode = () => {
|
|
@@ -1063,7 +1107,52 @@ export const ShogunButton = (() => {
|
|
|
1063
1107
|
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 })),
|
|
1064
1108
|
React.createElement("button", { type: "button", className: "shogun-submit-button", onClick: () => handleAuth("webauthn", formUsername), disabled: loading || !formUsername.trim() }, loading ? "Processing..." : `Continue with WebAuthn`),
|
|
1065
1109
|
React.createElement("div", { className: "shogun-form-footer" },
|
|
1066
|
-
React.createElement("button", { type: "button", className: "shogun-back-button", onClick: () => setAuthView("options"), disabled: loading }, "\u2190 Back to Options")
|
|
1110
|
+
React.createElement("button", { type: "button", className: "shogun-back-button", onClick: () => setAuthView("options"), disabled: loading }, "\u2190 Back to Options"),
|
|
1111
|
+
formMode === "login" && (React.createElement("button", { type: "button", className: "shogun-toggle-mode", onClick: () => setAuthView("webauthn-recovery"), disabled: loading }, "Restore with Recovery Code")))));
|
|
1112
|
+
const renderWebauthnRecoveryForm = () => (React.createElement("div", { className: "shogun-auth-form" },
|
|
1113
|
+
React.createElement("h3", null, "Restore WebAuthn Account"),
|
|
1114
|
+
React.createElement("div", { style: {
|
|
1115
|
+
backgroundColor: "#fef3c7",
|
|
1116
|
+
padding: "12px",
|
|
1117
|
+
borderRadius: "8px",
|
|
1118
|
+
marginBottom: "16px",
|
|
1119
|
+
border: "1px solid #f59e0b",
|
|
1120
|
+
} },
|
|
1121
|
+
React.createElement("p", { style: {
|
|
1122
|
+
fontSize: "14px",
|
|
1123
|
+
color: "#92400e",
|
|
1124
|
+
margin: "0",
|
|
1125
|
+
fontWeight: "500",
|
|
1126
|
+
} }, "\u26A0\uFE0F Recovery Required"),
|
|
1127
|
+
React.createElement("p", { style: {
|
|
1128
|
+
fontSize: "13px",
|
|
1129
|
+
color: "#a16207",
|
|
1130
|
+
margin: "4px 0 0 0",
|
|
1131
|
+
} }, "Enter the username and recovery code saved during signup to restore access on this device.")),
|
|
1132
|
+
React.createElement("div", { className: "shogun-form-group" },
|
|
1133
|
+
React.createElement("label", { htmlFor: "recoveryUsername" },
|
|
1134
|
+
React.createElement(UserIcon, null),
|
|
1135
|
+
React.createElement("span", null, "Username")),
|
|
1136
|
+
React.createElement("input", { type: "text", id: "recoveryUsername", value: formUsername, onChange: (e) => setFormUsername(e.target.value), disabled: loading, placeholder: "Enter your username", autoFocus: true })),
|
|
1137
|
+
React.createElement("div", { className: "shogun-form-group" },
|
|
1138
|
+
React.createElement("label", { htmlFor: "recoverySeed" },
|
|
1139
|
+
React.createElement(KeyIcon, null),
|
|
1140
|
+
React.createElement("span", null, "Recovery Code")),
|
|
1141
|
+
React.createElement("textarea", { id: "recoverySeed", value: webauthnRecoverySeed, onChange: (e) => setWebauthnRecoverySeed(e.target.value), disabled: loading, placeholder: "Enter your WebAuthn seed phrase...", rows: 4, style: {
|
|
1142
|
+
fontFamily: "monospace",
|
|
1143
|
+
fontSize: "12px",
|
|
1144
|
+
width: "100%",
|
|
1145
|
+
padding: "8px",
|
|
1146
|
+
border: "1px solid #f59e0b",
|
|
1147
|
+
borderRadius: "4px",
|
|
1148
|
+
backgroundColor: "#fffbeb",
|
|
1149
|
+
} })),
|
|
1150
|
+
React.createElement("button", { type: "button", className: "shogun-submit-button", onClick: handleWebauthnImport, disabled: loading }, loading ? "Restoring..." : "Restore Account"),
|
|
1151
|
+
React.createElement("div", { className: "shogun-form-footer" },
|
|
1152
|
+
React.createElement("button", { type: "button", className: "shogun-back-button", onClick: () => {
|
|
1153
|
+
setError("");
|
|
1154
|
+
setAuthView("webauthn-username");
|
|
1155
|
+
}, disabled: loading }, "\u2190 Back to WebAuthn"))));
|
|
1067
1156
|
const renderRecoveryForm = () => (React.createElement("div", { className: "shogun-auth-form" },
|
|
1068
1157
|
React.createElement("div", { className: "shogun-form-group" },
|
|
1069
1158
|
React.createElement("label", { htmlFor: "username" },
|
|
@@ -1176,8 +1265,8 @@ export const ShogunButton = (() => {
|
|
|
1176
1265
|
React.createElement("button", { type: "button", className: "shogun-submit-button", onClick: handleZkProofLogin, disabled: loading || !zkTrapdoor.trim() }, loading ? "Processing..." : "Login Anonymously"),
|
|
1177
1266
|
React.createElement("div", { className: "shogun-form-footer" },
|
|
1178
1267
|
React.createElement("button", { className: "shogun-toggle-mode", onClick: () => setAuthView("options"), disabled: loading }, "Back to Login Options"))));
|
|
1179
|
-
const
|
|
1180
|
-
React.createElement("h3", null, "
|
|
1268
|
+
const renderZkProofSignupResult = () => (React.createElement("div", { className: "shogun-auth-form" },
|
|
1269
|
+
React.createElement("h3", null, "ZK-Proof Account Created!"),
|
|
1181
1270
|
React.createElement("div", { style: {
|
|
1182
1271
|
backgroundColor: "#fef3c7",
|
|
1183
1272
|
padding: "12px",
|
|
@@ -1190,11 +1279,11 @@ export const ShogunButton = (() => {
|
|
|
1190
1279
|
color: "#92400e",
|
|
1191
1280
|
margin: "0",
|
|
1192
1281
|
fontWeight: "500",
|
|
1193
|
-
} }, "\u26A0\uFE0F Important: Save Your
|
|
1194
|
-
React.createElement("p", { style: { fontSize: "13px", color: "#a16207", margin: "4px 0 0 0" } }, "This
|
|
1282
|
+
} }, "\u26A0\uFE0F Important: Save Your Trapdoor"),
|
|
1283
|
+
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.")),
|
|
1195
1284
|
React.createElement("div", { className: "shogun-form-group" },
|
|
1196
|
-
React.createElement("label", null, "Your
|
|
1197
|
-
React.createElement("textarea", { value:
|
|
1285
|
+
React.createElement("label", null, "Your Trapdoor (Recovery Phrase):"),
|
|
1286
|
+
React.createElement("textarea", { value: zkSignupTrapdoor, readOnly: true, rows: 4, style: {
|
|
1198
1287
|
fontFamily: "monospace",
|
|
1199
1288
|
fontSize: "12px",
|
|
1200
1289
|
width: "100%",
|
|
@@ -1204,26 +1293,29 @@ export const ShogunButton = (() => {
|
|
|
1204
1293
|
backgroundColor: "#fffbeb",
|
|
1205
1294
|
} }),
|
|
1206
1295
|
React.createElement("button", { type: "button", className: "shogun-submit-button", style: { marginTop: "8px" }, onClick: async () => {
|
|
1207
|
-
if (
|
|
1208
|
-
|
|
1209
|
-
setShowCopySuccess(true);
|
|
1210
|
-
setTimeout(() => setShowCopySuccess(false), 3000);
|
|
1296
|
+
if (!zkSignupTrapdoor) {
|
|
1297
|
+
return;
|
|
1211
1298
|
}
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1299
|
+
try {
|
|
1300
|
+
if (navigator.clipboard) {
|
|
1301
|
+
await navigator.clipboard.writeText(zkSignupTrapdoor);
|
|
1302
|
+
setShowZkTrapdoorCopySuccess(true);
|
|
1303
|
+
setTimeout(() => setShowZkTrapdoorCopySuccess(false), 3000);
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
catch (copyError) {
|
|
1307
|
+
console.warn("Failed to copy trapdoor:", copyError);
|
|
1308
|
+
}
|
|
1309
|
+
}, disabled: !zkSignupTrapdoor }, "Copy Trapdoor"),
|
|
1310
|
+
showZkTrapdoorCopySuccess && (React.createElement("p", { style: {
|
|
1311
|
+
color: "#047857",
|
|
1312
|
+
fontSize: "12px",
|
|
1313
|
+
marginTop: "6px",
|
|
1314
|
+
} }, "Trapdoor copied to clipboard!"))),
|
|
1315
|
+
React.createElement("div", { className: "shogun-form-footer" },
|
|
1316
|
+
React.createElement("button", { type: "button", className: "shogun-submit-button", onClick: finalizeZkProofSignup }, "I Saved My Trapdoor"))));
|
|
1317
|
+
const renderWebauthnSignupResult = () => (React.createElement("div", { className: "shogun-auth-form" },
|
|
1318
|
+
React.createElement("h3", null, "WebAuthn Account Created!"),
|
|
1227
1319
|
React.createElement("div", { style: {
|
|
1228
1320
|
backgroundColor: "#fef3c7",
|
|
1229
1321
|
padding: "12px",
|
|
@@ -1236,11 +1328,11 @@ export const ShogunButton = (() => {
|
|
|
1236
1328
|
color: "#92400e",
|
|
1237
1329
|
margin: "0",
|
|
1238
1330
|
fontWeight: "500",
|
|
1239
|
-
} }, "\u26A0\uFE0F
|
|
1240
|
-
React.createElement("p", { style: { fontSize: "13px", color: "#a16207", margin: "4px 0 0 0" } }, "This
|
|
1331
|
+
} }, "\u26A0\uFE0F Important: Save Your Recovery Code"),
|
|
1332
|
+
React.createElement("p", { style: { fontSize: "13px", color: "#a16207", margin: "4px 0 0 0" } }, "This seed phrase lets you add new devices or recover your WebAuthn account. Keep it private and store it securely.")),
|
|
1241
1333
|
React.createElement("div", { className: "shogun-form-group" },
|
|
1242
|
-
React.createElement("label", null, "Your
|
|
1243
|
-
React.createElement("textarea", { value:
|
|
1334
|
+
React.createElement("label", null, "Your WebAuthn Recovery Code (Seed Phrase):"),
|
|
1335
|
+
React.createElement("textarea", { value: webauthnSeedPhrase, readOnly: true, rows: 4, style: {
|
|
1244
1336
|
fontFamily: "monospace",
|
|
1245
1337
|
fontSize: "12px",
|
|
1246
1338
|
width: "100%",
|
|
@@ -1250,13 +1342,13 @@ export const ShogunButton = (() => {
|
|
|
1250
1342
|
backgroundColor: "#fffbeb",
|
|
1251
1343
|
} }),
|
|
1252
1344
|
React.createElement("button", { type: "button", className: "shogun-submit-button", style: { marginTop: "8px" }, onClick: async () => {
|
|
1253
|
-
if (navigator.clipboard) {
|
|
1254
|
-
await navigator.clipboard.writeText(
|
|
1345
|
+
if (navigator.clipboard && webauthnSeedPhrase) {
|
|
1346
|
+
await navigator.clipboard.writeText(webauthnSeedPhrase);
|
|
1255
1347
|
setShowCopySuccess(true);
|
|
1256
1348
|
setTimeout(() => setShowCopySuccess(false), 3000);
|
|
1257
1349
|
}
|
|
1258
|
-
} }, showCopySuccess ? "β
Copied!" : "π Copy
|
|
1259
|
-
!navigator.clipboard && (React.createElement("p", { style: { fontSize: "12px", color: "#666", marginTop: "8px" } }, "\u26A0\uFE0F Please manually copy the
|
|
1350
|
+
}, disabled: !webauthnSeedPhrase }, showCopySuccess ? "β
Copied!" : "π Copy Recovery Code"),
|
|
1351
|
+
!navigator.clipboard && (React.createElement("p", { style: { fontSize: "12px", color: "#666", marginTop: "8px" } }, "\u26A0\uFE0F Please manually copy the code above for safekeeping."))),
|
|
1260
1352
|
React.createElement("div", { style: {
|
|
1261
1353
|
backgroundColor: "#dcfce7",
|
|
1262
1354
|
color: "#166534",
|
|
@@ -1266,7 +1358,7 @@ export const ShogunButton = (() => {
|
|
|
1266
1358
|
fontSize: "14px",
|
|
1267
1359
|
border: "1px solid #22c55e",
|
|
1268
1360
|
textAlign: "center",
|
|
1269
|
-
} }, "\u2705 You're now logged in
|
|
1361
|
+
} }, "\u2705 You're now logged in with WebAuthn!"),
|
|
1270
1362
|
React.createElement("button", { type: "button", className: "shogun-submit-button", style: { marginTop: "16px" }, onClick: finalizeZkProofSignup }, "Close and Start Using App")));
|
|
1271
1363
|
const renderImportForm = () => (React.createElement("div", { className: "shogun-auth-form" },
|
|
1272
1364
|
React.createElement("h3", null, "Import Gun Pair"),
|
|
@@ -1327,13 +1419,7 @@ export const ShogunButton = (() => {
|
|
|
1327
1419
|
React.createElement("button", { className: "shogun-connect-button", onClick: openModal },
|
|
1328
1420
|
React.createElement(WalletIcon, null),
|
|
1329
1421
|
React.createElement("span", null, "Login / Sign Up")),
|
|
1330
|
-
modalIsOpen && (React.createElement("div", { className: "shogun-modal-overlay", onClick:
|
|
1331
|
-
if (pendingZkConfirmation || hasPendingSignup) {
|
|
1332
|
-
setError("Please copy your trapdoor and press Continue before closing.");
|
|
1333
|
-
return;
|
|
1334
|
-
}
|
|
1335
|
-
closeModal();
|
|
1336
|
-
} },
|
|
1422
|
+
modalIsOpen && (React.createElement("div", { className: "shogun-modal-overlay", onClick: closeModal },
|
|
1337
1423
|
React.createElement("div", { className: "shogun-modal", onClick: (e) => e.stopPropagation() },
|
|
1338
1424
|
React.createElement("div", { className: "shogun-modal-header" },
|
|
1339
1425
|
React.createElement("h2", null, authView === "recover"
|
|
@@ -1348,12 +1434,10 @@ export const ShogunButton = (() => {
|
|
|
1348
1434
|
? "WebAuthn"
|
|
1349
1435
|
: authView === "zkproof-login"
|
|
1350
1436
|
? "ZK-Proof Login"
|
|
1351
|
-
:
|
|
1352
|
-
? "
|
|
1353
|
-
:
|
|
1354
|
-
|
|
1355
|
-
: "Sign Up"),
|
|
1356
|
-
React.createElement("button", { className: "shogun-close-button", onClick: closeModal, "aria-label": "Close", disabled: pendingZkConfirmation || hasPendingSignup },
|
|
1437
|
+
: formMode === "login"
|
|
1438
|
+
? "Login"
|
|
1439
|
+
: "Sign Up"),
|
|
1440
|
+
React.createElement("button", { className: "shogun-close-button", onClick: closeModal, "aria-label": "Close" },
|
|
1357
1441
|
React.createElement(CloseIcon, null))),
|
|
1358
1442
|
React.createElement("div", { className: "shogun-modal-content" },
|
|
1359
1443
|
error && React.createElement("div", { className: "shogun-error-message" }, error),
|
|
@@ -1372,6 +1456,8 @@ export const ShogunButton = (() => {
|
|
|
1372
1456
|
authView === "import" && renderImportForm(),
|
|
1373
1457
|
authView === "webauthn-username" &&
|
|
1374
1458
|
renderWebAuthnUsernameForm(),
|
|
1459
|
+
authView === "webauthn-recovery" &&
|
|
1460
|
+
renderWebauthnRecoveryForm(),
|
|
1375
1461
|
authView === "webauthn-signup-result" &&
|
|
1376
1462
|
renderWebauthnSignupResult(),
|
|
1377
1463
|
authView === "zkproof-login" && renderZkProofLoginForm(),
|