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: 'url',
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 === 'url') {
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
- const requestBody = {
387
- file_data: fileData,
388
- title,
389
- description,
390
- usage_type: usageType,
391
- payment_mode: 'credits', // Use subscription credits
392
- };
393
- // Add AI options if AI mode is enabled
394
- if (usageType === 'ai') {
395
- requestBody.ai_endpoint = 'art';
396
- requestBody.enable_c2pa = true; // C2PA auto-enabled with AI
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-proofofauthenticity",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "ProofOfAuthenticity by CHECKHC - Blockchain timestamping with AI detection and C2PA content authenticity.",
5
5
  "keywords": [
6
6
  "n8n",