n8n-nodes-proofofauthenticity 1.0.1 → 1.0.3
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
|
*/
|
|
@@ -104,10 +130,44 @@ class ProofOfAuthenticity {
|
|
|
104
130
|
credentials: [
|
|
105
131
|
{
|
|
106
132
|
name: 'proofOfAuthenticityApi',
|
|
107
|
-
required:
|
|
133
|
+
required: false,
|
|
134
|
+
displayOptions: {
|
|
135
|
+
show: {
|
|
136
|
+
credentialType: ['proofOfAuthenticityApi'],
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
name: 'digiCryptoStoreApi',
|
|
142
|
+
required: false,
|
|
143
|
+
displayOptions: {
|
|
144
|
+
show: {
|
|
145
|
+
credentialType: ['digiCryptoStoreApi'],
|
|
146
|
+
},
|
|
147
|
+
},
|
|
108
148
|
},
|
|
109
149
|
],
|
|
110
150
|
properties: [
|
|
151
|
+
// Credential Type Selection
|
|
152
|
+
{
|
|
153
|
+
displayName: 'Credential Type',
|
|
154
|
+
name: 'credentialType',
|
|
155
|
+
type: 'options',
|
|
156
|
+
options: [
|
|
157
|
+
{
|
|
158
|
+
name: 'ProofOfAuthenticity API (Light)',
|
|
159
|
+
value: 'proofOfAuthenticityApi',
|
|
160
|
+
description: 'Use dedicated ProofOfAuthenticity credentials',
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
name: 'DigiCryptoStore API (Shared)',
|
|
164
|
+
value: 'digiCryptoStoreApi',
|
|
165
|
+
description: 'Use existing DigiCryptoStore credentials (same API)',
|
|
166
|
+
},
|
|
167
|
+
],
|
|
168
|
+
default: 'proofOfAuthenticityApi',
|
|
169
|
+
description: 'Choose which credential to use. Both use the same CHECKHC API.',
|
|
170
|
+
},
|
|
111
171
|
// Operation
|
|
112
172
|
{
|
|
113
173
|
displayName: 'Operation',
|
|
@@ -315,7 +375,8 @@ class ProofOfAuthenticity {
|
|
|
315
375
|
for (let i = 0; i < items.length; i++) {
|
|
316
376
|
try {
|
|
317
377
|
const operation = this.getNodeParameter('operation', i);
|
|
318
|
-
const
|
|
378
|
+
const credentialType = this.getNodeParameter('credentialType', i, 'proofOfAuthenticityApi');
|
|
379
|
+
const credentials = await this.getCredentials(credentialType, i);
|
|
319
380
|
const baseUrl = credentials.digiCryptoStoreUrl.replace(/\/$/, '');
|
|
320
381
|
const apiKey = credentials.apiKey;
|
|
321
382
|
let responseData;
|
|
@@ -348,27 +409,52 @@ class ProofOfAuthenticity {
|
|
|
348
409
|
else {
|
|
349
410
|
fileData = this.getNodeParameter('fileData', i);
|
|
350
411
|
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
412
|
+
// MODE SIMPLE: Hash only (no file upload)
|
|
413
|
+
if (usageType === 'simple') {
|
|
414
|
+
// Calculate SHA-256 hash client-side
|
|
415
|
+
const { hash, fileBuffer, mimeType } = calculateSHA256(fileData);
|
|
416
|
+
// Extract filename from title or use default
|
|
417
|
+
const originalFilename = title || 'file';
|
|
418
|
+
const hashRequestBody = {
|
|
419
|
+
memo_hash: hash,
|
|
420
|
+
hash_algorithm: 'SHA-256',
|
|
421
|
+
original_filename: originalFilename,
|
|
422
|
+
file_size: fileBuffer.length,
|
|
423
|
+
file_type: mimeType,
|
|
424
|
+
timestamp: new Date().toISOString(),
|
|
425
|
+
payment_mode: 'credits',
|
|
426
|
+
};
|
|
427
|
+
const response = await axios_1.default.post(`${baseUrl}/api/storage/solmemo/create-hash`, hashRequestBody, {
|
|
428
|
+
timeout: REQUEST_TIMEOUT,
|
|
429
|
+
headers: {
|
|
430
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
431
|
+
'Content-Type': 'application/json',
|
|
432
|
+
},
|
|
433
|
+
...getAxiosConfig(baseUrl),
|
|
434
|
+
});
|
|
435
|
+
responseData = response.data;
|
|
436
|
+
}
|
|
437
|
+
// MODE AI: Full file upload with AI analysis + C2PA
|
|
438
|
+
else {
|
|
439
|
+
const requestBody = {
|
|
440
|
+
file_data: fileData,
|
|
441
|
+
title,
|
|
442
|
+
description,
|
|
443
|
+
usage_type: 'ai',
|
|
444
|
+
payment_mode: 'credits',
|
|
445
|
+
ai_endpoint: 'art',
|
|
446
|
+
enable_c2pa: true,
|
|
447
|
+
};
|
|
448
|
+
const response = await axios_1.default.post(`${baseUrl}/api/solmemo/create`, requestBody, {
|
|
449
|
+
timeout: 60000, // 60s for AI processing
|
|
450
|
+
headers: {
|
|
451
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
452
|
+
'Content-Type': 'application/json',
|
|
453
|
+
},
|
|
454
|
+
...getAxiosConfig(baseUrl),
|
|
455
|
+
});
|
|
456
|
+
responseData = response.data;
|
|
362
457
|
}
|
|
363
|
-
const response = await axios_1.default.post(`${baseUrl}/api/solmemo/create`, requestBody, {
|
|
364
|
-
timeout: usageType === 'ai' ? 60000 : REQUEST_TIMEOUT, // 60s if AI
|
|
365
|
-
headers: {
|
|
366
|
-
'Authorization': `Bearer ${apiKey}`,
|
|
367
|
-
'Content-Type': 'application/json',
|
|
368
|
-
},
|
|
369
|
-
...getAxiosConfig(baseUrl),
|
|
370
|
-
});
|
|
371
|
-
responseData = response.data;
|
|
372
458
|
}
|
|
373
459
|
// ============================================
|
|
374
460
|
// LIST CERTIFICATES OPERATION
|
package/package.json
CHANGED