shogun-core 5.2.2 → 6.0.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.
- package/README.md +123 -20
- package/dist/browser/shogun-core.js +1134 -493
- package/dist/browser/shogun-core.js.map +1 -1
- package/dist/config/simplified-config.js +108 -40
- package/dist/crypto/mls.js +34 -15
- package/dist/crypto/sframe.js +13 -11
- package/dist/examples/auth-test.js +263 -59
- package/dist/examples/crypto-identity-example.js +55 -21
- package/dist/examples/mls-3-member-test.js +97 -0
- package/dist/examples/mls-multi-member.js +153 -0
- package/dist/examples/mls-sframe-test.js +14 -11
- package/dist/examples/mls-simple-test.js +58 -0
- package/dist/examples/shogun-core-example.js +90 -0
- package/dist/examples/zkproof-credentials-example.js +9 -5
- package/dist/examples/zkproof-example.js +14 -10
- package/dist/gundb/api.js +17 -16
- package/dist/gundb/db.js +769 -328
- package/dist/index.js +4 -4
- package/dist/managers/CoreInitializer.js +21 -15
- package/dist/managers/CryptoIdentityManager.js +79 -32
- package/dist/plugins/zkproof/zkCredentials.js +4 -1
- package/dist/types/config/simplified-config.d.ts +64 -3
- package/dist/types/crypto/sframe.d.ts +4 -0
- package/dist/types/examples/mls-3-member-test.d.ts +6 -0
- package/dist/types/examples/mls-multi-member.d.ts +6 -0
- package/dist/types/examples/mls-simple-test.d.ts +6 -0
- package/dist/types/examples/shogun-core-example.d.ts +8 -0
- package/dist/types/gundb/api.d.ts +6 -13
- package/dist/types/gundb/db.d.ts +84 -41
- package/dist/types/index.d.ts +4 -2
- package/dist/types/interfaces/shogun.d.ts +1 -2
- package/dist/types/managers/CryptoIdentityManager.d.ts +2 -1
- package/package.json +11 -8
- package/dist/examples/mls-advanced-example.js +0 -294
- package/dist/examples/quick-auth-test.js +0 -61
- package/dist/examples/simple-api-test.js +0 -114
- package/dist/examples/simple-crypto-identity-example.js +0 -84
- package/dist/examples/timeout-test.js +0 -227
- package/dist/types/examples/mls-advanced-example.d.ts +0 -53
- package/dist/types/examples/quick-auth-test.d.ts +0 -8
- package/dist/types/examples/simple-api-test.d.ts +0 -10
- package/dist/types/examples/simple-crypto-identity-example.d.ts +0 -6
- package/dist/types/examples/timeout-test.d.ts +0 -8
package/dist/gundb/db.js
CHANGED
|
@@ -42,17 +42,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
42
42
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
43
43
|
};
|
|
44
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
-
exports.
|
|
46
|
-
const gun_1 = __importDefault(require("gun/gun"));
|
|
47
|
-
exports.Gun = gun_1.default;
|
|
45
|
+
exports.derive = exports.GunErrors = exports.crypto = exports.RxJS = exports.SEA = exports.DataBase = void 0;
|
|
48
46
|
const sea_1 = __importDefault(require("gun/sea"));
|
|
49
47
|
exports.SEA = sea_1.default;
|
|
50
|
-
require("gun/lib/then");
|
|
51
|
-
require("gun/lib/radix");
|
|
52
|
-
require("gun/lib/radisk");
|
|
53
|
-
require("gun/lib/store");
|
|
54
|
-
require("gun/lib/rindexed");
|
|
55
|
-
require("gun/lib/webrtc");
|
|
56
48
|
const derive_1 = __importDefault(require("./derive"));
|
|
57
49
|
exports.derive = derive_1.default;
|
|
58
50
|
const errorHandler_1 = require("../utils/errorHandler");
|
|
@@ -83,11 +75,17 @@ class DataBase {
|
|
|
83
75
|
constructor(gun, appScope = "shogun", core) {
|
|
84
76
|
this.user = null;
|
|
85
77
|
this.onAuthCallbacks = [];
|
|
78
|
+
// Memory leak prevention
|
|
79
|
+
this._activeTimeouts = new Set();
|
|
80
|
+
this._activeIntervals = new Set();
|
|
81
|
+
this._isDestroyed = false;
|
|
86
82
|
console.log("[DB] Initializing DataBase");
|
|
87
83
|
// Store core reference
|
|
88
84
|
this.core = core;
|
|
89
85
|
// Initialize event emitter
|
|
90
86
|
this.eventEmitter = new eventEmitter_1.EventEmitter();
|
|
87
|
+
// Setup cleanup handlers
|
|
88
|
+
this.setupCleanupHandlers();
|
|
91
89
|
// Validate Gun instance
|
|
92
90
|
if (!gun) {
|
|
93
91
|
throw new Error("Gun instance is required but was not provided");
|
|
@@ -129,7 +127,7 @@ class DataBase {
|
|
|
129
127
|
this.node = this.gun.get(appScope);
|
|
130
128
|
console.log("[DB] App scope node initialized");
|
|
131
129
|
// Initialize CryptoIdentityManager
|
|
132
|
-
this._cryptoIdentityManager = new CryptoIdentityManager_1.CryptoIdentityManager(this.core);
|
|
130
|
+
this._cryptoIdentityManager = new CryptoIdentityManager_1.CryptoIdentityManager(this.core, this);
|
|
133
131
|
console.log("[DB] CryptoIdentityManager initialized");
|
|
134
132
|
if (sessionResult.success) {
|
|
135
133
|
console.log("[DB] Session automatically restored");
|
|
@@ -381,46 +379,26 @@ class DataBase {
|
|
|
381
379
|
return this.navigateToPath(this.node, path);
|
|
382
380
|
}
|
|
383
381
|
/**
|
|
384
|
-
* Gets
|
|
385
|
-
* @
|
|
386
|
-
* @returns Promise resolving to the data
|
|
387
|
-
*/
|
|
388
|
-
async getData(path) {
|
|
389
|
-
const node = this.navigateToPath(this.node, path);
|
|
390
|
-
return new Promise((resolve, reject) => {
|
|
391
|
-
node.once((data) => {
|
|
392
|
-
resolve(data);
|
|
393
|
-
});
|
|
394
|
-
});
|
|
395
|
-
}
|
|
396
|
-
/**
|
|
397
|
-
* Puts data at the specified path
|
|
398
|
-
* @param path Path to store data
|
|
399
|
-
* @param data Data to store
|
|
400
|
-
* @returns Promise resolving to operation result
|
|
382
|
+
* Gets the Gun instance for direct operations
|
|
383
|
+
* @returns Gun instance
|
|
401
384
|
*/
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
return await node.put(data).then();
|
|
385
|
+
getGunInstance() {
|
|
386
|
+
return this.gun;
|
|
405
387
|
}
|
|
406
388
|
/**
|
|
407
|
-
*
|
|
408
|
-
* @
|
|
409
|
-
* @param data Data to store
|
|
410
|
-
* @returns Promise resolving to operation result
|
|
389
|
+
* Gets the app scope node for direct operations
|
|
390
|
+
* @returns Gun node
|
|
411
391
|
*/
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
return await node.set(data).then();
|
|
392
|
+
getAppNode() {
|
|
393
|
+
return this.node;
|
|
415
394
|
}
|
|
416
395
|
/**
|
|
417
|
-
*
|
|
418
|
-
* @param path Path to
|
|
419
|
-
* @returns
|
|
396
|
+
* Helper method to get a node at a specific path for direct GUN operations
|
|
397
|
+
* @param path Path to the node
|
|
398
|
+
* @returns Gun node at the specified path
|
|
420
399
|
*/
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
return await node.put(null).then();
|
|
400
|
+
getNode(path) {
|
|
401
|
+
return this.navigateToPath(this.node, path);
|
|
424
402
|
}
|
|
425
403
|
/**
|
|
426
404
|
* Checks if a user is currently logged in
|
|
@@ -577,6 +555,10 @@ class DataBase {
|
|
|
577
555
|
// Log out user
|
|
578
556
|
try {
|
|
579
557
|
currentUser.leave();
|
|
558
|
+
// Force clear any pending authentication
|
|
559
|
+
if (currentUser._ && currentUser._.sea) {
|
|
560
|
+
currentUser._.sea = null;
|
|
561
|
+
}
|
|
580
562
|
}
|
|
581
563
|
catch (gunError) {
|
|
582
564
|
console.error("Error during Gun logout:", gunError);
|
|
@@ -685,136 +667,6 @@ class DataBase {
|
|
|
685
667
|
// Validate password strength
|
|
686
668
|
return this.validatePasswordStrength(password);
|
|
687
669
|
}
|
|
688
|
-
/**
|
|
689
|
-
* Creates a new user in Gun
|
|
690
|
-
*/
|
|
691
|
-
async createNewUser(username, password) {
|
|
692
|
-
return new Promise((resolve) => {
|
|
693
|
-
// Validate inputs before creating user
|
|
694
|
-
if (!username ||
|
|
695
|
-
typeof username !== "string" ||
|
|
696
|
-
username.trim().length === 0) {
|
|
697
|
-
resolve({ success: false, error: "Invalid username provided" });
|
|
698
|
-
return;
|
|
699
|
-
}
|
|
700
|
-
if (!password ||
|
|
701
|
-
typeof password !== "string" ||
|
|
702
|
-
password.length === 0) {
|
|
703
|
-
resolve({ success: false, error: "Invalid password provided" });
|
|
704
|
-
return;
|
|
705
|
-
}
|
|
706
|
-
// Normalize username
|
|
707
|
-
const normalizedUsername = username.trim().toLowerCase();
|
|
708
|
-
if (normalizedUsername.length === 0) {
|
|
709
|
-
resolve({
|
|
710
|
-
success: false,
|
|
711
|
-
error: "Username cannot be empty",
|
|
712
|
-
});
|
|
713
|
-
return;
|
|
714
|
-
}
|
|
715
|
-
this.gun.user().create(normalizedUsername, password, (ack) => {
|
|
716
|
-
if (ack.err) {
|
|
717
|
-
console.error(`User creation error: ${ack.err}`);
|
|
718
|
-
resolve({ success: false, error: ack.err });
|
|
719
|
-
}
|
|
720
|
-
else {
|
|
721
|
-
// Validate that we got a userPub from creation
|
|
722
|
-
const userPub = ack.pub;
|
|
723
|
-
if (!userPub ||
|
|
724
|
-
typeof userPub !== "string" ||
|
|
725
|
-
userPub.trim().length === 0) {
|
|
726
|
-
console.error("User creation successful but no userPub returned:", ack);
|
|
727
|
-
resolve({
|
|
728
|
-
success: false,
|
|
729
|
-
error: "User creation successful but no userPub returned",
|
|
730
|
-
});
|
|
731
|
-
}
|
|
732
|
-
else {
|
|
733
|
-
resolve({ success: true, userPub: userPub });
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
});
|
|
737
|
-
});
|
|
738
|
-
}
|
|
739
|
-
/**
|
|
740
|
-
* Authenticates user after creation
|
|
741
|
-
*/
|
|
742
|
-
async authenticateNewUser(username, password, pair) {
|
|
743
|
-
return new Promise((resolve) => {
|
|
744
|
-
// Validate inputs before authentication
|
|
745
|
-
if (!username ||
|
|
746
|
-
typeof username !== "string" ||
|
|
747
|
-
username.trim().length === 0) {
|
|
748
|
-
resolve({ success: false, error: "Invalid username provided" });
|
|
749
|
-
return;
|
|
750
|
-
}
|
|
751
|
-
// Skip password validation when using pair authentication
|
|
752
|
-
if (!pair &&
|
|
753
|
-
(!password || typeof password !== "string" || password.length === 0)) {
|
|
754
|
-
resolve({ success: false, error: "Invalid password provided" });
|
|
755
|
-
return;
|
|
756
|
-
}
|
|
757
|
-
// Normalize username to match what was used in creation
|
|
758
|
-
const normalizedUsername = username.trim().toLowerCase();
|
|
759
|
-
if (normalizedUsername.length === 0) {
|
|
760
|
-
resolve({
|
|
761
|
-
success: false,
|
|
762
|
-
error: "Username cannot be empty",
|
|
763
|
-
});
|
|
764
|
-
return;
|
|
765
|
-
}
|
|
766
|
-
if (pair) {
|
|
767
|
-
this.gun.user().auth(pair, (ack) => {
|
|
768
|
-
if (ack.err) {
|
|
769
|
-
console.error(`Authentication after creation failed: ${ack.err}`);
|
|
770
|
-
resolve({ success: false, error: ack.err });
|
|
771
|
-
}
|
|
772
|
-
else {
|
|
773
|
-
// Add a small delay to ensure user state is properly set
|
|
774
|
-
setTimeout(() => {
|
|
775
|
-
// Extract userPub from multiple possible sources
|
|
776
|
-
const userPub = ack.pub || this.gun.user().is?.pub || ack.user?.pub;
|
|
777
|
-
if (!userPub) {
|
|
778
|
-
console.error("Authentication successful but no userPub found");
|
|
779
|
-
resolve({
|
|
780
|
-
success: false,
|
|
781
|
-
error: "No userPub returned from authentication",
|
|
782
|
-
});
|
|
783
|
-
}
|
|
784
|
-
else {
|
|
785
|
-
resolve({ success: true, userPub: userPub });
|
|
786
|
-
}
|
|
787
|
-
}, 100);
|
|
788
|
-
}
|
|
789
|
-
});
|
|
790
|
-
}
|
|
791
|
-
else {
|
|
792
|
-
this.gun.user().auth(normalizedUsername, password, (ack) => {
|
|
793
|
-
if (ack.err) {
|
|
794
|
-
console.error(`Authentication after creation failed: ${ack.err}`);
|
|
795
|
-
resolve({ success: false, error: ack.err });
|
|
796
|
-
}
|
|
797
|
-
else {
|
|
798
|
-
// Add a small delay to ensure user state is properly set
|
|
799
|
-
setTimeout(() => {
|
|
800
|
-
// Extract userPub from multiple possible sources
|
|
801
|
-
const userPub = ack.pub || this.gun.user().is?.pub || ack.user?.pub;
|
|
802
|
-
if (!userPub) {
|
|
803
|
-
console.error("Authentication successful but no userPub found");
|
|
804
|
-
resolve({
|
|
805
|
-
success: false,
|
|
806
|
-
error: "No userPub returned from authentication",
|
|
807
|
-
});
|
|
808
|
-
}
|
|
809
|
-
else {
|
|
810
|
-
resolve({ success: true, userPub: userPub });
|
|
811
|
-
}
|
|
812
|
-
}, 100);
|
|
813
|
-
}
|
|
814
|
-
});
|
|
815
|
-
}
|
|
816
|
-
});
|
|
817
|
-
}
|
|
818
670
|
/**
|
|
819
671
|
* Signs up a new user using direct Gun authentication
|
|
820
672
|
* @param username Username
|
|
@@ -822,13 +674,34 @@ class DataBase {
|
|
|
822
674
|
* @param pair Optional SEA pair for Web3 login
|
|
823
675
|
* @returns Promise resolving to signup result
|
|
824
676
|
*/
|
|
825
|
-
async signUp(username, password, pair) {
|
|
677
|
+
async signUp(username, password, pair, retryCount = 0, maxRetries = 3) {
|
|
826
678
|
try {
|
|
679
|
+
console.log(`🔄 [SIGNUP] Attempting signup for: ${username}`);
|
|
827
680
|
// Validate credentials with enhanced security
|
|
828
681
|
const validation = this.validateSignupCredentials(username, password, pair);
|
|
829
682
|
if (!validation.valid) {
|
|
830
683
|
return { success: false, error: validation.error };
|
|
831
684
|
}
|
|
685
|
+
// Check if authentication is in progress and retry if needed
|
|
686
|
+
if (this.isAuthInProgress()) {
|
|
687
|
+
if (retryCount < maxRetries) {
|
|
688
|
+
console.warn(`Authentication in progress during signup, retrying... (${retryCount + 1}/${maxRetries})`);
|
|
689
|
+
this.resetAuthState();
|
|
690
|
+
const baseDelay = 100 * Math.pow(2, retryCount);
|
|
691
|
+
const jitter = Math.random() * 100;
|
|
692
|
+
const delay = Math.min(baseDelay + jitter, 2000);
|
|
693
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
694
|
+
return this.signUp(username, password, pair, retryCount + 1, maxRetries);
|
|
695
|
+
}
|
|
696
|
+
else {
|
|
697
|
+
console.error("Max retries exceeded for signup due to concurrent operations");
|
|
698
|
+
this.resetAuthState();
|
|
699
|
+
return {
|
|
700
|
+
success: false,
|
|
701
|
+
error: "Signup failed after multiple retries due to concurrent operations",
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
}
|
|
832
705
|
let createResult;
|
|
833
706
|
if (pair) {
|
|
834
707
|
// For Web3/plugin authentication, use pair-based creation
|
|
@@ -836,15 +709,17 @@ class DataBase {
|
|
|
836
709
|
}
|
|
837
710
|
else {
|
|
838
711
|
// For password authentication, use standard creation
|
|
839
|
-
createResult = await this.
|
|
712
|
+
createResult = await this.createNewUserFixed(username, password);
|
|
840
713
|
}
|
|
841
714
|
if (!createResult.success) {
|
|
715
|
+
// Reset auth state after failed creation to prevent blocking future operations
|
|
716
|
+
this.resetAuthState();
|
|
842
717
|
return { success: false, error: createResult.error };
|
|
843
718
|
}
|
|
844
719
|
// Add a small delay to ensure user is properly registered
|
|
845
720
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
846
721
|
// Authenticate the newly created user
|
|
847
|
-
const authResult = await this.
|
|
722
|
+
const authResult = await this.authenticateNewUserFixed(username, password, pair);
|
|
848
723
|
if (!authResult.success) {
|
|
849
724
|
return { success: false, error: authResult.error };
|
|
850
725
|
}
|
|
@@ -921,6 +796,100 @@ class DataBase {
|
|
|
921
796
|
resolve({ success: true, userPub: pair.pub });
|
|
922
797
|
});
|
|
923
798
|
}
|
|
799
|
+
/**
|
|
800
|
+
* Creates a new user in Gun without waiting for acknowledgment
|
|
801
|
+
*/
|
|
802
|
+
async createNewUserFixed(username, password) {
|
|
803
|
+
return new Promise((resolve) => {
|
|
804
|
+
// Validate inputs before creating user
|
|
805
|
+
if (!username ||
|
|
806
|
+
typeof username !== "string" ||
|
|
807
|
+
username.trim().length === 0) {
|
|
808
|
+
resolve({ success: false, error: "Invalid username provided" });
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
if (!password ||
|
|
812
|
+
typeof password !== "string" ||
|
|
813
|
+
password.length === 0) {
|
|
814
|
+
resolve({ success: false, error: "Invalid password provided" });
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
// Normalize username
|
|
818
|
+
const normalizedUsername = username.trim().toLowerCase();
|
|
819
|
+
if (normalizedUsername.length === 0) {
|
|
820
|
+
resolve({
|
|
821
|
+
success: false,
|
|
822
|
+
error: "Username cannot be empty",
|
|
823
|
+
});
|
|
824
|
+
return;
|
|
825
|
+
}
|
|
826
|
+
console.log(`🔄 [CREATE] Creating user: ${normalizedUsername}`);
|
|
827
|
+
// Crea utente senza aspettare acknowledgment
|
|
828
|
+
this.gun.user().create(normalizedUsername, password, () => { });
|
|
829
|
+
// Aspetta che la creazione si completi
|
|
830
|
+
setTimeout(() => {
|
|
831
|
+
// Controlla se l'utente è stato creato
|
|
832
|
+
const user = this.gun.user();
|
|
833
|
+
if (user && user.is && user.is.pub) {
|
|
834
|
+
console.log("✅ [CREATE] User created successfully");
|
|
835
|
+
resolve({ success: true, userPub: user.is.pub });
|
|
836
|
+
}
|
|
837
|
+
else {
|
|
838
|
+
console.log("❌ [CREATE] User creation failed");
|
|
839
|
+
resolve({ success: false, error: "User creation failed" });
|
|
840
|
+
}
|
|
841
|
+
}, 2000); // Aspetta 2 secondi
|
|
842
|
+
});
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* Authenticates user after creation without waiting for acknowledgment
|
|
846
|
+
*/
|
|
847
|
+
async authenticateNewUserFixed(username, password, pair) {
|
|
848
|
+
return new Promise((resolve) => {
|
|
849
|
+
// Validate inputs before authentication
|
|
850
|
+
if (!username ||
|
|
851
|
+
typeof username !== "string" ||
|
|
852
|
+
username.trim().length === 0) {
|
|
853
|
+
resolve({ success: false, error: "Invalid username provided" });
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
// Skip password validation when using pair authentication
|
|
857
|
+
if (!pair &&
|
|
858
|
+
(!password || typeof password !== "string" || password.length === 0)) {
|
|
859
|
+
resolve({ success: false, error: "Invalid password provided" });
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
862
|
+
// Normalize username to match what was used in creation
|
|
863
|
+
const normalizedUsername = username.trim().toLowerCase();
|
|
864
|
+
if (normalizedUsername.length === 0) {
|
|
865
|
+
resolve({
|
|
866
|
+
success: false,
|
|
867
|
+
error: "Username cannot be empty",
|
|
868
|
+
});
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
console.log(`🔑 [AUTH] Authenticating user: ${normalizedUsername}`);
|
|
872
|
+
// Autentica senza aspettare acknowledgment
|
|
873
|
+
if (pair) {
|
|
874
|
+
this.gun.user().auth(pair);
|
|
875
|
+
}
|
|
876
|
+
else {
|
|
877
|
+
this.gun.user().auth(normalizedUsername, password);
|
|
878
|
+
}
|
|
879
|
+
// Aspetta che l'autenticazione si completi
|
|
880
|
+
setTimeout(() => {
|
|
881
|
+
const user = this.gun.user();
|
|
882
|
+
if (user && user.is && user.is.pub) {
|
|
883
|
+
console.log("✅ [AUTH] Authentication successful");
|
|
884
|
+
resolve({ success: true, userPub: user.is.pub });
|
|
885
|
+
}
|
|
886
|
+
else {
|
|
887
|
+
console.log("❌ [AUTH] Authentication failed");
|
|
888
|
+
resolve({ success: false, error: "Authentication failed" });
|
|
889
|
+
}
|
|
890
|
+
}, 2000); // Aspetta 2 secondi
|
|
891
|
+
});
|
|
892
|
+
}
|
|
924
893
|
async runPostAuthOnAuthResult(username, userPub, authResult) {
|
|
925
894
|
console.log(`[POSTAUTH] Starting post-auth setup for user: ${username}, userPub: ${userPub}`);
|
|
926
895
|
try {
|
|
@@ -956,7 +925,7 @@ class DataBase {
|
|
|
956
925
|
}
|
|
957
926
|
console.log(`[POSTAUTH] Normalized username: ${normalizedUsername}`);
|
|
958
927
|
console.log(`[POSTAUTH] Checking if user exists: ${userPub}`);
|
|
959
|
-
const existingUser =
|
|
928
|
+
const existingUser = this.gun.get(userPub);
|
|
960
929
|
const isNewUser = !existingUser || !existingUser.alias;
|
|
961
930
|
console.log(`[POSTAUTH] User is ${isNewUser ? "NEW" : "EXISTING"}: ${userPub}`);
|
|
962
931
|
// Get user's encryption public key (epub) for comprehensive tracking
|
|
@@ -975,8 +944,10 @@ class DataBase {
|
|
|
975
944
|
};
|
|
976
945
|
}
|
|
977
946
|
console.log(`[POSTAUTH] User tracking setup completed successfully for: ${normalizedUsername}`);
|
|
978
|
-
// Setup crypto identities for the user
|
|
979
|
-
if (this._cryptoIdentityManager &&
|
|
947
|
+
// Setup crypto identities for the user (skip if SKIP_CRYPTO_GENERATION is set)
|
|
948
|
+
if (this._cryptoIdentityManager &&
|
|
949
|
+
userSea &&
|
|
950
|
+
!process.env.SKIP_CRYPTO_GENERATION) {
|
|
980
951
|
console.log(`[POSTAUTH] Setting up crypto identities for: ${normalizedUsername}`);
|
|
981
952
|
try {
|
|
982
953
|
const cryptoSetupResult = await this._cryptoIdentityManager.setupCryptoIdentities(normalizedUsername, userSea, false);
|
|
@@ -994,7 +965,12 @@ class DataBase {
|
|
|
994
965
|
}
|
|
995
966
|
}
|
|
996
967
|
else {
|
|
997
|
-
|
|
968
|
+
if (process.env.SKIP_CRYPTO_GENERATION) {
|
|
969
|
+
console.log(`ℹ️ [POSTAUTH] Skipping crypto identities setup - SKIP_CRYPTO_GENERATION is set`);
|
|
970
|
+
}
|
|
971
|
+
else {
|
|
972
|
+
console.log(`ℹ️ [POSTAUTH] Skipping crypto identities setup - manager not available or no SEA pair`);
|
|
973
|
+
}
|
|
998
974
|
}
|
|
999
975
|
const result = {
|
|
1000
976
|
success: true,
|
|
@@ -1103,28 +1079,13 @@ class DataBase {
|
|
|
1103
1079
|
userPub: userPub,
|
|
1104
1080
|
createdAt: Date.now(),
|
|
1105
1081
|
};
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
this.node
|
|
1114
|
-
.get("aliases")
|
|
1115
|
-
.get(username)
|
|
1116
|
-
.put(aliasData, (ack) => {
|
|
1117
|
-
clearTimeout(timeout); // Clear timeout since callback fired
|
|
1118
|
-
if (ack && ack.err) {
|
|
1119
|
-
console.error(`Error creating alias index: ${ack.err}`);
|
|
1120
|
-
resolve(false);
|
|
1121
|
-
}
|
|
1122
|
-
else {
|
|
1123
|
-
console.log(`✓ Alias index created for ${username}`);
|
|
1124
|
-
resolve(true);
|
|
1125
|
-
}
|
|
1126
|
-
});
|
|
1127
|
-
});
|
|
1082
|
+
console.log(`🔄 [ALIAS] Creating alias index for ${username}`);
|
|
1083
|
+
// Store alias mapping without waiting for acknowledgment
|
|
1084
|
+
this.node.get("aliases").get(username).put(aliasData);
|
|
1085
|
+
// Aspetta un momento per la scrittura
|
|
1086
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
1087
|
+
console.log(`✅ [ALIAS] Alias index created for ${username}`);
|
|
1088
|
+
return true;
|
|
1128
1089
|
}
|
|
1129
1090
|
catch (error) {
|
|
1130
1091
|
console.error(`Error creating alias index: ${error}`);
|
|
@@ -1136,20 +1097,13 @@ class DataBase {
|
|
|
1136
1097
|
*/
|
|
1137
1098
|
async createUsernameMapping(username, userPub) {
|
|
1138
1099
|
try {
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
resolve(false);
|
|
1147
|
-
}
|
|
1148
|
-
else {
|
|
1149
|
-
resolve(true);
|
|
1150
|
-
}
|
|
1151
|
-
});
|
|
1152
|
-
});
|
|
1100
|
+
console.log(`🔄 [USERNAME] Creating username mapping for ${username}`);
|
|
1101
|
+
// Store username mapping without waiting for acknowledgment
|
|
1102
|
+
this.node.get("usernames").get(username).put(userPub);
|
|
1103
|
+
// Aspetta un momento per la scrittura
|
|
1104
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
1105
|
+
console.log(`✅ [USERNAME] Username mapping created for ${username}`);
|
|
1106
|
+
return true;
|
|
1153
1107
|
}
|
|
1154
1108
|
catch (error) {
|
|
1155
1109
|
console.error(`Error creating username mapping: ${error}`);
|
|
@@ -1168,20 +1122,13 @@ class DataBase {
|
|
|
1168
1122
|
registeredAt: Date.now().toString(),
|
|
1169
1123
|
lastSeen: Date.now().toString(),
|
|
1170
1124
|
};
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
resolve(false);
|
|
1179
|
-
}
|
|
1180
|
-
else {
|
|
1181
|
-
resolve(true);
|
|
1182
|
-
}
|
|
1183
|
-
});
|
|
1184
|
-
});
|
|
1125
|
+
console.log(`🔄 [REGISTRY] Creating user registry for ${username}`);
|
|
1126
|
+
// Store user registry without waiting for acknowledgment
|
|
1127
|
+
this.node.get("users").get(userPub).put(userData);
|
|
1128
|
+
// Aspetta un momento per la scrittura
|
|
1129
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
1130
|
+
console.log(`✅ [REGISTRY] User registry created for ${username}`);
|
|
1131
|
+
return true;
|
|
1185
1132
|
}
|
|
1186
1133
|
catch (error) {
|
|
1187
1134
|
console.error(`Error creating user registry: ${error}`);
|
|
@@ -1193,18 +1140,13 @@ class DataBase {
|
|
|
1193
1140
|
*/
|
|
1194
1141
|
async createReverseLookup(username, userPub) {
|
|
1195
1142
|
try {
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
return false;
|
|
1204
|
-
}
|
|
1205
|
-
else {
|
|
1206
|
-
return true;
|
|
1207
|
-
}
|
|
1143
|
+
console.log(`🔄 [REVERSE] Creating reverse lookup for ${username}`);
|
|
1144
|
+
// Store reverse lookup without waiting for acknowledgment
|
|
1145
|
+
this.node.get("userAliases").get(userPub).put(username);
|
|
1146
|
+
// Aspetta un momento per la scrittura
|
|
1147
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
1148
|
+
console.log(`✅ [REVERSE] Reverse lookup created for ${username}`);
|
|
1149
|
+
return true;
|
|
1208
1150
|
}
|
|
1209
1151
|
catch (error) {
|
|
1210
1152
|
console.error(`Error creating reverse lookup: ${error}`);
|
|
@@ -1216,20 +1158,13 @@ class DataBase {
|
|
|
1216
1158
|
*/
|
|
1217
1159
|
async createEpubIndex(epub, userPub) {
|
|
1218
1160
|
try {
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
resolve(false);
|
|
1227
|
-
}
|
|
1228
|
-
else {
|
|
1229
|
-
resolve(true);
|
|
1230
|
-
}
|
|
1231
|
-
});
|
|
1232
|
-
});
|
|
1161
|
+
console.log(`🔄 [EPUB] Creating epub index for ${userPub}`);
|
|
1162
|
+
// Store epub index without waiting for acknowledgment
|
|
1163
|
+
this.node.get("epubKeys").get(epub).put(userPub);
|
|
1164
|
+
// Aspetta un momento per la scrittura
|
|
1165
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
1166
|
+
console.log(`✅ [EPUB] Epub index created for ${userPub}`);
|
|
1167
|
+
return true;
|
|
1233
1168
|
}
|
|
1234
1169
|
catch (error) {
|
|
1235
1170
|
console.error(`Error creating epub index: ${error}`);
|
|
@@ -1247,17 +1182,13 @@ class DataBase {
|
|
|
1247
1182
|
registeredAt: Date.now(),
|
|
1248
1183
|
lastSeen: Date.now(),
|
|
1249
1184
|
};
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
resolve(true);
|
|
1258
|
-
}
|
|
1259
|
-
});
|
|
1260
|
-
});
|
|
1185
|
+
console.log(`🔄 [METADATA] Creating user metadata for ${username}`);
|
|
1186
|
+
// Store user metadata without waiting for acknowledgment
|
|
1187
|
+
this.gun.get(userPub).put(userMetadata);
|
|
1188
|
+
// Aspetta un momento per la scrittura
|
|
1189
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
1190
|
+
console.log(`✅ [METADATA] User metadata created for ${username}`);
|
|
1191
|
+
return true;
|
|
1261
1192
|
}
|
|
1262
1193
|
catch (error) {
|
|
1263
1194
|
console.error(`Error creating user metadata: ${error}`);
|
|
@@ -1277,7 +1208,7 @@ class DataBase {
|
|
|
1277
1208
|
}
|
|
1278
1209
|
// Method 1: Try GunDB standard alias lookup (~@alias)
|
|
1279
1210
|
try {
|
|
1280
|
-
const aliasData =
|
|
1211
|
+
const aliasData = this.gun.get(`~@${normalizedAlias}`);
|
|
1281
1212
|
if (aliasData && aliasData["~pubKeyOfUser"]) {
|
|
1282
1213
|
const userPub = aliasData["~pubKeyOfUser"]["#"] || aliasData["~pubKeyOfUser"];
|
|
1283
1214
|
if (userPub) {
|
|
@@ -1293,10 +1224,15 @@ class DataBase {
|
|
|
1293
1224
|
}
|
|
1294
1225
|
// Method 2: Try username mapping (usernames/alias -> userPub)
|
|
1295
1226
|
try {
|
|
1296
|
-
const
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1227
|
+
const userPubNode = this.node.get("usernames").get(normalizedAlias);
|
|
1228
|
+
// Use once to get the actual value
|
|
1229
|
+
const userPub = await new Promise((resolve) => {
|
|
1230
|
+
const timeout = setTimeout(() => resolve(null), 2000);
|
|
1231
|
+
userPubNode.once((data) => {
|
|
1232
|
+
clearTimeout(timeout);
|
|
1233
|
+
resolve(data);
|
|
1234
|
+
});
|
|
1235
|
+
});
|
|
1300
1236
|
if (userPub) {
|
|
1301
1237
|
const userData = await this.getUserDataByPub(userPub);
|
|
1302
1238
|
if (userData) {
|
|
@@ -1326,7 +1262,7 @@ class DataBase {
|
|
|
1326
1262
|
}
|
|
1327
1263
|
// Method 1: Try user registry (users/userPub -> user data)
|
|
1328
1264
|
try {
|
|
1329
|
-
const userData =
|
|
1265
|
+
const userData = this.node.get("users").get(userPub);
|
|
1330
1266
|
if (userData && userData.username) {
|
|
1331
1267
|
return {
|
|
1332
1268
|
userPub: userData.userPub || userPub,
|
|
@@ -1342,7 +1278,7 @@ class DataBase {
|
|
|
1342
1278
|
}
|
|
1343
1279
|
// Method 2: Try user's own node
|
|
1344
1280
|
try {
|
|
1345
|
-
const userNodeData =
|
|
1281
|
+
const userNodeData = this.gun.get(userPub);
|
|
1346
1282
|
if (userNodeData && userNodeData.username) {
|
|
1347
1283
|
return {
|
|
1348
1284
|
userPub: userPub,
|
|
@@ -1373,7 +1309,15 @@ class DataBase {
|
|
|
1373
1309
|
if (!epub || typeof epub !== "string") {
|
|
1374
1310
|
return null;
|
|
1375
1311
|
}
|
|
1376
|
-
const
|
|
1312
|
+
const userPubNode = this.node.get("epubKeys").get(epub);
|
|
1313
|
+
// Use once to get the actual value
|
|
1314
|
+
const userPub = await new Promise((resolve) => {
|
|
1315
|
+
const timeout = setTimeout(() => resolve(null), 2000);
|
|
1316
|
+
userPubNode.once((data) => {
|
|
1317
|
+
clearTimeout(timeout);
|
|
1318
|
+
resolve(data);
|
|
1319
|
+
});
|
|
1320
|
+
});
|
|
1377
1321
|
return userPub || null;
|
|
1378
1322
|
}
|
|
1379
1323
|
catch (error) {
|
|
@@ -1391,7 +1335,15 @@ class DataBase {
|
|
|
1391
1335
|
if (!userPub || typeof userPub !== "string") {
|
|
1392
1336
|
return null;
|
|
1393
1337
|
}
|
|
1394
|
-
const
|
|
1338
|
+
const aliasNode = this.node.get("userAliases").get(userPub);
|
|
1339
|
+
// Use once to get the actual value
|
|
1340
|
+
const alias = await new Promise((resolve) => {
|
|
1341
|
+
const timeout = setTimeout(() => resolve(null), 2000);
|
|
1342
|
+
aliasNode.once((data) => {
|
|
1343
|
+
clearTimeout(timeout);
|
|
1344
|
+
resolve(data);
|
|
1345
|
+
});
|
|
1346
|
+
});
|
|
1395
1347
|
return alias || null;
|
|
1396
1348
|
}
|
|
1397
1349
|
catch (error) {
|
|
@@ -1430,19 +1382,14 @@ class DataBase {
|
|
|
1430
1382
|
const timestamp = Date.now();
|
|
1431
1383
|
// Update in user registry
|
|
1432
1384
|
try {
|
|
1433
|
-
|
|
1434
|
-
.get("users")
|
|
1435
|
-
.get(userPub)
|
|
1436
|
-
.get("lastSeen")
|
|
1437
|
-
.put(timestamp)
|
|
1438
|
-
.then();
|
|
1385
|
+
this.node.get("users").get(userPub).get("lastSeen").put(timestamp);
|
|
1439
1386
|
}
|
|
1440
1387
|
catch (error) {
|
|
1441
1388
|
console.error(`Failed to update lastSeen in user registry:`, error);
|
|
1442
1389
|
}
|
|
1443
1390
|
// Update in user's own node
|
|
1444
1391
|
try {
|
|
1445
|
-
|
|
1392
|
+
this.gun.get(userPub).get("lastSeen").put(timestamp);
|
|
1446
1393
|
}
|
|
1447
1394
|
catch (error) {
|
|
1448
1395
|
console.error(`Failed to update lastSeen in user node:`, error);
|
|
@@ -1453,33 +1400,134 @@ class DataBase {
|
|
|
1453
1400
|
}
|
|
1454
1401
|
}
|
|
1455
1402
|
/**
|
|
1456
|
-
*
|
|
1403
|
+
* Resets Gun.js authentication state to allow new auth operations
|
|
1404
|
+
*/
|
|
1405
|
+
resetAuthState() {
|
|
1406
|
+
try {
|
|
1407
|
+
const currentUser = this.gun.user();
|
|
1408
|
+
if (currentUser && currentUser._) {
|
|
1409
|
+
// Reset the authentication flag
|
|
1410
|
+
if (currentUser._.sea) {
|
|
1411
|
+
currentUser._.sea = null;
|
|
1412
|
+
}
|
|
1413
|
+
// Reset the ing flag that prevents concurrent operations
|
|
1414
|
+
if (currentUser._.ing) {
|
|
1415
|
+
currentUser._.ing = false;
|
|
1416
|
+
}
|
|
1417
|
+
// Force clear any pending authentication callbacks
|
|
1418
|
+
if (currentUser._.auth) {
|
|
1419
|
+
currentUser._.auth = null;
|
|
1420
|
+
}
|
|
1421
|
+
// Clear any pending operations
|
|
1422
|
+
if (currentUser._.act) {
|
|
1423
|
+
currentUser._.act = null;
|
|
1424
|
+
}
|
|
1425
|
+
// Clear any pending callbacks
|
|
1426
|
+
if (currentUser._.cb) {
|
|
1427
|
+
currentUser._.cb = null;
|
|
1428
|
+
}
|
|
1429
|
+
// Clear any pending retries
|
|
1430
|
+
if (currentUser._.retries) {
|
|
1431
|
+
currentUser._.retries = 0;
|
|
1432
|
+
}
|
|
1433
|
+
// Clear any pending timeouts
|
|
1434
|
+
if (currentUser._.timeout) {
|
|
1435
|
+
clearTimeout(currentUser._.timeout);
|
|
1436
|
+
currentUser._.timeout = null;
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
// Also try to call leave() to ensure clean state
|
|
1440
|
+
try {
|
|
1441
|
+
currentUser.leave();
|
|
1442
|
+
}
|
|
1443
|
+
catch (leaveError) {
|
|
1444
|
+
// Ignore leave errors, just trying to clean up
|
|
1445
|
+
}
|
|
1446
|
+
// Force clear the user reference to ensure clean state
|
|
1447
|
+
this.user = null;
|
|
1448
|
+
console.log("Auth state reset completed");
|
|
1449
|
+
}
|
|
1450
|
+
catch (error) {
|
|
1451
|
+
console.warn("Error resetting auth state:", error);
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
/**
|
|
1455
|
+
* Performs authentication with Gun with retry mechanism
|
|
1457
1456
|
*/
|
|
1458
|
-
async performAuthentication(username, password, pair) {
|
|
1457
|
+
async performAuthentication(username, password, pair, retryCount = 0, maxRetries = 3) {
|
|
1459
1458
|
return new Promise((resolve) => {
|
|
1460
|
-
if
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1459
|
+
// Check if there's already an authentication operation in progress
|
|
1460
|
+
const currentUser = this.gun.user();
|
|
1461
|
+
if (currentUser && currentUser._ && currentUser._.ing) {
|
|
1462
|
+
if (retryCount < maxRetries) {
|
|
1463
|
+
console.warn(`Authentication already in progress, retrying... (${retryCount + 1}/${maxRetries})`);
|
|
1464
|
+
this.resetAuthState();
|
|
1465
|
+
// For the first retry, try to create a fresh authentication context
|
|
1466
|
+
if (retryCount === 0) {
|
|
1467
|
+
this.createFreshAuthContext();
|
|
1468
1468
|
}
|
|
1469
|
+
// Add exponential backoff delay with jitter
|
|
1470
|
+
const baseDelay = 200 * Math.pow(2, retryCount);
|
|
1471
|
+
const jitter = Math.random() * 200;
|
|
1472
|
+
const delay = Math.min(baseDelay + jitter, 3000);
|
|
1473
|
+
setTimeout(() => {
|
|
1474
|
+
this.performAuthentication(username, password, pair, retryCount + 1, maxRetries)
|
|
1475
|
+
.then(resolve)
|
|
1476
|
+
.catch((error) => resolve({ success: false, error: String(error) }));
|
|
1477
|
+
}, delay);
|
|
1478
|
+
return;
|
|
1479
|
+
}
|
|
1480
|
+
else {
|
|
1481
|
+
console.error("Max retries exceeded for authentication");
|
|
1482
|
+
this.resetAuthState();
|
|
1483
|
+
resolve({
|
|
1484
|
+
success: false,
|
|
1485
|
+
error: "Authentication failed after multiple retries",
|
|
1486
|
+
});
|
|
1487
|
+
return;
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
this.performAuthenticationInternal(username, password, pair, resolve);
|
|
1491
|
+
});
|
|
1492
|
+
}
|
|
1493
|
+
/**
|
|
1494
|
+
* Internal authentication method with timeout
|
|
1495
|
+
*/
|
|
1496
|
+
performAuthenticationInternal(username, password, pair, resolve) {
|
|
1497
|
+
let resolved = false;
|
|
1498
|
+
const timeout = 30000; // 15 second timeout for individual auth attempts
|
|
1499
|
+
const timeoutId = setTimeout(() => {
|
|
1500
|
+
if (!resolved) {
|
|
1501
|
+
resolved = true;
|
|
1502
|
+
console.error(`Authentication timeout for ${username} after ${timeout}ms`);
|
|
1503
|
+
this.resetAuthState();
|
|
1504
|
+
resolve({
|
|
1505
|
+
success: false,
|
|
1506
|
+
error: `Authentication timeout after ${timeout}ms`,
|
|
1469
1507
|
});
|
|
1470
1508
|
}
|
|
1509
|
+
}, timeout);
|
|
1510
|
+
const authCallback = (ack) => {
|
|
1511
|
+
if (resolved)
|
|
1512
|
+
return;
|
|
1513
|
+
resolved = true;
|
|
1514
|
+
clearTimeout(timeoutId);
|
|
1515
|
+
if (ack.err) {
|
|
1516
|
+
console.error(`Login error for ${username}: ${ack.err}`);
|
|
1517
|
+
// Reset auth state on error to prevent blocking future attempts
|
|
1518
|
+
this.resetAuthState();
|
|
1519
|
+
resolve({ success: false, error: ack.err });
|
|
1520
|
+
}
|
|
1471
1521
|
else {
|
|
1472
|
-
|
|
1473
|
-
if (ack.err) {
|
|
1474
|
-
console.error(`Login error for ${username}: ${ack.err}`);
|
|
1475
|
-
resolve({ success: false, error: ack.err });
|
|
1476
|
-
}
|
|
1477
|
-
else {
|
|
1478
|
-
resolve({ success: true, ack });
|
|
1479
|
-
}
|
|
1480
|
-
});
|
|
1522
|
+
resolve({ success: true, ack });
|
|
1481
1523
|
}
|
|
1482
|
-
}
|
|
1524
|
+
};
|
|
1525
|
+
if (pair) {
|
|
1526
|
+
this.gun.user().auth(pair, authCallback);
|
|
1527
|
+
}
|
|
1528
|
+
else {
|
|
1529
|
+
this.gun.user().auth(username, password, authCallback);
|
|
1530
|
+
}
|
|
1483
1531
|
}
|
|
1484
1532
|
/**
|
|
1485
1533
|
* Builds login result object
|
|
@@ -1511,18 +1559,34 @@ class DataBase {
|
|
|
1511
1559
|
*/
|
|
1512
1560
|
async login(username, password, pair) {
|
|
1513
1561
|
try {
|
|
1514
|
-
|
|
1515
|
-
|
|
1562
|
+
console.log(`🔑 [LOGIN] Attempting login for: ${username}`);
|
|
1563
|
+
// Pulisci lo stato utente esistente
|
|
1564
|
+
this.gun.user().leave();
|
|
1565
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
1566
|
+
// Autentica senza aspettare acknowledgment
|
|
1567
|
+
if (pair) {
|
|
1568
|
+
this.gun.user().auth(pair);
|
|
1569
|
+
}
|
|
1570
|
+
else {
|
|
1571
|
+
this.gun.user().auth(username, password);
|
|
1572
|
+
}
|
|
1573
|
+
// Aspetta che l'autenticazione si completi
|
|
1574
|
+
console.log("⏳ [LOGIN] Waiting for authentication to complete...");
|
|
1575
|
+
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
1576
|
+
// Controlla se l'autenticazione è riuscita
|
|
1577
|
+
const user = this.gun.user();
|
|
1578
|
+
const isAuthenticated = !!user.is;
|
|
1579
|
+
if (!isAuthenticated) {
|
|
1580
|
+
console.log("❌ [LOGIN] Authentication failed");
|
|
1516
1581
|
return {
|
|
1517
1582
|
success: false,
|
|
1518
1583
|
error: `User '${username}' not found. Please check your username or register first.`,
|
|
1519
1584
|
};
|
|
1520
1585
|
}
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
let
|
|
1525
|
-
let userPair = this.gun.user()?._?.sea;
|
|
1586
|
+
console.log("✅ [LOGIN] Authentication successful!");
|
|
1587
|
+
const userPub = user?.is?.pub;
|
|
1588
|
+
let alias = user?.is?.alias;
|
|
1589
|
+
let userPair = user?._?.sea;
|
|
1526
1590
|
if (!alias) {
|
|
1527
1591
|
alias = username;
|
|
1528
1592
|
}
|
|
@@ -1532,7 +1596,7 @@ class DataBase {
|
|
|
1532
1596
|
error: "Authentication failed: No user pub returned.",
|
|
1533
1597
|
};
|
|
1534
1598
|
}
|
|
1535
|
-
//
|
|
1599
|
+
// Esegui post-authentication tasks
|
|
1536
1600
|
try {
|
|
1537
1601
|
await this.runPostAuthOnAuthResult(alias, userPub, {
|
|
1538
1602
|
success: true,
|
|
@@ -1693,14 +1757,20 @@ class DataBase {
|
|
|
1693
1757
|
questions: JSON.stringify(securityQuestions),
|
|
1694
1758
|
hint: encryptedHint,
|
|
1695
1759
|
};
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
.
|
|
1699
|
-
.
|
|
1700
|
-
|
|
1760
|
+
console.log(`💾 [HINT] Saving security data for user: ${username}, pub: ${userPub}`);
|
|
1761
|
+
console.log(`💾 [HINT] Security payload:`, {
|
|
1762
|
+
questions: securityPayload.questions,
|
|
1763
|
+
hintLength: securityPayload.hint?.length || 0,
|
|
1764
|
+
});
|
|
1765
|
+
// Save in PUBLIC space, not user space - accessible without login
|
|
1766
|
+
const ack = this.gun.get("security")
|
|
1767
|
+
.get(userPub)
|
|
1768
|
+
.put(securityPayload);
|
|
1769
|
+
if (ack && ack.err) {
|
|
1701
1770
|
console.error("Error saving security data to public graph:", ack.err);
|
|
1702
1771
|
throw new Error(ack.err);
|
|
1703
1772
|
}
|
|
1773
|
+
console.log(`✅ [HINT] Security data saved successfully for ${username}`);
|
|
1704
1774
|
return { success: true };
|
|
1705
1775
|
}
|
|
1706
1776
|
catch (error) {
|
|
@@ -1716,19 +1786,82 @@ class DataBase {
|
|
|
1716
1786
|
*/
|
|
1717
1787
|
async forgotPassword(username, securityAnswers) {
|
|
1718
1788
|
// Attempting password recovery for
|
|
1789
|
+
// Add global timeout for the entire operation
|
|
1790
|
+
return Promise.race([
|
|
1791
|
+
this._forgotPasswordInternal(username, securityAnswers),
|
|
1792
|
+
new Promise((resolve) => {
|
|
1793
|
+
setTimeout(() => {
|
|
1794
|
+
console.log(`⏰ [FORGOT] Global timeout for password recovery: ${username}`);
|
|
1795
|
+
resolve({ success: false, error: "Password recovery timeout" });
|
|
1796
|
+
}, 10000); // 10 second global timeout
|
|
1797
|
+
}),
|
|
1798
|
+
]);
|
|
1799
|
+
}
|
|
1800
|
+
async _forgotPasswordInternal(username, securityAnswers) {
|
|
1719
1801
|
try {
|
|
1720
1802
|
// Find the user's data using direct lookup
|
|
1721
1803
|
const normalizedUsername = username.trim().toLowerCase();
|
|
1722
|
-
|
|
1723
|
-
|
|
1804
|
+
// Try multiple lookup methods with fallback
|
|
1805
|
+
let userPub = null;
|
|
1806
|
+
// Method 1: Try username mapping in app scope
|
|
1807
|
+
try {
|
|
1808
|
+
userPub = await new Promise((resolve) => {
|
|
1809
|
+
const timeout = setTimeout(() => {
|
|
1810
|
+
console.log(`⏰ [FORGOT] Timeout looking up user in usernames: ${username}`);
|
|
1811
|
+
resolve(null);
|
|
1812
|
+
}, 2000);
|
|
1813
|
+
this.node
|
|
1814
|
+
.get("usernames")
|
|
1815
|
+
.get(normalizedUsername)
|
|
1816
|
+
.once((data) => {
|
|
1817
|
+
clearTimeout(timeout);
|
|
1818
|
+
console.log(`🔍 [FORGOT] Username lookup result for ${username}:`, data);
|
|
1819
|
+
resolve(data);
|
|
1820
|
+
});
|
|
1821
|
+
});
|
|
1822
|
+
}
|
|
1823
|
+
catch (error) {
|
|
1824
|
+
console.log(`❌ [FORGOT] Username lookup failed: ${error}`);
|
|
1825
|
+
}
|
|
1826
|
+
// Method 2: Try direct user lookup if username mapping fails
|
|
1724
1827
|
if (!userPub) {
|
|
1828
|
+
console.log(`🔄 [FORGOT] Trying direct user lookup for: ${username}`);
|
|
1829
|
+
try {
|
|
1830
|
+
// Try to find user by searching in the users registry
|
|
1831
|
+
const usersNode = this.node.get("users");
|
|
1832
|
+
// This is a simplified approach - in a real implementation you'd need to iterate
|
|
1833
|
+
// For now, we'll try to get the userPub from the current user if available
|
|
1834
|
+
const currentUser = this.getCurrentUser();
|
|
1835
|
+
if (currentUser && currentUser.pub) {
|
|
1836
|
+
console.log(`🔍 [FORGOT] Using current user pub as fallback: ${currentUser.pub}`);
|
|
1837
|
+
userPub = currentUser.pub;
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
catch (error) {
|
|
1841
|
+
console.log(`❌ [FORGOT] Direct user lookup failed: ${error}`);
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
if (!userPub) {
|
|
1845
|
+
console.log(`❌ [FORGOT] User not found: ${username}`);
|
|
1725
1846
|
return { success: false, error: "User not found" };
|
|
1726
1847
|
}
|
|
1727
|
-
// Access the user's security data
|
|
1728
|
-
const
|
|
1729
|
-
|
|
1730
|
-
|
|
1848
|
+
// Access the user's security data from PUBLIC space (not user space)
|
|
1849
|
+
const securityDataNode = this.gun.get("security").get(userPub);
|
|
1850
|
+
console.log(`🔍 [FORGOT] Looking for security data for user: ${username}, pub: ${userPub}`);
|
|
1851
|
+
// Use once to get the actual value
|
|
1852
|
+
const securityData = await new Promise((resolve) => {
|
|
1853
|
+
const timeout = setTimeout(() => {
|
|
1854
|
+
console.log(`⏰ [FORGOT] Timeout waiting for security data for ${username} (3s)`);
|
|
1855
|
+
resolve(null);
|
|
1856
|
+
}, 3000); // Reduced timeout to 3 seconds
|
|
1857
|
+
securityDataNode.once((data) => {
|
|
1858
|
+
clearTimeout(timeout);
|
|
1859
|
+
console.log(`📊 [FORGOT] Security data received for ${username}:`, data);
|
|
1860
|
+
resolve(data);
|
|
1861
|
+
});
|
|
1862
|
+
});
|
|
1731
1863
|
if (!securityData || !securityData.hint) {
|
|
1864
|
+
console.log(`❌ [FORGOT] No security data or hint found for ${username}`);
|
|
1732
1865
|
return {
|
|
1733
1866
|
success: false,
|
|
1734
1867
|
error: "No password hint found",
|
|
@@ -1790,6 +1923,107 @@ class DataBase {
|
|
|
1790
1923
|
return { success: false, error: String(error) };
|
|
1791
1924
|
}
|
|
1792
1925
|
}
|
|
1926
|
+
/**
|
|
1927
|
+
* Recovers password hint using security question answers and userPub directly
|
|
1928
|
+
* @param userPub User's public key
|
|
1929
|
+
* @param securityAnswers Array of answers to security questions
|
|
1930
|
+
* @returns Promise resolving with the password hint
|
|
1931
|
+
*/
|
|
1932
|
+
async forgotPasswordByPub(userPub, securityAnswers) {
|
|
1933
|
+
// Add global timeout for the entire operation
|
|
1934
|
+
return Promise.race([
|
|
1935
|
+
this._forgotPasswordByPubInternal(userPub, securityAnswers),
|
|
1936
|
+
new Promise((resolve) => {
|
|
1937
|
+
setTimeout(() => {
|
|
1938
|
+
console.log(`⏰ [FORGOT] Global timeout for password recovery by pub: ${userPub}`);
|
|
1939
|
+
resolve({ success: false, error: "Password recovery timeout" });
|
|
1940
|
+
}, 10000); // 10 second global timeout
|
|
1941
|
+
}),
|
|
1942
|
+
]);
|
|
1943
|
+
}
|
|
1944
|
+
async _forgotPasswordByPubInternal(userPub, securityAnswers) {
|
|
1945
|
+
try {
|
|
1946
|
+
if (!userPub || typeof userPub !== "string") {
|
|
1947
|
+
return { success: false, error: "Invalid userPub provided" };
|
|
1948
|
+
}
|
|
1949
|
+
// Access the user's security data from PUBLIC space (not user space)
|
|
1950
|
+
const securityDataNode = this.gun.get("security").get(userPub);
|
|
1951
|
+
console.log(`🔍 [FORGOT] Looking for security data for userPub: ${userPub}`);
|
|
1952
|
+
// Use once to get the actual value
|
|
1953
|
+
const securityData = await new Promise((resolve) => {
|
|
1954
|
+
const timeout = setTimeout(() => {
|
|
1955
|
+
console.log(`⏰ [FORGOT] Timeout waiting for security data for userPub: ${userPub} (3s)`);
|
|
1956
|
+
resolve(null);
|
|
1957
|
+
}, 3000);
|
|
1958
|
+
securityDataNode.once((data) => {
|
|
1959
|
+
clearTimeout(timeout);
|
|
1960
|
+
console.log(`📊 [FORGOT] Security data received for userPub: ${userPub}:`, data);
|
|
1961
|
+
resolve(data);
|
|
1962
|
+
});
|
|
1963
|
+
});
|
|
1964
|
+
if (!securityData || !securityData.hint) {
|
|
1965
|
+
console.log(`❌ [FORGOT] No security data or hint found for userPub: ${userPub}`);
|
|
1966
|
+
return {
|
|
1967
|
+
success: false,
|
|
1968
|
+
error: "No password hint found",
|
|
1969
|
+
};
|
|
1970
|
+
}
|
|
1971
|
+
// Generate hash from security answers
|
|
1972
|
+
const answersText = securityAnswers.join("|");
|
|
1973
|
+
let proofOfWork;
|
|
1974
|
+
try {
|
|
1975
|
+
// Use SEA directly if available
|
|
1976
|
+
if (sea_1.default && sea_1.default.work) {
|
|
1977
|
+
proofOfWork = await sea_1.default.work(answersText, null, null, {
|
|
1978
|
+
name: "SHA-256",
|
|
1979
|
+
});
|
|
1980
|
+
}
|
|
1981
|
+
else if (this.crypto && this.crypto.hashText) {
|
|
1982
|
+
proofOfWork = await this.crypto.hashText(answersText);
|
|
1983
|
+
}
|
|
1984
|
+
else {
|
|
1985
|
+
throw new Error("Cryptographic functions not available");
|
|
1986
|
+
}
|
|
1987
|
+
if (!proofOfWork) {
|
|
1988
|
+
throw new Error("Failed to generate hash");
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
catch (hashError) {
|
|
1992
|
+
console.error("Error generating hash:", hashError);
|
|
1993
|
+
return { success: false, error: "Failed to generate security hash" };
|
|
1994
|
+
}
|
|
1995
|
+
// Decrypt the password hint with the proof of work
|
|
1996
|
+
let hint;
|
|
1997
|
+
try {
|
|
1998
|
+
if (sea_1.default && sea_1.default.decrypt) {
|
|
1999
|
+
hint = await sea_1.default.decrypt(securityData.hint, proofOfWork);
|
|
2000
|
+
}
|
|
2001
|
+
else if (this.crypto && this.crypto.decrypt) {
|
|
2002
|
+
hint = await this.crypto.decrypt(securityData.hint, proofOfWork);
|
|
2003
|
+
}
|
|
2004
|
+
else {
|
|
2005
|
+
throw new Error("Decryption functions not available");
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
catch (decryptError) {
|
|
2009
|
+
return {
|
|
2010
|
+
success: false,
|
|
2011
|
+
error: "Incorrect answers to security questions",
|
|
2012
|
+
};
|
|
2013
|
+
}
|
|
2014
|
+
if (hint === undefined) {
|
|
2015
|
+
return {
|
|
2016
|
+
success: false,
|
|
2017
|
+
error: "Incorrect answers to security questions",
|
|
2018
|
+
};
|
|
2019
|
+
}
|
|
2020
|
+
return { success: true, hint: hint };
|
|
2021
|
+
}
|
|
2022
|
+
catch (error) {
|
|
2023
|
+
console.error("Error recovering password hint by pub:", error);
|
|
2024
|
+
return { success: false, error: String(error) };
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
1793
2027
|
/**
|
|
1794
2028
|
* Adds an event listener
|
|
1795
2029
|
* @param event Event name
|
|
@@ -1934,13 +2168,220 @@ class DataBase {
|
|
|
1934
2168
|
isAuthenticated() {
|
|
1935
2169
|
return this.user?.is?.pub ? true : false;
|
|
1936
2170
|
}
|
|
2171
|
+
/**
|
|
2172
|
+
* Check if an authentication operation is currently in progress
|
|
2173
|
+
*/
|
|
2174
|
+
isAuthInProgress() {
|
|
2175
|
+
try {
|
|
2176
|
+
const currentUser = this.gun.user();
|
|
2177
|
+
return !!(currentUser && currentUser._ && currentUser._.ing);
|
|
2178
|
+
}
|
|
2179
|
+
catch (error) {
|
|
2180
|
+
console.warn("Error checking auth progress:", error);
|
|
2181
|
+
return false;
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
/**
|
|
2185
|
+
* Force reset authentication state (useful for debugging or recovery)
|
|
2186
|
+
*/
|
|
2187
|
+
forceResetAuthState() {
|
|
2188
|
+
this.resetAuthState();
|
|
2189
|
+
}
|
|
2190
|
+
/**
|
|
2191
|
+
* Aggressive cleanup for problematic users
|
|
2192
|
+
* This method performs a complete reset of all authentication state
|
|
2193
|
+
*/
|
|
2194
|
+
aggressiveAuthCleanup() {
|
|
2195
|
+
try {
|
|
2196
|
+
console.log("🧹 Performing aggressive auth cleanup...");
|
|
2197
|
+
// Reset all auth state
|
|
2198
|
+
this.resetAuthState();
|
|
2199
|
+
// Clear all Gun.js internal state
|
|
2200
|
+
const currentUser = this.gun.user();
|
|
2201
|
+
if (currentUser && currentUser._) {
|
|
2202
|
+
// Clear all possible internal flags
|
|
2203
|
+
const internalState = currentUser._;
|
|
2204
|
+
Object.keys(internalState).forEach((key) => {
|
|
2205
|
+
if (typeof internalState[key] === "boolean") {
|
|
2206
|
+
internalState[key] = false;
|
|
2207
|
+
}
|
|
2208
|
+
else if (typeof internalState[key] === "object" &&
|
|
2209
|
+
internalState[key] !== null) {
|
|
2210
|
+
if (key === "sea" ||
|
|
2211
|
+
key === "auth" ||
|
|
2212
|
+
key === "act" ||
|
|
2213
|
+
key === "cb") {
|
|
2214
|
+
internalState[key] = null;
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2217
|
+
});
|
|
2218
|
+
}
|
|
2219
|
+
// Force logout
|
|
2220
|
+
try {
|
|
2221
|
+
currentUser.leave();
|
|
2222
|
+
}
|
|
2223
|
+
catch (error) {
|
|
2224
|
+
// Ignore errors
|
|
2225
|
+
}
|
|
2226
|
+
// Clear user reference
|
|
2227
|
+
this.user = null;
|
|
2228
|
+
// Clear all session storage
|
|
2229
|
+
if (typeof sessionStorage !== "undefined") {
|
|
2230
|
+
try {
|
|
2231
|
+
const keys = Object.keys(sessionStorage);
|
|
2232
|
+
keys.forEach((key) => {
|
|
2233
|
+
if (key.includes("gun") ||
|
|
2234
|
+
key.includes("user") ||
|
|
2235
|
+
key.includes("auth")) {
|
|
2236
|
+
sessionStorage.removeItem(key);
|
|
2237
|
+
}
|
|
2238
|
+
});
|
|
2239
|
+
}
|
|
2240
|
+
catch (error) {
|
|
2241
|
+
// Ignore errors
|
|
2242
|
+
}
|
|
2243
|
+
}
|
|
2244
|
+
// Clear all local storage
|
|
2245
|
+
if (typeof localStorage !== "undefined") {
|
|
2246
|
+
try {
|
|
2247
|
+
const keys = Object.keys(localStorage);
|
|
2248
|
+
keys.forEach((key) => {
|
|
2249
|
+
if (key.includes("gun") ||
|
|
2250
|
+
key.includes("user") ||
|
|
2251
|
+
key.includes("auth")) {
|
|
2252
|
+
localStorage.removeItem(key);
|
|
2253
|
+
}
|
|
2254
|
+
});
|
|
2255
|
+
}
|
|
2256
|
+
catch (error) {
|
|
2257
|
+
// Ignore errors
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
console.log("✓ Aggressive auth cleanup completed");
|
|
2261
|
+
}
|
|
2262
|
+
catch (error) {
|
|
2263
|
+
console.error("Error during aggressive cleanup:", error);
|
|
2264
|
+
}
|
|
2265
|
+
}
|
|
2266
|
+
/**
|
|
2267
|
+
* Creates a completely fresh authentication context
|
|
2268
|
+
* This is a more aggressive approach when normal reset doesn't work
|
|
2269
|
+
*/
|
|
2270
|
+
createFreshAuthContext() {
|
|
2271
|
+
try {
|
|
2272
|
+
// Reset all auth state
|
|
2273
|
+
this.resetAuthState();
|
|
2274
|
+
// Create a completely new user instance
|
|
2275
|
+
const freshUser = this.gun.user();
|
|
2276
|
+
this.user = freshUser;
|
|
2277
|
+
// Clear any cached authentication data
|
|
2278
|
+
if (typeof sessionStorage !== "undefined") {
|
|
2279
|
+
try {
|
|
2280
|
+
sessionStorage.removeItem("gunSessionData");
|
|
2281
|
+
sessionStorage.removeItem("gunUserData");
|
|
2282
|
+
}
|
|
2283
|
+
catch (error) {
|
|
2284
|
+
console.warn("Error clearing session storage:", error);
|
|
2285
|
+
}
|
|
2286
|
+
}
|
|
2287
|
+
console.log("Fresh authentication context created");
|
|
2288
|
+
}
|
|
2289
|
+
catch (error) {
|
|
2290
|
+
console.error("Error creating fresh auth context:", error);
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
/**
|
|
2294
|
+
* Setup cleanup handlers for memory leak prevention
|
|
2295
|
+
*/
|
|
2296
|
+
setupCleanupHandlers() {
|
|
2297
|
+
// Handle process cleanup
|
|
2298
|
+
if (typeof process !== "undefined") {
|
|
2299
|
+
process.on("SIGINT", () => this.destroy());
|
|
2300
|
+
process.on("SIGTERM", () => this.destroy());
|
|
2301
|
+
process.on("exit", () => this.destroy());
|
|
2302
|
+
}
|
|
2303
|
+
}
|
|
2304
|
+
/**
|
|
2305
|
+
* Safe interval wrapper that tracks intervals for cleanup
|
|
2306
|
+
*/
|
|
2307
|
+
safeInterval(callback, delay) {
|
|
2308
|
+
if (this._isDestroyed) {
|
|
2309
|
+
return setInterval(() => { }, 0);
|
|
2310
|
+
}
|
|
2311
|
+
const interval = setInterval(() => {
|
|
2312
|
+
if (!this._isDestroyed) {
|
|
2313
|
+
callback();
|
|
2314
|
+
}
|
|
2315
|
+
}, delay);
|
|
2316
|
+
this._activeIntervals.add(interval);
|
|
2317
|
+
return interval;
|
|
2318
|
+
}
|
|
2319
|
+
/**
|
|
2320
|
+
* Clear a specific timeout
|
|
2321
|
+
*/
|
|
2322
|
+
clearSafeTimeout(timeout) {
|
|
2323
|
+
clearTimeout(timeout);
|
|
2324
|
+
this._activeTimeouts.delete(timeout);
|
|
2325
|
+
}
|
|
2326
|
+
/**
|
|
2327
|
+
* Clear a specific interval
|
|
2328
|
+
*/
|
|
2329
|
+
clearSafeInterval(interval) {
|
|
2330
|
+
clearInterval(interval);
|
|
2331
|
+
this._activeIntervals.delete(interval);
|
|
2332
|
+
}
|
|
2333
|
+
/**
|
|
2334
|
+
* Destroy the database instance and clean up all resources
|
|
2335
|
+
*/
|
|
2336
|
+
destroy() {
|
|
2337
|
+
if (this._isDestroyed) {
|
|
2338
|
+
return;
|
|
2339
|
+
}
|
|
2340
|
+
console.log("[DB] Destroying DataBase instance...");
|
|
2341
|
+
this._isDestroyed = true;
|
|
2342
|
+
// Clear all timeouts
|
|
2343
|
+
this._activeTimeouts.forEach((timeout) => {
|
|
2344
|
+
clearTimeout(timeout);
|
|
2345
|
+
});
|
|
2346
|
+
this._activeTimeouts.clear();
|
|
2347
|
+
// Clear all intervals
|
|
2348
|
+
this._activeIntervals.forEach((interval) => {
|
|
2349
|
+
clearInterval(interval);
|
|
2350
|
+
});
|
|
2351
|
+
this._activeIntervals.clear();
|
|
2352
|
+
// Clear event listeners
|
|
2353
|
+
this.eventEmitter.removeAllListeners();
|
|
2354
|
+
// Clear auth callbacks
|
|
2355
|
+
this.onAuthCallbacks.length = 0;
|
|
2356
|
+
// Clear Gun user
|
|
2357
|
+
if (this.user) {
|
|
2358
|
+
try {
|
|
2359
|
+
this.user.leave();
|
|
2360
|
+
}
|
|
2361
|
+
catch (error) {
|
|
2362
|
+
console.warn("Error during user leave:", error);
|
|
2363
|
+
}
|
|
2364
|
+
this.user = null;
|
|
2365
|
+
}
|
|
2366
|
+
// Clear Gun instance references
|
|
2367
|
+
if (this.gun) {
|
|
2368
|
+
try {
|
|
2369
|
+
// Clear any Gun event listeners if available
|
|
2370
|
+
if (typeof this.gun.off === "function") {
|
|
2371
|
+
this.gun.off();
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
catch (error) {
|
|
2375
|
+
console.warn("Error clearing Gun listeners:", error);
|
|
2376
|
+
}
|
|
2377
|
+
}
|
|
2378
|
+
// Clear other references
|
|
2379
|
+
this._rxjs = undefined;
|
|
2380
|
+
this._cryptoIdentityManager = undefined;
|
|
2381
|
+
this.core = undefined;
|
|
2382
|
+
console.log("[DB] DataBase instance destroyed");
|
|
2383
|
+
}
|
|
1937
2384
|
}
|
|
1938
2385
|
exports.DataBase = DataBase;
|
|
1939
2386
|
// Errors
|
|
1940
2387
|
DataBase.Errors = GunErrors;
|
|
1941
|
-
const createGun = (config) => {
|
|
1942
|
-
const gunInstance = (0, gun_1.default)(config);
|
|
1943
|
-
return gunInstance;
|
|
1944
|
-
};
|
|
1945
|
-
exports.createGun = createGun;
|
|
1946
|
-
exports.default = gun_1.default;
|