gun-eth 1.3.1 → 1.3.4

Sign up to get free protection for your applications and to get access to all the features.
package/src/gun-eth.js DELETED
@@ -1,571 +0,0 @@
1
- (function (root, factory) {
2
- if (typeof define === "function" && define.amd) {
3
- define(["gun", "gun/sea", "ethers"], factory);
4
- } else if (typeof module === "object" && module.exports) {
5
- module.exports = factory(require("gun/gun"), require("gun/sea"), require("ethers"));
6
- } else {
7
- factory(root.Gun, root.SEA, root.ethers);
8
- }
9
- })(typeof self !== "undefined" ? self : this, function (Gun, SEA, ethers) {
10
- console.log('Factory del plugin Gun-Eth chiamata');
11
-
12
- const MESSAGE_TO_SIGN = "Accesso a GunDB con Ethereum";
13
-
14
-
15
- // Funzione per verificare se ethers è disponibile
16
- function checkEthers() {
17
- if (typeof ethers === 'undefined') {
18
- console.error('Ethers.js non è disponibile. Assicurati che sia caricato prima di questo script.');
19
- return false;
20
- }
21
- console.log('Ethers version:', ethers.version);
22
- return true;
23
- }
24
-
25
- // Variabili globali
26
- let SHINE_ABI = [
27
- {
28
- "anonymous": false,
29
- "inputs": [
30
- {
31
- "indexed": true,
32
- "internalType": "bytes",
33
- "name": "nodeId",
34
- "type": "bytes"
35
- },
36
- {
37
- "indexed": false,
38
- "internalType": "bytes32",
39
- "name": "contentHash",
40
- "type": "bytes32"
41
- },
42
- {
43
- "indexed": false,
44
- "internalType": "address",
45
- "name": "updater",
46
- "type": "address"
47
- }
48
- ],
49
- "name": "DataUpdated",
50
- "type": "event"
51
- },
52
- {
53
- "inputs": [
54
- {
55
- "internalType": "bytes[]",
56
- "name": "nodeIds",
57
- "type": "bytes[]"
58
- },
59
- {
60
- "internalType": "bytes32[]",
61
- "name": "contentHashes",
62
- "type": "bytes32[]"
63
- }
64
- ],
65
- "name": "batchUpdateData",
66
- "outputs": [],
67
- "stateMutability": "nonpayable",
68
- "type": "function"
69
- },
70
- {
71
- "inputs": [
72
- {
73
- "internalType": "bytes",
74
- "name": "nodeId",
75
- "type": "bytes"
76
- }
77
- ],
78
- "name": "getLatestRecord",
79
- "outputs": [
80
- {
81
- "internalType": "bytes32",
82
- "name": "",
83
- "type": "bytes32"
84
- },
85
- {
86
- "internalType": "uint256",
87
- "name": "",
88
- "type": "uint256"
89
- },
90
- {
91
- "internalType": "address",
92
- "name": "",
93
- "type": "address"
94
- }
95
- ],
96
- "stateMutability": "view",
97
- "type": "function"
98
- },
99
- {
100
- "inputs": [
101
- {
102
- "internalType": "bytes",
103
- "name": "",
104
- "type": "bytes"
105
- }
106
- ],
107
- "name": "nodeData",
108
- "outputs": [
109
- {
110
- "internalType": "bytes32",
111
- "name": "contentHash",
112
- "type": "bytes32"
113
- },
114
- {
115
- "internalType": "uint256",
116
- "name": "timestamp",
117
- "type": "uint256"
118
- },
119
- {
120
- "internalType": "address",
121
- "name": "updater",
122
- "type": "address"
123
- }
124
- ],
125
- "stateMutability": "view",
126
- "type": "function"
127
- },
128
- {
129
- "inputs": [
130
- {
131
- "internalType": "bytes",
132
- "name": "nodeId",
133
- "type": "bytes"
134
- },
135
- {
136
- "internalType": "bytes32",
137
- "name": "contentHash",
138
- "type": "bytes32"
139
- }
140
- ],
141
- "name": "updateData",
142
- "outputs": [],
143
- "stateMutability": "nonpayable",
144
- "type": "function"
145
- },
146
- {
147
- "inputs": [
148
- {
149
- "internalType": "bytes",
150
- "name": "nodeId",
151
- "type": "bytes"
152
- },
153
- {
154
- "internalType": "bytes32",
155
- "name": "contentHash",
156
- "type": "bytes32"
157
- }
158
- ],
159
- "name": "verifyData",
160
- "outputs": [
161
- {
162
- "internalType": "bool",
163
- "name": "",
164
- "type": "bool"
165
- },
166
- {
167
- "internalType": "uint256",
168
- "name": "",
169
- "type": "uint256"
170
- },
171
- {
172
- "internalType": "address",
173
- "name": "",
174
- "type": "address"
175
- }
176
- ],
177
- "stateMutability": "view",
178
- "type": "function"
179
- }
180
- ]
181
-
182
- let SHINE_OPTIMISM_SEPOLIA = "0x43D838b683F772F08f321E5FA265ad3e333BE9C2";
183
- let SHINE_CONTRACT_ADDRESS;
184
- let customToken = "";
185
- let rpcUrl = "";
186
- let privateKey = "";
187
-
188
- /**
189
- * Funzione per ottenere il signer
190
- * @returns {Promise<ethers.Signer>} Il signer.
191
- */
192
- const getSigner = async () => {
193
- if (rpcUrl && privateKey) {
194
- // Modalità standalone
195
- const provider = new ethers.JsonRpcProvider(rpcUrl);
196
- return new ethers.Wallet(privateKey, provider);
197
- } else if (
198
- typeof window !== "undefined" &&
199
- typeof window.ethereum !== "undefined"
200
- ) {
201
- // Modalità browser
202
- await window.ethereum.request({ method: "eth_requestAccounts" });
203
- const provider = new ethers.BrowserProvider(window.ethereum);
204
- return provider.getSigner();
205
- } else {
206
- throw new Error("No valid Ethereum provider found");
207
- }
208
- };
209
-
210
- /**
211
- * Sets standalone configuration for Gun.
212
- * @param {string} newRpcUrl - The new RPC URL.
213
- * @param {string} newPrivateKey - The new private key.
214
- * @returns {Gun} The Gun instance for chaining.
215
- */
216
- Gun.chain.setStandaloneConfig = function (newRpcUrl, newPrivateKey) {
217
- rpcUrl = newRpcUrl;
218
- privateKey = newPrivateKey;
219
- console.log("Standalone configuration set");
220
- return this;
221
- };
222
-
223
- /**
224
- * Sets a custom token for Gun operations.
225
- * @param {string} token - The token to be set.
226
- * @returns {Gun} The Gun instance for chaining.
227
- */
228
- Gun.chain.setToken = function (token) {
229
- if (typeof token === "string" && token.length > 0) {
230
- customToken = token;
231
- console.log("Token set successfully:", token);
232
- } else {
233
- console.error("Invalid token. Must be a non-empty string.");
234
- }
235
- return this;
236
- };
237
-
238
- /**
239
- * Retrieves the current custom token.
240
- * @returns {string} The current custom token.
241
- */
242
- Gun.chain.getToken = function () {
243
- return customToken;
244
- };
245
-
246
- // Add custom token to all 'put' operations
247
- Gun.on("put", function (msg) {
248
- const to = this.to;
249
- msg.headers = {
250
- token: customToken,
251
- };
252
- to.next(msg);
253
- });
254
-
255
- /**
256
- * Verifies an Ethereum signature.
257
- * @param {string} message - The original message that was signed.
258
- * @param {string} signature - The signature to verify.
259
- * @returns {Promise<string|null>} The recovered address or null if verification fails.
260
- */
261
- Gun.chain.verifySignature = async function (message, signature) {
262
- try {
263
- const recoveredAddress = ethers.verifyMessage(message, signature);
264
- return recoveredAddress;
265
- } catch (error) {
266
- console.error("Error verifying signature:", error);
267
- return null;
268
- }
269
- };
270
-
271
- /**
272
- * Generates a password from a signature.
273
- * @param {string} signature - The signature to derive the password from.
274
- * @returns {string|null} The generated password or null if generation fails.
275
- */
276
- Gun.chain.generatePassword = function (signature) {
277
- try {
278
- const hexSignature = ethers.hexlify(signature);
279
- const hash = ethers.keccak256(hexSignature);
280
- console.log("Generated password:", hash);
281
- return hash;
282
- } catch (error) {
283
- console.error("Error generating password:", error);
284
- return null;
285
- }
286
- };
287
-
288
- /**
289
- * Creates an Ethereum signature for a given message.
290
- * @param {string} message - The message to sign.
291
- * @returns {Promise<string|null>} The signature or null if signing fails.
292
- */
293
- Gun.chain.createSignature = async function (message) {
294
- try {
295
- // Verifica se il messaggio è uguale a MESSAGE_TO_SIGN
296
- if (message !== MESSAGE_TO_SIGN) {
297
- throw new Error("Invalid message, valid message is: " + MESSAGE_TO_SIGN);
298
- }
299
- const signer = await getSigner();
300
- const signature = await signer.signMessage(message);
301
- console.log("Signature created:", signature);
302
- return signature;
303
- } catch (error) {
304
- console.error("Error creating signature:", error);
305
- return null;
306
- }
307
- };
308
-
309
- /**
310
- * Creates and stores an encrypted key pair for a given address.
311
- * @param {string} address - The Ethereum address to associate with the key pair.
312
- * @param {string} signature - The signature to use for encryption.
313
- * @returns {Promise<void>}
314
- */
315
- Gun.chain.createAndStoreEncryptedPair = async function (address, signature) {
316
- try {
317
- const gun = this;
318
- const pair = await SEA.pair();
319
- const encryptedPair = await SEA.encrypt(JSON.stringify(pair), signature);
320
- await gun.get("gun-eth").get("users").get(address).put({ encryptedPair });
321
- console.log("Encrypted pair stored for:", address);
322
- } catch (error) {
323
- console.error("Error creating and storing encrypted pair:", error);
324
- }
325
- };
326
-
327
- /**
328
- * Retrieves and decrypts a stored key pair for a given address.
329
- * @param {string} address - The Ethereum address associated with the key pair.
330
- * @param {string} signature - The signature to use for decryption.
331
- * @returns {Promise<Object|null>} The decrypted key pair or null if retrieval fails.
332
- */
333
- Gun.chain.getAndDecryptPair = async function (address, signature) {
334
- try {
335
- const gun = this;
336
- const encryptedData = await gun
337
- .get("gun-eth")
338
- .get("users")
339
- .get(address)
340
- .get("encryptedPair")
341
- .then();
342
- if (!encryptedData) {
343
- throw new Error("No encrypted data found for this address");
344
- }
345
- const decryptedPair = await SEA.decrypt(encryptedData, signature);
346
- console.log(decryptedPair);
347
- return decryptedPair;
348
- } catch (error) {
349
- console.error("Error retrieving and decrypting pair:", error);
350
- return null;
351
- }
352
- };
353
-
354
- /**
355
- * SHINE (Secure Hybrid Information and Network Environment) functionality.
356
- * @param {string} chain - The blockchain to use (e.g., "optimismSepolia").
357
- * @param {string} nodeId - The ID of the node to verify or write.
358
- * @param {Object} data - The data to write (if writing).
359
- * @param {Function} callback - Callback function to handle the result.
360
- * @returns {Gun} The Gun instance for chaining.
361
- */
362
- Gun.chain.shine = function (chain, nodeId, data, callback) {
363
- console.log("SHINE plugin called with:", { chain, nodeId, data });
364
-
365
- if (!checkEthers()) {
366
- if (callback) callback({ err: "Ethers.js non è disponibile" });
367
- return this;
368
- }
369
-
370
- if (typeof callback !== "function") {
371
- console.error("Callback must be a function");
372
- return this;
373
- }
374
-
375
- const gun = this;
376
-
377
- // Seleziona l'indirizzo basato sulla catena
378
- if (chain === "optimismSepolia") {
379
- SHINE_CONTRACT_ADDRESS = SHINE_OPTIMISM_SEPOLIA;
380
- } else {
381
- throw new Error("Chain not supported");
382
- }
383
-
384
- // Funzione per verificare on-chain
385
- const verifyOnChain = async (nodeId, contentHash) => {
386
- console.log("Verifying on chain:", { nodeId, contentHash });
387
- const signer = await getSigner();
388
- const contract = new ethers.Contract(
389
- SHINE_CONTRACT_ADDRESS,
390
- SHINE_ABI,
391
- signer
392
- );
393
- const [isValid, timestamp, updater] = await contract.verifyData(
394
- ethers.toUtf8Bytes(nodeId),
395
- contentHash
396
- );
397
- console.log("Verification result:", { isValid, timestamp, updater });
398
- return { isValid, timestamp, updater };
399
- };
400
-
401
- // Funzione per scrivere on-chain
402
- const writeOnChain = async (nodeId, contentHash) => {
403
- console.log("Writing on chain:", { nodeId, contentHash });
404
- const signer = await getSigner();
405
- const contract = new ethers.Contract(
406
- SHINE_CONTRACT_ADDRESS,
407
- SHINE_ABI,
408
- signer
409
- );
410
- const tx = await contract.updateData(
411
- ethers.toUtf8Bytes(nodeId),
412
- contentHash
413
- );
414
- console.log("Transaction sent:", tx.hash);
415
- const receipt = await tx.wait();
416
- console.log("Transaction confirmed:", receipt);
417
- return tx;
418
- };
419
-
420
- // Nuova funzione per ottenere l'ultimo record dalla blockchain
421
- const getLatestRecord = async (nodeId) => {
422
- const signer = await getSigner();
423
- const contract = new ethers.Contract(
424
- SHINE_CONTRACT_ADDRESS,
425
- SHINE_ABI,
426
- signer
427
- );
428
- const [contentHash, timestamp, updater] = await contract.getLatestRecord(
429
- ethers.toUtf8Bytes(nodeId)
430
- );
431
- console.log("Latest record from blockchain:", {
432
- nodeId,
433
- contentHash,
434
- timestamp,
435
- updater,
436
- });
437
- return { contentHash, timestamp, updater };
438
- };
439
-
440
- // Processo SHINE
441
- if (nodeId && !data) {
442
- // Caso 1: Utente passa solo il nodo
443
- gun.get(nodeId).once(async (existingData) => {
444
- if (!existingData) {
445
- if (callback) callback({ err: "Node not found in GunDB" });
446
- return;
447
- }
448
-
449
- console.log("existingData", existingData);
450
-
451
- // Usa il contentHash memorizzato invece di ricalcolarlo
452
- const contentHash = existingData._contentHash;
453
- console.log("contentHash", contentHash);
454
-
455
- if (!contentHash) {
456
- if (callback) callback({ err: "No content hash found for this node" });
457
- return;
458
- }
459
-
460
- try {
461
- const { isValid, timestamp, updater } = await verifyOnChain(
462
- nodeId,
463
- contentHash
464
- );
465
- const latestRecord = await getLatestRecord(nodeId);
466
-
467
- if (isValid) {
468
- if (callback)
469
- callback({
470
- ok: true,
471
- message: "Data verified on blockchain",
472
- timestamp,
473
- updater,
474
- latestRecord,
475
- });
476
- } else {
477
- if (callback)
478
- callback({
479
- ok: false,
480
- message: "Data not verified on blockchain",
481
- latestRecord,
482
- });
483
- }
484
- } catch (error) {
485
- if (callback) callback({ err: error.message });
486
- }
487
- });
488
- } else if (data && !nodeId) {
489
- // Caso 2: Utente passa solo il testo (data)
490
- const newNodeId = Gun.text.random();
491
- const dataString = JSON.stringify(data);
492
- const contentHash = ethers.keccak256(ethers.toUtf8Bytes(dataString));
493
-
494
- gun
495
- .get(newNodeId)
496
- .put({ ...data, _contentHash: contentHash }, async (ack) => {
497
- console.log("ack", ack);
498
- if (ack.err) {
499
- if (callback) callback({ err: "Error saving data to GunDB" });
500
- return;
501
- }
502
-
503
- try {
504
- const tx = await writeOnChain(newNodeId, contentHash);
505
- if (callback)
506
- callback({
507
- ok: true,
508
- message: "Data written to GunDB and blockchain",
509
- nodeId: newNodeId,
510
- txHash: tx.hash,
511
- });
512
- } catch (error) {
513
- if (callback) callback({ err: error.message });
514
- }
515
- });
516
- } else {
517
- if (callback)
518
- callback({
519
- err: "Invalid input. Provide either nodeId or data, not both.",
520
- });
521
- }
522
-
523
- return gun;
524
- };
525
-
526
- /**
527
- * Converts a Gun private key to an Ethereum account.
528
- * @param {string} gunPrivateKey - The Gun private key in base64url format.
529
- * @returns {Object} An object containing the Ethereum account and public key.
530
- */
531
- Gun.chain.gunToEthAccount = function (gunPrivateKey) {
532
- // Function to convert base64url to hex
533
- const base64UrlToHex = (base64url) => {
534
- const padding = "=".repeat((4 - (base64url.length % 4)) % 4);
535
- const base64 = base64url.replace(/-/g, "+").replace(/_/g, "/") + padding;
536
- const binary = atob(base64);
537
- return Array.from(binary, (char) =>
538
- char.charCodeAt(0).toString(16).padStart(2, "0")
539
- ).join("");
540
- };
541
-
542
- // Convert Gun private key to hex format
543
- const hexPrivateKey = "0x" + base64UrlToHex(gunPrivateKey);
544
-
545
- // Create an Ethereum wallet from the private key
546
- const wallet = new ethers.Wallet(hexPrivateKey);
547
-
548
- // Get the public address (public key)
549
- const publicKey = wallet.address;
550
-
551
- return {
552
- account: wallet,
553
- publicKey: publicKey,
554
- };
555
- };
556
-
557
- /**
558
- * Sets SHINE configuration.
559
- * @param {Object} abi - The ABI of the SHINE contract.
560
- * @param {string} optimismSepoliaAddress - The contract address on Optimism Sepolia.
561
- * @returns {Gun} The Gun instance for chaining.
562
- */
563
- Gun.chain.setShineConfig = function (abi, optimismSepoliaAddress) {
564
- SHINE_ABI = abi;
565
- SHINE_OPTIMISM_SEPOLIA = optimismSepoliaAddress;
566
- console.log("SHINE configuration set");
567
- return this;
568
- };
569
-
570
- console.log('Plugin Gun-Eth caricato con successo');
571
- });
File without changes
File without changes