shogun-button-react 6.3.3 → 6.3.6

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.
@@ -21,6 +21,8 @@ type ShogunContextType = {
21
21
  put: (path: string, data: any) => Promise<void>;
22
22
  get: (path: string) => any;
23
23
  remove: (path: string) => Promise<void>;
24
+ completePendingSignup: () => void;
25
+ hasPendingSignup: boolean;
24
26
  };
25
27
  export declare const useShogun: () => ShogunContextType;
26
28
  type ShogunButtonProviderProps = {
@@ -25,6 +25,8 @@ const defaultShogunContext = {
25
25
  put: async () => { },
26
26
  get: () => null,
27
27
  remove: async () => { },
28
+ completePendingSignup: () => { },
29
+ hasPendingSignup: false,
28
30
  };
29
31
  // Create context using React's createContext directly
30
32
  const ShogunContext = createContext(defaultShogunContext);
@@ -36,6 +38,7 @@ export function ShogunButtonProvider({ children, core, options, onLoginSuccess,
36
38
  const [isLoggedIn, setIsLoggedIn] = useState(false);
37
39
  const [userPub, setUserPub] = useState(null);
38
40
  const [username, setUsername] = useState(null);
41
+ const [pendingSignupData, setPendingSignupData] = useState(null);
39
42
  // Effetto per gestire l'inizializzazione e pulizia
40
43
  useEffect(() => {
41
44
  var _a, _b;
@@ -324,12 +327,18 @@ export function ShogunButtonProvider({ children, core, options, onLoginSuccess,
324
327
  setIsLoggedIn(true);
325
328
  setUserPub(userPub);
326
329
  setUsername(displayName);
327
- onSignupSuccess === null || onSignupSuccess === void 0 ? void 0 : onSignupSuccess({
330
+ const signupPayload = {
328
331
  userPub: userPub,
329
332
  username: displayName,
330
- seedPhrase: result.seedPhrase, // Include seedPhrase/trapdoor for ZK-Proof
333
+ seedPhrase: result.seedPhrase,
331
334
  authMethod: authMethod,
332
- });
335
+ };
336
+ if (authMethod === "zkproof" && onSignupSuccess) {
337
+ setPendingSignupData(signupPayload);
338
+ }
339
+ else {
340
+ onSignupSuccess === null || onSignupSuccess === void 0 ? void 0 : onSignupSuccess(signupPayload);
341
+ }
333
342
  }
334
343
  else {
335
344
  onError === null || onError === void 0 ? void 0 : onError(result.error);
@@ -349,6 +358,7 @@ export function ShogunButtonProvider({ children, core, options, onLoginSuccess,
349
358
  setIsLoggedIn(false);
350
359
  setUserPub(null);
351
360
  setUsername(null);
361
+ setPendingSignupData(null);
352
362
  };
353
363
  // Implementazione del metodo setProvider
354
364
  const setProvider = (provider) => {
@@ -462,6 +472,13 @@ export function ShogunButtonProvider({ children, core, options, onLoginSuccess,
462
472
  const gunPlugin = null;
463
473
  // Plugin hooks removed - GunAdvancedPlugin no longer available
464
474
  const pluginHooks = {};
475
+ const completePendingSignup = React.useCallback(() => {
476
+ if (pendingSignupData) {
477
+ const dataToEmit = pendingSignupData;
478
+ setPendingSignupData(null);
479
+ onSignupSuccess === null || onSignupSuccess === void 0 ? void 0 : onSignupSuccess(dataToEmit);
480
+ }
481
+ }, [pendingSignupData, onSignupSuccess]);
465
482
  // Create a properly typed context value
466
483
  const contextValue = React.useMemo(() => ({
467
484
  core,
@@ -479,6 +496,8 @@ export function ShogunButtonProvider({ children, core, options, onLoginSuccess,
479
496
  importGunPair,
480
497
  setProvider,
481
498
  gunPlugin,
499
+ completePendingSignup,
500
+ hasPendingSignup: Boolean(pendingSignupData),
482
501
  put: async (path, data) => {
483
502
  if (isShogunCore(core)) {
484
503
  if (!core.gun)
@@ -537,6 +556,8 @@ export function ShogunButtonProvider({ children, core, options, onLoginSuccess,
537
556
  importGunPair,
538
557
  gunPlugin,
539
558
  pluginHooks,
559
+ pendingSignupData,
560
+ completePendingSignup,
540
561
  ]);
541
562
  // Provide the context value to children
542
563
  return (React.createElement(ShogunContext.Provider, { value: contextValue }, children));
@@ -586,7 +607,7 @@ const ExportIcon = () => (React.createElement("svg", { xmlns: "http://www.w3.org
586
607
  // Component for Shogun login button
587
608
  export const ShogunButton = (() => {
588
609
  const Button = () => {
589
- const { isLoggedIn, username, logout, login, signUp, core, options, exportGunPair, importGunPair, hasPlugin, } = useShogun();
610
+ const { isLoggedIn, username, logout, login, signUp, core, options, exportGunPair, importGunPair, hasPlugin, completePendingSignup, hasPendingSignup, } = useShogun();
590
611
  // Form states
591
612
  const [modalIsOpen, setModalIsOpen] = useState(false);
592
613
  const [formUsername, setFormUsername] = useState("");
@@ -609,7 +630,9 @@ export const ShogunButton = (() => {
609
630
  const [showImportSuccess, setShowImportSuccess] = useState(false);
610
631
  const [zkTrapdoor, setZkTrapdoor] = useState("");
611
632
  const [zkGeneratedTrapdoor, setZkGeneratedTrapdoor] = useState("");
633
+ const [webauthnSeedPhrase, setWebauthnSeedPhrase] = useState("");
612
634
  const dropdownRef = useRef(null);
635
+ const [pendingZkConfirmation, setPendingZkConfirmation] = useState(false);
613
636
  // Handle click outside to close dropdown
614
637
  useEffect(() => {
615
638
  const handleClickOutside = (event) => {
@@ -670,7 +693,19 @@ export const ShogunButton = (() => {
670
693
  window.location.href = result.redirectUrl;
671
694
  }
672
695
  else {
673
- setModalIsOpen(false);
696
+ const shouldShowWebauthnSeed = formMode === "signup" &&
697
+ method === "webauthn" &&
698
+ result &&
699
+ result.success &&
700
+ result.seedPhrase;
701
+ if (shouldShowWebauthnSeed) {
702
+ setWebauthnSeedPhrase(result.seedPhrase);
703
+ setShowCopySuccess(false);
704
+ setAuthView("webauthn-signup-result");
705
+ }
706
+ else {
707
+ setModalIsOpen(false);
708
+ }
674
709
  }
675
710
  }
676
711
  catch (e) {
@@ -772,6 +807,7 @@ export const ShogunButton = (() => {
772
807
  // Show the trapdoor to the user - CRITICAL for account recovery!
773
808
  setZkGeneratedTrapdoor(result.seedPhrase);
774
809
  setAuthView("zkproof-signup-result");
810
+ setPendingZkConfirmation(true);
775
811
  }
776
812
  else if (result && !result.success) {
777
813
  throw new Error(result.error || "ZK-Proof signup failed");
@@ -895,6 +931,8 @@ export const ShogunButton = (() => {
895
931
  setRecoveredHint("");
896
932
  setZkTrapdoor("");
897
933
  setZkGeneratedTrapdoor("");
934
+ setWebauthnSeedPhrase("");
935
+ setPendingZkConfirmation(false);
898
936
  };
899
937
  const openModal = () => {
900
938
  resetForm();
@@ -902,6 +940,17 @@ export const ShogunButton = (() => {
902
940
  setModalIsOpen(true);
903
941
  };
904
942
  const closeModal = () => {
943
+ if (pendingZkConfirmation || hasPendingSignup) {
944
+ setError("Please save your trapdoor and confirm before leaving this screen.");
945
+ return;
946
+ }
947
+ setModalIsOpen(false);
948
+ };
949
+ const finalizeZkProofSignup = () => {
950
+ completePendingSignup();
951
+ setError("");
952
+ setPendingZkConfirmation(false);
953
+ setAuthView("options");
905
954
  setModalIsOpen(false);
906
955
  };
907
956
  const toggleMode = () => {
@@ -1127,6 +1176,52 @@ export const ShogunButton = (() => {
1127
1176
  React.createElement("button", { type: "button", className: "shogun-submit-button", onClick: handleZkProofLogin, disabled: loading || !zkTrapdoor.trim() }, loading ? "Processing..." : "Login Anonymously"),
1128
1177
  React.createElement("div", { className: "shogun-form-footer" },
1129
1178
  React.createElement("button", { className: "shogun-toggle-mode", onClick: () => setAuthView("options"), disabled: loading }, "Back to Login Options"))));
1179
+ const renderWebauthnSignupResult = () => (React.createElement("div", { className: "shogun-auth-form" },
1180
+ React.createElement("h3", null, "WebAuthn Account Created!"),
1181
+ React.createElement("div", { style: {
1182
+ backgroundColor: "#fef3c7",
1183
+ padding: "12px",
1184
+ borderRadius: "8px",
1185
+ marginBottom: "16px",
1186
+ border: "1px solid #f59e0b",
1187
+ } },
1188
+ React.createElement("p", { style: {
1189
+ fontSize: "14px",
1190
+ color: "#92400e",
1191
+ margin: "0",
1192
+ fontWeight: "500",
1193
+ } }, "\u26A0\uFE0F Important: Save Your Recovery Code"),
1194
+ 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.")),
1195
+ React.createElement("div", { className: "shogun-form-group" },
1196
+ React.createElement("label", null, "Your WebAuthn Recovery Code (Seed Phrase):"),
1197
+ React.createElement("textarea", { value: webauthnSeedPhrase, readOnly: true, rows: 4, style: {
1198
+ fontFamily: "monospace",
1199
+ fontSize: "12px",
1200
+ width: "100%",
1201
+ padding: "8px",
1202
+ border: "2px solid #f59e0b",
1203
+ borderRadius: "4px",
1204
+ backgroundColor: "#fffbeb",
1205
+ } }),
1206
+ React.createElement("button", { type: "button", className: "shogun-submit-button", style: { marginTop: "8px" }, onClick: async () => {
1207
+ if (navigator.clipboard && webauthnSeedPhrase) {
1208
+ await navigator.clipboard.writeText(webauthnSeedPhrase);
1209
+ setShowCopySuccess(true);
1210
+ setTimeout(() => setShowCopySuccess(false), 3000);
1211
+ }
1212
+ }, disabled: !webauthnSeedPhrase }, showCopySuccess ? "✅ Copied!" : "📋 Copy Recovery Code"),
1213
+ !navigator.clipboard && (React.createElement("p", { style: { fontSize: "12px", color: "#666", marginTop: "8px" } }, "\u26A0\uFE0F Please manually copy the code above for safekeeping."))),
1214
+ React.createElement("div", { style: {
1215
+ backgroundColor: "#dcfce7",
1216
+ color: "#166534",
1217
+ padding: "12px",
1218
+ borderRadius: "8px",
1219
+ marginTop: "16px",
1220
+ fontSize: "14px",
1221
+ border: "1px solid #22c55e",
1222
+ textAlign: "center",
1223
+ } }, "\u2705 You're now logged in with WebAuthn!"),
1224
+ React.createElement("button", { type: "button", className: "shogun-submit-button", style: { marginTop: "16px" }, onClick: finalizeZkProofSignup }, "Close and Start Using App")));
1130
1225
  const renderZkProofSignupResult = () => (React.createElement("div", { className: "shogun-auth-form" },
1131
1226
  React.createElement("h3", null, "ZK-Proof Account Created!"),
1132
1227
  React.createElement("div", { style: {
@@ -1172,7 +1267,7 @@ export const ShogunButton = (() => {
1172
1267
  border: "1px solid #22c55e",
1173
1268
  textAlign: "center",
1174
1269
  } }, "\u2705 You're now logged in anonymously!"),
1175
- React.createElement("button", { type: "button", className: "shogun-submit-button", style: { marginTop: "16px" }, onClick: () => setModalIsOpen(false) }, "Close and Start Using App")));
1270
+ React.createElement("button", { type: "button", className: "shogun-submit-button", style: { marginTop: "16px" }, onClick: finalizeZkProofSignup }, "Close and Start Using App")));
1176
1271
  const renderImportForm = () => (React.createElement("div", { className: "shogun-auth-form" },
1177
1272
  React.createElement("h3", null, "Import Gun Pair"),
1178
1273
  React.createElement("div", { style: {
@@ -1232,7 +1327,13 @@ export const ShogunButton = (() => {
1232
1327
  React.createElement("button", { className: "shogun-connect-button", onClick: openModal },
1233
1328
  React.createElement(WalletIcon, null),
1234
1329
  React.createElement("span", null, "Login / Sign Up")),
1235
- modalIsOpen && (React.createElement("div", { className: "shogun-modal-overlay", onClick: closeModal },
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
+ } },
1236
1337
  React.createElement("div", { className: "shogun-modal", onClick: (e) => e.stopPropagation() },
1237
1338
  React.createElement("div", { className: "shogun-modal-header" },
1238
1339
  React.createElement("h2", null, authView === "recover"
@@ -1252,7 +1353,7 @@ export const ShogunButton = (() => {
1252
1353
  : formMode === "login"
1253
1354
  ? "Login"
1254
1355
  : "Sign Up"),
1255
- React.createElement("button", { className: "shogun-close-button", onClick: closeModal, "aria-label": "Close" },
1356
+ React.createElement("button", { className: "shogun-close-button", onClick: closeModal, "aria-label": "Close", disabled: pendingZkConfirmation || hasPendingSignup },
1256
1357
  React.createElement(CloseIcon, null))),
1257
1358
  React.createElement("div", { className: "shogun-modal-content" },
1258
1359
  error && React.createElement("div", { className: "shogun-error-message" }, error),
@@ -1271,6 +1372,8 @@ export const ShogunButton = (() => {
1271
1372
  authView === "import" && renderImportForm(),
1272
1373
  authView === "webauthn-username" &&
1273
1374
  renderWebAuthnUsernameForm(),
1375
+ authView === "webauthn-signup-result" &&
1376
+ renderWebauthnSignupResult(),
1274
1377
  authView === "zkproof-login" && renderZkProofLoginForm(),
1275
1378
  authView === "zkproof-signup-result" &&
1276
1379
  renderZkProofSignupResult()))))));