shogun-core 5.2.2 → 5.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -149954,7 +149954,7 @@ class DataBase {
149954
149954
  this.node = this.gun.get(appScope);
149955
149955
  console.log("[DB] App scope node initialized");
149956
149956
  // Initialize CryptoIdentityManager
149957
- this._cryptoIdentityManager = new CryptoIdentityManager_1.CryptoIdentityManager(this.core);
149957
+ this._cryptoIdentityManager = new CryptoIdentityManager_1.CryptoIdentityManager(this.core, this);
149958
149958
  console.log("[DB] CryptoIdentityManager initialized");
149959
149959
  if (sessionResult.success) {
149960
149960
  console.log("[DB] Session automatically restored");
@@ -150403,6 +150403,10 @@ class DataBase {
150403
150403
  // Log out user
150404
150404
  try {
150405
150405
  currentUser.leave();
150406
+ // Force clear any pending authentication
150407
+ if (currentUser._ && currentUser._.sea) {
150408
+ currentUser._.sea = null;
150409
+ }
150406
150410
  }
150407
150411
  catch (gunError) {
150408
150412
  console.error("Error during Gun logout:", gunError);
@@ -150541,6 +150545,8 @@ class DataBase {
150541
150545
  this.gun.user().create(normalizedUsername, password, (ack) => {
150542
150546
  if (ack.err) {
150543
150547
  console.error(`User creation error: ${ack.err}`);
150548
+ // Reset auth state after failed creation to prevent blocking future operations
150549
+ this.resetAuthState();
150544
150550
  resolve({ success: false, error: ack.err });
150545
150551
  }
150546
150552
  else {
@@ -150593,6 +150599,8 @@ class DataBase {
150593
150599
  this.gun.user().auth(pair, (ack) => {
150594
150600
  if (ack.err) {
150595
150601
  console.error(`Authentication after creation failed: ${ack.err}`);
150602
+ // Reset auth state on error to prevent blocking future operations
150603
+ this.resetAuthState();
150596
150604
  resolve({ success: false, error: ack.err });
150597
150605
  }
150598
150606
  else {
@@ -150618,6 +150626,8 @@ class DataBase {
150618
150626
  this.gun.user().auth(normalizedUsername, password, (ack) => {
150619
150627
  if (ack.err) {
150620
150628
  console.error(`Authentication after creation failed: ${ack.err}`);
150629
+ // Reset auth state on error to prevent blocking future operations
150630
+ this.resetAuthState();
150621
150631
  resolve({ success: false, error: ack.err });
150622
150632
  }
150623
150633
  else {
@@ -150648,13 +150658,33 @@ class DataBase {
150648
150658
  * @param pair Optional SEA pair for Web3 login
150649
150659
  * @returns Promise resolving to signup result
150650
150660
  */
150651
- async signUp(username, password, pair) {
150661
+ async signUp(username, password, pair, retryCount = 0, maxRetries = 3) {
150652
150662
  try {
150653
150663
  // Validate credentials with enhanced security
150654
150664
  const validation = this.validateSignupCredentials(username, password, pair);
150655
150665
  if (!validation.valid) {
150656
150666
  return { success: false, error: validation.error };
150657
150667
  }
150668
+ // Check if authentication is in progress and retry if needed
150669
+ if (this.isAuthInProgress()) {
150670
+ if (retryCount < maxRetries) {
150671
+ console.warn(`Authentication in progress during signup, retrying... (${retryCount + 1}/${maxRetries})`);
150672
+ this.resetAuthState();
150673
+ const baseDelay = 100 * Math.pow(2, retryCount);
150674
+ const jitter = Math.random() * 100;
150675
+ const delay = Math.min(baseDelay + jitter, 2000);
150676
+ await new Promise((resolve) => setTimeout(resolve, delay));
150677
+ return this.signUp(username, password, pair, retryCount + 1, maxRetries);
150678
+ }
150679
+ else {
150680
+ console.error("Max retries exceeded for signup due to concurrent operations");
150681
+ this.resetAuthState();
150682
+ return {
150683
+ success: false,
150684
+ error: "Signup failed after multiple retries due to concurrent operations",
150685
+ };
150686
+ }
150687
+ }
150658
150688
  let createResult;
150659
150689
  if (pair) {
150660
150690
  // For Web3/plugin authentication, use pair-based creation
@@ -150665,6 +150695,8 @@ class DataBase {
150665
150695
  createResult = await this.createNewUser(username, password);
150666
150696
  }
150667
150697
  if (!createResult.success) {
150698
+ // Reset auth state after failed creation to prevent blocking future operations
150699
+ this.resetAuthState();
150668
150700
  return { success: false, error: createResult.error };
150669
150701
  }
150670
150702
  // Add a small delay to ensure user is properly registered
@@ -151279,33 +151311,134 @@ class DataBase {
151279
151311
  }
151280
151312
  }
151281
151313
  /**
151282
- * Performs authentication with Gun
151314
+ * Resets Gun.js authentication state to allow new auth operations
151283
151315
  */
151284
- async performAuthentication(username, password, pair) {
151316
+ resetAuthState() {
151317
+ try {
151318
+ const currentUser = this.gun.user();
151319
+ if (currentUser && currentUser._) {
151320
+ // Reset the authentication flag
151321
+ if (currentUser._.sea) {
151322
+ currentUser._.sea = null;
151323
+ }
151324
+ // Reset the ing flag that prevents concurrent operations
151325
+ if (currentUser._.ing) {
151326
+ currentUser._.ing = false;
151327
+ }
151328
+ // Force clear any pending authentication callbacks
151329
+ if (currentUser._.auth) {
151330
+ currentUser._.auth = null;
151331
+ }
151332
+ // Clear any pending operations
151333
+ if (currentUser._.act) {
151334
+ currentUser._.act = null;
151335
+ }
151336
+ // Clear any pending callbacks
151337
+ if (currentUser._.cb) {
151338
+ currentUser._.cb = null;
151339
+ }
151340
+ // Clear any pending retries
151341
+ if (currentUser._.retries) {
151342
+ currentUser._.retries = 0;
151343
+ }
151344
+ // Clear any pending timeouts
151345
+ if (currentUser._.timeout) {
151346
+ clearTimeout(currentUser._.timeout);
151347
+ currentUser._.timeout = null;
151348
+ }
151349
+ }
151350
+ // Also try to call leave() to ensure clean state
151351
+ try {
151352
+ currentUser.leave();
151353
+ }
151354
+ catch (leaveError) {
151355
+ // Ignore leave errors, just trying to clean up
151356
+ }
151357
+ // Force clear the user reference to ensure clean state
151358
+ this.user = null;
151359
+ console.log("Auth state reset completed");
151360
+ }
151361
+ catch (error) {
151362
+ console.warn("Error resetting auth state:", error);
151363
+ }
151364
+ }
151365
+ /**
151366
+ * Performs authentication with Gun with retry mechanism
151367
+ */
151368
+ async performAuthentication(username, password, pair, retryCount = 0, maxRetries = 3) {
151285
151369
  return new Promise((resolve) => {
151286
- if (pair) {
151287
- this.gun.user().auth(pair, (ack) => {
151288
- if (ack.err) {
151289
- console.error(`Login error for ${username}: ${ack.err}`);
151290
- resolve({ success: false, error: ack.err });
151291
- }
151292
- else {
151293
- resolve({ success: true, ack });
151370
+ // Check if there's already an authentication operation in progress
151371
+ const currentUser = this.gun.user();
151372
+ if (currentUser && currentUser._ && currentUser._.ing) {
151373
+ if (retryCount < maxRetries) {
151374
+ console.warn(`Authentication already in progress, retrying... (${retryCount + 1}/${maxRetries})`);
151375
+ this.resetAuthState();
151376
+ // For the first retry, try to create a fresh authentication context
151377
+ if (retryCount === 0) {
151378
+ this.createFreshAuthContext();
151294
151379
  }
151380
+ // Add exponential backoff delay with jitter
151381
+ const baseDelay = 200 * Math.pow(2, retryCount);
151382
+ const jitter = Math.random() * 200;
151383
+ const delay = Math.min(baseDelay + jitter, 3000);
151384
+ setTimeout(() => {
151385
+ this.performAuthentication(username, password, pair, retryCount + 1, maxRetries)
151386
+ .then(resolve)
151387
+ .catch((error) => resolve({ success: false, error: String(error) }));
151388
+ }, delay);
151389
+ return;
151390
+ }
151391
+ else {
151392
+ console.error("Max retries exceeded for authentication");
151393
+ this.resetAuthState();
151394
+ resolve({
151395
+ success: false,
151396
+ error: "Authentication failed after multiple retries",
151397
+ });
151398
+ return;
151399
+ }
151400
+ }
151401
+ this.performAuthenticationInternal(username, password, pair, resolve);
151402
+ });
151403
+ }
151404
+ /**
151405
+ * Internal authentication method with timeout
151406
+ */
151407
+ performAuthenticationInternal(username, password, pair, resolve) {
151408
+ let resolved = false;
151409
+ const timeout = 15000; // 15 second timeout for individual auth attempts
151410
+ const timeoutId = setTimeout(() => {
151411
+ if (!resolved) {
151412
+ resolved = true;
151413
+ console.error(`Authentication timeout for ${username} after ${timeout}ms`);
151414
+ this.resetAuthState();
151415
+ resolve({
151416
+ success: false,
151417
+ error: `Authentication timeout after ${timeout}ms`,
151295
151418
  });
151296
151419
  }
151420
+ }, timeout);
151421
+ const authCallback = (ack) => {
151422
+ if (resolved)
151423
+ return;
151424
+ resolved = true;
151425
+ clearTimeout(timeoutId);
151426
+ if (ack.err) {
151427
+ console.error(`Login error for ${username}: ${ack.err}`);
151428
+ // Reset auth state on error to prevent blocking future attempts
151429
+ this.resetAuthState();
151430
+ resolve({ success: false, error: ack.err });
151431
+ }
151297
151432
  else {
151298
- this.gun.user().auth(username, password, (ack) => {
151299
- if (ack.err) {
151300
- console.error(`Login error for ${username}: ${ack.err}`);
151301
- resolve({ success: false, error: ack.err });
151302
- }
151303
- else {
151304
- resolve({ success: true, ack });
151305
- }
151306
- });
151433
+ resolve({ success: true, ack });
151307
151434
  }
151308
- });
151435
+ };
151436
+ if (pair) {
151437
+ this.gun.user().auth(pair, authCallback);
151438
+ }
151439
+ else {
151440
+ this.gun.user().auth(username, password, authCallback);
151441
+ }
151309
151442
  }
151310
151443
  /**
151311
151444
  * Builds login result object
@@ -151339,9 +151472,28 @@ class DataBase {
151339
151472
  try {
151340
151473
  const loginResult = await this.performAuthentication(username, password, pair);
151341
151474
  if (!loginResult.success) {
151475
+ // Provide more specific error messages based on the error type
151476
+ let errorMessage = `User '${username}' not found. Please check your username or register first.`;
151477
+ if (loginResult.error) {
151478
+ if (loginResult.error.includes("already being created or authenticated")) {
151479
+ errorMessage =
151480
+ "Authentication is already in progress. Please wait and try again.";
151481
+ }
151482
+ else if (loginResult.error.includes("Wrong user or password")) {
151483
+ errorMessage =
151484
+ "Invalid username or password. Please check your credentials.";
151485
+ }
151486
+ else if (loginResult.error.includes("User already created")) {
151487
+ errorMessage =
151488
+ "User already exists. Please try logging in instead.";
151489
+ }
151490
+ else {
151491
+ errorMessage = loginResult.error;
151492
+ }
151493
+ }
151342
151494
  return {
151343
151495
  success: false,
151344
- error: `User '${username}' not found. Please check your username or register first.`,
151496
+ error: errorMessage,
151345
151497
  };
151346
151498
  }
151347
151499
  // Add a small delay to ensure user state is properly set
@@ -151760,6 +151912,128 @@ class DataBase {
151760
151912
  isAuthenticated() {
151761
151913
  return this.user?.is?.pub ? true : false;
151762
151914
  }
151915
+ /**
151916
+ * Check if an authentication operation is currently in progress
151917
+ */
151918
+ isAuthInProgress() {
151919
+ try {
151920
+ const currentUser = this.gun.user();
151921
+ return !!(currentUser && currentUser._ && currentUser._.ing);
151922
+ }
151923
+ catch (error) {
151924
+ console.warn("Error checking auth progress:", error);
151925
+ return false;
151926
+ }
151927
+ }
151928
+ /**
151929
+ * Force reset authentication state (useful for debugging or recovery)
151930
+ */
151931
+ forceResetAuthState() {
151932
+ this.resetAuthState();
151933
+ }
151934
+ /**
151935
+ * Aggressive cleanup for problematic users
151936
+ * This method performs a complete reset of all authentication state
151937
+ */
151938
+ aggressiveAuthCleanup() {
151939
+ try {
151940
+ console.log("🧹 Performing aggressive auth cleanup...");
151941
+ // Reset all auth state
151942
+ this.resetAuthState();
151943
+ // Clear all Gun.js internal state
151944
+ const currentUser = this.gun.user();
151945
+ if (currentUser && currentUser._) {
151946
+ // Clear all possible internal flags
151947
+ const internalState = currentUser._;
151948
+ Object.keys(internalState).forEach((key) => {
151949
+ if (typeof internalState[key] === "boolean") {
151950
+ internalState[key] = false;
151951
+ }
151952
+ else if (typeof internalState[key] === "object" &&
151953
+ internalState[key] !== null) {
151954
+ if (key === "sea" ||
151955
+ key === "auth" ||
151956
+ key === "act" ||
151957
+ key === "cb") {
151958
+ internalState[key] = null;
151959
+ }
151960
+ }
151961
+ });
151962
+ }
151963
+ // Force logout
151964
+ try {
151965
+ currentUser.leave();
151966
+ }
151967
+ catch (error) {
151968
+ // Ignore errors
151969
+ }
151970
+ // Clear user reference
151971
+ this.user = null;
151972
+ // Clear all session storage
151973
+ if (typeof sessionStorage !== "undefined") {
151974
+ try {
151975
+ const keys = Object.keys(sessionStorage);
151976
+ keys.forEach((key) => {
151977
+ if (key.includes("gun") ||
151978
+ key.includes("user") ||
151979
+ key.includes("auth")) {
151980
+ sessionStorage.removeItem(key);
151981
+ }
151982
+ });
151983
+ }
151984
+ catch (error) {
151985
+ // Ignore errors
151986
+ }
151987
+ }
151988
+ // Clear all local storage
151989
+ if (typeof localStorage !== "undefined") {
151990
+ try {
151991
+ const keys = Object.keys(localStorage);
151992
+ keys.forEach((key) => {
151993
+ if (key.includes("gun") ||
151994
+ key.includes("user") ||
151995
+ key.includes("auth")) {
151996
+ localStorage.removeItem(key);
151997
+ }
151998
+ });
151999
+ }
152000
+ catch (error) {
152001
+ // Ignore errors
152002
+ }
152003
+ }
152004
+ console.log("✓ Aggressive auth cleanup completed");
152005
+ }
152006
+ catch (error) {
152007
+ console.error("Error during aggressive cleanup:", error);
152008
+ }
152009
+ }
152010
+ /**
152011
+ * Creates a completely fresh authentication context
152012
+ * This is a more aggressive approach when normal reset doesn't work
152013
+ */
152014
+ createFreshAuthContext() {
152015
+ try {
152016
+ // Reset all auth state
152017
+ this.resetAuthState();
152018
+ // Create a completely new user instance
152019
+ const freshUser = this.gun.user();
152020
+ this.user = freshUser;
152021
+ // Clear any cached authentication data
152022
+ if (typeof sessionStorage !== "undefined") {
152023
+ try {
152024
+ sessionStorage.removeItem("gunSessionData");
152025
+ sessionStorage.removeItem("gunUserData");
152026
+ }
152027
+ catch (error) {
152028
+ console.warn("Error clearing session storage:", error);
152029
+ }
152030
+ }
152031
+ console.log("Fresh authentication context created");
152032
+ }
152033
+ catch (error) {
152034
+ console.error("Error creating fresh auth context:", error);
152035
+ }
152036
+ }
151763
152037
  }
151764
152038
  exports.DataBase = DataBase;
151765
152039
  // Errors
@@ -153286,8 +153560,9 @@ const errorHandler_1 = __webpack_require__(/*! ../utils/errorHandler */ "./src/u
153286
153560
  * Genera automaticamente tutte le identità crypto disponibili dopo l'autenticazione SEA
153287
153561
  */
153288
153562
  class CryptoIdentityManager {
153289
- constructor(core) {
153563
+ constructor(core, db) {
153290
153564
  this.core = core;
153565
+ this.db = db;
153291
153566
  this.pgpManager = new pgp_1.PGPManager();
153292
153567
  this.mlsManager = new mls_1.MLSManager("default-user");
153293
153568
  this.sframeManager = new sframe_1.SFrameManager();
@@ -153409,7 +153684,7 @@ class CryptoIdentityManager {
153409
153684
  }
153410
153685
  // Salva su GunDB nel percorso privato dell'utente
153411
153686
  const saveResult = await new Promise((resolve, reject) => {
153412
- this.core.gun
153687
+ this.db.gun
153413
153688
  .user()
153414
153689
  .get("crypto-identities")
153415
153690
  .put(encryptedIdentities, (ack) => {
@@ -153429,7 +153704,7 @@ class CryptoIdentityManager {
153429
153704
  name: "SHA-256",
153430
153705
  });
153431
153706
  await new Promise((resolve, reject) => {
153432
- this.core.gun
153707
+ this.db.gun
153433
153708
  .user()
153434
153709
  .get("crypto-identities-hash")
153435
153710
  .put(identitiesHash, (ack) => {
@@ -153470,7 +153745,7 @@ class CryptoIdentityManager {
153470
153745
  console.log(`🔍 [CryptoIdentityManager] Retrieving crypto identities for: ${username}`);
153471
153746
  // Recupera le identità criptate da GunDB
153472
153747
  const encryptedIdentities = await new Promise((resolve, reject) => {
153473
- this.core.gun
153748
+ this.db.gun
153474
153749
  .user()
153475
153750
  .get("crypto-identities")
153476
153751
  .once((data) => {
@@ -153522,7 +153797,7 @@ class CryptoIdentityManager {
153522
153797
  async hasStoredIdentities(username) {
153523
153798
  try {
153524
153799
  const hasIdentities = await new Promise((resolve) => {
153525
- this.core.gun
153800
+ this.db.gun
153526
153801
  .user()
153527
153802
  .get("crypto-identities")
153528
153803
  .once((data) => {
@@ -153609,7 +153884,7 @@ class CryptoIdentityManager {
153609
153884
  };
153610
153885
  }
153611
153886
  // Ottieni il SEA pair dell'utente corrente
153612
- const userInstance = this.core.gun.user();
153887
+ const userInstance = this.db.gun.user();
153613
153888
  const seaPair = userInstance?._?.sea;
153614
153889
  if (!seaPair) {
153615
153890
  return {