gun-eth 1.3.2 → 1.3.5

Sign up to get free protection for your applications and to get access to all the features.
package/src/index.js CHANGED
@@ -1,346 +1,533 @@
1
- const Gun = require("gun/gun");
2
- const SEA = require("gun/sea");
3
- const ethers = require("ethers");
4
- const SHINE = require("../abis/SHINE.json");
5
-
6
- const SHINE_ABI = SHINE.abi;
7
- const SHINE_OPTIMISM_SEPOLIA = SHINE.address;
8
-
9
- let SHINE_CONTRACT_ADDRESS;
10
-
11
- let rpcUrl = "";
12
- let privateKey = "";
13
-
14
- const MESSAGE_TO_SIGN = "Accesso a GunDB con Ethereum";
15
-
16
- /**
17
- * Funzione per ottenere il signer
18
- * @returns {Promise<ethers.Signer>} Il signer.
19
- */
20
- const getSigner = async () => {
21
- if (rpcUrl && privateKey) {
22
- // Modalità standalone
23
- const provider = new ethers.JsonRpcProvider(rpcUrl);
24
- return new ethers.Wallet(privateKey, provider);
25
- } else if (
26
- typeof window !== "undefined" &&
27
- typeof window.ethereum !== "undefined"
28
- ) {
29
- // Modalità browser
30
- await window.ethereum.request({ method: "eth_requestAccounts" });
31
- const provider = new ethers.BrowserProvider(window.ethereum);
32
- return provider.getSigner();
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/gun"),
7
+ require("gun/sea"),
8
+ require("ethers")
9
+ );
33
10
  } else {
34
- throw new Error("No valid Ethereum provider found");
35
- }
36
- };
37
-
38
- /**
39
- * Sets standalone configuration for Gun.
40
- * @param {string} newRpcUrl - The new RPC URL.
41
- * @param {string} newPrivateKey - The new private key.
42
- * @returns {Gun} The Gun instance for chaining.
43
- */
44
- Gun.chain.setStandaloneConfig = function (newRpcUrl, newPrivateKey) {
45
- rpcUrl = newRpcUrl;
46
- privateKey = newPrivateKey;
47
- console.log("Standalone configuration set");
48
- return this;
49
- };
50
-
51
- /**
52
- * Verifies an Ethereum signature.
53
- * @param {string} message - The original message that was signed.
54
- * @param {string} signature - The signature to verify.
55
- * @returns {Promise<string|null>} The recovered address or null if verification fails.
56
- */
57
- Gun.chain.verifySignature = async function (message, signature) {
58
- try {
59
- const recoveredAddress = ethers.verifyMessage(message, signature);
60
- return recoveredAddress;
61
- } catch (error) {
62
- console.error("Error verifying signature:", error);
63
- return null;
11
+ factory(root.Gun, root.SEA, root.ethers);
64
12
  }
65
- };
66
-
67
- /**
68
- * Generates a password from a signature.
69
- * @param {string} signature - The signature to derive the password from.
70
- * @returns {string|null} The generated password or null if generation fails.
71
- */
72
- Gun.chain.generatePassword = function (signature) {
73
- try {
74
- const hexSignature = ethers.hexlify(signature);
75
- const hash = ethers.keccak256(hexSignature);
76
- console.log("Generated password:", hash);
77
- return hash;
78
- } catch (error) {
79
- console.error("Error generating password:", error);
80
- return null;
81
- }
82
- };
83
-
84
- /**
85
- * Creates an Ethereum signature for a given message.
86
- * @param {string} message - The message to sign.
87
- * @returns {Promise<string|null>} The signature or null if signing fails.
88
- */
89
- Gun.chain.createSignature = async function (message) {
90
- try {
91
- // Verifica se il messaggio è uguale a MESSAGE_TO_SIGN
92
- if (message !== MESSAGE_TO_SIGN) {
93
- throw new Error("Invalid message, valid message is: " + MESSAGE_TO_SIGN);
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;
94
25
  }
95
- const signer = await getSigner();
96
- const signature = await signer.signMessage(message);
97
- console.log("Signature created:", signature);
98
- return signature;
99
- } catch (error) {
100
- console.error("Error creating signature:", error);
101
- return null;
26
+ console.log("Ethers version:", ethers.version);
27
+ return true;
102
28
  }
103
- };
104
-
105
- /**
106
- * Creates and stores an encrypted key pair for a given address.
107
- * @param {string} address - The Ethereum address to associate with the key pair.
108
- * @param {string} signature - The signature to use for encryption.
109
- * @returns {Promise<void>}
110
- */
111
- Gun.chain.createAndStoreEncryptedPair = async function (address, signature) {
112
- try {
113
- const gun = this;
114
- const pair = await SEA.pair();
115
- const encryptedPair = await SEA.encrypt(JSON.stringify(pair), signature);
116
- await gun.get("gun-eth").get("users").get(address).put({ encryptedPair });
117
- console.log("Encrypted pair stored for:", address);
118
- } catch (error) {
119
- console.error("Error creating and storing encrypted pair:", error);
120
- }
121
- };
122
-
123
- /**
124
- * Retrieves and decrypts a stored key pair for a given address.
125
- * @param {string} address - The Ethereum address associated with the key pair.
126
- * @param {string} signature - The signature to use for decryption.
127
- * @returns {Promise<Object|null>} The decrypted key pair or null if retrieval fails.
128
- */
129
- Gun.chain.getAndDecryptPair = async function (address, signature) {
130
- try {
131
- const gun = this;
132
- const encryptedData = await gun
133
- .get("gun-eth")
134
- .get("users")
135
- .get(address)
136
- .get("encryptedPair")
137
- .then();
138
- if (!encryptedData) {
139
- throw new Error("No encrypted data found for this address");
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");
140
211
  }
141
- const decryptedPair = await SEA.decrypt(encryptedData, signature);
142
- console.log(decryptedPair);
143
- return decryptedPair;
144
- } catch (error) {
145
- console.error("Error retrieving and decrypting pair:", error);
146
- return null;
147
- }
148
- };
149
-
150
- /**
151
- * SHINE (Secure Hybrid Information and Network Environment) functionality.
152
- * @param {string} chain - The blockchain to use (e.g., "optimismSepolia").
153
- * @param {string} nodeId - The ID of the node to verify or write.
154
- * @param {Object} data - The data to write (if writing).
155
- * @param {Function} callback - Callback function to handle the result.
156
- * @returns {Gun} The Gun instance for chaining.
157
- */
158
- Gun.chain.shine = function (chain, nodeId, data, callback) {
159
- console.log("SHINE plugin called with:", { chain, nodeId, data });
160
-
161
- if (typeof callback !== "function") {
162
- console.error("Callback must be a function");
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");
163
224
  return this;
164
- }
225
+ };
165
226
 
166
- const gun = this;
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
+ };
167
242
 
168
- // Seleziona l'indirizzo basato sulla catena
169
- if (chain === "optimismSepolia") {
170
- SHINE_CONTRACT_ADDRESS = SHINE_OPTIMISM_SEPOLIA;
171
- } else {
172
- throw new Error("Chain not supported");
173
- }
174
- // Funzione per verificare on-chain
175
- const verifyOnChain = async (nodeId, contentHash) => {
176
- console.log("Verifying on chain:", { nodeId, contentHash });
177
- const signer = await getSigner();
178
- const contract = new ethers.Contract(
179
- SHINE_CONTRACT_ADDRESS,
180
- SHINE_ABI,
181
- signer
182
- );
183
- const [isValid, timestamp, updater] = await contract.verifyData(
184
- ethers.toUtf8Bytes(nodeId),
185
- contentHash
186
- );
187
- console.log("Verification result:", { isValid, timestamp, updater });
188
- return { isValid, timestamp, updater };
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
+ }
189
258
  };
190
259
 
191
- // Funzione per scrivere on-chain
192
- const writeOnChain = async (nodeId, contentHash) => {
193
- console.log("Writing on chain:", { nodeId, contentHash });
194
- const signer = await getSigner();
195
- const contract = new ethers.Contract(
196
- SHINE_CONTRACT_ADDRESS,
197
- SHINE_ABI,
198
- signer
199
- );
200
- const tx = await contract.updateData(
201
- ethers.toUtf8Bytes(nodeId),
202
- contentHash
203
- );
204
- console.log("Transaction sent:", tx.hash);
205
- const receipt = await tx.wait();
206
- console.log("Transaction confirmed:", receipt);
207
- return tx;
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
+ }
208
281
  };
209
282
 
210
- // Nuova funzione per ottenere l'ultimo record dalla blockchain
211
- const getLatestRecord = async (nodeId) => {
212
- const signer = await getSigner();
213
- const contract = new ethers.Contract(
214
- SHINE_CONTRACT_ADDRESS,
215
- SHINE_ABI,
216
- signer
217
- );
218
- const [contentHash, timestamp, updater] = await contract.getLatestRecord(
219
- ethers.toUtf8Bytes(nodeId)
220
- );
221
- console.log("Latest record from blockchain:", {
222
- nodeId,
223
- contentHash,
224
- timestamp,
225
- updater,
226
- });
227
- return { contentHash, timestamp, updater };
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
+ }
228
299
  };
229
300
 
230
- // Processo SHINE
231
- if (nodeId && !data) {
232
- // Caso 1: Utente passa solo il nodo
233
- gun.get(nodeId).once(async (existingData) => {
234
- if (!existingData) {
235
- if (callback) callback({ err: "Node not found in GunDB" });
236
- return;
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");
237
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
+ };
238
327
 
239
- console.log("existingData", existingData);
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
+ }
240
343
 
241
- // Usa il contentHash memorizzato invece di ricalcolarlo
242
- const contentHash = existingData._contentHash;
243
- console.log("contentHash", contentHash);
344
+ if (typeof callback !== "function") {
345
+ console.error("Callback must be a function");
346
+ return this;
347
+ }
244
348
 
245
- if (!contentHash) {
246
- if (callback) callback({ err: "No content hash found for this node" });
247
- return;
248
- }
349
+ const gun = this;
249
350
 
250
- try {
251
- const { isValid, timestamp, updater } = await verifyOnChain(
252
- nodeId,
253
- contentHash
254
- );
255
- const latestRecord = await getLatestRecord(nodeId);
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
+ }
256
357
 
257
- if (isValid) {
258
- if (callback)
259
- callback({
260
- ok: true,
261
- message: "Data verified on blockchain",
262
- timestamp,
263
- updater,
264
- latestRecord,
265
- });
266
- } else {
267
- if (callback)
268
- callback({
269
- ok: false,
270
- message: "Data not verified on blockchain",
271
- latestRecord,
272
- });
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;
273
421
  }
274
- } catch (error) {
275
- if (callback) callback({ err: error.message });
276
- }
277
- });
278
- } else if (data && !nodeId) {
279
- // Caso 2: Utente passa solo il testo (data)
280
- const newNodeId = Gun.text.random();
281
- const dataString = JSON.stringify(data);
282
- const contentHash = ethers.keccak256(ethers.toUtf8Bytes(dataString));
283
-
284
- gun
285
- .get(newNodeId)
286
- .put({ ...data, _contentHash: contentHash }, async (ack) => {
287
- console.log("ack", ack);
288
- if (ack.err) {
289
- if (callback) callback({ err: "Error saving data to GunDB" });
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" });
290
432
  return;
291
433
  }
292
434
 
293
435
  try {
294
- const tx = await writeOnChain(newNodeId, contentHash);
295
- if (callback)
296
- callback({
297
- ok: true,
298
- message: "Data written to GunDB and blockchain",
299
- nodeId: newNodeId,
300
- txHash: tx.hash,
301
- });
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
+ }
302
459
  } catch (error) {
303
460
  if (callback) callback({ err: error.message });
304
461
  }
305
462
  });
306
- } else {
307
- if (callback)
308
- callback({
309
- err: "Invalid input. Provide either nodeId or data, not both.",
310
- });
311
- }
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
+ }
312
497
 
313
- return gun;
314
- };
315
-
316
-
317
- /**
318
- * Converts a Gun private key to an Ethereum account.
319
- * @param {string} gunPrivateKey - The Gun private key in base64url format.
320
- * @returns {Object} An object containing the Ethereum account and public key.
321
- */
322
- Gun.chain.gunToEthAccount = function(gunPrivateKey) {
323
- // Function to convert base64url to hex
324
- const base64UrlToHex = (base64url) => {
325
- const padding = "=".repeat((4 - (base64url.length % 4)) % 4);
326
- const base64 = base64url.replace(/-/g, "+").replace(/_/g, "/") + padding;
327
- const binary = atob(base64);
328
- return Array.from(binary, (char) => char.charCodeAt(0).toString(16).padStart(2, "0")).join("");
498
+ return gun;
329
499
  };
330
500
 
331
- // Convert Gun private key to hex format
332
- const hexPrivateKey = "0x" + base64UrlToHex(gunPrivateKey);
333
-
334
- // Create an Ethereum wallet from the private key
335
- const wallet = new ethers.Wallet(hexPrivateKey);
336
-
337
- // Get the public address (public key)
338
- const publicKey = wallet.address;
339
-
340
- return {
341
- account: wallet,
342
- publicKey: publicKey
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
+ };
343
530
  };
344
- };
345
531
 
346
- module.exports = Gun;
532
+ console.log("Plugin Gun-Eth successfully loaded");
533
+ });