n8n-nodes-proofofauthenticity 1.0.2 → 1.0.4
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.
|
@@ -40,6 +40,7 @@ exports.ProofOfAuthenticity = void 0;
|
|
|
40
40
|
const n8n_workflow_1 = require("n8n-workflow");
|
|
41
41
|
const axios_1 = __importDefault(require("axios"));
|
|
42
42
|
const https = __importStar(require("https"));
|
|
43
|
+
const crypto = __importStar(require("crypto"));
|
|
43
44
|
// Security and Performance Constants
|
|
44
45
|
const REQUEST_TIMEOUT = 30000; // 30 seconds for API requests
|
|
45
46
|
const DOWNLOAD_TIMEOUT = 120000; // 2 minutes for file downloads
|
|
@@ -73,6 +74,31 @@ function validateUrl(url) {
|
|
|
73
74
|
throw new Error(`URL points to local hostname: ${hostname}`);
|
|
74
75
|
}
|
|
75
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Calculates SHA-256 hash from file data (base64 or data URI)
|
|
79
|
+
*/
|
|
80
|
+
function calculateSHA256(fileData) {
|
|
81
|
+
let base64Data;
|
|
82
|
+
let mimeType = 'application/octet-stream';
|
|
83
|
+
// Handle data URI format: data:image/jpeg;base64,xxx
|
|
84
|
+
if (fileData.startsWith('data:')) {
|
|
85
|
+
const matches = fileData.match(/^data:([^;]+);base64,(.+)$/);
|
|
86
|
+
if (matches) {
|
|
87
|
+
mimeType = matches[1];
|
|
88
|
+
base64Data = matches[2];
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
const parts = fileData.split(',');
|
|
92
|
+
base64Data = parts[1] || parts[0];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
base64Data = fileData;
|
|
97
|
+
}
|
|
98
|
+
const fileBuffer = Buffer.from(base64Data, 'base64');
|
|
99
|
+
const hash = crypto.createHash('sha256').update(fileBuffer).digest('hex');
|
|
100
|
+
return { hash, fileBuffer, mimeType };
|
|
101
|
+
}
|
|
76
102
|
/**
|
|
77
103
|
* Creates axios config with HTTPS agent for self-signed certificates in local development
|
|
78
104
|
*/
|
|
@@ -204,6 +230,11 @@ class ProofOfAuthenticity {
|
|
|
204
230
|
},
|
|
205
231
|
},
|
|
206
232
|
options: [
|
|
233
|
+
{
|
|
234
|
+
name: 'Binary (from previous node)',
|
|
235
|
+
value: 'binary',
|
|
236
|
+
description: 'Use binary data from previous node (e.g., Form Trigger)',
|
|
237
|
+
},
|
|
207
238
|
{
|
|
208
239
|
name: 'URL',
|
|
209
240
|
value: 'url',
|
|
@@ -215,9 +246,23 @@ class ProofOfAuthenticity {
|
|
|
215
246
|
description: 'File content as base64 encoded string',
|
|
216
247
|
},
|
|
217
248
|
],
|
|
218
|
-
default: '
|
|
249
|
+
default: 'binary',
|
|
219
250
|
description: 'How to provide the file content',
|
|
220
251
|
},
|
|
252
|
+
{
|
|
253
|
+
displayName: 'Binary Property',
|
|
254
|
+
name: 'binaryPropertyName',
|
|
255
|
+
type: 'string',
|
|
256
|
+
displayOptions: {
|
|
257
|
+
show: {
|
|
258
|
+
operation: ['createCertificate'],
|
|
259
|
+
inputType: ['binary'],
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
default: 'data',
|
|
263
|
+
placeholder: 'data',
|
|
264
|
+
description: 'Name of the binary property containing the file (default: "data" for Form Trigger)',
|
|
265
|
+
},
|
|
221
266
|
{
|
|
222
267
|
displayName: 'File URL',
|
|
223
268
|
name: 'fileUrl',
|
|
@@ -366,7 +411,16 @@ class ProofOfAuthenticity {
|
|
|
366
411
|
// Map certification mode to API parameters
|
|
367
412
|
const usageType = certificationMode === 'simple' ? 'simple' : 'ai';
|
|
368
413
|
let fileData;
|
|
369
|
-
if (inputType === '
|
|
414
|
+
if (inputType === 'binary') {
|
|
415
|
+
// Read binary data from previous node (e.g., Form Trigger)
|
|
416
|
+
const binaryPropertyName = this.getNodeParameter('binaryPropertyName', i, 'data');
|
|
417
|
+
const binaryData = this.helpers.assertBinaryData(i, binaryPropertyName);
|
|
418
|
+
const buffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
|
|
419
|
+
const mimeType = binaryData.mimeType || 'application/octet-stream';
|
|
420
|
+
const base64Data = buffer.toString('base64');
|
|
421
|
+
fileData = `data:${mimeType};base64,${base64Data}`;
|
|
422
|
+
}
|
|
423
|
+
else if (inputType === 'url') {
|
|
370
424
|
const fileUrl = this.getNodeParameter('fileUrl', i);
|
|
371
425
|
// Validate URL to prevent SSRF
|
|
372
426
|
validateUrl(fileUrl);
|
|
@@ -383,27 +437,52 @@ class ProofOfAuthenticity {
|
|
|
383
437
|
else {
|
|
384
438
|
fileData = this.getNodeParameter('fileData', i);
|
|
385
439
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
440
|
+
// MODE SIMPLE: Hash only (no file upload)
|
|
441
|
+
if (usageType === 'simple') {
|
|
442
|
+
// Calculate SHA-256 hash client-side
|
|
443
|
+
const { hash, fileBuffer, mimeType } = calculateSHA256(fileData);
|
|
444
|
+
// Extract filename from title or use default
|
|
445
|
+
const originalFilename = title || 'file';
|
|
446
|
+
const hashRequestBody = {
|
|
447
|
+
memo_hash: hash,
|
|
448
|
+
hash_algorithm: 'SHA-256',
|
|
449
|
+
original_filename: originalFilename,
|
|
450
|
+
file_size: fileBuffer.length,
|
|
451
|
+
file_type: mimeType,
|
|
452
|
+
timestamp: new Date().toISOString(),
|
|
453
|
+
payment_mode: 'credits',
|
|
454
|
+
};
|
|
455
|
+
const response = await axios_1.default.post(`${baseUrl}/api/storage/solmemo/create-hash`, hashRequestBody, {
|
|
456
|
+
timeout: REQUEST_TIMEOUT,
|
|
457
|
+
headers: {
|
|
458
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
459
|
+
'Content-Type': 'application/json',
|
|
460
|
+
},
|
|
461
|
+
...getAxiosConfig(baseUrl),
|
|
462
|
+
});
|
|
463
|
+
responseData = response.data;
|
|
464
|
+
}
|
|
465
|
+
// MODE AI: Full file upload with AI analysis + C2PA
|
|
466
|
+
else {
|
|
467
|
+
const requestBody = {
|
|
468
|
+
file_data: fileData,
|
|
469
|
+
title,
|
|
470
|
+
description,
|
|
471
|
+
usage_type: 'ai',
|
|
472
|
+
payment_mode: 'credits',
|
|
473
|
+
ai_endpoint: 'art',
|
|
474
|
+
enable_c2pa: true,
|
|
475
|
+
};
|
|
476
|
+
const response = await axios_1.default.post(`${baseUrl}/api/solmemo/create`, requestBody, {
|
|
477
|
+
timeout: 60000, // 60s for AI processing
|
|
478
|
+
headers: {
|
|
479
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
480
|
+
'Content-Type': 'application/json',
|
|
481
|
+
},
|
|
482
|
+
...getAxiosConfig(baseUrl),
|
|
483
|
+
});
|
|
484
|
+
responseData = response.data;
|
|
397
485
|
}
|
|
398
|
-
const response = await axios_1.default.post(`${baseUrl}/api/solmemo/create`, requestBody, {
|
|
399
|
-
timeout: usageType === 'ai' ? 60000 : REQUEST_TIMEOUT, // 60s if AI
|
|
400
|
-
headers: {
|
|
401
|
-
'Authorization': `Bearer ${apiKey}`,
|
|
402
|
-
'Content-Type': 'application/json',
|
|
403
|
-
},
|
|
404
|
-
...getAxiosConfig(baseUrl),
|
|
405
|
-
});
|
|
406
|
-
responseData = response.data;
|
|
407
486
|
}
|
|
408
487
|
// ============================================
|
|
409
488
|
// LIST CERTIFICATES OPERATION
|
package/package.json
CHANGED