gun-eth 1.3.6 → 1.4.0

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