shogun-core 1.1.4 → 1.2.2
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 +61 -1327
- package/dist/browser/shogun-core.js +1 -1
- package/dist/browser/shogun-core.js.LICENSE.txt +0 -9
- package/dist/browser/shogun-core.light.js +1 -1
- package/dist/browser/shogun-core.vendors.light.js +1 -1
- package/dist/browser.js +27 -11
- package/dist/core.js +603 -0
- package/dist/{gun → gundb}/crypto.js +38 -8
- package/dist/gundb/gun.js +676 -0
- package/dist/{gun → gundb}/index.js +0 -5
- package/dist/{gun → gundb}/utils.js +6 -0
- package/dist/index.js +1 -807
- package/dist/plugins/index.js +15 -28
- package/dist/plugins/{stealth → nostr}/index.js +3 -4
- package/dist/plugins/nostr/nostrConnector.js +656 -0
- package/dist/plugins/nostr/nostrConnectorPlugin.js +259 -0
- package/dist/plugins/{metamask → web3}/index.js +2 -2
- package/dist/plugins/{metamask/metamask.js → web3/web3Connector.js} +8 -8
- package/dist/plugins/{metamask/metamaskPlugin.js → web3/web3ConnectorPlugin.js} +32 -42
- package/dist/plugins/webauthn/webauthnPlugin.js +4 -0
- package/dist/types/browser.d.ts +9 -4
- package/dist/types/core.d.ts +221 -0
- package/dist/types/{gun → gundb}/crypto.d.ts +20 -5
- package/dist/types/{gun → gundb}/gun.d.ts +56 -28
- package/dist/types/gundb/index.d.ts +1 -0
- package/dist/types/{gun → gundb}/utils.d.ts +1 -0
- package/dist/types/index.d.ts +1 -282
- package/dist/types/plugins/index.d.ts +7 -10
- package/dist/types/plugins/nostr/index.d.ts +3 -0
- package/dist/types/plugins/nostr/nostrConnector.d.ts +111 -0
- package/dist/types/plugins/nostr/nostrConnectorPlugin.d.ts +87 -0
- package/dist/types/plugins/nostr/types.d.ts +122 -0
- package/dist/types/plugins/web3/index.d.ts +3 -0
- package/dist/types/plugins/{metamask → web3}/types.d.ts +4 -4
- package/dist/types/plugins/{metamask/metamask.d.ts → web3/web3Connector.d.ts} +7 -7
- package/dist/types/plugins/{metamask/metamaskPlugin.d.ts → web3/web3ConnectorPlugin.d.ts} +4 -4
- package/dist/types/shogun.js +40 -15
- package/dist/types/types/shogun.d.ts +67 -67
- package/dist/types/utils/errorHandler.d.ts +39 -36
- package/dist/types/utils/utility.d.ts +0 -4
- package/dist/utils/errorHandler.js +43 -40
- package/dist/utils/utility.js +0 -8
- package/package.json +2 -2
- package/dist/config.js +0 -18
- package/dist/gun/gun.js +0 -542
- package/dist/plugins/stealth/stealth.js +0 -176
- package/dist/plugins/stealth/stealthPlugin.js +0 -113
- package/dist/plugins/stealth/types.js +0 -2
- package/dist/plugins/utils/stubs/didStub.js +0 -35
- package/dist/plugins/utils/stubs/stealthStub.js +0 -35
- package/dist/plugins/utils/stubs/webauthnStub.js +0 -29
- package/dist/plugins/wallet/index.js +0 -20
- package/dist/plugins/wallet/types.js +0 -15
- package/dist/plugins/wallet/walletManager.js +0 -1832
- package/dist/plugins/wallet/walletPlugin.js +0 -236
- package/dist/types/config.d.ts +0 -15
- package/dist/types/gun/index.d.ts +0 -6
- package/dist/types/gun/types.d.ts +0 -2
- package/dist/types/plugins/metamask/index.d.ts +0 -3
- package/dist/types/plugins/stealth/index.d.ts +0 -3
- package/dist/types/plugins/stealth/stealth.d.ts +0 -93
- package/dist/types/plugins/stealth/stealthPlugin.d.ts +0 -60
- package/dist/types/plugins/stealth/types.d.ts +0 -93
- package/dist/types/plugins/utils/stubs/didStub.d.ts +0 -15
- package/dist/types/plugins/utils/stubs/stealthStub.d.ts +0 -15
- package/dist/types/plugins/utils/stubs/webauthnStub.d.ts +0 -13
- package/dist/types/plugins/wallet/index.d.ts +0 -3
- package/dist/types/plugins/wallet/types.d.ts +0 -167
- package/dist/types/plugins/wallet/walletManager.d.ts +0 -306
- package/dist/types/plugins/wallet/walletPlugin.d.ts +0 -126
- package/dist/types/utils/stubs/didStub.d.ts +0 -15
- package/dist/types/utils/stubs/stealthStub.d.ts +0 -15
- package/dist/types/utils/stubs/webauthnStub.d.ts +0 -13
- package/dist/utils/stubs/didStub.js +0 -35
- package/dist/utils/stubs/stealthStub.js +0 -35
- package/dist/utils/stubs/webauthnStub.js +0 -29
- /package/dist/{gun → gundb}/errors.js +0 -0
- /package/dist/{gun → gundb}/rxjs-integration.js +0 -0
- /package/dist/{gun → plugins/nostr}/types.js +0 -0
- /package/dist/plugins/{metamask → web3}/types.js +0 -0
- /package/dist/types/{gun → gundb}/errors.d.ts +0 -0
- /package/dist/types/{gun → gundb}/rxjs-integration.d.ts +0 -0
|
@@ -0,0 +1,676 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* GunDB class with enhanced features:
|
|
4
|
+
* - Dynamic peer linking
|
|
5
|
+
* - Support for remove/unset operations
|
|
6
|
+
* - Direct authentication through Gun.user()
|
|
7
|
+
*/
|
|
8
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
|
+
if (k2 === undefined) k2 = k;
|
|
10
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
15
|
+
}) : (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
o[k2] = m[k];
|
|
18
|
+
}));
|
|
19
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
20
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
21
|
+
}) : function(o, v) {
|
|
22
|
+
o["default"] = v;
|
|
23
|
+
});
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.GunDB = void 0;
|
|
43
|
+
const logger_1 = require("../utils/logger");
|
|
44
|
+
const errorHandler_1 = require("../utils/errorHandler");
|
|
45
|
+
const rxjs_integration_1 = require("./rxjs-integration");
|
|
46
|
+
const GunErrors = __importStar(require("./errors"));
|
|
47
|
+
const crypto = __importStar(require("./crypto"));
|
|
48
|
+
const utils = __importStar(require("./utils"));
|
|
49
|
+
class GunDB {
|
|
50
|
+
gun;
|
|
51
|
+
user = null;
|
|
52
|
+
crypto;
|
|
53
|
+
utils;
|
|
54
|
+
node;
|
|
55
|
+
onAuthCallbacks = [];
|
|
56
|
+
// Integrated modules
|
|
57
|
+
_rxjs;
|
|
58
|
+
constructor(gun, appScope = "shogun") {
|
|
59
|
+
(0, logger_1.log)("Initializing GunDB");
|
|
60
|
+
// Validate Gun instance
|
|
61
|
+
if (!gun) {
|
|
62
|
+
throw new Error("Gun instance is required but was not provided");
|
|
63
|
+
}
|
|
64
|
+
if (typeof gun !== "object") {
|
|
65
|
+
throw new Error(`Gun instance must be an object, received: ${typeof gun}`);
|
|
66
|
+
}
|
|
67
|
+
if (typeof gun.user !== "function") {
|
|
68
|
+
throw new Error(`Gun instance is invalid: gun.user is not a function. Received gun.user type: ${typeof gun.user}`);
|
|
69
|
+
}
|
|
70
|
+
if (typeof gun.get !== "function") {
|
|
71
|
+
throw new Error(`Gun instance is invalid: gun.get is not a function. Received gun.get type: ${typeof gun.get}`);
|
|
72
|
+
}
|
|
73
|
+
if (typeof gun.on !== "function") {
|
|
74
|
+
throw new Error(`Gun instance is invalid: gun.on is not a function. Received gun.on type: ${typeof gun.on}`);
|
|
75
|
+
}
|
|
76
|
+
this.gun = gun;
|
|
77
|
+
try {
|
|
78
|
+
this.user = this.gun.user().recall({ sessionStorage: true });
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
(0, logger_1.logError)("Error initializing Gun user:", error);
|
|
82
|
+
throw new Error(`Failed to initialize Gun user: ${error}`);
|
|
83
|
+
}
|
|
84
|
+
this.subscribeToAuthEvents();
|
|
85
|
+
// bind crypto and utils
|
|
86
|
+
this.crypto = crypto;
|
|
87
|
+
this.utils = utils;
|
|
88
|
+
this.node = this.gun.get(appScope);
|
|
89
|
+
}
|
|
90
|
+
subscribeToAuthEvents() {
|
|
91
|
+
this.gun.on("auth", (ack) => {
|
|
92
|
+
(0, logger_1.log)("Auth event received:", ack);
|
|
93
|
+
if (ack.err) {
|
|
94
|
+
errorHandler_1.ErrorHandler.handle(errorHandler_1.ErrorType.GUN, "AUTH_EVENT_ERROR", ack.err, new Error(ack.err));
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
this.notifyAuthListeners(ack.sea?.pub || "");
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
notifyAuthListeners(pub) {
|
|
102
|
+
const user = this.gun.user();
|
|
103
|
+
this.onAuthCallbacks.forEach((cb) => cb(user));
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Adds a new peer to the network
|
|
107
|
+
* @param peer URL of the peer to add
|
|
108
|
+
*/
|
|
109
|
+
addPeer(peer) {
|
|
110
|
+
this.gun.opt({ peers: [peer] });
|
|
111
|
+
(0, logger_1.log)(`Added new peer: ${peer}`);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Removes a peer from the network
|
|
115
|
+
* @param peer URL of the peer to remove
|
|
116
|
+
*/
|
|
117
|
+
removePeer(peer) {
|
|
118
|
+
try {
|
|
119
|
+
// Get current peers from Gun instance
|
|
120
|
+
const gunOpts = this.gun._.opt;
|
|
121
|
+
if (gunOpts && gunOpts.peers) {
|
|
122
|
+
// Remove the peer from the peers object
|
|
123
|
+
delete gunOpts.peers[peer];
|
|
124
|
+
// Also try to close the connection if it exists
|
|
125
|
+
const peerConnection = gunOpts.peers[peer];
|
|
126
|
+
if (peerConnection && typeof peerConnection.close === "function") {
|
|
127
|
+
peerConnection.close();
|
|
128
|
+
}
|
|
129
|
+
(0, logger_1.log)(`Removed peer: ${peer}`);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
(0, logger_1.log)(`Peer not found in current connections: ${peer}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
(0, logger_1.logError)(`Error removing peer ${peer}:`, error);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Gets the list of currently connected peers
|
|
141
|
+
* @returns Array of peer URLs
|
|
142
|
+
*/
|
|
143
|
+
getCurrentPeers() {
|
|
144
|
+
try {
|
|
145
|
+
const gunOpts = this.gun._.opt;
|
|
146
|
+
if (gunOpts && gunOpts.peers) {
|
|
147
|
+
return Object.keys(gunOpts.peers).filter((peer) => {
|
|
148
|
+
const peerObj = gunOpts.peers[peer];
|
|
149
|
+
// Check if peer is actually connected (not just configured)
|
|
150
|
+
return peerObj && peerObj.wire && peerObj.wire.hied !== "bye";
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
(0, logger_1.logError)("Error getting current peers:", error);
|
|
157
|
+
return [];
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Gets the list of all configured peers (connected and disconnected)
|
|
162
|
+
* @returns Array of peer URLs
|
|
163
|
+
*/
|
|
164
|
+
getAllConfiguredPeers() {
|
|
165
|
+
try {
|
|
166
|
+
const gunOpts = this.gun._.opt;
|
|
167
|
+
if (gunOpts && gunOpts.peers) {
|
|
168
|
+
return Object.keys(gunOpts.peers);
|
|
169
|
+
}
|
|
170
|
+
return [];
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
(0, logger_1.logError)("Error getting configured peers:", error);
|
|
174
|
+
return [];
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Gets detailed information about all peers
|
|
179
|
+
* @returns Object with peer information
|
|
180
|
+
*/
|
|
181
|
+
getPeerInfo() {
|
|
182
|
+
try {
|
|
183
|
+
const gunOpts = this.gun._.opt;
|
|
184
|
+
const peerInfo = {};
|
|
185
|
+
if (gunOpts && gunOpts.peers) {
|
|
186
|
+
Object.keys(gunOpts.peers).forEach((peer) => {
|
|
187
|
+
const peerObj = gunOpts.peers[peer];
|
|
188
|
+
const isConnected = peerObj && peerObj.wire && peerObj.wire.hied !== "bye";
|
|
189
|
+
const status = isConnected
|
|
190
|
+
? "connected"
|
|
191
|
+
: peerObj && peerObj.wire
|
|
192
|
+
? "disconnected"
|
|
193
|
+
: "not_initialized";
|
|
194
|
+
peerInfo[peer] = {
|
|
195
|
+
connected: isConnected,
|
|
196
|
+
status: status,
|
|
197
|
+
};
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
return peerInfo;
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
(0, logger_1.logError)("Error getting peer info:", error);
|
|
204
|
+
return {};
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Reconnects to a specific peer
|
|
209
|
+
* @param peer URL of the peer to reconnect
|
|
210
|
+
*/
|
|
211
|
+
reconnectToPeer(peer) {
|
|
212
|
+
try {
|
|
213
|
+
// First remove the peer
|
|
214
|
+
this.removePeer(peer);
|
|
215
|
+
// Wait a moment then add it back
|
|
216
|
+
setTimeout(() => {
|
|
217
|
+
this.addPeer(peer);
|
|
218
|
+
(0, logger_1.log)(`Reconnected to peer: ${peer}`);
|
|
219
|
+
}, 1000);
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
(0, logger_1.logError)(`Error reconnecting to peer ${peer}:`, error);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Clears all peers and optionally adds new ones
|
|
227
|
+
* @param newPeers Optional array of new peers to add
|
|
228
|
+
*/
|
|
229
|
+
resetPeers(newPeers) {
|
|
230
|
+
try {
|
|
231
|
+
const gunOpts = this.gun._.opt;
|
|
232
|
+
if (gunOpts && gunOpts.peers) {
|
|
233
|
+
// Clear all existing peers
|
|
234
|
+
Object.keys(gunOpts.peers).forEach((peer) => {
|
|
235
|
+
this.removePeer(peer);
|
|
236
|
+
});
|
|
237
|
+
// Add new peers if provided
|
|
238
|
+
if (newPeers && newPeers.length > 0) {
|
|
239
|
+
newPeers.forEach((peer) => {
|
|
240
|
+
this.addPeer(peer);
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
(0, logger_1.log)(`Reset peers. New peers: ${newPeers ? newPeers.join(", ") : "none"}`);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
catch (error) {
|
|
247
|
+
(0, logger_1.logError)("Error resetting peers:", error);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Registers an authentication callback
|
|
252
|
+
* @param callback Function to call on auth events
|
|
253
|
+
* @returns Function to unsubscribe the callback
|
|
254
|
+
*/
|
|
255
|
+
onAuth(callback) {
|
|
256
|
+
this.onAuthCallbacks.push(callback);
|
|
257
|
+
const user = this.gun.user();
|
|
258
|
+
if (user && user.is)
|
|
259
|
+
callback(user);
|
|
260
|
+
return () => {
|
|
261
|
+
const i = this.onAuthCallbacks.indexOf(callback);
|
|
262
|
+
if (i !== -1)
|
|
263
|
+
this.onAuthCallbacks.splice(i, 1);
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Gets the Gun instance
|
|
268
|
+
* @returns Gun instance
|
|
269
|
+
*/
|
|
270
|
+
getGun() {
|
|
271
|
+
return this.gun;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Gets the current user instance
|
|
275
|
+
* @returns User instance
|
|
276
|
+
*/
|
|
277
|
+
getUser() {
|
|
278
|
+
return this.gun.user();
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Gets a node at the specified path
|
|
282
|
+
* @param path Path to the node
|
|
283
|
+
* @returns Gun node
|
|
284
|
+
*/
|
|
285
|
+
get(path) {
|
|
286
|
+
return this.gun.get(path);
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Puts data at the specified path
|
|
290
|
+
* @param path Path to store data
|
|
291
|
+
* @param data Data to store
|
|
292
|
+
* @returns Promise resolving to operation result
|
|
293
|
+
*/
|
|
294
|
+
async put(path, data) {
|
|
295
|
+
return new Promise((resolve) => {
|
|
296
|
+
this.gun.get(path).put(data, (ack) => {
|
|
297
|
+
resolve(ack.err ? { success: false, error: ack.err } : { success: true });
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Sets data at the specified path
|
|
303
|
+
* @param path Path to store data
|
|
304
|
+
* @param data Data to store
|
|
305
|
+
* @returns Promise resolving to operation result
|
|
306
|
+
*/
|
|
307
|
+
async set(path, data) {
|
|
308
|
+
return new Promise((resolve) => {
|
|
309
|
+
this.gun.get(path).set(data, (ack) => {
|
|
310
|
+
resolve(ack.err ? { success: false, error: ack.err } : { success: true });
|
|
311
|
+
});
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Removes data at the specified path
|
|
316
|
+
* @param path Path to remove
|
|
317
|
+
* @returns Promise resolving to operation result
|
|
318
|
+
*/
|
|
319
|
+
async remove(path) {
|
|
320
|
+
return new Promise((resolve) => {
|
|
321
|
+
this.gun.get(path).put(null, (ack) => {
|
|
322
|
+
resolve(ack.err ? { success: false, error: ack.err } : { success: true });
|
|
323
|
+
});
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Signs up a new user using direct Gun authentication
|
|
328
|
+
* @param username Username
|
|
329
|
+
* @param password Password
|
|
330
|
+
* @returns Promise resolving to signup result
|
|
331
|
+
*/
|
|
332
|
+
async signUp(username, password) {
|
|
333
|
+
(0, logger_1.log)("Attempting user registration:", username);
|
|
334
|
+
try {
|
|
335
|
+
// Validate credentials
|
|
336
|
+
if (password.length < 8) {
|
|
337
|
+
const err = "Passwords must be more than 8 characters long!";
|
|
338
|
+
(0, logger_1.log)(err);
|
|
339
|
+
return { success: false, error: err };
|
|
340
|
+
}
|
|
341
|
+
if (username.length < 1) {
|
|
342
|
+
const err = "Username must be more than 0 characters long!";
|
|
343
|
+
(0, logger_1.log)(err);
|
|
344
|
+
return { success: false, error: err };
|
|
345
|
+
}
|
|
346
|
+
// Create user directly with Gun
|
|
347
|
+
const createResult = await new Promise((resolve) => {
|
|
348
|
+
this.gun.user().create(username, password, (ack) => {
|
|
349
|
+
if (ack.err) {
|
|
350
|
+
(0, logger_1.logError)(`User creation error: ${ack.err}`);
|
|
351
|
+
resolve({ success: false, error: ack.err });
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
(0, logger_1.log)(`User created successfully: ${username}`);
|
|
355
|
+
resolve({ success: true, pub: ack.pub });
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
});
|
|
359
|
+
if (!createResult.success) {
|
|
360
|
+
return createResult;
|
|
361
|
+
}
|
|
362
|
+
// Store user metadata with improved safety
|
|
363
|
+
try {
|
|
364
|
+
const user = this.gun.get(createResult.pub).put({
|
|
365
|
+
username: username,
|
|
366
|
+
pub: createResult.pub,
|
|
367
|
+
});
|
|
368
|
+
this.gun.get("users").set(user);
|
|
369
|
+
}
|
|
370
|
+
catch (metadataError) {
|
|
371
|
+
(0, logger_1.logError)(`Warning: Could not store user metadata: ${metadataError}`);
|
|
372
|
+
// Continue with login attempt even if metadata storage fails
|
|
373
|
+
}
|
|
374
|
+
// Login after creation
|
|
375
|
+
(0, logger_1.log)(`Attempting login after registration for: ${username}`);
|
|
376
|
+
try {
|
|
377
|
+
const loginResult = await this.login(username, password);
|
|
378
|
+
if (!loginResult.success) {
|
|
379
|
+
(0, logger_1.logError)(`Login after registration failed: ${loginResult.error}`);
|
|
380
|
+
return {
|
|
381
|
+
success: false,
|
|
382
|
+
error: `Registration completed but login failed: ${loginResult.error}`,
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
(0, logger_1.log)(`Login after registration successful for: ${username}`);
|
|
386
|
+
return loginResult;
|
|
387
|
+
}
|
|
388
|
+
catch (loginError) {
|
|
389
|
+
(0, logger_1.logError)(`Exception during post-registration login: ${loginError}`);
|
|
390
|
+
return {
|
|
391
|
+
success: false,
|
|
392
|
+
error: "Exception during post-registration login",
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
catch (error) {
|
|
397
|
+
(0, logger_1.logError)(`Unexpected error during registration flow: ${error}`);
|
|
398
|
+
return {
|
|
399
|
+
success: false,
|
|
400
|
+
error: `Unexpected error during registration: ${error}`,
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Logs in a user using direct Gun authentication
|
|
406
|
+
* @param username Username
|
|
407
|
+
* @param password Password
|
|
408
|
+
* @param callback Optional callback for login result
|
|
409
|
+
* @returns Promise resolving to login result
|
|
410
|
+
*/
|
|
411
|
+
async login(username, password, callback) {
|
|
412
|
+
(0, logger_1.log)(`Attempting login for user: ${username}`);
|
|
413
|
+
try {
|
|
414
|
+
// Authenticate with Gun directly
|
|
415
|
+
const authResult = await new Promise((resolve) => {
|
|
416
|
+
this.gun.user().auth(username, password, (ack) => {
|
|
417
|
+
if (ack.err) {
|
|
418
|
+
(0, logger_1.logError)(`Login error for ${username}: ${ack.err}`);
|
|
419
|
+
resolve({ success: false, error: ack.err });
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
(0, logger_1.log)(`Login successful for: ${username}`);
|
|
423
|
+
resolve({ success: true, ack });
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
});
|
|
427
|
+
if (!authResult.success) {
|
|
428
|
+
const result = { success: false, error: authResult.error };
|
|
429
|
+
if (callback)
|
|
430
|
+
callback(result);
|
|
431
|
+
return result;
|
|
432
|
+
}
|
|
433
|
+
const userPub = this.gun.user().is?.pub;
|
|
434
|
+
// Update users collection if needed - improved null safety
|
|
435
|
+
try {
|
|
436
|
+
let userExists = false;
|
|
437
|
+
// Check if user already exists in the collection
|
|
438
|
+
await new Promise((resolve) => {
|
|
439
|
+
this.gun
|
|
440
|
+
.get("users")
|
|
441
|
+
.map()
|
|
442
|
+
.once((userData, key) => {
|
|
443
|
+
if (userData && userData.pub === userPub) {
|
|
444
|
+
userExists = true;
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
// Give it a moment to check all users
|
|
448
|
+
setTimeout(() => resolve(), 100);
|
|
449
|
+
});
|
|
450
|
+
// Only add user if not already in collection
|
|
451
|
+
if (!userExists && userPub) {
|
|
452
|
+
const newUser = this.gun.get(userPub).put({
|
|
453
|
+
username: username,
|
|
454
|
+
pub: userPub,
|
|
455
|
+
});
|
|
456
|
+
this.gun.get("users").set(newUser);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
catch (collectionError) {
|
|
460
|
+
// Log but don't fail the login for collection errors
|
|
461
|
+
(0, logger_1.logError)(`Warning: Could not update user collection: ${collectionError}`);
|
|
462
|
+
}
|
|
463
|
+
(0, logger_1.log)(`Login successful for: ${username} (${userPub})`);
|
|
464
|
+
this._savePair();
|
|
465
|
+
const result = {
|
|
466
|
+
success: true,
|
|
467
|
+
userPub,
|
|
468
|
+
username,
|
|
469
|
+
};
|
|
470
|
+
if (callback)
|
|
471
|
+
callback(result);
|
|
472
|
+
return result;
|
|
473
|
+
}
|
|
474
|
+
catch (error) {
|
|
475
|
+
(0, logger_1.logError)(`Exception during login for ${username}: ${error}`);
|
|
476
|
+
const result = { success: false, error: String(error) };
|
|
477
|
+
if (callback)
|
|
478
|
+
callback(result);
|
|
479
|
+
return result;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
_savePair() {
|
|
483
|
+
try {
|
|
484
|
+
const pair = this.gun.user()?._?.sea;
|
|
485
|
+
if (pair && typeof localStorage !== "undefined") {
|
|
486
|
+
localStorage.setItem("pair", JSON.stringify(pair));
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
catch (error) {
|
|
490
|
+
console.error("Error saving auth pair:", error);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Logs out the current user using direct Gun authentication
|
|
495
|
+
*/
|
|
496
|
+
logout() {
|
|
497
|
+
try {
|
|
498
|
+
// Check if the user is actually logged in before attempting to logout
|
|
499
|
+
if (!this.isLoggedIn()) {
|
|
500
|
+
(0, logger_1.log)("No user logged in, skipping logout");
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
// Direct logout using Gun
|
|
504
|
+
this.gun.user().leave();
|
|
505
|
+
(0, logger_1.log)("Logout completed");
|
|
506
|
+
}
|
|
507
|
+
catch (error) {
|
|
508
|
+
(0, logger_1.logError)("Error during logout:", error);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Checks if a user is currently logged in
|
|
513
|
+
* @returns True if logged in
|
|
514
|
+
*/
|
|
515
|
+
isLoggedIn() {
|
|
516
|
+
return !!this.gun.user()?.is?.pub;
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Gets the current user
|
|
520
|
+
* @returns Current user object or null
|
|
521
|
+
*/
|
|
522
|
+
getCurrentUser() {
|
|
523
|
+
const pub = this.gun.user()?.is?.pub;
|
|
524
|
+
return pub ? { pub, user: this.gun.user() } : null;
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Accesses the RxJS module for reactive programming
|
|
528
|
+
* @returns GunRxJS instance
|
|
529
|
+
*/
|
|
530
|
+
rx() {
|
|
531
|
+
if (!this._rxjs) {
|
|
532
|
+
this._rxjs = new rxjs_integration_1.GunRxJS(this.gun);
|
|
533
|
+
}
|
|
534
|
+
return this._rxjs;
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* Sets up security questions and password hint
|
|
538
|
+
* @param username Username
|
|
539
|
+
* @param password Current password
|
|
540
|
+
* @param hint Password hint
|
|
541
|
+
* @param securityQuestions Array of security questions
|
|
542
|
+
* @param securityAnswers Array of answers to security questions
|
|
543
|
+
* @returns Promise resolving with the operation result
|
|
544
|
+
*/
|
|
545
|
+
async setPasswordHint(username, password, hint, securityQuestions, securityAnswers) {
|
|
546
|
+
(0, logger_1.log)("Setting password hint for:", username);
|
|
547
|
+
// Verify that the user is authenticated
|
|
548
|
+
const loginResult = await this.login(username, password);
|
|
549
|
+
if (!loginResult.success) {
|
|
550
|
+
return { success: false, error: "Authentication failed" };
|
|
551
|
+
}
|
|
552
|
+
try {
|
|
553
|
+
// Generate a proof of work from security question answers
|
|
554
|
+
const proofOfWork = (await this.crypto.hashText(securityAnswers.join("|")));
|
|
555
|
+
// Encrypt the password hint with the proof of work
|
|
556
|
+
// The PoW (a string) is used as the encryption key
|
|
557
|
+
const encryptedHint = await this.crypto.encrypt(hint, proofOfWork);
|
|
558
|
+
// Save security questions and encrypted hint
|
|
559
|
+
await this.saveUserData("security", {
|
|
560
|
+
questions: securityQuestions,
|
|
561
|
+
hint: encryptedHint,
|
|
562
|
+
});
|
|
563
|
+
return { success: true };
|
|
564
|
+
}
|
|
565
|
+
catch (error) {
|
|
566
|
+
(0, logger_1.logError)("Error setting password hint:", error);
|
|
567
|
+
return { success: false, error: String(error) };
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Recovers password hint using security question answers
|
|
572
|
+
* @param username Username
|
|
573
|
+
* @param securityAnswers Array of answers to security questions
|
|
574
|
+
* @returns Promise resolving with the password hint
|
|
575
|
+
*/
|
|
576
|
+
async forgotPassword(username, securityAnswers) {
|
|
577
|
+
(0, logger_1.log)("Attempting password recovery for:", username);
|
|
578
|
+
try {
|
|
579
|
+
// Verify the user exists
|
|
580
|
+
const user = this.gun.user().recall({ sessionStorage: true });
|
|
581
|
+
if (!user || !user.is) {
|
|
582
|
+
return { success: false, error: "User not found" };
|
|
583
|
+
}
|
|
584
|
+
// Retrieve security questions and encrypted hint
|
|
585
|
+
const securityData = await this.getUserData("security");
|
|
586
|
+
if (!securityData || !securityData.hint) {
|
|
587
|
+
return {
|
|
588
|
+
success: false,
|
|
589
|
+
error: "No password hint found",
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
// Decrypt the password hint with the proof of work
|
|
593
|
+
const hint = await this.crypto.decrypt(securityData.hint, (await this.crypto.hashText(securityAnswers.join("|"))));
|
|
594
|
+
if (hint === undefined) {
|
|
595
|
+
return {
|
|
596
|
+
success: false,
|
|
597
|
+
error: "Incorrect answers to security questions",
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
return { success: true, hint: hint };
|
|
601
|
+
}
|
|
602
|
+
catch (error) {
|
|
603
|
+
(0, logger_1.logError)("Error recovering password hint:", error);
|
|
604
|
+
return { success: false, error: String(error) };
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Hashes text with Gun.SEA
|
|
609
|
+
* @param text Text to hash
|
|
610
|
+
* @returns Promise that resolves with the hashed text
|
|
611
|
+
*/
|
|
612
|
+
async hashText(text) {
|
|
613
|
+
return this.crypto.hashText(text);
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* Encrypts data with Gun.SEA
|
|
617
|
+
* @param data Data to encrypt
|
|
618
|
+
* @param key Encryption key
|
|
619
|
+
* @returns Promise that resolves with the encrypted data
|
|
620
|
+
*/
|
|
621
|
+
async encrypt(data, key) {
|
|
622
|
+
return this.crypto.encrypt(data, key);
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* Decrypts data with Gun.SEA
|
|
626
|
+
* @param encryptedData Encrypted data
|
|
627
|
+
* @param key Decryption key
|
|
628
|
+
* @returns Promise that resolves with the decrypted data
|
|
629
|
+
*/
|
|
630
|
+
async decrypt(encryptedData, key) {
|
|
631
|
+
return this.crypto.decrypt(encryptedData, key);
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Saves user data at the specified path
|
|
635
|
+
* @param path Path to save the data
|
|
636
|
+
* @param data Data to save
|
|
637
|
+
* @returns Promise that resolves when the data is saved
|
|
638
|
+
*/
|
|
639
|
+
async saveUserData(path, data) {
|
|
640
|
+
return new Promise((resolve, reject) => {
|
|
641
|
+
const user = this.gun.user();
|
|
642
|
+
if (!user.is) {
|
|
643
|
+
reject(new Error("User not authenticated"));
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
user.get(path).put(data, (ack) => {
|
|
647
|
+
if (ack.err) {
|
|
648
|
+
reject(new Error(ack.err));
|
|
649
|
+
}
|
|
650
|
+
else {
|
|
651
|
+
resolve();
|
|
652
|
+
}
|
|
653
|
+
});
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* Gets user data from the specified path
|
|
658
|
+
* @param path Path to get the data from
|
|
659
|
+
* @returns Promise that resolves with the data
|
|
660
|
+
*/
|
|
661
|
+
async getUserData(path) {
|
|
662
|
+
return new Promise((resolve) => {
|
|
663
|
+
const user = this.gun.user();
|
|
664
|
+
if (!user.is) {
|
|
665
|
+
resolve(null);
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
user.get(path).once((data) => {
|
|
669
|
+
resolve(data);
|
|
670
|
+
});
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
// Errors
|
|
674
|
+
static Errors = GunErrors;
|
|
675
|
+
}
|
|
676
|
+
exports.GunDB = GunDB;
|
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Gun module for Shogun
|
|
4
|
-
* Provides the main interface for interacting with GunDB
|
|
5
|
-
* with all modules integrated into the main class
|
|
6
|
-
*/
|
|
7
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
3
|
exports.GunDB = void 0;
|
|
9
4
|
// Export the main class
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getArrayFromIndexedObject = exports.getIndexedObjectFromArray = exports.qs = exports.getSet = exports.getUUID = exports.getTargetPub = exports.getPub = exports.getId = void 0;
|
|
4
|
+
exports.app_scoped = app_scoped;
|
|
4
5
|
/**
|
|
5
6
|
* Extracts the ID of a Gun node
|
|
6
7
|
* @param node - Gun node object containing metadata
|
|
@@ -88,3 +89,8 @@ const getArrayFromIndexedObject = (indexedObj) => {
|
|
|
88
89
|
return Object.values(indexedObj);
|
|
89
90
|
};
|
|
90
91
|
exports.getArrayFromIndexedObject = getArrayFromIndexedObject;
|
|
92
|
+
function app_scoped(string, scope) {
|
|
93
|
+
if (scope.length > 0)
|
|
94
|
+
return `${scope}-${string}`;
|
|
95
|
+
return string;
|
|
96
|
+
}
|