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
|
@@ -96755,9 +96755,15 @@ var AbstractRelay = class {
|
|
|
96755
96755
|
publishTimeout = 4400;
|
|
96756
96756
|
pingFrequency = 2e4;
|
|
96757
96757
|
pingTimeout = 2e4;
|
|
96758
|
+
resubscribeBackoff = [1e4, 1e4, 1e4, 2e4, 2e4, 3e4, 6e4];
|
|
96758
96759
|
openSubs = /* @__PURE__ */ new Map();
|
|
96759
96760
|
enablePing;
|
|
96761
|
+
enableReconnect;
|
|
96760
96762
|
connectionTimeoutHandle;
|
|
96763
|
+
reconnectTimeoutHandle;
|
|
96764
|
+
pingTimeoutHandle;
|
|
96765
|
+
reconnectAttempts = 0;
|
|
96766
|
+
closedIntentionally = false;
|
|
96761
96767
|
connectionPromise;
|
|
96762
96768
|
openCountRequests = /* @__PURE__ */ new Map();
|
|
96763
96769
|
openEventPublishes = /* @__PURE__ */ new Map();
|
|
@@ -96774,6 +96780,7 @@ var AbstractRelay = class {
|
|
|
96774
96780
|
this.verifyEvent = opts.verifyEvent;
|
|
96775
96781
|
this._WebSocket = opts.websocketImplementation || WebSocket;
|
|
96776
96782
|
this.enablePing = opts.enablePing;
|
|
96783
|
+
this.enableReconnect = opts.enableReconnect || false;
|
|
96777
96784
|
}
|
|
96778
96785
|
static async connect(url, opts) {
|
|
96779
96786
|
const relay = new AbstractRelay(url, opts);
|
|
@@ -96797,6 +96804,32 @@ var AbstractRelay = class {
|
|
|
96797
96804
|
get connected() {
|
|
96798
96805
|
return this._connected;
|
|
96799
96806
|
}
|
|
96807
|
+
async reconnect() {
|
|
96808
|
+
const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)];
|
|
96809
|
+
this.reconnectAttempts++;
|
|
96810
|
+
this.reconnectTimeoutHandle = setTimeout(async () => {
|
|
96811
|
+
try {
|
|
96812
|
+
await this.connect();
|
|
96813
|
+
} catch (err) {
|
|
96814
|
+
}
|
|
96815
|
+
}, backoff);
|
|
96816
|
+
}
|
|
96817
|
+
handleHardClose(reason) {
|
|
96818
|
+
if (this.pingTimeoutHandle) {
|
|
96819
|
+
clearTimeout(this.pingTimeoutHandle);
|
|
96820
|
+
this.pingTimeoutHandle = void 0;
|
|
96821
|
+
}
|
|
96822
|
+
this._connected = false;
|
|
96823
|
+
this.connectionPromise = void 0;
|
|
96824
|
+
const wasIntentional = this.closedIntentionally;
|
|
96825
|
+
this.closedIntentionally = false;
|
|
96826
|
+
this.onclose?.();
|
|
96827
|
+
if (this.enableReconnect && !wasIntentional) {
|
|
96828
|
+
this.reconnect();
|
|
96829
|
+
} else {
|
|
96830
|
+
this.closeAllSubscriptions(reason);
|
|
96831
|
+
}
|
|
96832
|
+
}
|
|
96800
96833
|
async connect() {
|
|
96801
96834
|
if (this.connectionPromise)
|
|
96802
96835
|
return this.connectionPromise;
|
|
@@ -96817,8 +96850,20 @@ var AbstractRelay = class {
|
|
|
96817
96850
|
return;
|
|
96818
96851
|
}
|
|
96819
96852
|
this.ws.onopen = () => {
|
|
96853
|
+
if (this.reconnectTimeoutHandle) {
|
|
96854
|
+
clearTimeout(this.reconnectTimeoutHandle);
|
|
96855
|
+
this.reconnectTimeoutHandle = void 0;
|
|
96856
|
+
}
|
|
96820
96857
|
clearTimeout(this.connectionTimeoutHandle);
|
|
96821
96858
|
this._connected = true;
|
|
96859
|
+
this.reconnectAttempts = 0;
|
|
96860
|
+
for (const sub of this.openSubs.values()) {
|
|
96861
|
+
sub.eosed = false;
|
|
96862
|
+
if (typeof this.enableReconnect === "function") {
|
|
96863
|
+
sub.filters = this.enableReconnect(sub.filters);
|
|
96864
|
+
}
|
|
96865
|
+
sub.fire();
|
|
96866
|
+
}
|
|
96822
96867
|
if (this.enablePing) {
|
|
96823
96868
|
this.pingpong();
|
|
96824
96869
|
}
|
|
@@ -96827,28 +96872,22 @@ var AbstractRelay = class {
|
|
|
96827
96872
|
this.ws.onerror = (ev) => {
|
|
96828
96873
|
clearTimeout(this.connectionTimeoutHandle);
|
|
96829
96874
|
reject(ev.message || "websocket error");
|
|
96830
|
-
this.
|
|
96831
|
-
this.connectionPromise = void 0;
|
|
96832
|
-
this.onclose?.();
|
|
96833
|
-
this.closeAllSubscriptions("relay connection errored");
|
|
96875
|
+
this.handleHardClose("relay connection errored");
|
|
96834
96876
|
};
|
|
96835
96877
|
this.ws.onclose = (ev) => {
|
|
96836
96878
|
clearTimeout(this.connectionTimeoutHandle);
|
|
96837
96879
|
reject(ev.message || "websocket closed");
|
|
96838
|
-
this.
|
|
96839
|
-
this.connectionPromise = void 0;
|
|
96840
|
-
this.onclose?.();
|
|
96841
|
-
this.closeAllSubscriptions("relay connection closed");
|
|
96880
|
+
this.handleHardClose("relay connection closed");
|
|
96842
96881
|
};
|
|
96843
96882
|
this.ws.onmessage = this._onmessage.bind(this);
|
|
96844
96883
|
});
|
|
96845
96884
|
return this.connectionPromise;
|
|
96846
96885
|
}
|
|
96847
|
-
|
|
96848
|
-
return new Promise((
|
|
96886
|
+
waitForPingPong() {
|
|
96887
|
+
return new Promise((resolve) => {
|
|
96849
96888
|
;
|
|
96850
|
-
this.ws
|
|
96851
|
-
this.ws
|
|
96889
|
+
this.ws.once("pong", () => resolve(true));
|
|
96890
|
+
this.ws.ping();
|
|
96852
96891
|
});
|
|
96853
96892
|
}
|
|
96854
96893
|
async waitForDummyReq() {
|
|
@@ -96865,16 +96904,15 @@ var AbstractRelay = class {
|
|
|
96865
96904
|
async pingpong() {
|
|
96866
96905
|
if (this.ws?.readyState === 1) {
|
|
96867
96906
|
const result = await Promise.any([
|
|
96868
|
-
this.ws && this.ws.ping && this.ws.
|
|
96907
|
+
this.ws && this.ws.ping && this.ws.once ? this.waitForPingPong() : this.waitForDummyReq(),
|
|
96869
96908
|
new Promise((res) => setTimeout(() => res(false), this.pingTimeout))
|
|
96870
96909
|
]);
|
|
96871
96910
|
if (result) {
|
|
96872
|
-
setTimeout(() => this.pingpong(), this.pingFrequency);
|
|
96911
|
+
this.pingTimeoutHandle = setTimeout(() => this.pingpong(), this.pingFrequency);
|
|
96873
96912
|
} else {
|
|
96874
|
-
this.
|
|
96875
|
-
|
|
96876
|
-
|
|
96877
|
-
this.ws?.close();
|
|
96913
|
+
if (this.ws?.readyState === this._WebSocket.OPEN) {
|
|
96914
|
+
this.ws?.close();
|
|
96915
|
+
}
|
|
96878
96916
|
}
|
|
96879
96917
|
}
|
|
96880
96918
|
}
|
|
@@ -97037,10 +97075,21 @@ var AbstractRelay = class {
|
|
|
97037
97075
|
return subscription;
|
|
97038
97076
|
}
|
|
97039
97077
|
close() {
|
|
97078
|
+
this.closedIntentionally = true;
|
|
97079
|
+
if (this.reconnectTimeoutHandle) {
|
|
97080
|
+
clearTimeout(this.reconnectTimeoutHandle);
|
|
97081
|
+
this.reconnectTimeoutHandle = void 0;
|
|
97082
|
+
}
|
|
97083
|
+
if (this.pingTimeoutHandle) {
|
|
97084
|
+
clearTimeout(this.pingTimeoutHandle);
|
|
97085
|
+
this.pingTimeoutHandle = void 0;
|
|
97086
|
+
}
|
|
97040
97087
|
this.closeAllSubscriptions("relay connection closed by us");
|
|
97041
97088
|
this._connected = false;
|
|
97042
97089
|
this.onclose?.();
|
|
97043
|
-
this.ws?.
|
|
97090
|
+
if (this.ws?.readyState === this._WebSocket.OPEN) {
|
|
97091
|
+
this.ws?.close();
|
|
97092
|
+
}
|
|
97044
97093
|
}
|
|
97045
97094
|
_onmessage(ev) {
|
|
97046
97095
|
this.incomingMessageQueue.enqueue(ev.data);
|
|
@@ -97113,11 +97162,11 @@ try {
|
|
|
97113
97162
|
} catch {
|
|
97114
97163
|
}
|
|
97115
97164
|
var Relay = class extends AbstractRelay {
|
|
97116
|
-
constructor(url) {
|
|
97117
|
-
super(url, { verifyEvent, websocketImplementation: _WebSocket });
|
|
97165
|
+
constructor(url, options) {
|
|
97166
|
+
super(url, { verifyEvent, websocketImplementation: _WebSocket, ...options });
|
|
97118
97167
|
}
|
|
97119
|
-
static async connect(url) {
|
|
97120
|
-
const relay = new Relay(url);
|
|
97168
|
+
static async connect(url, options) {
|
|
97169
|
+
const relay = new Relay(url, options);
|
|
97121
97170
|
await relay.connect();
|
|
97122
97171
|
return relay;
|
|
97123
97172
|
}
|
|
@@ -97130,12 +97179,14 @@ var AbstractSimplePool = class {
|
|
|
97130
97179
|
trackRelays = false;
|
|
97131
97180
|
verifyEvent;
|
|
97132
97181
|
enablePing;
|
|
97182
|
+
enableReconnect;
|
|
97133
97183
|
trustedRelayURLs = /* @__PURE__ */ new Set();
|
|
97134
97184
|
_WebSocket;
|
|
97135
97185
|
constructor(opts) {
|
|
97136
97186
|
this.verifyEvent = opts.verifyEvent;
|
|
97137
97187
|
this._WebSocket = opts.websocketImplementation;
|
|
97138
97188
|
this.enablePing = opts.enablePing;
|
|
97189
|
+
this.enableReconnect = opts.enableReconnect;
|
|
97139
97190
|
}
|
|
97140
97191
|
async ensureRelay(url, params) {
|
|
97141
97192
|
url = normalizeURL(url);
|
|
@@ -97144,10 +97195,13 @@ var AbstractSimplePool = class {
|
|
|
97144
97195
|
relay = new AbstractRelay(url, {
|
|
97145
97196
|
verifyEvent: this.trustedRelayURLs.has(url) ? alwaysTrue : this.verifyEvent,
|
|
97146
97197
|
websocketImplementation: this._WebSocket,
|
|
97147
|
-
enablePing: this.enablePing
|
|
97198
|
+
enablePing: this.enablePing,
|
|
97199
|
+
enableReconnect: this.enableReconnect
|
|
97148
97200
|
});
|
|
97149
97201
|
relay.onclose = () => {
|
|
97150
|
-
|
|
97202
|
+
if (relay && !relay.enableReconnect) {
|
|
97203
|
+
this.relays.delete(url);
|
|
97204
|
+
}
|
|
97151
97205
|
};
|
|
97152
97206
|
if (params?.connectionTimeout)
|
|
97153
97207
|
relay.connectionTimeout = params.connectionTimeout;
|
|
@@ -98642,13 +98696,13 @@ async function getZapEndpoint(metadata) {
|
|
|
98642
98696
|
try {
|
|
98643
98697
|
let lnurl = "";
|
|
98644
98698
|
let { lud06, lud16 } = JSON.parse(metadata.content);
|
|
98645
|
-
if (
|
|
98699
|
+
if (lud16) {
|
|
98700
|
+
let [name, domain] = lud16.split("@");
|
|
98701
|
+
lnurl = new URL(`/.well-known/lnurlp/${name}`, `https://${domain}`).toString();
|
|
98702
|
+
} else if (lud06) {
|
|
98646
98703
|
let { words } = import_base4.bech32.decode(lud06, 1e3);
|
|
98647
98704
|
let data = import_base4.bech32.fromWords(words);
|
|
98648
98705
|
lnurl = utf8Decoder.decode(data);
|
|
98649
|
-
} else if (lud16) {
|
|
98650
|
-
let [name, domain] = lud16.split("@");
|
|
98651
|
-
lnurl = new URL(`/.well-known/lnurlp/${name}`, `https://${domain}`).toString();
|
|
98652
98706
|
} else {
|
|
98653
98707
|
return null;
|
|
98654
98708
|
}
|
|
@@ -145094,38 +145148,101 @@ module.exports = function whichTypedArray(value) {
|
|
|
145094
145148
|
/*!*****************************************!*\
|
|
145095
145149
|
!*** ./src/config/simplified-config.ts ***!
|
|
145096
145150
|
\*****************************************/
|
|
145097
|
-
/***/ ((__unused_webpack_module, exports)
|
|
145151
|
+
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
145098
145152
|
|
|
145099
145153
|
"use strict";
|
|
145100
145154
|
|
|
145101
145155
|
/**
|
|
145102
145156
|
* Simplified configuration options to reduce complexity
|
|
145103
145157
|
* Provides sensible defaults and easy-to-use presets
|
|
145158
|
+
*
|
|
145159
|
+
* NOTE: This file is deprecated. ShogunCore now requires an existing Gun instance.
|
|
145160
|
+
* Use the examples in the examples/ directory for proper usage.
|
|
145104
145161
|
*/
|
|
145162
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
145163
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
145164
|
+
};
|
|
145105
145165
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
145106
|
-
exports.QuickConfig = exports.ConfigHelpers = exports.ShogunConfigBuilder = exports.ShogunPresets = void 0;
|
|
145166
|
+
exports.QuickConfig = exports.ConfigHelpers = exports.ShogunConfigBuilder = exports.ShogunPresets = exports.GunInstanceHelpers = void 0;
|
|
145167
|
+
const gun_1 = __importDefault(__webpack_require__(/*! gun/gun */ "./node_modules/gun/gun.js"));
|
|
145168
|
+
__webpack_require__(/*! gun/lib/then */ "./node_modules/gun/lib/then.js");
|
|
145169
|
+
__webpack_require__(/*! gun/lib/radix */ "./node_modules/gun/lib/radix.js");
|
|
145170
|
+
__webpack_require__(/*! gun/lib/radisk */ "./node_modules/gun/lib/radisk.js");
|
|
145171
|
+
__webpack_require__(/*! gun/lib/store */ "./node_modules/gun/lib/store.js");
|
|
145172
|
+
__webpack_require__(/*! gun/lib/rindexed */ "./node_modules/gun/lib/rindexed.js");
|
|
145173
|
+
__webpack_require__(/*! gun/lib/webrtc */ "./node_modules/gun/lib/webrtc.js");
|
|
145174
|
+
/**
|
|
145175
|
+
* Helper functions to create Gun instances with common configurations
|
|
145176
|
+
* These functions create Gun instances that can be passed to ShogunCore
|
|
145177
|
+
*/
|
|
145178
|
+
exports.GunInstanceHelpers = {
|
|
145179
|
+
/**
|
|
145180
|
+
* Create a minimal Gun instance for simple apps
|
|
145181
|
+
*/
|
|
145182
|
+
minimal: () => (0, gun_1.default)({
|
|
145183
|
+
peers: ["https://shogunnode.scobrudot.dev/gun"],
|
|
145184
|
+
localStorage: true,
|
|
145185
|
+
}),
|
|
145186
|
+
/**
|
|
145187
|
+
* Create a development Gun instance with local storage
|
|
145188
|
+
*/
|
|
145189
|
+
development: () => (0, gun_1.default)({
|
|
145190
|
+
peers: ["https://shogunnode.scobrudot.dev/gun"],
|
|
145191
|
+
localStorage: true,
|
|
145192
|
+
radisk: false,
|
|
145193
|
+
}),
|
|
145194
|
+
/**
|
|
145195
|
+
* Create a production Gun instance with multiple peers
|
|
145196
|
+
*/
|
|
145197
|
+
production: (customPeers) => (0, gun_1.default)({
|
|
145198
|
+
peers: customPeers || [
|
|
145199
|
+
"https://shogunnode.scobrudot.dev/gun",
|
|
145200
|
+
"https://peer.wallie.io/gun",
|
|
145201
|
+
],
|
|
145202
|
+
localStorage: true,
|
|
145203
|
+
radisk: true,
|
|
145204
|
+
}),
|
|
145205
|
+
/**
|
|
145206
|
+
* Create an offline-first Gun instance
|
|
145207
|
+
*/
|
|
145208
|
+
offline: () => (0, gun_1.default)({
|
|
145209
|
+
peers: [],
|
|
145210
|
+
localStorage: true,
|
|
145211
|
+
radisk: true,
|
|
145212
|
+
}),
|
|
145213
|
+
/**
|
|
145214
|
+
* Create a Gun instance for Web3-enabled apps
|
|
145215
|
+
*/
|
|
145216
|
+
web3: () => (0, gun_1.default)({
|
|
145217
|
+
peers: ["https://shogunnode.scobrudot.dev/gun"],
|
|
145218
|
+
localStorage: true,
|
|
145219
|
+
}),
|
|
145220
|
+
/**
|
|
145221
|
+
* Create a Gun instance for WebAuthn-enabled apps
|
|
145222
|
+
*/
|
|
145223
|
+
webauthn: () => (0, gun_1.default)({
|
|
145224
|
+
peers: ["https://shogunnode.scobrudot.dev/gun"],
|
|
145225
|
+
localStorage: true,
|
|
145226
|
+
}),
|
|
145227
|
+
};
|
|
145107
145228
|
/**
|
|
145108
145229
|
* Preset configurations for common use cases
|
|
145230
|
+
* @deprecated Use GunInstanceHelpers to create Gun instances and pass them to ShogunCore
|
|
145109
145231
|
*/
|
|
145110
145232
|
exports.ShogunPresets = {
|
|
145111
145233
|
/**
|
|
145112
145234
|
* Minimal configuration for simple apps
|
|
145235
|
+
* @deprecated Use GunInstanceHelpers.minimal() instead
|
|
145113
145236
|
*/
|
|
145114
145237
|
minimal: () => ({
|
|
145115
|
-
|
|
145116
|
-
peers: ["https://relay.shogun-eco.xyz/gun"],
|
|
145117
|
-
localStorage: true,
|
|
145118
|
-
},
|
|
145238
|
+
gunInstance: exports.GunInstanceHelpers.minimal(),
|
|
145119
145239
|
}),
|
|
145120
145240
|
/**
|
|
145121
145241
|
* Development configuration with local storage
|
|
145242
|
+
* @deprecated Use GunInstanceHelpers.development() instead
|
|
145122
145243
|
*/
|
|
145123
145244
|
development: () => ({
|
|
145124
|
-
|
|
145125
|
-
peers: ["https://relay.shogun-eco.xyz/gun"],
|
|
145126
|
-
localStorage: true,
|
|
145127
|
-
radisk: false,
|
|
145128
|
-
},
|
|
145245
|
+
gunInstance: exports.GunInstanceHelpers.development(),
|
|
145129
145246
|
timeouts: {
|
|
145130
145247
|
login: 5000,
|
|
145131
145248
|
signup: 5000,
|
|
@@ -145134,16 +145251,10 @@ exports.ShogunPresets = {
|
|
|
145134
145251
|
}),
|
|
145135
145252
|
/**
|
|
145136
145253
|
* Production configuration with multiple peers
|
|
145254
|
+
* @deprecated Use GunInstanceHelpers.production() instead
|
|
145137
145255
|
*/
|
|
145138
145256
|
production: (customPeers) => ({
|
|
145139
|
-
|
|
145140
|
-
peers: customPeers || [
|
|
145141
|
-
"https://relay.shogun-eco.xyz/gun",
|
|
145142
|
-
"https://peer.wallie.io/gun",
|
|
145143
|
-
],
|
|
145144
|
-
localStorage: true,
|
|
145145
|
-
radisk: true,
|
|
145146
|
-
},
|
|
145257
|
+
gunInstance: exports.GunInstanceHelpers.production(customPeers),
|
|
145147
145258
|
timeouts: {
|
|
145148
145259
|
login: 10000,
|
|
145149
145260
|
signup: 10000,
|
|
@@ -145152,62 +145263,59 @@ exports.ShogunPresets = {
|
|
|
145152
145263
|
}),
|
|
145153
145264
|
/**
|
|
145154
145265
|
* Offline-first configuration
|
|
145266
|
+
* @deprecated Use GunInstanceHelpers.offline() instead
|
|
145155
145267
|
*/
|
|
145156
145268
|
offline: () => ({
|
|
145157
|
-
|
|
145158
|
-
peers: [],
|
|
145159
|
-
localStorage: true,
|
|
145160
|
-
radisk: true,
|
|
145161
|
-
},
|
|
145269
|
+
gunInstance: exports.GunInstanceHelpers.offline(),
|
|
145162
145270
|
}),
|
|
145163
145271
|
/**
|
|
145164
145272
|
* Web3-enabled configuration
|
|
145273
|
+
* @deprecated Use GunInstanceHelpers.web3() instead
|
|
145165
145274
|
*/
|
|
145166
145275
|
web3: () => ({
|
|
145167
|
-
|
|
145168
|
-
peers: ["https://relay.shogun-eco.xyz/gun"],
|
|
145169
|
-
localStorage: true,
|
|
145170
|
-
},
|
|
145276
|
+
gunInstance: exports.GunInstanceHelpers.web3(),
|
|
145171
145277
|
web3: {
|
|
145172
145278
|
enabled: true,
|
|
145173
145279
|
},
|
|
145174
145280
|
}),
|
|
145175
145281
|
/**
|
|
145176
145282
|
* WebAuthn-enabled configuration
|
|
145283
|
+
* @deprecated Use GunInstanceHelpers.webauthn() instead
|
|
145177
145284
|
*/
|
|
145178
145285
|
webauthn: () => ({
|
|
145179
|
-
|
|
145180
|
-
peers: ["https://relay.shogun-eco.xyz/gun"],
|
|
145181
|
-
localStorage: true,
|
|
145182
|
-
},
|
|
145286
|
+
gunInstance: exports.GunInstanceHelpers.webauthn(),
|
|
145183
145287
|
webauthn: {
|
|
145184
145288
|
enabled: true,
|
|
145185
145289
|
rpName: "My Shogun App",
|
|
145186
|
-
rpId: window.location.hostname,
|
|
145290
|
+
rpId: true ? window.location.hostname : 0,
|
|
145187
145291
|
},
|
|
145188
145292
|
}),
|
|
145189
145293
|
};
|
|
145190
145294
|
/**
|
|
145191
145295
|
* Configuration builder for custom setups
|
|
145296
|
+
* @deprecated Use GunInstanceHelpers to create Gun instances and pass them to ShogunCore
|
|
145192
145297
|
*/
|
|
145193
145298
|
class ShogunConfigBuilder {
|
|
145194
145299
|
constructor() {
|
|
145195
145300
|
this.config = {};
|
|
145301
|
+
this.gunOptions = {};
|
|
145196
145302
|
}
|
|
145197
145303
|
/**
|
|
145198
|
-
* Set Gun options
|
|
145304
|
+
* Set Gun options (deprecated - use GunInstanceHelpers instead)
|
|
145305
|
+
* @deprecated Use GunInstanceHelpers to create Gun instances
|
|
145199
145306
|
*/
|
|
145200
|
-
|
|
145201
|
-
this.
|
|
145307
|
+
setGunOptions(options) {
|
|
145308
|
+
this.gunOptions = { ...this.gunOptions, ...options };
|
|
145202
145309
|
return this;
|
|
145203
145310
|
}
|
|
145204
145311
|
/**
|
|
145205
|
-
* Add peers
|
|
145312
|
+
* Add peers (deprecated - use GunInstanceHelpers instead)
|
|
145313
|
+
* @deprecated Use GunInstanceHelpers to create Gun instances
|
|
145206
145314
|
*/
|
|
145207
145315
|
peers(peerList) {
|
|
145208
|
-
this.
|
|
145209
|
-
...this.
|
|
145210
|
-
peers: [...(this.
|
|
145316
|
+
this.gunOptions = {
|
|
145317
|
+
...this.gunOptions,
|
|
145318
|
+
peers: [...(this.gunOptions?.peers || []), ...peerList],
|
|
145211
145319
|
};
|
|
145212
145320
|
return this;
|
|
145213
145321
|
}
|
|
@@ -145245,18 +145353,24 @@ class ShogunConfigBuilder {
|
|
|
145245
145353
|
}
|
|
145246
145354
|
/**
|
|
145247
145355
|
* Build the final configuration
|
|
145356
|
+
* @deprecated Use GunInstanceHelpers to create Gun instances and pass them to ShogunCore
|
|
145248
145357
|
*/
|
|
145249
145358
|
build() {
|
|
145250
|
-
return
|
|
145359
|
+
return {
|
|
145360
|
+
...this.config,
|
|
145361
|
+
gunInstance: (0, gun_1.default)(this.gunOptions),
|
|
145362
|
+
};
|
|
145251
145363
|
}
|
|
145252
145364
|
}
|
|
145253
145365
|
exports.ShogunConfigBuilder = ShogunConfigBuilder;
|
|
145254
145366
|
/**
|
|
145255
145367
|
* Helper functions for common configuration patterns
|
|
145368
|
+
* @deprecated Use GunInstanceHelpers to create Gun instances and pass them to ShogunCore
|
|
145256
145369
|
*/
|
|
145257
145370
|
exports.ConfigHelpers = {
|
|
145258
145371
|
/**
|
|
145259
145372
|
* Create a configuration for a specific environment
|
|
145373
|
+
* @deprecated Use GunInstanceHelpers instead
|
|
145260
145374
|
*/
|
|
145261
145375
|
forEnvironment(env) {
|
|
145262
145376
|
switch (env) {
|
|
@@ -145272,12 +145386,14 @@ exports.ConfigHelpers = {
|
|
|
145272
145386
|
},
|
|
145273
145387
|
/**
|
|
145274
145388
|
* Create a configuration with custom peers
|
|
145389
|
+
* @deprecated Use GunInstanceHelpers.production(peers) instead
|
|
145275
145390
|
*/
|
|
145276
145391
|
withPeers(peers) {
|
|
145277
145392
|
return exports.ShogunPresets.production(peers);
|
|
145278
145393
|
},
|
|
145279
145394
|
/**
|
|
145280
145395
|
* Create a configuration for a specific use case
|
|
145396
|
+
* @deprecated Use GunInstanceHelpers instead
|
|
145281
145397
|
*/
|
|
145282
145398
|
forUseCase(useCase) {
|
|
145283
145399
|
const baseConfig = exports.ShogunPresets.production();
|
|
@@ -145310,26 +145426,32 @@ exports.ConfigHelpers = {
|
|
|
145310
145426
|
};
|
|
145311
145427
|
/**
|
|
145312
145428
|
* Quick configuration functions
|
|
145429
|
+
* @deprecated Use GunInstanceHelpers to create Gun instances and pass them to ShogunCore
|
|
145313
145430
|
*/
|
|
145314
145431
|
exports.QuickConfig = {
|
|
145315
145432
|
/**
|
|
145316
145433
|
* Minimal setup for quick testing
|
|
145434
|
+
* @deprecated Use GunInstanceHelpers.minimal() instead
|
|
145317
145435
|
*/
|
|
145318
145436
|
test: () => exports.ShogunPresets.minimal(),
|
|
145319
145437
|
/**
|
|
145320
145438
|
* Standard setup for most apps
|
|
145439
|
+
* @deprecated Use GunInstanceHelpers.production() instead
|
|
145321
145440
|
*/
|
|
145322
145441
|
standard: () => exports.ShogunPresets.production(),
|
|
145323
145442
|
/**
|
|
145324
145443
|
* Setup with WebAuthn for secure apps
|
|
145444
|
+
* @deprecated Use GunInstanceHelpers.webauthn() instead
|
|
145325
145445
|
*/
|
|
145326
145446
|
secure: () => exports.ShogunPresets.webauthn(),
|
|
145327
145447
|
/**
|
|
145328
145448
|
* Setup with Web3 for crypto apps
|
|
145449
|
+
* @deprecated Use GunInstanceHelpers.web3() instead
|
|
145329
145450
|
*/
|
|
145330
145451
|
crypto: () => exports.ShogunPresets.web3(),
|
|
145331
145452
|
/**
|
|
145332
145453
|
* Offline setup for local development
|
|
145454
|
+
* @deprecated Use GunInstanceHelpers.offline() instead
|
|
145333
145455
|
*/
|
|
145334
145456
|
local: () => exports.ShogunPresets.offline(),
|
|
145335
145457
|
};
|
|
@@ -146898,7 +147020,9 @@ class MLSManager {
|
|
|
146898
147020
|
console.group("🔍 [MLS Debug] Commit Structure");
|
|
146899
147021
|
console.log("commitResult keys:", Object.keys(commitResult));
|
|
146900
147022
|
console.log("commit:", commitResult.commit);
|
|
146901
|
-
|
|
147023
|
+
if (commitResult.commit?.wireformat === "mls_private_message") {
|
|
147024
|
+
console.log("commit.privateMessage:", commitResult.commit.privateMessage);
|
|
147025
|
+
}
|
|
146902
147026
|
console.groupEnd();
|
|
146903
147027
|
// RFC 9420 Section 11.2: Commit Distribution
|
|
146904
147028
|
// ⚠️ IMPORTANT: The returned commit MUST be sent to all existing group members
|
|
@@ -146962,8 +147086,8 @@ class MLSManager {
|
|
|
146962
147086
|
else {
|
|
146963
147087
|
console.log(` Node ${i}:`, {
|
|
146964
147088
|
type: typeof node,
|
|
146965
|
-
isObject: typeof node === "object",
|
|
146966
|
-
hasNodeType:
|
|
147089
|
+
isObject: typeof node === "object" && node !== null,
|
|
147090
|
+
hasNodeType: typeof node === "object" && node !== null && "nodeType" in node,
|
|
146967
147091
|
nodeType: node?.nodeType,
|
|
146968
147092
|
keys: node && typeof node === "object"
|
|
146969
147093
|
? Object.keys(node).slice(0, 5)
|
|
@@ -147040,10 +147164,11 @@ class MLSManager {
|
|
|
147040
147164
|
}
|
|
147041
147165
|
// Decode the message
|
|
147042
147166
|
const decoded = (0, ts_mls_1.decodeMlsMessage)(envelope.ciphertext, 0);
|
|
147043
|
-
if (!decoded) {
|
|
147167
|
+
if (!decoded || decoded.length === 0) {
|
|
147168
|
+
// Changed from 0n to 0 to fix type error
|
|
147044
147169
|
throw new Error("Failed to decode message");
|
|
147045
147170
|
}
|
|
147046
|
-
const
|
|
147171
|
+
const decodedMessage = decoded[0];
|
|
147047
147172
|
if (decodedMessage.wireformat !== "mls_private_message") {
|
|
147048
147173
|
throw new Error("Expected private message");
|
|
147049
147174
|
}
|
|
@@ -147149,7 +147274,7 @@ class MLSManager {
|
|
|
147149
147274
|
}
|
|
147150
147275
|
catch (error) {
|
|
147151
147276
|
console.error("❌ [MLS] Failed to process commit:", error);
|
|
147152
|
-
console.error("❌ [MLS Debug] Error details:", error instanceof Error ? error.stack :
|
|
147277
|
+
console.error("❌ [MLS Debug] Error details:", error instanceof Error ? error.stack : String(error));
|
|
147153
147278
|
console.error("❌ [MLS Debug] Error message:", error instanceof Error ? error.message : String(error));
|
|
147154
147279
|
throw new Error(`Commit processing failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
147155
147280
|
}
|
|
@@ -147169,7 +147294,7 @@ class MLSManager {
|
|
|
147169
147294
|
const removeProposals = memberIndices.map((index) => ({
|
|
147170
147295
|
proposalType: "remove",
|
|
147171
147296
|
remove: {
|
|
147172
|
-
removed: index, //
|
|
147297
|
+
removed: index, // Changed from BigInt(index) to number
|
|
147173
147298
|
},
|
|
147174
147299
|
}));
|
|
147175
147300
|
// Create commit with remove proposals
|
|
@@ -147177,11 +147302,21 @@ class MLSManager {
|
|
|
147177
147302
|
// Update group state
|
|
147178
147303
|
this.groups.set(groupId, commitResult.newState);
|
|
147179
147304
|
// Encode the commit
|
|
147180
|
-
|
|
147181
|
-
|
|
147182
|
-
wireformat
|
|
147183
|
-
|
|
147184
|
-
|
|
147305
|
+
let encodedCommit;
|
|
147306
|
+
if (commitResult.commit &&
|
|
147307
|
+
commitResult.commit.wireformat === "mls_public_message") {
|
|
147308
|
+
encodedCommit = (0, ts_mls_1.encodeMlsMessage)({
|
|
147309
|
+
publicMessage: commitResult.commit
|
|
147310
|
+
.publicMessage,
|
|
147311
|
+
wireformat: "mls_public_message",
|
|
147312
|
+
version: "mls10",
|
|
147313
|
+
});
|
|
147314
|
+
}
|
|
147315
|
+
else {
|
|
147316
|
+
// Fallback or error handling if not a public message
|
|
147317
|
+
// For now, we'll assume it should be public for remove operation.
|
|
147318
|
+
throw new Error("Commit result does not contain a public message for encoding.");
|
|
147319
|
+
}
|
|
147185
147320
|
console.log("✅ [MLS] Members removed");
|
|
147186
147321
|
return encodedCommit;
|
|
147187
147322
|
}
|
|
@@ -147274,9 +147409,15 @@ class MLSManager {
|
|
|
147274
147409
|
const node = state.ratchetTree[i];
|
|
147275
147410
|
if (node &&
|
|
147276
147411
|
node.nodeType === "leaf" &&
|
|
147277
|
-
node.leaf
|
|
147278
|
-
const
|
|
147279
|
-
|
|
147412
|
+
node.leaf.credential) {
|
|
147413
|
+
const credential = node.leaf.credential;
|
|
147414
|
+
if (credential.credentialType === "basic" && credential.identity) {
|
|
147415
|
+
const identity = new TextDecoder().decode(credential.identity);
|
|
147416
|
+
members.push(identity);
|
|
147417
|
+
}
|
|
147418
|
+
else {
|
|
147419
|
+
console.warn("Skipping credential without basic identity:", credential);
|
|
147420
|
+
}
|
|
147280
147421
|
}
|
|
147281
147422
|
}
|
|
147282
147423
|
}
|
|
@@ -148181,6 +148322,13 @@ class SFrameManager {
|
|
|
148181
148322
|
throw new Error(`SFrame key derivation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
148182
148323
|
}
|
|
148183
148324
|
}
|
|
148325
|
+
/**
|
|
148326
|
+
* Set a shared SFrame key (e.g., from another member)
|
|
148327
|
+
*/
|
|
148328
|
+
async setSharedKey(sframeKey) {
|
|
148329
|
+
this.keys.set(sframeKey.keyId, sframeKey);
|
|
148330
|
+
console.log(`✅ [SFrame] Shared key ${sframeKey.keyId} set.`);
|
|
148331
|
+
}
|
|
148184
148332
|
/**
|
|
148185
148333
|
* Set the active encryption key
|
|
148186
148334
|
*/
|
|
@@ -148226,11 +148374,9 @@ class SFrameManager {
|
|
|
148226
148374
|
tagLength: 128, // 128-bit authentication tag
|
|
148227
148375
|
}, sframeKey.key, frameData);
|
|
148228
148376
|
// RFC 9605: SFrame format = header + ciphertext (IV is derived, not transmitted)
|
|
148229
|
-
|
|
148230
|
-
const encrypted = new Uint8Array(header.length + iv.length + ciphertext.byteLength);
|
|
148377
|
+
const encrypted = new Uint8Array(header.length + ciphertext.byteLength);
|
|
148231
148378
|
encrypted.set(header, 0);
|
|
148232
|
-
encrypted.set(
|
|
148233
|
-
encrypted.set(new Uint8Array(ciphertext), header.length + iv.length);
|
|
148379
|
+
encrypted.set(new Uint8Array(ciphertext), header.length);
|
|
148234
148380
|
// Increment frame counter
|
|
148235
148381
|
this.frameCounter++;
|
|
148236
148382
|
return encrypted;
|
|
@@ -148255,20 +148401,17 @@ class SFrameManager {
|
|
|
148255
148401
|
if (!sframeKey) {
|
|
148256
148402
|
throw new Error(`SFrame key ${keyId} not found`);
|
|
148257
148403
|
}
|
|
148258
|
-
//
|
|
148259
|
-
const iv = encryptedFrame.slice(5, 17);
|
|
148260
|
-
// RFC 9605: Verify IV derivation (optional check for debugging)
|
|
148261
|
-
// Reconstruct expected IV from frame count and salt
|
|
148404
|
+
// RFC 9605: IV is derived from frame count and salt (not transmitted)
|
|
148262
148405
|
const counterBytes = new Uint8Array(12);
|
|
148263
148406
|
const counterView = new DataView(counterBytes.buffer);
|
|
148264
148407
|
counterView.setUint32(4, Math.floor(frameCount / 0x100000000), false);
|
|
148265
148408
|
counterView.setUint32(8, frameCount & 0xffffffff, false);
|
|
148266
|
-
const
|
|
148409
|
+
const iv = new Uint8Array(12);
|
|
148267
148410
|
for (let i = 0; i < 12; i++) {
|
|
148268
|
-
|
|
148411
|
+
iv[i] = sframeKey.salt[i] ^ counterBytes[i];
|
|
148269
148412
|
}
|
|
148270
148413
|
// Extract ciphertext (rest of the data)
|
|
148271
|
-
const ciphertext = encryptedFrame.slice(
|
|
148414
|
+
const ciphertext = encryptedFrame.slice(header.length);
|
|
148272
148415
|
// Decrypt the frame with header authentication (RFC 9605 Section 4.3)
|
|
148273
148416
|
const plaintext = await crypto.subtle.decrypt({
|
|
148274
148417
|
name: "AES-GCM",
|
|
@@ -149170,7 +149313,8 @@ class SimpleGunAPI {
|
|
|
149170
149313
|
console.warn("DEPRECATED: putArray() is unreliable with GunDB. Use direct GunDB operations instead.");
|
|
149171
149314
|
try {
|
|
149172
149315
|
const indexed = this.arrayToIndexedObject(arr);
|
|
149173
|
-
|
|
149316
|
+
const node = this.db.getNode(path);
|
|
149317
|
+
node.put(indexed);
|
|
149174
149318
|
return true;
|
|
149175
149319
|
}
|
|
149176
149320
|
catch (error) {
|
|
@@ -149187,7 +149331,14 @@ class SimpleGunAPI {
|
|
|
149187
149331
|
async getArray(path) {
|
|
149188
149332
|
console.warn("DEPRECATED: getArray() is unreliable with GunDB. Use direct GunDB operations instead.");
|
|
149189
149333
|
try {
|
|
149190
|
-
const
|
|
149334
|
+
const node = this.db.getNode(path);
|
|
149335
|
+
const indexedObj = await new Promise((resolve) => {
|
|
149336
|
+
const timeout = setTimeout(() => resolve(null), 2000);
|
|
149337
|
+
node.once((data) => {
|
|
149338
|
+
clearTimeout(timeout);
|
|
149339
|
+
resolve(data);
|
|
149340
|
+
});
|
|
149341
|
+
});
|
|
149191
149342
|
return this.indexedObjectToArray(indexedObj);
|
|
149192
149343
|
}
|
|
149193
149344
|
catch (error) {
|
|
@@ -149472,19 +149623,12 @@ class QuickStart {
|
|
|
149472
149623
|
}
|
|
149473
149624
|
exports.QuickStart = QuickStart;
|
|
149474
149625
|
/**
|
|
149475
|
-
* Auto Quick Start helper - creates a simple API with
|
|
149476
|
-
*
|
|
149626
|
+
* Auto Quick Start helper - creates a simple API with an existing Gun instance
|
|
149627
|
+
* Requires a Gun instance to be passed in
|
|
149477
149628
|
*/
|
|
149478
149629
|
class AutoQuickStart {
|
|
149479
|
-
constructor(
|
|
149480
|
-
|
|
149481
|
-
peers: config?.peers || [],
|
|
149482
|
-
...config,
|
|
149483
|
-
};
|
|
149484
|
-
// Remove appScope from gunConfig as it's not a Gun configuration option
|
|
149485
|
-
delete gunConfig.appScope;
|
|
149486
|
-
this.gunInstance = (0, db_1.createGun)(gunConfig);
|
|
149487
|
-
const appScope = config?.appScope || "shogun";
|
|
149630
|
+
constructor(gunInstance, appScope = "shogun") {
|
|
149631
|
+
this.gunInstance = gunInstance;
|
|
149488
149632
|
this.db = new db_1.DataBase(this.gunInstance, appScope);
|
|
149489
149633
|
this.simpleAPI = new SimpleGunAPI(this.db);
|
|
149490
149634
|
}
|
|
@@ -149513,10 +149657,10 @@ function quickStart(gunInstance, appScope) {
|
|
|
149513
149657
|
return new QuickStart(gunInstance, appScope);
|
|
149514
149658
|
}
|
|
149515
149659
|
/**
|
|
149516
|
-
* Global helper for auto quick setup -
|
|
149660
|
+
* Global helper for auto quick setup - requires existing Gun instance
|
|
149517
149661
|
*/
|
|
149518
|
-
function autoQuickStart(
|
|
149519
|
-
return new AutoQuickStart(
|
|
149662
|
+
function autoQuickStart(gunInstance, appScope = "shogun") {
|
|
149663
|
+
return new AutoQuickStart(gunInstance, appScope);
|
|
149520
149664
|
}
|
|
149521
149665
|
|
|
149522
149666
|
|
|
@@ -149823,6 +149967,7 @@ function randomUUID() {
|
|
|
149823
149967
|
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
149824
149968
|
|
|
149825
149969
|
"use strict";
|
|
149970
|
+
/* provided dependency */ var process = __webpack_require__(/*! process/browser */ "./node_modules/process/browser.js");
|
|
149826
149971
|
|
|
149827
149972
|
/**
|
|
149828
149973
|
* GunDB class with enhanced features:
|
|
@@ -149867,17 +150012,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
149867
150012
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
149868
150013
|
};
|
|
149869
150014
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
149870
|
-
exports.
|
|
149871
|
-
const gun_1 = __importDefault(__webpack_require__(/*! gun/gun */ "./node_modules/gun/gun.js"));
|
|
149872
|
-
exports.Gun = gun_1.default;
|
|
150015
|
+
exports.derive = exports.GunErrors = exports.crypto = exports.RxJS = exports.SEA = exports.DataBase = void 0;
|
|
149873
150016
|
const sea_1 = __importDefault(__webpack_require__(/*! gun/sea */ "./node_modules/gun/sea.js"));
|
|
149874
150017
|
exports.SEA = sea_1.default;
|
|
149875
|
-
__webpack_require__(/*! gun/lib/then */ "./node_modules/gun/lib/then.js");
|
|
149876
|
-
__webpack_require__(/*! gun/lib/radix */ "./node_modules/gun/lib/radix.js");
|
|
149877
|
-
__webpack_require__(/*! gun/lib/radisk */ "./node_modules/gun/lib/radisk.js");
|
|
149878
|
-
__webpack_require__(/*! gun/lib/store */ "./node_modules/gun/lib/store.js");
|
|
149879
|
-
__webpack_require__(/*! gun/lib/rindexed */ "./node_modules/gun/lib/rindexed.js");
|
|
149880
|
-
__webpack_require__(/*! gun/lib/webrtc */ "./node_modules/gun/lib/webrtc.js");
|
|
149881
150018
|
const derive_1 = __importDefault(__webpack_require__(/*! ./derive */ "./src/gundb/derive.ts"));
|
|
149882
150019
|
exports.derive = derive_1.default;
|
|
149883
150020
|
const errorHandler_1 = __webpack_require__(/*! ../utils/errorHandler */ "./src/utils/errorHandler.ts");
|
|
@@ -149908,11 +150045,17 @@ class DataBase {
|
|
|
149908
150045
|
constructor(gun, appScope = "shogun", core) {
|
|
149909
150046
|
this.user = null;
|
|
149910
150047
|
this.onAuthCallbacks = [];
|
|
150048
|
+
// Memory leak prevention
|
|
150049
|
+
this._activeTimeouts = new Set();
|
|
150050
|
+
this._activeIntervals = new Set();
|
|
150051
|
+
this._isDestroyed = false;
|
|
149911
150052
|
console.log("[DB] Initializing DataBase");
|
|
149912
150053
|
// Store core reference
|
|
149913
150054
|
this.core = core;
|
|
149914
150055
|
// Initialize event emitter
|
|
149915
150056
|
this.eventEmitter = new eventEmitter_1.EventEmitter();
|
|
150057
|
+
// Setup cleanup handlers
|
|
150058
|
+
this.setupCleanupHandlers();
|
|
149916
150059
|
// Validate Gun instance
|
|
149917
150060
|
if (!gun) {
|
|
149918
150061
|
throw new Error("Gun instance is required but was not provided");
|
|
@@ -149954,7 +150097,7 @@ class DataBase {
|
|
|
149954
150097
|
this.node = this.gun.get(appScope);
|
|
149955
150098
|
console.log("[DB] App scope node initialized");
|
|
149956
150099
|
// Initialize CryptoIdentityManager
|
|
149957
|
-
this._cryptoIdentityManager = new CryptoIdentityManager_1.CryptoIdentityManager(this.core);
|
|
150100
|
+
this._cryptoIdentityManager = new CryptoIdentityManager_1.CryptoIdentityManager(this.core, this);
|
|
149958
150101
|
console.log("[DB] CryptoIdentityManager initialized");
|
|
149959
150102
|
if (sessionResult.success) {
|
|
149960
150103
|
console.log("[DB] Session automatically restored");
|
|
@@ -150206,46 +150349,26 @@ class DataBase {
|
|
|
150206
150349
|
return this.navigateToPath(this.node, path);
|
|
150207
150350
|
}
|
|
150208
150351
|
/**
|
|
150209
|
-
* Gets
|
|
150210
|
-
* @
|
|
150211
|
-
* @returns Promise resolving to the data
|
|
150212
|
-
*/
|
|
150213
|
-
async getData(path) {
|
|
150214
|
-
const node = this.navigateToPath(this.node, path);
|
|
150215
|
-
return new Promise((resolve, reject) => {
|
|
150216
|
-
node.once((data) => {
|
|
150217
|
-
resolve(data);
|
|
150218
|
-
});
|
|
150219
|
-
});
|
|
150220
|
-
}
|
|
150221
|
-
/**
|
|
150222
|
-
* Puts data at the specified path
|
|
150223
|
-
* @param path Path to store data
|
|
150224
|
-
* @param data Data to store
|
|
150225
|
-
* @returns Promise resolving to operation result
|
|
150352
|
+
* Gets the Gun instance for direct operations
|
|
150353
|
+
* @returns Gun instance
|
|
150226
150354
|
*/
|
|
150227
|
-
|
|
150228
|
-
|
|
150229
|
-
return await node.put(data).then();
|
|
150355
|
+
getGunInstance() {
|
|
150356
|
+
return this.gun;
|
|
150230
150357
|
}
|
|
150231
150358
|
/**
|
|
150232
|
-
*
|
|
150233
|
-
* @
|
|
150234
|
-
* @param data Data to store
|
|
150235
|
-
* @returns Promise resolving to operation result
|
|
150359
|
+
* Gets the app scope node for direct operations
|
|
150360
|
+
* @returns Gun node
|
|
150236
150361
|
*/
|
|
150237
|
-
|
|
150238
|
-
|
|
150239
|
-
return await node.set(data).then();
|
|
150362
|
+
getAppNode() {
|
|
150363
|
+
return this.node;
|
|
150240
150364
|
}
|
|
150241
150365
|
/**
|
|
150242
|
-
*
|
|
150243
|
-
* @param path Path to
|
|
150244
|
-
* @returns
|
|
150366
|
+
* Helper method to get a node at a specific path for direct GUN operations
|
|
150367
|
+
* @param path Path to the node
|
|
150368
|
+
* @returns Gun node at the specified path
|
|
150245
150369
|
*/
|
|
150246
|
-
|
|
150247
|
-
|
|
150248
|
-
return await node.put(null).then();
|
|
150370
|
+
getNode(path) {
|
|
150371
|
+
return this.navigateToPath(this.node, path);
|
|
150249
150372
|
}
|
|
150250
150373
|
/**
|
|
150251
150374
|
* Checks if a user is currently logged in
|
|
@@ -150403,6 +150526,10 @@ class DataBase {
|
|
|
150403
150526
|
// Log out user
|
|
150404
150527
|
try {
|
|
150405
150528
|
currentUser.leave();
|
|
150529
|
+
// Force clear any pending authentication
|
|
150530
|
+
if (currentUser._ && currentUser._.sea) {
|
|
150531
|
+
currentUser._.sea = null;
|
|
150532
|
+
}
|
|
150406
150533
|
}
|
|
150407
150534
|
catch (gunError) {
|
|
150408
150535
|
console.error("Error during Gun logout:", gunError);
|
|
@@ -150511,136 +150638,6 @@ class DataBase {
|
|
|
150511
150638
|
// Validate password strength
|
|
150512
150639
|
return this.validatePasswordStrength(password);
|
|
150513
150640
|
}
|
|
150514
|
-
/**
|
|
150515
|
-
* Creates a new user in Gun
|
|
150516
|
-
*/
|
|
150517
|
-
async createNewUser(username, password) {
|
|
150518
|
-
return new Promise((resolve) => {
|
|
150519
|
-
// Validate inputs before creating user
|
|
150520
|
-
if (!username ||
|
|
150521
|
-
typeof username !== "string" ||
|
|
150522
|
-
username.trim().length === 0) {
|
|
150523
|
-
resolve({ success: false, error: "Invalid username provided" });
|
|
150524
|
-
return;
|
|
150525
|
-
}
|
|
150526
|
-
if (!password ||
|
|
150527
|
-
typeof password !== "string" ||
|
|
150528
|
-
password.length === 0) {
|
|
150529
|
-
resolve({ success: false, error: "Invalid password provided" });
|
|
150530
|
-
return;
|
|
150531
|
-
}
|
|
150532
|
-
// Normalize username
|
|
150533
|
-
const normalizedUsername = username.trim().toLowerCase();
|
|
150534
|
-
if (normalizedUsername.length === 0) {
|
|
150535
|
-
resolve({
|
|
150536
|
-
success: false,
|
|
150537
|
-
error: "Username cannot be empty",
|
|
150538
|
-
});
|
|
150539
|
-
return;
|
|
150540
|
-
}
|
|
150541
|
-
this.gun.user().create(normalizedUsername, password, (ack) => {
|
|
150542
|
-
if (ack.err) {
|
|
150543
|
-
console.error(`User creation error: ${ack.err}`);
|
|
150544
|
-
resolve({ success: false, error: ack.err });
|
|
150545
|
-
}
|
|
150546
|
-
else {
|
|
150547
|
-
// Validate that we got a userPub from creation
|
|
150548
|
-
const userPub = ack.pub;
|
|
150549
|
-
if (!userPub ||
|
|
150550
|
-
typeof userPub !== "string" ||
|
|
150551
|
-
userPub.trim().length === 0) {
|
|
150552
|
-
console.error("User creation successful but no userPub returned:", ack);
|
|
150553
|
-
resolve({
|
|
150554
|
-
success: false,
|
|
150555
|
-
error: "User creation successful but no userPub returned",
|
|
150556
|
-
});
|
|
150557
|
-
}
|
|
150558
|
-
else {
|
|
150559
|
-
resolve({ success: true, userPub: userPub });
|
|
150560
|
-
}
|
|
150561
|
-
}
|
|
150562
|
-
});
|
|
150563
|
-
});
|
|
150564
|
-
}
|
|
150565
|
-
/**
|
|
150566
|
-
* Authenticates user after creation
|
|
150567
|
-
*/
|
|
150568
|
-
async authenticateNewUser(username, password, pair) {
|
|
150569
|
-
return new Promise((resolve) => {
|
|
150570
|
-
// Validate inputs before authentication
|
|
150571
|
-
if (!username ||
|
|
150572
|
-
typeof username !== "string" ||
|
|
150573
|
-
username.trim().length === 0) {
|
|
150574
|
-
resolve({ success: false, error: "Invalid username provided" });
|
|
150575
|
-
return;
|
|
150576
|
-
}
|
|
150577
|
-
// Skip password validation when using pair authentication
|
|
150578
|
-
if (!pair &&
|
|
150579
|
-
(!password || typeof password !== "string" || password.length === 0)) {
|
|
150580
|
-
resolve({ success: false, error: "Invalid password provided" });
|
|
150581
|
-
return;
|
|
150582
|
-
}
|
|
150583
|
-
// Normalize username to match what was used in creation
|
|
150584
|
-
const normalizedUsername = username.trim().toLowerCase();
|
|
150585
|
-
if (normalizedUsername.length === 0) {
|
|
150586
|
-
resolve({
|
|
150587
|
-
success: false,
|
|
150588
|
-
error: "Username cannot be empty",
|
|
150589
|
-
});
|
|
150590
|
-
return;
|
|
150591
|
-
}
|
|
150592
|
-
if (pair) {
|
|
150593
|
-
this.gun.user().auth(pair, (ack) => {
|
|
150594
|
-
if (ack.err) {
|
|
150595
|
-
console.error(`Authentication after creation failed: ${ack.err}`);
|
|
150596
|
-
resolve({ success: false, error: ack.err });
|
|
150597
|
-
}
|
|
150598
|
-
else {
|
|
150599
|
-
// Add a small delay to ensure user state is properly set
|
|
150600
|
-
setTimeout(() => {
|
|
150601
|
-
// Extract userPub from multiple possible sources
|
|
150602
|
-
const userPub = ack.pub || this.gun.user().is?.pub || ack.user?.pub;
|
|
150603
|
-
if (!userPub) {
|
|
150604
|
-
console.error("Authentication successful but no userPub found");
|
|
150605
|
-
resolve({
|
|
150606
|
-
success: false,
|
|
150607
|
-
error: "No userPub returned from authentication",
|
|
150608
|
-
});
|
|
150609
|
-
}
|
|
150610
|
-
else {
|
|
150611
|
-
resolve({ success: true, userPub: userPub });
|
|
150612
|
-
}
|
|
150613
|
-
}, 100);
|
|
150614
|
-
}
|
|
150615
|
-
});
|
|
150616
|
-
}
|
|
150617
|
-
else {
|
|
150618
|
-
this.gun.user().auth(normalizedUsername, password, (ack) => {
|
|
150619
|
-
if (ack.err) {
|
|
150620
|
-
console.error(`Authentication after creation failed: ${ack.err}`);
|
|
150621
|
-
resolve({ success: false, error: ack.err });
|
|
150622
|
-
}
|
|
150623
|
-
else {
|
|
150624
|
-
// Add a small delay to ensure user state is properly set
|
|
150625
|
-
setTimeout(() => {
|
|
150626
|
-
// Extract userPub from multiple possible sources
|
|
150627
|
-
const userPub = ack.pub || this.gun.user().is?.pub || ack.user?.pub;
|
|
150628
|
-
if (!userPub) {
|
|
150629
|
-
console.error("Authentication successful but no userPub found");
|
|
150630
|
-
resolve({
|
|
150631
|
-
success: false,
|
|
150632
|
-
error: "No userPub returned from authentication",
|
|
150633
|
-
});
|
|
150634
|
-
}
|
|
150635
|
-
else {
|
|
150636
|
-
resolve({ success: true, userPub: userPub });
|
|
150637
|
-
}
|
|
150638
|
-
}, 100);
|
|
150639
|
-
}
|
|
150640
|
-
});
|
|
150641
|
-
}
|
|
150642
|
-
});
|
|
150643
|
-
}
|
|
150644
150641
|
/**
|
|
150645
150642
|
* Signs up a new user using direct Gun authentication
|
|
150646
150643
|
* @param username Username
|
|
@@ -150648,13 +150645,34 @@ class DataBase {
|
|
|
150648
150645
|
* @param pair Optional SEA pair for Web3 login
|
|
150649
150646
|
* @returns Promise resolving to signup result
|
|
150650
150647
|
*/
|
|
150651
|
-
async signUp(username, password, pair) {
|
|
150648
|
+
async signUp(username, password, pair, retryCount = 0, maxRetries = 3) {
|
|
150652
150649
|
try {
|
|
150650
|
+
console.log(`🔄 [SIGNUP] Attempting signup for: ${username}`);
|
|
150653
150651
|
// Validate credentials with enhanced security
|
|
150654
150652
|
const validation = this.validateSignupCredentials(username, password, pair);
|
|
150655
150653
|
if (!validation.valid) {
|
|
150656
150654
|
return { success: false, error: validation.error };
|
|
150657
150655
|
}
|
|
150656
|
+
// Check if authentication is in progress and retry if needed
|
|
150657
|
+
if (this.isAuthInProgress()) {
|
|
150658
|
+
if (retryCount < maxRetries) {
|
|
150659
|
+
console.warn(`Authentication in progress during signup, retrying... (${retryCount + 1}/${maxRetries})`);
|
|
150660
|
+
this.resetAuthState();
|
|
150661
|
+
const baseDelay = 100 * Math.pow(2, retryCount);
|
|
150662
|
+
const jitter = Math.random() * 100;
|
|
150663
|
+
const delay = Math.min(baseDelay + jitter, 2000);
|
|
150664
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
150665
|
+
return this.signUp(username, password, pair, retryCount + 1, maxRetries);
|
|
150666
|
+
}
|
|
150667
|
+
else {
|
|
150668
|
+
console.error("Max retries exceeded for signup due to concurrent operations");
|
|
150669
|
+
this.resetAuthState();
|
|
150670
|
+
return {
|
|
150671
|
+
success: false,
|
|
150672
|
+
error: "Signup failed after multiple retries due to concurrent operations",
|
|
150673
|
+
};
|
|
150674
|
+
}
|
|
150675
|
+
}
|
|
150658
150676
|
let createResult;
|
|
150659
150677
|
if (pair) {
|
|
150660
150678
|
// For Web3/plugin authentication, use pair-based creation
|
|
@@ -150662,15 +150680,17 @@ class DataBase {
|
|
|
150662
150680
|
}
|
|
150663
150681
|
else {
|
|
150664
150682
|
// For password authentication, use standard creation
|
|
150665
|
-
createResult = await this.
|
|
150683
|
+
createResult = await this.createNewUserFixed(username, password);
|
|
150666
150684
|
}
|
|
150667
150685
|
if (!createResult.success) {
|
|
150686
|
+
// Reset auth state after failed creation to prevent blocking future operations
|
|
150687
|
+
this.resetAuthState();
|
|
150668
150688
|
return { success: false, error: createResult.error };
|
|
150669
150689
|
}
|
|
150670
150690
|
// Add a small delay to ensure user is properly registered
|
|
150671
150691
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
150672
150692
|
// Authenticate the newly created user
|
|
150673
|
-
const authResult = await this.
|
|
150693
|
+
const authResult = await this.authenticateNewUserFixed(username, password, pair);
|
|
150674
150694
|
if (!authResult.success) {
|
|
150675
150695
|
return { success: false, error: authResult.error };
|
|
150676
150696
|
}
|
|
@@ -150747,6 +150767,100 @@ class DataBase {
|
|
|
150747
150767
|
resolve({ success: true, userPub: pair.pub });
|
|
150748
150768
|
});
|
|
150749
150769
|
}
|
|
150770
|
+
/**
|
|
150771
|
+
* Creates a new user in Gun without waiting for acknowledgment
|
|
150772
|
+
*/
|
|
150773
|
+
async createNewUserFixed(username, password) {
|
|
150774
|
+
return new Promise((resolve) => {
|
|
150775
|
+
// Validate inputs before creating user
|
|
150776
|
+
if (!username ||
|
|
150777
|
+
typeof username !== "string" ||
|
|
150778
|
+
username.trim().length === 0) {
|
|
150779
|
+
resolve({ success: false, error: "Invalid username provided" });
|
|
150780
|
+
return;
|
|
150781
|
+
}
|
|
150782
|
+
if (!password ||
|
|
150783
|
+
typeof password !== "string" ||
|
|
150784
|
+
password.length === 0) {
|
|
150785
|
+
resolve({ success: false, error: "Invalid password provided" });
|
|
150786
|
+
return;
|
|
150787
|
+
}
|
|
150788
|
+
// Normalize username
|
|
150789
|
+
const normalizedUsername = username.trim().toLowerCase();
|
|
150790
|
+
if (normalizedUsername.length === 0) {
|
|
150791
|
+
resolve({
|
|
150792
|
+
success: false,
|
|
150793
|
+
error: "Username cannot be empty",
|
|
150794
|
+
});
|
|
150795
|
+
return;
|
|
150796
|
+
}
|
|
150797
|
+
console.log(`🔄 [CREATE] Creating user: ${normalizedUsername}`);
|
|
150798
|
+
// Crea utente senza aspettare acknowledgment
|
|
150799
|
+
this.gun.user().create(normalizedUsername, password, () => { });
|
|
150800
|
+
// Aspetta che la creazione si completi
|
|
150801
|
+
setTimeout(() => {
|
|
150802
|
+
// Controlla se l'utente è stato creato
|
|
150803
|
+
const user = this.gun.user();
|
|
150804
|
+
if (user && user.is && user.is.pub) {
|
|
150805
|
+
console.log("✅ [CREATE] User created successfully");
|
|
150806
|
+
resolve({ success: true, userPub: user.is.pub });
|
|
150807
|
+
}
|
|
150808
|
+
else {
|
|
150809
|
+
console.log("❌ [CREATE] User creation failed");
|
|
150810
|
+
resolve({ success: false, error: "User creation failed" });
|
|
150811
|
+
}
|
|
150812
|
+
}, 2000); // Aspetta 2 secondi
|
|
150813
|
+
});
|
|
150814
|
+
}
|
|
150815
|
+
/**
|
|
150816
|
+
* Authenticates user after creation without waiting for acknowledgment
|
|
150817
|
+
*/
|
|
150818
|
+
async authenticateNewUserFixed(username, password, pair) {
|
|
150819
|
+
return new Promise((resolve) => {
|
|
150820
|
+
// Validate inputs before authentication
|
|
150821
|
+
if (!username ||
|
|
150822
|
+
typeof username !== "string" ||
|
|
150823
|
+
username.trim().length === 0) {
|
|
150824
|
+
resolve({ success: false, error: "Invalid username provided" });
|
|
150825
|
+
return;
|
|
150826
|
+
}
|
|
150827
|
+
// Skip password validation when using pair authentication
|
|
150828
|
+
if (!pair &&
|
|
150829
|
+
(!password || typeof password !== "string" || password.length === 0)) {
|
|
150830
|
+
resolve({ success: false, error: "Invalid password provided" });
|
|
150831
|
+
return;
|
|
150832
|
+
}
|
|
150833
|
+
// Normalize username to match what was used in creation
|
|
150834
|
+
const normalizedUsername = username.trim().toLowerCase();
|
|
150835
|
+
if (normalizedUsername.length === 0) {
|
|
150836
|
+
resolve({
|
|
150837
|
+
success: false,
|
|
150838
|
+
error: "Username cannot be empty",
|
|
150839
|
+
});
|
|
150840
|
+
return;
|
|
150841
|
+
}
|
|
150842
|
+
console.log(`🔑 [AUTH] Authenticating user: ${normalizedUsername}`);
|
|
150843
|
+
// Autentica senza aspettare acknowledgment
|
|
150844
|
+
if (pair) {
|
|
150845
|
+
this.gun.user().auth(pair);
|
|
150846
|
+
}
|
|
150847
|
+
else {
|
|
150848
|
+
this.gun.user().auth(normalizedUsername, password);
|
|
150849
|
+
}
|
|
150850
|
+
// Aspetta che l'autenticazione si completi
|
|
150851
|
+
setTimeout(() => {
|
|
150852
|
+
const user = this.gun.user();
|
|
150853
|
+
if (user && user.is && user.is.pub) {
|
|
150854
|
+
console.log("✅ [AUTH] Authentication successful");
|
|
150855
|
+
resolve({ success: true, userPub: user.is.pub });
|
|
150856
|
+
}
|
|
150857
|
+
else {
|
|
150858
|
+
console.log("❌ [AUTH] Authentication failed");
|
|
150859
|
+
resolve({ success: false, error: "Authentication failed" });
|
|
150860
|
+
}
|
|
150861
|
+
}, 2000); // Aspetta 2 secondi
|
|
150862
|
+
});
|
|
150863
|
+
}
|
|
150750
150864
|
async runPostAuthOnAuthResult(username, userPub, authResult) {
|
|
150751
150865
|
console.log(`[POSTAUTH] Starting post-auth setup for user: ${username}, userPub: ${userPub}`);
|
|
150752
150866
|
try {
|
|
@@ -150782,7 +150896,7 @@ class DataBase {
|
|
|
150782
150896
|
}
|
|
150783
150897
|
console.log(`[POSTAUTH] Normalized username: ${normalizedUsername}`);
|
|
150784
150898
|
console.log(`[POSTAUTH] Checking if user exists: ${userPub}`);
|
|
150785
|
-
const existingUser =
|
|
150899
|
+
const existingUser = this.gun.get(userPub);
|
|
150786
150900
|
const isNewUser = !existingUser || !existingUser.alias;
|
|
150787
150901
|
console.log(`[POSTAUTH] User is ${isNewUser ? "NEW" : "EXISTING"}: ${userPub}`);
|
|
150788
150902
|
// Get user's encryption public key (epub) for comprehensive tracking
|
|
@@ -150801,8 +150915,10 @@ class DataBase {
|
|
|
150801
150915
|
};
|
|
150802
150916
|
}
|
|
150803
150917
|
console.log(`[POSTAUTH] User tracking setup completed successfully for: ${normalizedUsername}`);
|
|
150804
|
-
// Setup crypto identities for the user
|
|
150805
|
-
if (this._cryptoIdentityManager &&
|
|
150918
|
+
// Setup crypto identities for the user (skip if SKIP_CRYPTO_GENERATION is set)
|
|
150919
|
+
if (this._cryptoIdentityManager &&
|
|
150920
|
+
userSea &&
|
|
150921
|
+
!process.env.SKIP_CRYPTO_GENERATION) {
|
|
150806
150922
|
console.log(`[POSTAUTH] Setting up crypto identities for: ${normalizedUsername}`);
|
|
150807
150923
|
try {
|
|
150808
150924
|
const cryptoSetupResult = await this._cryptoIdentityManager.setupCryptoIdentities(normalizedUsername, userSea, false);
|
|
@@ -150820,7 +150936,12 @@ class DataBase {
|
|
|
150820
150936
|
}
|
|
150821
150937
|
}
|
|
150822
150938
|
else {
|
|
150823
|
-
|
|
150939
|
+
if (process.env.SKIP_CRYPTO_GENERATION) {
|
|
150940
|
+
console.log(`ℹ️ [POSTAUTH] Skipping crypto identities setup - SKIP_CRYPTO_GENERATION is set`);
|
|
150941
|
+
}
|
|
150942
|
+
else {
|
|
150943
|
+
console.log(`ℹ️ [POSTAUTH] Skipping crypto identities setup - manager not available or no SEA pair`);
|
|
150944
|
+
}
|
|
150824
150945
|
}
|
|
150825
150946
|
const result = {
|
|
150826
150947
|
success: true,
|
|
@@ -150929,28 +151050,13 @@ class DataBase {
|
|
|
150929
151050
|
userPub: userPub,
|
|
150930
151051
|
createdAt: Date.now(),
|
|
150931
151052
|
};
|
|
150932
|
-
|
|
150933
|
-
|
|
150934
|
-
|
|
150935
|
-
|
|
150936
|
-
|
|
150937
|
-
|
|
150938
|
-
|
|
150939
|
-
this.node
|
|
150940
|
-
.get("aliases")
|
|
150941
|
-
.get(username)
|
|
150942
|
-
.put(aliasData, (ack) => {
|
|
150943
|
-
clearTimeout(timeout); // Clear timeout since callback fired
|
|
150944
|
-
if (ack && ack.err) {
|
|
150945
|
-
console.error(`Error creating alias index: ${ack.err}`);
|
|
150946
|
-
resolve(false);
|
|
150947
|
-
}
|
|
150948
|
-
else {
|
|
150949
|
-
console.log(`✓ Alias index created for ${username}`);
|
|
150950
|
-
resolve(true);
|
|
150951
|
-
}
|
|
150952
|
-
});
|
|
150953
|
-
});
|
|
151053
|
+
console.log(`🔄 [ALIAS] Creating alias index for ${username}`);
|
|
151054
|
+
// Store alias mapping without waiting for acknowledgment
|
|
151055
|
+
this.node.get("aliases").get(username).put(aliasData);
|
|
151056
|
+
// Aspetta un momento per la scrittura
|
|
151057
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
151058
|
+
console.log(`✅ [ALIAS] Alias index created for ${username}`);
|
|
151059
|
+
return true;
|
|
150954
151060
|
}
|
|
150955
151061
|
catch (error) {
|
|
150956
151062
|
console.error(`Error creating alias index: ${error}`);
|
|
@@ -150962,20 +151068,13 @@ class DataBase {
|
|
|
150962
151068
|
*/
|
|
150963
151069
|
async createUsernameMapping(username, userPub) {
|
|
150964
151070
|
try {
|
|
150965
|
-
|
|
150966
|
-
|
|
150967
|
-
|
|
150968
|
-
|
|
150969
|
-
|
|
150970
|
-
|
|
150971
|
-
|
|
150972
|
-
resolve(false);
|
|
150973
|
-
}
|
|
150974
|
-
else {
|
|
150975
|
-
resolve(true);
|
|
150976
|
-
}
|
|
150977
|
-
});
|
|
150978
|
-
});
|
|
151071
|
+
console.log(`🔄 [USERNAME] Creating username mapping for ${username}`);
|
|
151072
|
+
// Store username mapping without waiting for acknowledgment
|
|
151073
|
+
this.node.get("usernames").get(username).put(userPub);
|
|
151074
|
+
// Aspetta un momento per la scrittura
|
|
151075
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
151076
|
+
console.log(`✅ [USERNAME] Username mapping created for ${username}`);
|
|
151077
|
+
return true;
|
|
150979
151078
|
}
|
|
150980
151079
|
catch (error) {
|
|
150981
151080
|
console.error(`Error creating username mapping: ${error}`);
|
|
@@ -150994,20 +151093,13 @@ class DataBase {
|
|
|
150994
151093
|
registeredAt: Date.now().toString(),
|
|
150995
151094
|
lastSeen: Date.now().toString(),
|
|
150996
151095
|
};
|
|
150997
|
-
|
|
150998
|
-
|
|
150999
|
-
|
|
151000
|
-
|
|
151001
|
-
|
|
151002
|
-
|
|
151003
|
-
|
|
151004
|
-
resolve(false);
|
|
151005
|
-
}
|
|
151006
|
-
else {
|
|
151007
|
-
resolve(true);
|
|
151008
|
-
}
|
|
151009
|
-
});
|
|
151010
|
-
});
|
|
151096
|
+
console.log(`🔄 [REGISTRY] Creating user registry for ${username}`);
|
|
151097
|
+
// Store user registry without waiting for acknowledgment
|
|
151098
|
+
this.node.get("users").get(userPub).put(userData);
|
|
151099
|
+
// Aspetta un momento per la scrittura
|
|
151100
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
151101
|
+
console.log(`✅ [REGISTRY] User registry created for ${username}`);
|
|
151102
|
+
return true;
|
|
151011
151103
|
}
|
|
151012
151104
|
catch (error) {
|
|
151013
151105
|
console.error(`Error creating user registry: ${error}`);
|
|
@@ -151019,18 +151111,13 @@ class DataBase {
|
|
|
151019
151111
|
*/
|
|
151020
151112
|
async createReverseLookup(username, userPub) {
|
|
151021
151113
|
try {
|
|
151022
|
-
|
|
151023
|
-
|
|
151024
|
-
|
|
151025
|
-
|
|
151026
|
-
|
|
151027
|
-
|
|
151028
|
-
|
|
151029
|
-
return false;
|
|
151030
|
-
}
|
|
151031
|
-
else {
|
|
151032
|
-
return true;
|
|
151033
|
-
}
|
|
151114
|
+
console.log(`🔄 [REVERSE] Creating reverse lookup for ${username}`);
|
|
151115
|
+
// Store reverse lookup without waiting for acknowledgment
|
|
151116
|
+
this.node.get("userAliases").get(userPub).put(username);
|
|
151117
|
+
// Aspetta un momento per la scrittura
|
|
151118
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
151119
|
+
console.log(`✅ [REVERSE] Reverse lookup created for ${username}`);
|
|
151120
|
+
return true;
|
|
151034
151121
|
}
|
|
151035
151122
|
catch (error) {
|
|
151036
151123
|
console.error(`Error creating reverse lookup: ${error}`);
|
|
@@ -151042,20 +151129,13 @@ class DataBase {
|
|
|
151042
151129
|
*/
|
|
151043
151130
|
async createEpubIndex(epub, userPub) {
|
|
151044
151131
|
try {
|
|
151045
|
-
|
|
151046
|
-
|
|
151047
|
-
|
|
151048
|
-
|
|
151049
|
-
|
|
151050
|
-
|
|
151051
|
-
|
|
151052
|
-
resolve(false);
|
|
151053
|
-
}
|
|
151054
|
-
else {
|
|
151055
|
-
resolve(true);
|
|
151056
|
-
}
|
|
151057
|
-
});
|
|
151058
|
-
});
|
|
151132
|
+
console.log(`🔄 [EPUB] Creating epub index for ${userPub}`);
|
|
151133
|
+
// Store epub index without waiting for acknowledgment
|
|
151134
|
+
this.node.get("epubKeys").get(epub).put(userPub);
|
|
151135
|
+
// Aspetta un momento per la scrittura
|
|
151136
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
151137
|
+
console.log(`✅ [EPUB] Epub index created for ${userPub}`);
|
|
151138
|
+
return true;
|
|
151059
151139
|
}
|
|
151060
151140
|
catch (error) {
|
|
151061
151141
|
console.error(`Error creating epub index: ${error}`);
|
|
@@ -151073,17 +151153,13 @@ class DataBase {
|
|
|
151073
151153
|
registeredAt: Date.now(),
|
|
151074
151154
|
lastSeen: Date.now(),
|
|
151075
151155
|
};
|
|
151076
|
-
|
|
151077
|
-
|
|
151078
|
-
|
|
151079
|
-
|
|
151080
|
-
|
|
151081
|
-
|
|
151082
|
-
|
|
151083
|
-
resolve(true);
|
|
151084
|
-
}
|
|
151085
|
-
});
|
|
151086
|
-
});
|
|
151156
|
+
console.log(`🔄 [METADATA] Creating user metadata for ${username}`);
|
|
151157
|
+
// Store user metadata without waiting for acknowledgment
|
|
151158
|
+
this.gun.get(userPub).put(userMetadata);
|
|
151159
|
+
// Aspetta un momento per la scrittura
|
|
151160
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
151161
|
+
console.log(`✅ [METADATA] User metadata created for ${username}`);
|
|
151162
|
+
return true;
|
|
151087
151163
|
}
|
|
151088
151164
|
catch (error) {
|
|
151089
151165
|
console.error(`Error creating user metadata: ${error}`);
|
|
@@ -151103,7 +151179,7 @@ class DataBase {
|
|
|
151103
151179
|
}
|
|
151104
151180
|
// Method 1: Try GunDB standard alias lookup (~@alias)
|
|
151105
151181
|
try {
|
|
151106
|
-
const aliasData =
|
|
151182
|
+
const aliasData = this.gun.get(`~@${normalizedAlias}`);
|
|
151107
151183
|
if (aliasData && aliasData["~pubKeyOfUser"]) {
|
|
151108
151184
|
const userPub = aliasData["~pubKeyOfUser"]["#"] || aliasData["~pubKeyOfUser"];
|
|
151109
151185
|
if (userPub) {
|
|
@@ -151119,10 +151195,15 @@ class DataBase {
|
|
|
151119
151195
|
}
|
|
151120
151196
|
// Method 2: Try username mapping (usernames/alias -> userPub)
|
|
151121
151197
|
try {
|
|
151122
|
-
const
|
|
151123
|
-
|
|
151124
|
-
|
|
151125
|
-
|
|
151198
|
+
const userPubNode = this.node.get("usernames").get(normalizedAlias);
|
|
151199
|
+
// Use once to get the actual value
|
|
151200
|
+
const userPub = await new Promise((resolve) => {
|
|
151201
|
+
const timeout = setTimeout(() => resolve(null), 2000);
|
|
151202
|
+
userPubNode.once((data) => {
|
|
151203
|
+
clearTimeout(timeout);
|
|
151204
|
+
resolve(data);
|
|
151205
|
+
});
|
|
151206
|
+
});
|
|
151126
151207
|
if (userPub) {
|
|
151127
151208
|
const userData = await this.getUserDataByPub(userPub);
|
|
151128
151209
|
if (userData) {
|
|
@@ -151152,7 +151233,7 @@ class DataBase {
|
|
|
151152
151233
|
}
|
|
151153
151234
|
// Method 1: Try user registry (users/userPub -> user data)
|
|
151154
151235
|
try {
|
|
151155
|
-
const userData =
|
|
151236
|
+
const userData = this.node.get("users").get(userPub);
|
|
151156
151237
|
if (userData && userData.username) {
|
|
151157
151238
|
return {
|
|
151158
151239
|
userPub: userData.userPub || userPub,
|
|
@@ -151168,7 +151249,7 @@ class DataBase {
|
|
|
151168
151249
|
}
|
|
151169
151250
|
// Method 2: Try user's own node
|
|
151170
151251
|
try {
|
|
151171
|
-
const userNodeData =
|
|
151252
|
+
const userNodeData = this.gun.get(userPub);
|
|
151172
151253
|
if (userNodeData && userNodeData.username) {
|
|
151173
151254
|
return {
|
|
151174
151255
|
userPub: userPub,
|
|
@@ -151199,7 +151280,15 @@ class DataBase {
|
|
|
151199
151280
|
if (!epub || typeof epub !== "string") {
|
|
151200
151281
|
return null;
|
|
151201
151282
|
}
|
|
151202
|
-
const
|
|
151283
|
+
const userPubNode = this.node.get("epubKeys").get(epub);
|
|
151284
|
+
// Use once to get the actual value
|
|
151285
|
+
const userPub = await new Promise((resolve) => {
|
|
151286
|
+
const timeout = setTimeout(() => resolve(null), 2000);
|
|
151287
|
+
userPubNode.once((data) => {
|
|
151288
|
+
clearTimeout(timeout);
|
|
151289
|
+
resolve(data);
|
|
151290
|
+
});
|
|
151291
|
+
});
|
|
151203
151292
|
return userPub || null;
|
|
151204
151293
|
}
|
|
151205
151294
|
catch (error) {
|
|
@@ -151217,7 +151306,15 @@ class DataBase {
|
|
|
151217
151306
|
if (!userPub || typeof userPub !== "string") {
|
|
151218
151307
|
return null;
|
|
151219
151308
|
}
|
|
151220
|
-
const
|
|
151309
|
+
const aliasNode = this.node.get("userAliases").get(userPub);
|
|
151310
|
+
// Use once to get the actual value
|
|
151311
|
+
const alias = await new Promise((resolve) => {
|
|
151312
|
+
const timeout = setTimeout(() => resolve(null), 2000);
|
|
151313
|
+
aliasNode.once((data) => {
|
|
151314
|
+
clearTimeout(timeout);
|
|
151315
|
+
resolve(data);
|
|
151316
|
+
});
|
|
151317
|
+
});
|
|
151221
151318
|
return alias || null;
|
|
151222
151319
|
}
|
|
151223
151320
|
catch (error) {
|
|
@@ -151256,19 +151353,14 @@ class DataBase {
|
|
|
151256
151353
|
const timestamp = Date.now();
|
|
151257
151354
|
// Update in user registry
|
|
151258
151355
|
try {
|
|
151259
|
-
|
|
151260
|
-
.get("users")
|
|
151261
|
-
.get(userPub)
|
|
151262
|
-
.get("lastSeen")
|
|
151263
|
-
.put(timestamp)
|
|
151264
|
-
.then();
|
|
151356
|
+
this.node.get("users").get(userPub).get("lastSeen").put(timestamp);
|
|
151265
151357
|
}
|
|
151266
151358
|
catch (error) {
|
|
151267
151359
|
console.error(`Failed to update lastSeen in user registry:`, error);
|
|
151268
151360
|
}
|
|
151269
151361
|
// Update in user's own node
|
|
151270
151362
|
try {
|
|
151271
|
-
|
|
151363
|
+
this.gun.get(userPub).get("lastSeen").put(timestamp);
|
|
151272
151364
|
}
|
|
151273
151365
|
catch (error) {
|
|
151274
151366
|
console.error(`Failed to update lastSeen in user node:`, error);
|
|
@@ -151279,33 +151371,134 @@ class DataBase {
|
|
|
151279
151371
|
}
|
|
151280
151372
|
}
|
|
151281
151373
|
/**
|
|
151282
|
-
*
|
|
151374
|
+
* Resets Gun.js authentication state to allow new auth operations
|
|
151283
151375
|
*/
|
|
151284
|
-
|
|
151376
|
+
resetAuthState() {
|
|
151377
|
+
try {
|
|
151378
|
+
const currentUser = this.gun.user();
|
|
151379
|
+
if (currentUser && currentUser._) {
|
|
151380
|
+
// Reset the authentication flag
|
|
151381
|
+
if (currentUser._.sea) {
|
|
151382
|
+
currentUser._.sea = null;
|
|
151383
|
+
}
|
|
151384
|
+
// Reset the ing flag that prevents concurrent operations
|
|
151385
|
+
if (currentUser._.ing) {
|
|
151386
|
+
currentUser._.ing = false;
|
|
151387
|
+
}
|
|
151388
|
+
// Force clear any pending authentication callbacks
|
|
151389
|
+
if (currentUser._.auth) {
|
|
151390
|
+
currentUser._.auth = null;
|
|
151391
|
+
}
|
|
151392
|
+
// Clear any pending operations
|
|
151393
|
+
if (currentUser._.act) {
|
|
151394
|
+
currentUser._.act = null;
|
|
151395
|
+
}
|
|
151396
|
+
// Clear any pending callbacks
|
|
151397
|
+
if (currentUser._.cb) {
|
|
151398
|
+
currentUser._.cb = null;
|
|
151399
|
+
}
|
|
151400
|
+
// Clear any pending retries
|
|
151401
|
+
if (currentUser._.retries) {
|
|
151402
|
+
currentUser._.retries = 0;
|
|
151403
|
+
}
|
|
151404
|
+
// Clear any pending timeouts
|
|
151405
|
+
if (currentUser._.timeout) {
|
|
151406
|
+
clearTimeout(currentUser._.timeout);
|
|
151407
|
+
currentUser._.timeout = null;
|
|
151408
|
+
}
|
|
151409
|
+
}
|
|
151410
|
+
// Also try to call leave() to ensure clean state
|
|
151411
|
+
try {
|
|
151412
|
+
currentUser.leave();
|
|
151413
|
+
}
|
|
151414
|
+
catch (leaveError) {
|
|
151415
|
+
// Ignore leave errors, just trying to clean up
|
|
151416
|
+
}
|
|
151417
|
+
// Force clear the user reference to ensure clean state
|
|
151418
|
+
this.user = null;
|
|
151419
|
+
console.log("Auth state reset completed");
|
|
151420
|
+
}
|
|
151421
|
+
catch (error) {
|
|
151422
|
+
console.warn("Error resetting auth state:", error);
|
|
151423
|
+
}
|
|
151424
|
+
}
|
|
151425
|
+
/**
|
|
151426
|
+
* Performs authentication with Gun with retry mechanism
|
|
151427
|
+
*/
|
|
151428
|
+
async performAuthentication(username, password, pair, retryCount = 0, maxRetries = 3) {
|
|
151285
151429
|
return new Promise((resolve) => {
|
|
151286
|
-
if
|
|
151287
|
-
|
|
151288
|
-
|
|
151289
|
-
|
|
151290
|
-
|
|
151291
|
-
|
|
151292
|
-
|
|
151293
|
-
|
|
151430
|
+
// Check if there's already an authentication operation in progress
|
|
151431
|
+
const currentUser = this.gun.user();
|
|
151432
|
+
if (currentUser && currentUser._ && currentUser._.ing) {
|
|
151433
|
+
if (retryCount < maxRetries) {
|
|
151434
|
+
console.warn(`Authentication already in progress, retrying... (${retryCount + 1}/${maxRetries})`);
|
|
151435
|
+
this.resetAuthState();
|
|
151436
|
+
// For the first retry, try to create a fresh authentication context
|
|
151437
|
+
if (retryCount === 0) {
|
|
151438
|
+
this.createFreshAuthContext();
|
|
151294
151439
|
}
|
|
151440
|
+
// Add exponential backoff delay with jitter
|
|
151441
|
+
const baseDelay = 200 * Math.pow(2, retryCount);
|
|
151442
|
+
const jitter = Math.random() * 200;
|
|
151443
|
+
const delay = Math.min(baseDelay + jitter, 3000);
|
|
151444
|
+
setTimeout(() => {
|
|
151445
|
+
this.performAuthentication(username, password, pair, retryCount + 1, maxRetries)
|
|
151446
|
+
.then(resolve)
|
|
151447
|
+
.catch((error) => resolve({ success: false, error: String(error) }));
|
|
151448
|
+
}, delay);
|
|
151449
|
+
return;
|
|
151450
|
+
}
|
|
151451
|
+
else {
|
|
151452
|
+
console.error("Max retries exceeded for authentication");
|
|
151453
|
+
this.resetAuthState();
|
|
151454
|
+
resolve({
|
|
151455
|
+
success: false,
|
|
151456
|
+
error: "Authentication failed after multiple retries",
|
|
151457
|
+
});
|
|
151458
|
+
return;
|
|
151459
|
+
}
|
|
151460
|
+
}
|
|
151461
|
+
this.performAuthenticationInternal(username, password, pair, resolve);
|
|
151462
|
+
});
|
|
151463
|
+
}
|
|
151464
|
+
/**
|
|
151465
|
+
* Internal authentication method with timeout
|
|
151466
|
+
*/
|
|
151467
|
+
performAuthenticationInternal(username, password, pair, resolve) {
|
|
151468
|
+
let resolved = false;
|
|
151469
|
+
const timeout = 30000; // 15 second timeout for individual auth attempts
|
|
151470
|
+
const timeoutId = setTimeout(() => {
|
|
151471
|
+
if (!resolved) {
|
|
151472
|
+
resolved = true;
|
|
151473
|
+
console.error(`Authentication timeout for ${username} after ${timeout}ms`);
|
|
151474
|
+
this.resetAuthState();
|
|
151475
|
+
resolve({
|
|
151476
|
+
success: false,
|
|
151477
|
+
error: `Authentication timeout after ${timeout}ms`,
|
|
151295
151478
|
});
|
|
151296
151479
|
}
|
|
151480
|
+
}, timeout);
|
|
151481
|
+
const authCallback = (ack) => {
|
|
151482
|
+
if (resolved)
|
|
151483
|
+
return;
|
|
151484
|
+
resolved = true;
|
|
151485
|
+
clearTimeout(timeoutId);
|
|
151486
|
+
if (ack.err) {
|
|
151487
|
+
console.error(`Login error for ${username}: ${ack.err}`);
|
|
151488
|
+
// Reset auth state on error to prevent blocking future attempts
|
|
151489
|
+
this.resetAuthState();
|
|
151490
|
+
resolve({ success: false, error: ack.err });
|
|
151491
|
+
}
|
|
151297
151492
|
else {
|
|
151298
|
-
|
|
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
|
-
});
|
|
151493
|
+
resolve({ success: true, ack });
|
|
151307
151494
|
}
|
|
151308
|
-
}
|
|
151495
|
+
};
|
|
151496
|
+
if (pair) {
|
|
151497
|
+
this.gun.user().auth(pair, authCallback);
|
|
151498
|
+
}
|
|
151499
|
+
else {
|
|
151500
|
+
this.gun.user().auth(username, password, authCallback);
|
|
151501
|
+
}
|
|
151309
151502
|
}
|
|
151310
151503
|
/**
|
|
151311
151504
|
* Builds login result object
|
|
@@ -151337,18 +151530,34 @@ class DataBase {
|
|
|
151337
151530
|
*/
|
|
151338
151531
|
async login(username, password, pair) {
|
|
151339
151532
|
try {
|
|
151340
|
-
|
|
151341
|
-
|
|
151533
|
+
console.log(`🔑 [LOGIN] Attempting login for: ${username}`);
|
|
151534
|
+
// Pulisci lo stato utente esistente
|
|
151535
|
+
this.gun.user().leave();
|
|
151536
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
151537
|
+
// Autentica senza aspettare acknowledgment
|
|
151538
|
+
if (pair) {
|
|
151539
|
+
this.gun.user().auth(pair);
|
|
151540
|
+
}
|
|
151541
|
+
else {
|
|
151542
|
+
this.gun.user().auth(username, password);
|
|
151543
|
+
}
|
|
151544
|
+
// Aspetta che l'autenticazione si completi
|
|
151545
|
+
console.log("⏳ [LOGIN] Waiting for authentication to complete...");
|
|
151546
|
+
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
151547
|
+
// Controlla se l'autenticazione è riuscita
|
|
151548
|
+
const user = this.gun.user();
|
|
151549
|
+
const isAuthenticated = !!user.is;
|
|
151550
|
+
if (!isAuthenticated) {
|
|
151551
|
+
console.log("❌ [LOGIN] Authentication failed");
|
|
151342
151552
|
return {
|
|
151343
151553
|
success: false,
|
|
151344
151554
|
error: `User '${username}' not found. Please check your username or register first.`,
|
|
151345
151555
|
};
|
|
151346
151556
|
}
|
|
151347
|
-
|
|
151348
|
-
|
|
151349
|
-
|
|
151350
|
-
let
|
|
151351
|
-
let userPair = this.gun.user()?._?.sea;
|
|
151557
|
+
console.log("✅ [LOGIN] Authentication successful!");
|
|
151558
|
+
const userPub = user?.is?.pub;
|
|
151559
|
+
let alias = user?.is?.alias;
|
|
151560
|
+
let userPair = user?._?.sea;
|
|
151352
151561
|
if (!alias) {
|
|
151353
151562
|
alias = username;
|
|
151354
151563
|
}
|
|
@@ -151358,7 +151567,7 @@ class DataBase {
|
|
|
151358
151567
|
error: "Authentication failed: No user pub returned.",
|
|
151359
151568
|
};
|
|
151360
151569
|
}
|
|
151361
|
-
//
|
|
151570
|
+
// Esegui post-authentication tasks
|
|
151362
151571
|
try {
|
|
151363
151572
|
await this.runPostAuthOnAuthResult(alias, userPub, {
|
|
151364
151573
|
success: true,
|
|
@@ -151519,14 +151728,20 @@ class DataBase {
|
|
|
151519
151728
|
questions: JSON.stringify(securityQuestions),
|
|
151520
151729
|
hint: encryptedHint,
|
|
151521
151730
|
};
|
|
151522
|
-
|
|
151523
|
-
|
|
151524
|
-
.
|
|
151525
|
-
.
|
|
151526
|
-
|
|
151731
|
+
console.log(`💾 [HINT] Saving security data for user: ${username}, pub: ${userPub}`);
|
|
151732
|
+
console.log(`💾 [HINT] Security payload:`, {
|
|
151733
|
+
questions: securityPayload.questions,
|
|
151734
|
+
hintLength: securityPayload.hint?.length || 0,
|
|
151735
|
+
});
|
|
151736
|
+
// Save in PUBLIC space, not user space - accessible without login
|
|
151737
|
+
const ack = this.gun.get("security")
|
|
151738
|
+
.get(userPub)
|
|
151739
|
+
.put(securityPayload);
|
|
151740
|
+
if (ack && ack.err) {
|
|
151527
151741
|
console.error("Error saving security data to public graph:", ack.err);
|
|
151528
151742
|
throw new Error(ack.err);
|
|
151529
151743
|
}
|
|
151744
|
+
console.log(`✅ [HINT] Security data saved successfully for ${username}`);
|
|
151530
151745
|
return { success: true };
|
|
151531
151746
|
}
|
|
151532
151747
|
catch (error) {
|
|
@@ -151542,19 +151757,82 @@ class DataBase {
|
|
|
151542
151757
|
*/
|
|
151543
151758
|
async forgotPassword(username, securityAnswers) {
|
|
151544
151759
|
// Attempting password recovery for
|
|
151760
|
+
// Add global timeout for the entire operation
|
|
151761
|
+
return Promise.race([
|
|
151762
|
+
this._forgotPasswordInternal(username, securityAnswers),
|
|
151763
|
+
new Promise((resolve) => {
|
|
151764
|
+
setTimeout(() => {
|
|
151765
|
+
console.log(`⏰ [FORGOT] Global timeout for password recovery: ${username}`);
|
|
151766
|
+
resolve({ success: false, error: "Password recovery timeout" });
|
|
151767
|
+
}, 10000); // 10 second global timeout
|
|
151768
|
+
}),
|
|
151769
|
+
]);
|
|
151770
|
+
}
|
|
151771
|
+
async _forgotPasswordInternal(username, securityAnswers) {
|
|
151545
151772
|
try {
|
|
151546
151773
|
// Find the user's data using direct lookup
|
|
151547
151774
|
const normalizedUsername = username.trim().toLowerCase();
|
|
151548
|
-
|
|
151549
|
-
|
|
151775
|
+
// Try multiple lookup methods with fallback
|
|
151776
|
+
let userPub = null;
|
|
151777
|
+
// Method 1: Try username mapping in app scope
|
|
151778
|
+
try {
|
|
151779
|
+
userPub = await new Promise((resolve) => {
|
|
151780
|
+
const timeout = setTimeout(() => {
|
|
151781
|
+
console.log(`⏰ [FORGOT] Timeout looking up user in usernames: ${username}`);
|
|
151782
|
+
resolve(null);
|
|
151783
|
+
}, 2000);
|
|
151784
|
+
this.node
|
|
151785
|
+
.get("usernames")
|
|
151786
|
+
.get(normalizedUsername)
|
|
151787
|
+
.once((data) => {
|
|
151788
|
+
clearTimeout(timeout);
|
|
151789
|
+
console.log(`🔍 [FORGOT] Username lookup result for ${username}:`, data);
|
|
151790
|
+
resolve(data);
|
|
151791
|
+
});
|
|
151792
|
+
});
|
|
151793
|
+
}
|
|
151794
|
+
catch (error) {
|
|
151795
|
+
console.log(`❌ [FORGOT] Username lookup failed: ${error}`);
|
|
151796
|
+
}
|
|
151797
|
+
// Method 2: Try direct user lookup if username mapping fails
|
|
151550
151798
|
if (!userPub) {
|
|
151799
|
+
console.log(`🔄 [FORGOT] Trying direct user lookup for: ${username}`);
|
|
151800
|
+
try {
|
|
151801
|
+
// Try to find user by searching in the users registry
|
|
151802
|
+
const usersNode = this.node.get("users");
|
|
151803
|
+
// This is a simplified approach - in a real implementation you'd need to iterate
|
|
151804
|
+
// For now, we'll try to get the userPub from the current user if available
|
|
151805
|
+
const currentUser = this.getCurrentUser();
|
|
151806
|
+
if (currentUser && currentUser.pub) {
|
|
151807
|
+
console.log(`🔍 [FORGOT] Using current user pub as fallback: ${currentUser.pub}`);
|
|
151808
|
+
userPub = currentUser.pub;
|
|
151809
|
+
}
|
|
151810
|
+
}
|
|
151811
|
+
catch (error) {
|
|
151812
|
+
console.log(`❌ [FORGOT] Direct user lookup failed: ${error}`);
|
|
151813
|
+
}
|
|
151814
|
+
}
|
|
151815
|
+
if (!userPub) {
|
|
151816
|
+
console.log(`❌ [FORGOT] User not found: ${username}`);
|
|
151551
151817
|
return { success: false, error: "User not found" };
|
|
151552
151818
|
}
|
|
151553
|
-
// Access the user's security data
|
|
151554
|
-
const
|
|
151555
|
-
|
|
151556
|
-
|
|
151819
|
+
// Access the user's security data from PUBLIC space (not user space)
|
|
151820
|
+
const securityDataNode = this.gun.get("security").get(userPub);
|
|
151821
|
+
console.log(`🔍 [FORGOT] Looking for security data for user: ${username}, pub: ${userPub}`);
|
|
151822
|
+
// Use once to get the actual value
|
|
151823
|
+
const securityData = await new Promise((resolve) => {
|
|
151824
|
+
const timeout = setTimeout(() => {
|
|
151825
|
+
console.log(`⏰ [FORGOT] Timeout waiting for security data for ${username} (3s)`);
|
|
151826
|
+
resolve(null);
|
|
151827
|
+
}, 3000); // Reduced timeout to 3 seconds
|
|
151828
|
+
securityDataNode.once((data) => {
|
|
151829
|
+
clearTimeout(timeout);
|
|
151830
|
+
console.log(`📊 [FORGOT] Security data received for ${username}:`, data);
|
|
151831
|
+
resolve(data);
|
|
151832
|
+
});
|
|
151833
|
+
});
|
|
151557
151834
|
if (!securityData || !securityData.hint) {
|
|
151835
|
+
console.log(`❌ [FORGOT] No security data or hint found for ${username}`);
|
|
151558
151836
|
return {
|
|
151559
151837
|
success: false,
|
|
151560
151838
|
error: "No password hint found",
|
|
@@ -151616,6 +151894,107 @@ class DataBase {
|
|
|
151616
151894
|
return { success: false, error: String(error) };
|
|
151617
151895
|
}
|
|
151618
151896
|
}
|
|
151897
|
+
/**
|
|
151898
|
+
* Recovers password hint using security question answers and userPub directly
|
|
151899
|
+
* @param userPub User's public key
|
|
151900
|
+
* @param securityAnswers Array of answers to security questions
|
|
151901
|
+
* @returns Promise resolving with the password hint
|
|
151902
|
+
*/
|
|
151903
|
+
async forgotPasswordByPub(userPub, securityAnswers) {
|
|
151904
|
+
// Add global timeout for the entire operation
|
|
151905
|
+
return Promise.race([
|
|
151906
|
+
this._forgotPasswordByPubInternal(userPub, securityAnswers),
|
|
151907
|
+
new Promise((resolve) => {
|
|
151908
|
+
setTimeout(() => {
|
|
151909
|
+
console.log(`⏰ [FORGOT] Global timeout for password recovery by pub: ${userPub}`);
|
|
151910
|
+
resolve({ success: false, error: "Password recovery timeout" });
|
|
151911
|
+
}, 10000); // 10 second global timeout
|
|
151912
|
+
}),
|
|
151913
|
+
]);
|
|
151914
|
+
}
|
|
151915
|
+
async _forgotPasswordByPubInternal(userPub, securityAnswers) {
|
|
151916
|
+
try {
|
|
151917
|
+
if (!userPub || typeof userPub !== "string") {
|
|
151918
|
+
return { success: false, error: "Invalid userPub provided" };
|
|
151919
|
+
}
|
|
151920
|
+
// Access the user's security data from PUBLIC space (not user space)
|
|
151921
|
+
const securityDataNode = this.gun.get("security").get(userPub);
|
|
151922
|
+
console.log(`🔍 [FORGOT] Looking for security data for userPub: ${userPub}`);
|
|
151923
|
+
// Use once to get the actual value
|
|
151924
|
+
const securityData = await new Promise((resolve) => {
|
|
151925
|
+
const timeout = setTimeout(() => {
|
|
151926
|
+
console.log(`⏰ [FORGOT] Timeout waiting for security data for userPub: ${userPub} (3s)`);
|
|
151927
|
+
resolve(null);
|
|
151928
|
+
}, 3000);
|
|
151929
|
+
securityDataNode.once((data) => {
|
|
151930
|
+
clearTimeout(timeout);
|
|
151931
|
+
console.log(`📊 [FORGOT] Security data received for userPub: ${userPub}:`, data);
|
|
151932
|
+
resolve(data);
|
|
151933
|
+
});
|
|
151934
|
+
});
|
|
151935
|
+
if (!securityData || !securityData.hint) {
|
|
151936
|
+
console.log(`❌ [FORGOT] No security data or hint found for userPub: ${userPub}`);
|
|
151937
|
+
return {
|
|
151938
|
+
success: false,
|
|
151939
|
+
error: "No password hint found",
|
|
151940
|
+
};
|
|
151941
|
+
}
|
|
151942
|
+
// Generate hash from security answers
|
|
151943
|
+
const answersText = securityAnswers.join("|");
|
|
151944
|
+
let proofOfWork;
|
|
151945
|
+
try {
|
|
151946
|
+
// Use SEA directly if available
|
|
151947
|
+
if (sea_1.default && sea_1.default.work) {
|
|
151948
|
+
proofOfWork = await sea_1.default.work(answersText, null, null, {
|
|
151949
|
+
name: "SHA-256",
|
|
151950
|
+
});
|
|
151951
|
+
}
|
|
151952
|
+
else if (this.crypto && this.crypto.hashText) {
|
|
151953
|
+
proofOfWork = await this.crypto.hashText(answersText);
|
|
151954
|
+
}
|
|
151955
|
+
else {
|
|
151956
|
+
throw new Error("Cryptographic functions not available");
|
|
151957
|
+
}
|
|
151958
|
+
if (!proofOfWork) {
|
|
151959
|
+
throw new Error("Failed to generate hash");
|
|
151960
|
+
}
|
|
151961
|
+
}
|
|
151962
|
+
catch (hashError) {
|
|
151963
|
+
console.error("Error generating hash:", hashError);
|
|
151964
|
+
return { success: false, error: "Failed to generate security hash" };
|
|
151965
|
+
}
|
|
151966
|
+
// Decrypt the password hint with the proof of work
|
|
151967
|
+
let hint;
|
|
151968
|
+
try {
|
|
151969
|
+
if (sea_1.default && sea_1.default.decrypt) {
|
|
151970
|
+
hint = await sea_1.default.decrypt(securityData.hint, proofOfWork);
|
|
151971
|
+
}
|
|
151972
|
+
else if (this.crypto && this.crypto.decrypt) {
|
|
151973
|
+
hint = await this.crypto.decrypt(securityData.hint, proofOfWork);
|
|
151974
|
+
}
|
|
151975
|
+
else {
|
|
151976
|
+
throw new Error("Decryption functions not available");
|
|
151977
|
+
}
|
|
151978
|
+
}
|
|
151979
|
+
catch (decryptError) {
|
|
151980
|
+
return {
|
|
151981
|
+
success: false,
|
|
151982
|
+
error: "Incorrect answers to security questions",
|
|
151983
|
+
};
|
|
151984
|
+
}
|
|
151985
|
+
if (hint === undefined) {
|
|
151986
|
+
return {
|
|
151987
|
+
success: false,
|
|
151988
|
+
error: "Incorrect answers to security questions",
|
|
151989
|
+
};
|
|
151990
|
+
}
|
|
151991
|
+
return { success: true, hint: hint };
|
|
151992
|
+
}
|
|
151993
|
+
catch (error) {
|
|
151994
|
+
console.error("Error recovering password hint by pub:", error);
|
|
151995
|
+
return { success: false, error: String(error) };
|
|
151996
|
+
}
|
|
151997
|
+
}
|
|
151619
151998
|
/**
|
|
151620
151999
|
* Adds an event listener
|
|
151621
152000
|
* @param event Event name
|
|
@@ -151760,16 +152139,223 @@ class DataBase {
|
|
|
151760
152139
|
isAuthenticated() {
|
|
151761
152140
|
return this.user?.is?.pub ? true : false;
|
|
151762
152141
|
}
|
|
152142
|
+
/**
|
|
152143
|
+
* Check if an authentication operation is currently in progress
|
|
152144
|
+
*/
|
|
152145
|
+
isAuthInProgress() {
|
|
152146
|
+
try {
|
|
152147
|
+
const currentUser = this.gun.user();
|
|
152148
|
+
return !!(currentUser && currentUser._ && currentUser._.ing);
|
|
152149
|
+
}
|
|
152150
|
+
catch (error) {
|
|
152151
|
+
console.warn("Error checking auth progress:", error);
|
|
152152
|
+
return false;
|
|
152153
|
+
}
|
|
152154
|
+
}
|
|
152155
|
+
/**
|
|
152156
|
+
* Force reset authentication state (useful for debugging or recovery)
|
|
152157
|
+
*/
|
|
152158
|
+
forceResetAuthState() {
|
|
152159
|
+
this.resetAuthState();
|
|
152160
|
+
}
|
|
152161
|
+
/**
|
|
152162
|
+
* Aggressive cleanup for problematic users
|
|
152163
|
+
* This method performs a complete reset of all authentication state
|
|
152164
|
+
*/
|
|
152165
|
+
aggressiveAuthCleanup() {
|
|
152166
|
+
try {
|
|
152167
|
+
console.log("🧹 Performing aggressive auth cleanup...");
|
|
152168
|
+
// Reset all auth state
|
|
152169
|
+
this.resetAuthState();
|
|
152170
|
+
// Clear all Gun.js internal state
|
|
152171
|
+
const currentUser = this.gun.user();
|
|
152172
|
+
if (currentUser && currentUser._) {
|
|
152173
|
+
// Clear all possible internal flags
|
|
152174
|
+
const internalState = currentUser._;
|
|
152175
|
+
Object.keys(internalState).forEach((key) => {
|
|
152176
|
+
if (typeof internalState[key] === "boolean") {
|
|
152177
|
+
internalState[key] = false;
|
|
152178
|
+
}
|
|
152179
|
+
else if (typeof internalState[key] === "object" &&
|
|
152180
|
+
internalState[key] !== null) {
|
|
152181
|
+
if (key === "sea" ||
|
|
152182
|
+
key === "auth" ||
|
|
152183
|
+
key === "act" ||
|
|
152184
|
+
key === "cb") {
|
|
152185
|
+
internalState[key] = null;
|
|
152186
|
+
}
|
|
152187
|
+
}
|
|
152188
|
+
});
|
|
152189
|
+
}
|
|
152190
|
+
// Force logout
|
|
152191
|
+
try {
|
|
152192
|
+
currentUser.leave();
|
|
152193
|
+
}
|
|
152194
|
+
catch (error) {
|
|
152195
|
+
// Ignore errors
|
|
152196
|
+
}
|
|
152197
|
+
// Clear user reference
|
|
152198
|
+
this.user = null;
|
|
152199
|
+
// Clear all session storage
|
|
152200
|
+
if (typeof sessionStorage !== "undefined") {
|
|
152201
|
+
try {
|
|
152202
|
+
const keys = Object.keys(sessionStorage);
|
|
152203
|
+
keys.forEach((key) => {
|
|
152204
|
+
if (key.includes("gun") ||
|
|
152205
|
+
key.includes("user") ||
|
|
152206
|
+
key.includes("auth")) {
|
|
152207
|
+
sessionStorage.removeItem(key);
|
|
152208
|
+
}
|
|
152209
|
+
});
|
|
152210
|
+
}
|
|
152211
|
+
catch (error) {
|
|
152212
|
+
// Ignore errors
|
|
152213
|
+
}
|
|
152214
|
+
}
|
|
152215
|
+
// Clear all local storage
|
|
152216
|
+
if (typeof localStorage !== "undefined") {
|
|
152217
|
+
try {
|
|
152218
|
+
const keys = Object.keys(localStorage);
|
|
152219
|
+
keys.forEach((key) => {
|
|
152220
|
+
if (key.includes("gun") ||
|
|
152221
|
+
key.includes("user") ||
|
|
152222
|
+
key.includes("auth")) {
|
|
152223
|
+
localStorage.removeItem(key);
|
|
152224
|
+
}
|
|
152225
|
+
});
|
|
152226
|
+
}
|
|
152227
|
+
catch (error) {
|
|
152228
|
+
// Ignore errors
|
|
152229
|
+
}
|
|
152230
|
+
}
|
|
152231
|
+
console.log("✓ Aggressive auth cleanup completed");
|
|
152232
|
+
}
|
|
152233
|
+
catch (error) {
|
|
152234
|
+
console.error("Error during aggressive cleanup:", error);
|
|
152235
|
+
}
|
|
152236
|
+
}
|
|
152237
|
+
/**
|
|
152238
|
+
* Creates a completely fresh authentication context
|
|
152239
|
+
* This is a more aggressive approach when normal reset doesn't work
|
|
152240
|
+
*/
|
|
152241
|
+
createFreshAuthContext() {
|
|
152242
|
+
try {
|
|
152243
|
+
// Reset all auth state
|
|
152244
|
+
this.resetAuthState();
|
|
152245
|
+
// Create a completely new user instance
|
|
152246
|
+
const freshUser = this.gun.user();
|
|
152247
|
+
this.user = freshUser;
|
|
152248
|
+
// Clear any cached authentication data
|
|
152249
|
+
if (typeof sessionStorage !== "undefined") {
|
|
152250
|
+
try {
|
|
152251
|
+
sessionStorage.removeItem("gunSessionData");
|
|
152252
|
+
sessionStorage.removeItem("gunUserData");
|
|
152253
|
+
}
|
|
152254
|
+
catch (error) {
|
|
152255
|
+
console.warn("Error clearing session storage:", error);
|
|
152256
|
+
}
|
|
152257
|
+
}
|
|
152258
|
+
console.log("Fresh authentication context created");
|
|
152259
|
+
}
|
|
152260
|
+
catch (error) {
|
|
152261
|
+
console.error("Error creating fresh auth context:", error);
|
|
152262
|
+
}
|
|
152263
|
+
}
|
|
152264
|
+
/**
|
|
152265
|
+
* Setup cleanup handlers for memory leak prevention
|
|
152266
|
+
*/
|
|
152267
|
+
setupCleanupHandlers() {
|
|
152268
|
+
// Handle process cleanup
|
|
152269
|
+
if (typeof process !== "undefined") {
|
|
152270
|
+
process.on("SIGINT", () => this.destroy());
|
|
152271
|
+
process.on("SIGTERM", () => this.destroy());
|
|
152272
|
+
process.on("exit", () => this.destroy());
|
|
152273
|
+
}
|
|
152274
|
+
}
|
|
152275
|
+
/**
|
|
152276
|
+
* Safe interval wrapper that tracks intervals for cleanup
|
|
152277
|
+
*/
|
|
152278
|
+
safeInterval(callback, delay) {
|
|
152279
|
+
if (this._isDestroyed) {
|
|
152280
|
+
return setInterval(() => { }, 0);
|
|
152281
|
+
}
|
|
152282
|
+
const interval = setInterval(() => {
|
|
152283
|
+
if (!this._isDestroyed) {
|
|
152284
|
+
callback();
|
|
152285
|
+
}
|
|
152286
|
+
}, delay);
|
|
152287
|
+
this._activeIntervals.add(interval);
|
|
152288
|
+
return interval;
|
|
152289
|
+
}
|
|
152290
|
+
/**
|
|
152291
|
+
* Clear a specific timeout
|
|
152292
|
+
*/
|
|
152293
|
+
clearSafeTimeout(timeout) {
|
|
152294
|
+
clearTimeout(timeout);
|
|
152295
|
+
this._activeTimeouts.delete(timeout);
|
|
152296
|
+
}
|
|
152297
|
+
/**
|
|
152298
|
+
* Clear a specific interval
|
|
152299
|
+
*/
|
|
152300
|
+
clearSafeInterval(interval) {
|
|
152301
|
+
clearInterval(interval);
|
|
152302
|
+
this._activeIntervals.delete(interval);
|
|
152303
|
+
}
|
|
152304
|
+
/**
|
|
152305
|
+
* Destroy the database instance and clean up all resources
|
|
152306
|
+
*/
|
|
152307
|
+
destroy() {
|
|
152308
|
+
if (this._isDestroyed) {
|
|
152309
|
+
return;
|
|
152310
|
+
}
|
|
152311
|
+
console.log("[DB] Destroying DataBase instance...");
|
|
152312
|
+
this._isDestroyed = true;
|
|
152313
|
+
// Clear all timeouts
|
|
152314
|
+
this._activeTimeouts.forEach((timeout) => {
|
|
152315
|
+
clearTimeout(timeout);
|
|
152316
|
+
});
|
|
152317
|
+
this._activeTimeouts.clear();
|
|
152318
|
+
// Clear all intervals
|
|
152319
|
+
this._activeIntervals.forEach((interval) => {
|
|
152320
|
+
clearInterval(interval);
|
|
152321
|
+
});
|
|
152322
|
+
this._activeIntervals.clear();
|
|
152323
|
+
// Clear event listeners
|
|
152324
|
+
this.eventEmitter.removeAllListeners();
|
|
152325
|
+
// Clear auth callbacks
|
|
152326
|
+
this.onAuthCallbacks.length = 0;
|
|
152327
|
+
// Clear Gun user
|
|
152328
|
+
if (this.user) {
|
|
152329
|
+
try {
|
|
152330
|
+
this.user.leave();
|
|
152331
|
+
}
|
|
152332
|
+
catch (error) {
|
|
152333
|
+
console.warn("Error during user leave:", error);
|
|
152334
|
+
}
|
|
152335
|
+
this.user = null;
|
|
152336
|
+
}
|
|
152337
|
+
// Clear Gun instance references
|
|
152338
|
+
if (this.gun) {
|
|
152339
|
+
try {
|
|
152340
|
+
// Clear any Gun event listeners if available
|
|
152341
|
+
if (typeof this.gun.off === "function") {
|
|
152342
|
+
this.gun.off();
|
|
152343
|
+
}
|
|
152344
|
+
}
|
|
152345
|
+
catch (error) {
|
|
152346
|
+
console.warn("Error clearing Gun listeners:", error);
|
|
152347
|
+
}
|
|
152348
|
+
}
|
|
152349
|
+
// Clear other references
|
|
152350
|
+
this._rxjs = undefined;
|
|
152351
|
+
this._cryptoIdentityManager = undefined;
|
|
152352
|
+
this.core = undefined;
|
|
152353
|
+
console.log("[DB] DataBase instance destroyed");
|
|
152354
|
+
}
|
|
151763
152355
|
}
|
|
151764
152356
|
exports.DataBase = DataBase;
|
|
151765
152357
|
// Errors
|
|
151766
152358
|
DataBase.Errors = GunErrors;
|
|
151767
|
-
const createGun = (config) => {
|
|
151768
|
-
const gunInstance = (0, gun_1.default)(config);
|
|
151769
|
-
return gunInstance;
|
|
151770
|
-
};
|
|
151771
|
-
exports.createGun = createGun;
|
|
151772
|
-
exports["default"] = gun_1.default;
|
|
151773
152359
|
|
|
151774
152360
|
|
|
151775
152361
|
/***/ }),
|
|
@@ -152654,10 +153240,10 @@ Object.defineProperty(exports, "quickStart", ({ enumerable: true, get: function
|
|
|
152654
153240
|
Object.defineProperty(exports, "createSimpleAPI", ({ enumerable: true, get: function () { return gundb_1.createSimpleAPI; } }));
|
|
152655
153241
|
Object.defineProperty(exports, "AutoQuickStart", ({ enumerable: true, get: function () { return gundb_1.AutoQuickStart; } }));
|
|
152656
153242
|
Object.defineProperty(exports, "autoQuickStart", ({ enumerable: true, get: function () { return gundb_1.autoQuickStart; } }));
|
|
152657
|
-
const
|
|
152658
|
-
|
|
152659
|
-
const
|
|
152660
|
-
exports.
|
|
153243
|
+
const gun_1 = __importDefault(__webpack_require__(/*! gun */ "./node_modules/gun/gun.js"));
|
|
153244
|
+
exports.Gun = gun_1.default;
|
|
153245
|
+
const sea_1 = __importDefault(__webpack_require__(/*! gun/sea */ "./node_modules/gun/sea.js"));
|
|
153246
|
+
exports.SEA = sea_1.default;
|
|
152661
153247
|
__exportStar(__webpack_require__(/*! ./utils/errorHandler */ "./src/utils/errorHandler.ts"), exports);
|
|
152662
153248
|
__exportStar(__webpack_require__(/*! ./plugins */ "./src/plugins/index.ts"), exports);
|
|
152663
153249
|
__exportStar(__webpack_require__(/*! ./interfaces/shogun */ "./src/interfaces/shogun.ts"), exports);
|
|
@@ -153086,38 +153672,43 @@ class CoreInitializer {
|
|
|
153086
153672
|
/**
|
|
153087
153673
|
* Initialize Gun instance
|
|
153088
153674
|
*/
|
|
153089
|
-
// Sì, è corretto.
|
|
153090
153675
|
initializeGun(config) {
|
|
153091
153676
|
try {
|
|
153092
|
-
if (config.gunInstance) {
|
|
153093
|
-
|
|
153094
|
-
this.core._gun = config.gunInstance;
|
|
153677
|
+
if (!config.gunInstance) {
|
|
153678
|
+
throw new Error("Gun instance is required but was not provided");
|
|
153095
153679
|
}
|
|
153096
|
-
|
|
153097
|
-
|
|
153098
|
-
|
|
153680
|
+
// Validate Gun instance
|
|
153681
|
+
if (typeof config.gunInstance !== "object") {
|
|
153682
|
+
throw new Error(`Gun instance must be an object, received: ${typeof config.gunInstance}`);
|
|
153099
153683
|
}
|
|
153100
|
-
|
|
153101
|
-
throw new Error(
|
|
153102
|
-
// removed by dead control flow
|
|
153103
|
-
|
|
153684
|
+
if (typeof config.gunInstance.user !== "function") {
|
|
153685
|
+
throw new Error(`Gun instance is invalid: gun.user is not a function. Received gun.user type: ${typeof config.gunInstance.user}`);
|
|
153104
153686
|
}
|
|
153687
|
+
if (typeof config.gunInstance.get !== "function") {
|
|
153688
|
+
throw new Error(`Gun instance is invalid: gun.get is not a function. Received gun.get type: ${typeof config.gunInstance.get}`);
|
|
153689
|
+
}
|
|
153690
|
+
if (typeof config.gunInstance.on !== "function") {
|
|
153691
|
+
throw new Error(`Gun instance is invalid: gun.on is not a function. Received gun.on type: ${typeof config.gunInstance.on}`);
|
|
153692
|
+
}
|
|
153693
|
+
console.log("Using provided Gun instance:", config.gunInstance);
|
|
153694
|
+
this.core._gun = config.gunInstance;
|
|
153105
153695
|
}
|
|
153106
153696
|
catch (error) {
|
|
153107
153697
|
if (typeof console !== "undefined" && console.error) {
|
|
153108
|
-
console.error("Error
|
|
153698
|
+
console.error("Error validating Gun instance:", error);
|
|
153109
153699
|
}
|
|
153110
|
-
|
|
153700
|
+
throw new Error(`Failed to validate Gun instance: ${error}`);
|
|
153111
153701
|
}
|
|
153112
153702
|
try {
|
|
153113
|
-
this.core.db = new gundb_1.DataBase(this.core._gun,
|
|
153703
|
+
this.core.db = new gundb_1.DataBase(this.core._gun, "shogun", // Default app scope
|
|
153704
|
+
this.core);
|
|
153114
153705
|
return true;
|
|
153115
153706
|
}
|
|
153116
153707
|
catch (error) {
|
|
153117
153708
|
if (typeof console !== "undefined" && console.error) {
|
|
153118
|
-
console.error("Error initializing
|
|
153709
|
+
console.error("Error initializing DataBase:", error);
|
|
153119
153710
|
}
|
|
153120
|
-
throw new Error(`Failed to initialize
|
|
153711
|
+
throw new Error(`Failed to initialize DataBase: ${error}`);
|
|
153121
153712
|
}
|
|
153122
153713
|
}
|
|
153123
153714
|
/**
|
|
@@ -153286,8 +153877,9 @@ const errorHandler_1 = __webpack_require__(/*! ../utils/errorHandler */ "./src/u
|
|
|
153286
153877
|
* Genera automaticamente tutte le identità crypto disponibili dopo l'autenticazione SEA
|
|
153287
153878
|
*/
|
|
153288
153879
|
class CryptoIdentityManager {
|
|
153289
|
-
constructor(core) {
|
|
153880
|
+
constructor(core, db) {
|
|
153290
153881
|
this.core = core;
|
|
153882
|
+
this.db = db || core.db; // Use core.db if db not provided
|
|
153291
153883
|
this.pgpManager = new pgp_1.PGPManager();
|
|
153292
153884
|
this.mlsManager = new mls_1.MLSManager("default-user");
|
|
153293
153885
|
this.sframeManager = new sframe_1.SFrameManager();
|
|
@@ -153374,6 +153966,11 @@ class CryptoIdentityManager {
|
|
|
153374
153966
|
console.error(`❌ [${username}] SFrame key generation failed:`, error);
|
|
153375
153967
|
}
|
|
153376
153968
|
console.log(`✅ [CryptoIdentityManager] All crypto identities generated for: ${username}`);
|
|
153969
|
+
// Force garbage collection after generation
|
|
153970
|
+
if (typeof __webpack_require__.g !== "undefined" && __webpack_require__.g.gc) {
|
|
153971
|
+
__webpack_require__.g.gc();
|
|
153972
|
+
console.log(`🧹 [${username}] Forced garbage collection after identity generation`);
|
|
153973
|
+
}
|
|
153377
153974
|
return {
|
|
153378
153975
|
success: true,
|
|
153379
153976
|
identities,
|
|
@@ -153409,41 +154006,76 @@ class CryptoIdentityManager {
|
|
|
153409
154006
|
}
|
|
153410
154007
|
// Salva su GunDB nel percorso privato dell'utente
|
|
153411
154008
|
const saveResult = await new Promise((resolve, reject) => {
|
|
153412
|
-
|
|
153413
|
-
.
|
|
153414
|
-
.
|
|
153415
|
-
|
|
153416
|
-
|
|
153417
|
-
|
|
153418
|
-
|
|
153419
|
-
|
|
153420
|
-
|
|
153421
|
-
|
|
153422
|
-
|
|
153423
|
-
|
|
153424
|
-
|
|
153425
|
-
|
|
154009
|
+
const timeout = setTimeout(() => {
|
|
154010
|
+
console.warn(`⚠️ [${username}] Save identities timeout after 5 seconds, continuing anyway`);
|
|
154011
|
+
savedKeys.push("crypto-identities");
|
|
154012
|
+
resolve(true); // Resolve anyway to not block the process
|
|
154013
|
+
}, 5000); // 5 second timeout
|
|
154014
|
+
try {
|
|
154015
|
+
this.db.gun
|
|
154016
|
+
.user()
|
|
154017
|
+
.get("crypto-identities")
|
|
154018
|
+
.put(encryptedIdentities, (ack) => {
|
|
154019
|
+
clearTimeout(timeout);
|
|
154020
|
+
if (ack && ack.err) {
|
|
154021
|
+
console.error(`❌ [${username}] Failed to save identities:`, ack.err);
|
|
154022
|
+
reject(new Error(ack.err));
|
|
154023
|
+
}
|
|
154024
|
+
else {
|
|
154025
|
+
console.log(`✅ [${username}] Crypto identities saved successfully`);
|
|
154026
|
+
savedKeys.push("crypto-identities");
|
|
154027
|
+
resolve(true);
|
|
154028
|
+
}
|
|
154029
|
+
});
|
|
154030
|
+
}
|
|
154031
|
+
catch (putError) {
|
|
154032
|
+
clearTimeout(timeout);
|
|
154033
|
+
console.error(`❌ [${username}] Error during put operation:`, putError);
|
|
154034
|
+
// Don't reject, just resolve to not block - Gun might save eventually
|
|
154035
|
+
savedKeys.push("crypto-identities");
|
|
154036
|
+
resolve(true);
|
|
154037
|
+
}
|
|
153426
154038
|
});
|
|
153427
154039
|
// Salva anche una copia di backup nel percorso pubblico (solo hash per verifica)
|
|
153428
154040
|
const identitiesHash = await sea_1.default.work(identitiesJson, null, null, {
|
|
153429
154041
|
name: "SHA-256",
|
|
153430
154042
|
});
|
|
153431
154043
|
await new Promise((resolve, reject) => {
|
|
153432
|
-
|
|
153433
|
-
.
|
|
153434
|
-
.
|
|
153435
|
-
|
|
153436
|
-
|
|
153437
|
-
|
|
153438
|
-
|
|
153439
|
-
|
|
153440
|
-
|
|
153441
|
-
|
|
153442
|
-
|
|
153443
|
-
|
|
153444
|
-
|
|
153445
|
-
|
|
154044
|
+
const timeout = setTimeout(() => {
|
|
154045
|
+
console.warn(`⚠️ [${username}] Save identities hash timeout after 5 seconds, continuing anyway`);
|
|
154046
|
+
savedKeys.push("crypto-identities-hash");
|
|
154047
|
+
resolve(true); // Resolve anyway to not block the process
|
|
154048
|
+
}, 5000); // 5 second timeout
|
|
154049
|
+
try {
|
|
154050
|
+
this.db.gun
|
|
154051
|
+
.user()
|
|
154052
|
+
.get("crypto-identities-hash")
|
|
154053
|
+
.put(identitiesHash, (ack) => {
|
|
154054
|
+
clearTimeout(timeout);
|
|
154055
|
+
if (ack && ack.err) {
|
|
154056
|
+
console.error(`❌ [${username}] Failed to save identities hash:`, ack.err);
|
|
154057
|
+
reject(new Error(ack.err));
|
|
154058
|
+
}
|
|
154059
|
+
else {
|
|
154060
|
+
console.log(`✅ [${username}] Crypto identities hash saved`);
|
|
154061
|
+
savedKeys.push("crypto-identities-hash");
|
|
154062
|
+
resolve(true);
|
|
154063
|
+
}
|
|
154064
|
+
});
|
|
154065
|
+
}
|
|
154066
|
+
catch (putError) {
|
|
154067
|
+
clearTimeout(timeout);
|
|
154068
|
+
console.error(`❌ [${username}] Error during hash put operation:`, putError);
|
|
154069
|
+
// Don't reject, just resolve to not block - Gun might save eventually
|
|
154070
|
+
savedKeys.push("crypto-identities-hash");
|
|
154071
|
+
resolve(true);
|
|
154072
|
+
}
|
|
153446
154073
|
});
|
|
154074
|
+
// Force garbage collection after saving
|
|
154075
|
+
if (typeof __webpack_require__.g !== "undefined" && __webpack_require__.g.gc) {
|
|
154076
|
+
__webpack_require__.g.gc();
|
|
154077
|
+
console.log(`🧹 [${username}] Forced garbage collection after saving identities`);
|
|
154078
|
+
}
|
|
153447
154079
|
return {
|
|
153448
154080
|
success: true,
|
|
153449
154081
|
savedKeys,
|
|
@@ -153470,7 +154102,7 @@ class CryptoIdentityManager {
|
|
|
153470
154102
|
console.log(`🔍 [CryptoIdentityManager] Retrieving crypto identities for: ${username}`);
|
|
153471
154103
|
// Recupera le identità criptate da GunDB
|
|
153472
154104
|
const encryptedIdentities = await new Promise((resolve, reject) => {
|
|
153473
|
-
this.
|
|
154105
|
+
this.db.gun
|
|
153474
154106
|
.user()
|
|
153475
154107
|
.get("crypto-identities")
|
|
153476
154108
|
.once((data) => {
|
|
@@ -153522,7 +154154,7 @@ class CryptoIdentityManager {
|
|
|
153522
154154
|
async hasStoredIdentities(username) {
|
|
153523
154155
|
try {
|
|
153524
154156
|
const hasIdentities = await new Promise((resolve) => {
|
|
153525
|
-
this.
|
|
154157
|
+
this.db.gun
|
|
153526
154158
|
.user()
|
|
153527
154159
|
.get("crypto-identities")
|
|
153528
154160
|
.once((data) => {
|
|
@@ -153609,7 +154241,13 @@ class CryptoIdentityManager {
|
|
|
153609
154241
|
};
|
|
153610
154242
|
}
|
|
153611
154243
|
// Ottieni il SEA pair dell'utente corrente
|
|
153612
|
-
|
|
154244
|
+
if (!this.db || !this.db.gun) {
|
|
154245
|
+
return {
|
|
154246
|
+
success: false,
|
|
154247
|
+
error: "Database not available",
|
|
154248
|
+
};
|
|
154249
|
+
}
|
|
154250
|
+
const userInstance = this.db.gun.user();
|
|
153613
154251
|
const seaPair = userInstance?._?.sea;
|
|
153614
154252
|
if (!seaPair) {
|
|
153615
154253
|
return {
|
|
@@ -158640,7 +159278,10 @@ class ZkCredentials {
|
|
|
158640
159278
|
const externalNullifier = BigInt(ethers_1.ethers.keccak256(ethers_1.ethers.toUtf8Bytes(credentialData.type)));
|
|
158641
159279
|
// Generate ZK proof
|
|
158642
159280
|
// Note: This requires circuit files to be available
|
|
158643
|
-
const fullProof = await (0, proof_1.generateProof)(identity, group, signalBigInt, externalNullifier
|
|
159281
|
+
const fullProof = await (0, proof_1.generateProof)(identity, group, signalBigInt, externalNullifier, {
|
|
159282
|
+
wasmFilePath: "./circuits/semaphore/20/semaphore.wasm",
|
|
159283
|
+
zkeyFilePath: "./circuits/semaphore/20/semaphore.zkey",
|
|
159284
|
+
});
|
|
158644
159285
|
return {
|
|
158645
159286
|
type: credentialData.type,
|
|
158646
159287
|
claim: credentialData.claim,
|