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.
Files changed (82) hide show
  1. package/README.md +61 -1327
  2. package/dist/browser/shogun-core.js +1 -1
  3. package/dist/browser/shogun-core.js.LICENSE.txt +0 -9
  4. package/dist/browser/shogun-core.light.js +1 -1
  5. package/dist/browser/shogun-core.vendors.light.js +1 -1
  6. package/dist/browser.js +27 -11
  7. package/dist/core.js +603 -0
  8. package/dist/{gun → gundb}/crypto.js +38 -8
  9. package/dist/gundb/gun.js +676 -0
  10. package/dist/{gun → gundb}/index.js +0 -5
  11. package/dist/{gun → gundb}/utils.js +6 -0
  12. package/dist/index.js +1 -807
  13. package/dist/plugins/index.js +15 -28
  14. package/dist/plugins/{stealth → nostr}/index.js +3 -4
  15. package/dist/plugins/nostr/nostrConnector.js +656 -0
  16. package/dist/plugins/nostr/nostrConnectorPlugin.js +259 -0
  17. package/dist/plugins/{metamask → web3}/index.js +2 -2
  18. package/dist/plugins/{metamask/metamask.js → web3/web3Connector.js} +8 -8
  19. package/dist/plugins/{metamask/metamaskPlugin.js → web3/web3ConnectorPlugin.js} +32 -42
  20. package/dist/plugins/webauthn/webauthnPlugin.js +4 -0
  21. package/dist/types/browser.d.ts +9 -4
  22. package/dist/types/core.d.ts +221 -0
  23. package/dist/types/{gun → gundb}/crypto.d.ts +20 -5
  24. package/dist/types/{gun → gundb}/gun.d.ts +56 -28
  25. package/dist/types/gundb/index.d.ts +1 -0
  26. package/dist/types/{gun → gundb}/utils.d.ts +1 -0
  27. package/dist/types/index.d.ts +1 -282
  28. package/dist/types/plugins/index.d.ts +7 -10
  29. package/dist/types/plugins/nostr/index.d.ts +3 -0
  30. package/dist/types/plugins/nostr/nostrConnector.d.ts +111 -0
  31. package/dist/types/plugins/nostr/nostrConnectorPlugin.d.ts +87 -0
  32. package/dist/types/plugins/nostr/types.d.ts +122 -0
  33. package/dist/types/plugins/web3/index.d.ts +3 -0
  34. package/dist/types/plugins/{metamask → web3}/types.d.ts +4 -4
  35. package/dist/types/plugins/{metamask/metamask.d.ts → web3/web3Connector.d.ts} +7 -7
  36. package/dist/types/plugins/{metamask/metamaskPlugin.d.ts → web3/web3ConnectorPlugin.d.ts} +4 -4
  37. package/dist/types/shogun.js +40 -15
  38. package/dist/types/types/shogun.d.ts +67 -67
  39. package/dist/types/utils/errorHandler.d.ts +39 -36
  40. package/dist/types/utils/utility.d.ts +0 -4
  41. package/dist/utils/errorHandler.js +43 -40
  42. package/dist/utils/utility.js +0 -8
  43. package/package.json +2 -2
  44. package/dist/config.js +0 -18
  45. package/dist/gun/gun.js +0 -542
  46. package/dist/plugins/stealth/stealth.js +0 -176
  47. package/dist/plugins/stealth/stealthPlugin.js +0 -113
  48. package/dist/plugins/stealth/types.js +0 -2
  49. package/dist/plugins/utils/stubs/didStub.js +0 -35
  50. package/dist/plugins/utils/stubs/stealthStub.js +0 -35
  51. package/dist/plugins/utils/stubs/webauthnStub.js +0 -29
  52. package/dist/plugins/wallet/index.js +0 -20
  53. package/dist/plugins/wallet/types.js +0 -15
  54. package/dist/plugins/wallet/walletManager.js +0 -1832
  55. package/dist/plugins/wallet/walletPlugin.js +0 -236
  56. package/dist/types/config.d.ts +0 -15
  57. package/dist/types/gun/index.d.ts +0 -6
  58. package/dist/types/gun/types.d.ts +0 -2
  59. package/dist/types/plugins/metamask/index.d.ts +0 -3
  60. package/dist/types/plugins/stealth/index.d.ts +0 -3
  61. package/dist/types/plugins/stealth/stealth.d.ts +0 -93
  62. package/dist/types/plugins/stealth/stealthPlugin.d.ts +0 -60
  63. package/dist/types/plugins/stealth/types.d.ts +0 -93
  64. package/dist/types/plugins/utils/stubs/didStub.d.ts +0 -15
  65. package/dist/types/plugins/utils/stubs/stealthStub.d.ts +0 -15
  66. package/dist/types/plugins/utils/stubs/webauthnStub.d.ts +0 -13
  67. package/dist/types/plugins/wallet/index.d.ts +0 -3
  68. package/dist/types/plugins/wallet/types.d.ts +0 -167
  69. package/dist/types/plugins/wallet/walletManager.d.ts +0 -306
  70. package/dist/types/plugins/wallet/walletPlugin.d.ts +0 -126
  71. package/dist/types/utils/stubs/didStub.d.ts +0 -15
  72. package/dist/types/utils/stubs/stealthStub.d.ts +0 -15
  73. package/dist/types/utils/stubs/webauthnStub.d.ts +0 -13
  74. package/dist/utils/stubs/didStub.js +0 -35
  75. package/dist/utils/stubs/stealthStub.js +0 -35
  76. package/dist/utils/stubs/webauthnStub.js +0 -29
  77. /package/dist/{gun → gundb}/errors.js +0 -0
  78. /package/dist/{gun → gundb}/rxjs-integration.js +0 -0
  79. /package/dist/{gun → plugins/nostr}/types.js +0 -0
  80. /package/dist/plugins/{metamask → web3}/types.js +0 -0
  81. /package/dist/types/{gun → gundb}/errors.d.ts +0 -0
  82. /package/dist/types/{gun → gundb}/rxjs-integration.d.ts +0 -0
@@ -0,0 +1,656 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NostrConnector = void 0;
4
+ /**
5
+ * The BitcoinWallet class provides functionality for connecting, signing up, and logging in using Bitcoin wallets.
6
+ * Supports Alby and Nostr extensions, as well as manual key management.
7
+ */
8
+ const logger_1 = require("../../utils/logger");
9
+ const errorHandler_1 = require("../../utils/errorHandler");
10
+ const eventEmitter_1 = require("../../utils/eventEmitter");
11
+ /**
12
+ * Class for Bitcoin wallet connections and operations
13
+ */
14
+ class NostrConnector extends eventEmitter_1.EventEmitter {
15
+ MESSAGE_TO_SIGN = "I Love Shogun!";
16
+ DEFAULT_CONFIG = {
17
+ cacheDuration: 24 * 60 * 60 * 1000, // 24 hours instead of 30 minutes for better UX
18
+ maxRetries: 3,
19
+ retryDelay: 1000,
20
+ timeout: 60000,
21
+ network: "mainnet",
22
+ useApi: false,
23
+ };
24
+ config;
25
+ signatureCache = new Map();
26
+ // Connection state
27
+ connectedAddress = null;
28
+ connectedType = null;
29
+ manualKeyPair = null;
30
+ constructor(config = {}) {
31
+ super();
32
+ this.config = { ...this.DEFAULT_CONFIG, ...config };
33
+ this.setupEventListeners();
34
+ }
35
+ /**
36
+ * Setup event listeners
37
+ */
38
+ setupEventListeners() {
39
+ // Currently no global events to listen to
40
+ // This would be the place to add listeners for wallet connections/disconnections
41
+ }
42
+ /**
43
+ * Cleanup event listeners
44
+ */
45
+ cleanup() {
46
+ this.removeAllListeners();
47
+ this.connectedAddress = null;
48
+ this.connectedType = null;
49
+ this.manualKeyPair = null;
50
+ }
51
+ /**
52
+ * Get cached signature if valid
53
+ */
54
+ getCachedSignature(address) {
55
+ // First check in-memory cache
56
+ const cached = this.signatureCache.get(address);
57
+ if (cached) {
58
+ const now = Date.now();
59
+ if (now - cached.timestamp <= this.config.cacheDuration) {
60
+ return cached.signature;
61
+ }
62
+ else {
63
+ this.signatureCache.delete(address);
64
+ }
65
+ }
66
+ // Then check localStorage for persistence across page reloads
67
+ try {
68
+ const localStorageKey = `shogun_bitcoin_sig_${address}`;
69
+ const localCached = localStorage.getItem(localStorageKey);
70
+ if (localCached) {
71
+ const parsedCache = JSON.parse(localCached);
72
+ const now = Date.now();
73
+ if (now - parsedCache.timestamp <= this.config.cacheDuration) {
74
+ // Restore to in-memory cache
75
+ this.signatureCache.set(address, parsedCache);
76
+ return parsedCache.signature;
77
+ }
78
+ else {
79
+ // Remove expired cache
80
+ localStorage.removeItem(localStorageKey);
81
+ }
82
+ }
83
+ }
84
+ catch (error) {
85
+ (0, logger_1.logError)("Error reading signature cache from localStorage:", error);
86
+ }
87
+ return null;
88
+ }
89
+ /**
90
+ * Cache signature
91
+ */
92
+ cacheSignature(address, signature) {
93
+ const cacheEntry = {
94
+ signature,
95
+ timestamp: Date.now(),
96
+ address,
97
+ };
98
+ // Store in memory
99
+ this.signatureCache.set(address, cacheEntry);
100
+ // Store in localStorage for persistence
101
+ try {
102
+ const localStorageKey = `shogun_bitcoin_sig_${address}`;
103
+ localStorage.setItem(localStorageKey, JSON.stringify(cacheEntry));
104
+ (0, logger_1.log)(`Cached signature for address: ${address.substring(0, 10)}...`);
105
+ }
106
+ catch (error) {
107
+ (0, logger_1.logError)("Error saving signature cache to localStorage:", error);
108
+ }
109
+ }
110
+ /**
111
+ * Clear signature cache for a specific address or all addresses
112
+ */
113
+ clearSignatureCache(address) {
114
+ if (address) {
115
+ // Clear cache for specific address
116
+ this.signatureCache.delete(address);
117
+ try {
118
+ const localStorageKey = `shogun_bitcoin_sig_${address}`;
119
+ localStorage.removeItem(localStorageKey);
120
+ (0, logger_1.log)(`Cleared signature cache for address: ${address.substring(0, 10)}...`);
121
+ }
122
+ catch (error) {
123
+ (0, logger_1.logError)("Error clearing signature cache from localStorage:", error);
124
+ }
125
+ }
126
+ else {
127
+ // Clear all signature caches
128
+ this.signatureCache.clear();
129
+ try {
130
+ // Find and remove all shogun_bitcoin_sig_ keys
131
+ const keysToRemove = [];
132
+ for (let i = 0; i < localStorage.length; i++) {
133
+ const key = localStorage.key(i);
134
+ if (key && key.startsWith("shogun_bitcoin_sig_")) {
135
+ keysToRemove.push(key);
136
+ }
137
+ }
138
+ keysToRemove.forEach((key) => localStorage.removeItem(key));
139
+ (0, logger_1.log)(`Cleared all signature caches (${keysToRemove.length} entries)`);
140
+ }
141
+ catch (error) {
142
+ (0, logger_1.logError)("Error clearing all signature caches from localStorage:", error);
143
+ }
144
+ }
145
+ }
146
+ /**
147
+ * Validates that the address is valid
148
+ */
149
+ validateAddress(address) {
150
+ if (!address) {
151
+ throw new Error("Address not provided");
152
+ }
153
+ try {
154
+ const normalizedAddress = String(address).trim();
155
+ // Basic validation for Bitcoin addresses and Nostr pubkeys
156
+ if (this.connectedType === "nostr") {
157
+ // Nostr pubkeys are typically hex strings starting with 'npub' when encoded
158
+ if (!/^(npub1|[0-9a-f]{64})/.test(normalizedAddress)) {
159
+ throw new Error("Invalid Nostr public key format");
160
+ }
161
+ }
162
+ else {
163
+ // Simple format check for Bitcoin addresses
164
+ // More sophisticated validation would require a library
165
+ if (!/^(bc1|[13])[a-zA-HJ-NP-Z0-9]{25,59}$/.test(normalizedAddress)) {
166
+ throw new Error("Invalid Bitcoin address format");
167
+ }
168
+ }
169
+ return normalizedAddress;
170
+ }
171
+ catch (error) {
172
+ errorHandler_1.ErrorHandler.handle(errorHandler_1.ErrorType.VALIDATION, "INVALID_ADDRESS", "Invalid Bitcoin address provided", error);
173
+ throw error;
174
+ }
175
+ }
176
+ /**
177
+ * Check if Alby extension is available
178
+ * @deprecated Alby support is deprecated, use Nostr instead
179
+ */
180
+ isAlbyAvailable() {
181
+ (0, logger_1.logWarn)("Alby support is deprecated, use Nostr instead");
182
+ // Return false to encourage using Nostr
183
+ return false;
184
+ }
185
+ /**
186
+ * Check if Nostr extension is available
187
+ */
188
+ isNostrExtensionAvailable() {
189
+ return typeof window !== "undefined" && !!window.nostr;
190
+ }
191
+ /**
192
+ * Check if any Bitcoin wallet is available
193
+ */
194
+ isAvailable() {
195
+ return this.isNostrExtensionAvailable() || this.manualKeyPair !== null;
196
+ }
197
+ /**
198
+ * Connect to a wallet type
199
+ */
200
+ async connectWallet(type = "nostr") {
201
+ (0, logger_1.log)(`Connecting to Bitcoin wallet via ${type}...`);
202
+ try {
203
+ let result;
204
+ // Attempt to connect to the specified wallet type
205
+ switch (type) {
206
+ case "alby":
207
+ (0, logger_1.log)("Alby is deprecated, redirecting to Nostr");
208
+ result = await this.connectNostr();
209
+ break;
210
+ case "nostr":
211
+ result = await this.connectNostr();
212
+ break;
213
+ case "manual":
214
+ result = await this.connectManual();
215
+ break;
216
+ default:
217
+ throw new Error(`Unsupported wallet type: ${type}`);
218
+ }
219
+ if (result.success && result.address) {
220
+ this.connectedAddress = result.address;
221
+ this.connectedType = type;
222
+ (0, logger_1.log)(`Successfully connected to ${type} wallet: ${result.address}`);
223
+ this.emit("wallet_connected", {
224
+ address: result.address,
225
+ type: this.connectedType,
226
+ });
227
+ }
228
+ return result;
229
+ }
230
+ catch (error) {
231
+ (0, logger_1.logError)(`Error connecting to ${type} wallet:`, error);
232
+ return {
233
+ success: false,
234
+ error: error.message || "Failed to connect to wallet",
235
+ };
236
+ }
237
+ }
238
+ /**
239
+ * Connect to Nostr extension
240
+ */
241
+ async connectNostr() {
242
+ if (!this.isNostrExtensionAvailable()) {
243
+ return {
244
+ success: false,
245
+ error: "Nostr extension is not available. Please install a Nostr compatible extension.",
246
+ };
247
+ }
248
+ try {
249
+ // Get public key from Nostr extension
250
+ const pubKey = await window.nostr.getPublicKey();
251
+ if (!pubKey) {
252
+ throw new Error("Could not get public key from Nostr extension");
253
+ }
254
+ this.connectedAddress = pubKey;
255
+ this.connectedType = "nostr";
256
+ // Emit connected event
257
+ this.emit("connected", { address: pubKey, type: "nostr" });
258
+ const username = `nostr_${pubKey.substring(0, 10)}`;
259
+ return {
260
+ success: true,
261
+ address: pubKey,
262
+ username,
263
+ extensionType: "nostr",
264
+ };
265
+ }
266
+ catch (error) {
267
+ throw new Error(`Nostr connection error: ${error.message}`);
268
+ }
269
+ }
270
+ /**
271
+ * Set up manual key pair for connection
272
+ */
273
+ async connectManual() {
274
+ // For manual connection, we'd need to have a keypair set
275
+ if (!this.manualKeyPair) {
276
+ return {
277
+ success: false,
278
+ error: "No manual key pair configured. Use setKeyPair() first.",
279
+ };
280
+ }
281
+ this.connectedAddress = this.manualKeyPair.address;
282
+ this.connectedType = "manual";
283
+ // Emit connected event
284
+ this.emit("connected", {
285
+ address: this.manualKeyPair.address,
286
+ type: "manual",
287
+ });
288
+ const username = `btc_${this.manualKeyPair.address.substring(0, 10)}`;
289
+ return {
290
+ success: true,
291
+ address: this.manualKeyPair.address,
292
+ username,
293
+ extensionType: "manual",
294
+ };
295
+ }
296
+ /**
297
+ * Set a manual key pair for use
298
+ */
299
+ setKeyPair(keyPair) {
300
+ this.manualKeyPair = keyPair;
301
+ if (keyPair.address) {
302
+ this.connectedAddress = keyPair.address;
303
+ this.connectedType = "manual";
304
+ }
305
+ }
306
+ /**
307
+ * Generate credentials using the connected wallet
308
+ */
309
+ async generateCredentials(address) {
310
+ (0, logger_1.logDebug)(`Generating credentials for address: ${address}`);
311
+ try {
312
+ // Validate the address
313
+ const validAddress = this.validateAddress(address);
314
+ // Check cache first
315
+ const cachedSignature = this.getCachedSignature(validAddress);
316
+ if (cachedSignature) {
317
+ (0, logger_1.logDebug)("Using cached signature");
318
+ return await this.generateCredentialsFromSignature(validAddress, cachedSignature);
319
+ }
320
+ // For consistent authentication, we need to use a deterministic approach
321
+ // that doesn't require a fresh signature each time
322
+ const message = this.MESSAGE_TO_SIGN;
323
+ let signature;
324
+ // NEW STRATEGY: Always try deterministic signature first for consistency
325
+ // This ensures that existing users get the same credentials even after localStorage.clear()
326
+ try {
327
+ // First, try to use a deterministic signature based on the address
328
+ // This ensures consistent credentials across sessions
329
+ signature = await this.generateDeterministicSignature(validAddress);
330
+ (0, logger_1.log)("Using deterministic signature for consistency");
331
+ // Cache this deterministic signature for future use
332
+ this.cacheSignature(validAddress, signature);
333
+ return await this.generateCredentialsFromSignature(validAddress, signature);
334
+ }
335
+ catch (deterministicError) {
336
+ (0, logger_1.logError)("Error generating deterministic signature:", deterministicError);
337
+ // Fallback to requesting a real signature only if deterministic fails
338
+ try {
339
+ signature = await this.requestSignatureWithTimeout(validAddress, message, this.config.timeout);
340
+ // Cache the signature for future use
341
+ this.cacheSignature(validAddress, signature);
342
+ (0, logger_1.log)("Using real Nostr signature as fallback");
343
+ }
344
+ catch (signError) {
345
+ (0, logger_1.logError)("Error requesting signature:", signError);
346
+ // Final fallback: use deterministic signature anyway
347
+ signature = await this.generateDeterministicSignature(validAddress);
348
+ this.cacheSignature(validAddress, signature);
349
+ (0, logger_1.log)("Using deterministic signature as final fallback");
350
+ }
351
+ }
352
+ return await this.generateCredentialsFromSignature(validAddress, signature);
353
+ }
354
+ catch (error) {
355
+ (0, logger_1.logError)("Error generating credentials:", error);
356
+ throw error;
357
+ }
358
+ }
359
+ /**
360
+ * Generate a deterministic signature for consistent authentication
361
+ */
362
+ async generateDeterministicSignature(address) {
363
+ // Create a deterministic signature based on the address and a fixed message
364
+ // This ensures the same credentials are generated each time for the same address
365
+ const baseString = `${address}_${this.MESSAGE_TO_SIGN}_shogun_deterministic`;
366
+ // Simple hash function to create a deterministic signature
367
+ let hash = "";
368
+ let runningValue = 0;
369
+ for (let i = 0; i < baseString.length; i++) {
370
+ const charCode = baseString.charCodeAt(i);
371
+ runningValue = (runningValue * 31 + charCode) & 0xffffffff;
372
+ if (i % 4 === 3) {
373
+ hash += runningValue.toString(16).padStart(8, "0");
374
+ }
375
+ }
376
+ // Ensure we have exactly 128 characters (64 bytes in hex)
377
+ while (hash.length < 128) {
378
+ runningValue = (runningValue * 31 + hash.length) & 0xffffffff;
379
+ hash += runningValue.toString(16).padStart(8, "0");
380
+ }
381
+ // Ensure the result is exactly 128 characters and contains only valid hex characters
382
+ let deterministicSignature = hash.substring(0, 128);
383
+ // Double-check that it's a valid hex string
384
+ deterministicSignature = deterministicSignature
385
+ .toLowerCase()
386
+ .replace(/[^0-9a-f]/g, "0");
387
+ // Ensure it's exactly 128 characters
388
+ if (deterministicSignature.length < 128) {
389
+ deterministicSignature = deterministicSignature.padEnd(128, "0");
390
+ }
391
+ else if (deterministicSignature.length > 128) {
392
+ deterministicSignature = deterministicSignature.substring(0, 128);
393
+ }
394
+ (0, logger_1.log)(`Generated deterministic signature: ${deterministicSignature.substring(0, 16)}... (${deterministicSignature.length} chars)`);
395
+ return deterministicSignature;
396
+ }
397
+ /**
398
+ * Generate credentials from an existing signature
399
+ */
400
+ async generateCredentialsFromSignature(address, signature) {
401
+ (0, logger_1.log)("Generating credentials from signature");
402
+ // Create deterministic username based on the address - similar to MetaMask's approach
403
+ const username = `${address.toLowerCase()}`;
404
+ // Create password from the signature
405
+ const password = await this.generatePassword(signature);
406
+ return {
407
+ username,
408
+ password,
409
+ message: this.MESSAGE_TO_SIGN,
410
+ signature,
411
+ };
412
+ }
413
+ /**
414
+ * Generate a password from a signature
415
+ */
416
+ async generatePassword(signature) {
417
+ if (!signature) {
418
+ throw new Error("Invalid signature");
419
+ }
420
+ try {
421
+ // Create a deterministic hash from the signature
422
+ // Following a similar approach to the Ethereum connector for consistency
423
+ // Normalize the signature to ensure it's clean
424
+ const normalizedSig = signature.toLowerCase().replace(/[^a-f0-9]/g, "");
425
+ // Create a hash using a simple algorithm
426
+ // In a production environment, you would use a proper crypto library
427
+ // For example:
428
+ // const hashBuffer = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(normalizedSig));
429
+ // const hashArray = Array.from(new Uint8Array(hashBuffer));
430
+ // const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
431
+ // For now, implement a simple deterministic hash
432
+ let hash = "";
433
+ let runningValue = 0;
434
+ for (let i = 0; i < normalizedSig.length; i++) {
435
+ const charCode = normalizedSig.charCodeAt(i);
436
+ runningValue = (runningValue * 31 + charCode) & 0xffffffff;
437
+ if (i % 8 === 7) {
438
+ hash += runningValue.toString(16).padStart(8, "0");
439
+ }
440
+ }
441
+ // Ensure we have at least 64 characters
442
+ while (hash.length < 64) {
443
+ runningValue = (runningValue * 31 + hash.length) & 0xffffffff;
444
+ hash += runningValue.toString(16).padStart(8, "0");
445
+ }
446
+ // Trim to 64 characters (matching the Ethereum approach that returns 64 chars)
447
+ return hash.substring(0, 64);
448
+ }
449
+ catch (error) {
450
+ (0, logger_1.logError)("Error generating password:", error);
451
+ throw new Error("Failed to generate password from signature");
452
+ }
453
+ }
454
+ /**
455
+ * Verify a signature
456
+ */
457
+ async verifySignature(message, signature, address) {
458
+ try {
459
+ (0, logger_1.log)(`Verifying signature for address: ${address}`);
460
+ if (!signature || !message) {
461
+ (0, logger_1.logError)("Invalid message or signature for verification");
462
+ return false;
463
+ }
464
+ // Log signature details for debugging
465
+ (0, logger_1.log)(`Signature to verify: ${signature.substring(0, 20)}... (length: ${signature.length})`);
466
+ (0, logger_1.log)(`Message to verify: ${message}`);
467
+ // For Nostr wallet type, we need to use a proper verification approach
468
+ if (this.connectedType === "nostr" || this.connectedType === "alby") {
469
+ (0, logger_1.log)("Using Nostr-specific verification");
470
+ try {
471
+ // In a production implementation, we would use proper nostr verification
472
+ // using secp256k1 to verify the signature
473
+ //
474
+ // For example with nostr-tools:
475
+ // import * as nostr from 'nostr-tools';
476
+ // const event = {
477
+ // kind: 1,
478
+ // created_at: Math.floor(Date.now() / 1000),
479
+ // tags: [],
480
+ // content: message,
481
+ // pubkey: address,
482
+ // id: '', // would be computed
483
+ // sig: signature
484
+ // };
485
+ // const verified = nostr.verifySignature(event);
486
+ // return verified;
487
+ // Instead for now, we're checking if the address matches what we have connected
488
+ // This ensures at least some level of verification
489
+ if (address.toLowerCase() !== this.connectedAddress?.toLowerCase()) {
490
+ (0, logger_1.logError)("Address mismatch in signature verification");
491
+ (0, logger_1.logError)(`Expected: ${this.connectedAddress}, Got: ${address}`);
492
+ return false;
493
+ }
494
+ // Basic verification that signature exists and is a hex string
495
+ const isValidHexFormat = /^[0-9a-f]+$/i.test(signature);
496
+ const hasValidLength = signature.length >= 64;
497
+ (0, logger_1.log)(`Signature format check: hex=${isValidHexFormat}, length=${hasValidLength} (${signature.length} chars)`);
498
+ if (!isValidHexFormat) {
499
+ (0, logger_1.logError)("Invalid signature format - not a valid hex string");
500
+ (0, logger_1.logError)(`Signature contains invalid characters: ${signature}`);
501
+ return false;
502
+ }
503
+ if (!hasValidLength) {
504
+ (0, logger_1.logError)(`Invalid signature length: ${signature.length} (minimum 64 required)`);
505
+ return false;
506
+ }
507
+ (0, logger_1.log)("Nostr signature appears valid");
508
+ return true;
509
+ }
510
+ catch (verifyError) {
511
+ (0, logger_1.logError)("Error in signature verification:", verifyError);
512
+ return false;
513
+ }
514
+ }
515
+ else if (this.connectedType === "manual" && this.manualKeyPair) {
516
+ (0, logger_1.log)("Using manual verification for keypair");
517
+ // For manual keypairs, implement proper signature verification
518
+ // For now, we're just checking that the address matches our keypair
519
+ try {
520
+ const addressMatch = address.toLowerCase() === this.manualKeyPair.address.toLowerCase();
521
+ (0, logger_1.log)(`Manual verification - address match: ${addressMatch}`);
522
+ return addressMatch;
523
+ }
524
+ catch (manualVerifyError) {
525
+ (0, logger_1.logError)("Error in manual signature verification:", manualVerifyError);
526
+ return false;
527
+ }
528
+ }
529
+ // For other wallet types or if API verification is enabled
530
+ if (this.config.useApi && this.config.apiUrl) {
531
+ (0, logger_1.log)("Using API-based verification");
532
+ try {
533
+ // In a real implementation, this would make an API call to verify
534
+ // return await this.verifySignatureViaApi(message, signature, address);
535
+ // For now, return true as this is a placeholder
536
+ return true;
537
+ }
538
+ catch (apiError) {
539
+ (0, logger_1.logError)("API verification error:", apiError);
540
+ return false;
541
+ }
542
+ }
543
+ (0, logger_1.logWarn)("No specific verification method available, signature cannot be fully verified");
544
+ return false;
545
+ }
546
+ catch (error) {
547
+ (0, logger_1.logError)("Error verifying signature:", error);
548
+ return false;
549
+ }
550
+ }
551
+ /**
552
+ * Get the currently connected address
553
+ */
554
+ getConnectedAddress() {
555
+ return this.connectedAddress;
556
+ }
557
+ /**
558
+ * Get the currently connected wallet type
559
+ */
560
+ getConnectedType() {
561
+ return this.connectedType;
562
+ }
563
+ /**
564
+ * Request signature with timeout
565
+ */
566
+ requestSignatureWithTimeout(address, message, timeout = 30000) {
567
+ return new Promise((resolve, reject) => {
568
+ const timeoutId = setTimeout(() => {
569
+ reject(new Error("Signature request timed out"));
570
+ }, timeout);
571
+ this.requestSignature(address, message)
572
+ .then((signature) => {
573
+ clearTimeout(timeoutId);
574
+ resolve(signature);
575
+ })
576
+ .catch((error) => {
577
+ clearTimeout(timeoutId);
578
+ reject(error);
579
+ });
580
+ });
581
+ }
582
+ /**
583
+ * Request a signature from the connected wallet
584
+ */
585
+ async requestSignature(address, message) {
586
+ if (!this.connectedType) {
587
+ throw new Error("No wallet connected");
588
+ }
589
+ try {
590
+ switch (this.connectedType) {
591
+ case "alby":
592
+ // Redirect Alby requests to Nostr
593
+ (0, logger_1.logWarn)("Alby is deprecated, redirecting signature request to Nostr");
594
+ if (!window.nostr) {
595
+ throw new Error("Nostr extension not available");
596
+ }
597
+ // For Nostr, we need to create an event to sign
598
+ const albyRedirectEvent = {
599
+ kind: 1,
600
+ created_at: Math.floor(Date.now() / 1000),
601
+ tags: [],
602
+ content: message,
603
+ pubkey: address,
604
+ };
605
+ const albyRedirectResult = await window.nostr.signEvent(albyRedirectEvent);
606
+ return albyRedirectResult.sig;
607
+ case "nostr":
608
+ (0, logger_1.log)("Requesting Nostr signature for message:", message);
609
+ // For Nostr, we need to create an event to sign
610
+ const nostrEvent = {
611
+ kind: 1,
612
+ created_at: Math.floor(Date.now() / 1000),
613
+ tags: [],
614
+ content: message,
615
+ pubkey: address,
616
+ };
617
+ const nostrSignedEvent = await window.nostr.signEvent(nostrEvent);
618
+ (0, logger_1.log)("Received Nostr signature:", nostrSignedEvent.sig.substring(0, 20) + "...");
619
+ // Normalize the signature to ensure compatibility with GunDB
620
+ let signature = nostrSignedEvent.sig;
621
+ // Ensure the signature is in the expected format (hex string)
622
+ if (signature && typeof signature === "string") {
623
+ // Remove any non-hex characters and ensure lowercase
624
+ signature = signature.replace(/[^a-f0-9]/gi, "").toLowerCase();
625
+ // Ensure it's a valid length hex string (64 bytes = 128 hex chars for secp256k1)
626
+ if (signature.length > 128) {
627
+ signature = signature.substring(0, 128);
628
+ }
629
+ else if (signature.length < 128) {
630
+ // Pad with zeros if needed (shouldn't happen with valid signatures)
631
+ signature = signature.padStart(128, "0");
632
+ }
633
+ (0, logger_1.log)(`Normalized Nostr signature: ${signature.substring(0, 10)}...`);
634
+ }
635
+ return signature;
636
+ case "manual":
637
+ (0, logger_1.log)("Using manual key pair for signature");
638
+ if (!this.manualKeyPair) {
639
+ throw new Error("No manual key pair available");
640
+ }
641
+ // In a real implementation, we would use a Bitcoin signing library here
642
+ // For now, create a deterministic signature from the private key and message
643
+ const manualSignature = `${this.manualKeyPair.privateKey.substring(0, 32)}_${message}_${Date.now()}`;
644
+ (0, logger_1.log)("Generated manual signature:", manualSignature.substring(0, 20) + "...");
645
+ return manualSignature;
646
+ default:
647
+ throw new Error(`Unsupported wallet type: ${this.connectedType}`);
648
+ }
649
+ }
650
+ catch (error) {
651
+ (0, logger_1.logError)("Error requesting signature:", error);
652
+ throw new Error(`Failed to get signature: ${error.message}`);
653
+ }
654
+ }
655
+ }
656
+ exports.NostrConnector = NostrConnector;