n8n-nodes-proofofauthenticity 1.0.0
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.
- package/LICENSE +21 -0
- package/README.md +71 -0
- package/dist/credentials/ProofOfAuthenticityApi.credentials.d.ts +9 -0
- package/dist/credentials/ProofOfAuthenticityApi.credentials.js +49 -0
- package/dist/nodes/ProofOfAuthenticity/ProofOfAuthenticity.node.d.ts +5 -0
- package/dist/nodes/ProofOfAuthenticity/ProofOfAuthenticity.node.js +425 -0
- package/dist/nodes/ProofOfAuthenticity/proofofauthenticity.png +0 -0
- package/index.js +2 -0
- package/package.json +60 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 CHECKHC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# ProofOfAuthenticity
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/n8n-nodes-proofofauthenticity)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
> Developed by **[CHECKHC](https://checkhc.net)** - Blockchain content certification experts
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
**ProofOfAuthenticity** is an n8n community node that provides blockchain timestamping with optional AI authenticity detection and C2PA content authenticity metadata.
|
|
11
|
+
|
|
12
|
+
### Features
|
|
13
|
+
|
|
14
|
+
- **Blockchain Timestamping** - SHA-256 hash certified on Solana blockchain
|
|
15
|
+
- **AI Authenticity Detection** - Detect AI-generated vs human-created content
|
|
16
|
+
- **C2PA Integration** - Content Authenticity Initiative standard metadata
|
|
17
|
+
|
|
18
|
+
## Operations
|
|
19
|
+
|
|
20
|
+
### Create Certificate
|
|
21
|
+
|
|
22
|
+
Certify content with blockchain timestamp.
|
|
23
|
+
|
|
24
|
+
| Parameter | Description |
|
|
25
|
+
|-----------|-------------|
|
|
26
|
+
| Input Type | URL or Base64 |
|
|
27
|
+
| File URL/Data | The file to certify |
|
|
28
|
+
| Title | Certificate title (required) |
|
|
29
|
+
| Author | Author name (optional) |
|
|
30
|
+
| Description | Description (optional) |
|
|
31
|
+
| Certification Mode | Simple or AI + C2PA |
|
|
32
|
+
|
|
33
|
+
### List Certificates
|
|
34
|
+
|
|
35
|
+
List blockchain certificates with optional filters (hash, filename, signature).
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
### Via n8n Community Nodes
|
|
40
|
+
|
|
41
|
+
1. Go to **Settings** > **Community Nodes**
|
|
42
|
+
2. Select **Install**
|
|
43
|
+
3. Enter `n8n-nodes-proofofauthenticity`
|
|
44
|
+
4. Click **Install**
|
|
45
|
+
|
|
46
|
+
### Manual Installation
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
cd ~/.n8n/nodes
|
|
50
|
+
yarn add n8n-nodes-proofofauthenticity
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Configuration
|
|
54
|
+
|
|
55
|
+
1. Create a credential of type **ProofOfAuthenticity API**
|
|
56
|
+
2. Enter your DigiCryptoStore instance URL
|
|
57
|
+
3. Enter your API Key (Settings > API Keys)
|
|
58
|
+
|
|
59
|
+
## Support
|
|
60
|
+
|
|
61
|
+
- **GitHub**: Issues/Discussions
|
|
62
|
+
- **Email**: contact@checkhc.net
|
|
63
|
+
- **Website**: [https://checkhc.net](https://checkhc.net)
|
|
64
|
+
|
|
65
|
+
## License
|
|
66
|
+
|
|
67
|
+
MIT
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
**Powered by [CHECKHC](https://checkhc.net)**
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { IAuthenticateGeneric, ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
|
|
2
|
+
export declare class ProofOfAuthenticityApi implements ICredentialType {
|
|
3
|
+
name: string;
|
|
4
|
+
displayName: string;
|
|
5
|
+
documentationUrl: string;
|
|
6
|
+
properties: INodeProperties[];
|
|
7
|
+
authenticate: IAuthenticateGeneric;
|
|
8
|
+
test: ICredentialTestRequest;
|
|
9
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ProofOfAuthenticityApi = void 0;
|
|
4
|
+
class ProofOfAuthenticityApi {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.name = 'proofOfAuthenticityApi';
|
|
7
|
+
this.displayName = 'ProofOfAuthenticity API';
|
|
8
|
+
this.documentationUrl = 'https://docs.checkhc.net/';
|
|
9
|
+
this.properties = [
|
|
10
|
+
{
|
|
11
|
+
displayName: 'DigiCryptoStore URL',
|
|
12
|
+
name: 'digiCryptoStoreUrl',
|
|
13
|
+
type: 'string',
|
|
14
|
+
default: 'https://localhost:3000',
|
|
15
|
+
placeholder: 'https://your-instance.com or https://localhost:3000',
|
|
16
|
+
description: 'The URL of your DigiCryptoStore instance (with HTTPS)',
|
|
17
|
+
required: true,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
displayName: 'API Key (Bearer Token)',
|
|
21
|
+
name: 'apiKey',
|
|
22
|
+
type: 'string',
|
|
23
|
+
typeOptions: {
|
|
24
|
+
password: true,
|
|
25
|
+
},
|
|
26
|
+
default: '',
|
|
27
|
+
placeholder: 'your-api-key',
|
|
28
|
+
description: 'API Key for authentication (found in Settings > API Keys)',
|
|
29
|
+
required: true,
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
this.authenticate = {
|
|
33
|
+
type: 'generic',
|
|
34
|
+
properties: {
|
|
35
|
+
headers: {
|
|
36
|
+
Authorization: '=Bearer {{$credentials.apiKey}}',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
this.test = {
|
|
41
|
+
request: {
|
|
42
|
+
baseURL: '={{$credentials.digiCryptoStoreUrl}}',
|
|
43
|
+
url: '/api/auth/me',
|
|
44
|
+
method: 'GET',
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.ProofOfAuthenticityApi = ProofOfAuthenticityApi;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
|
|
2
|
+
export declare class ProofOfAuthenticity implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
5
|
+
}
|
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.ProofOfAuthenticity = void 0;
|
|
40
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
41
|
+
const axios_1 = __importDefault(require("axios"));
|
|
42
|
+
const https = __importStar(require("https"));
|
|
43
|
+
// Security and Performance Constants
|
|
44
|
+
const REQUEST_TIMEOUT = 30000; // 30 seconds for API requests
|
|
45
|
+
const DOWNLOAD_TIMEOUT = 120000; // 2 minutes for file downloads
|
|
46
|
+
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB maximum file size
|
|
47
|
+
/**
|
|
48
|
+
* Validates URL to prevent SSRF attacks
|
|
49
|
+
* Only allows http/https protocols and blocks private IPs
|
|
50
|
+
*/
|
|
51
|
+
function validateUrl(url) {
|
|
52
|
+
const parsed = new URL(url);
|
|
53
|
+
// Only allow http/https
|
|
54
|
+
if (!['http:', 'https:'].includes(parsed.protocol)) {
|
|
55
|
+
throw new Error(`Invalid URL protocol: ${parsed.protocol}. Only http/https allowed.`);
|
|
56
|
+
}
|
|
57
|
+
// Block private IPs and localhost (except for development)
|
|
58
|
+
const hostname = parsed.hostname.toLowerCase();
|
|
59
|
+
const privatePatterns = [
|
|
60
|
+
/^10\./,
|
|
61
|
+
/^172\.(1[6-9]|2[0-9]|3[0-1])\./,
|
|
62
|
+
/^192\.168\./,
|
|
63
|
+
/^127\./,
|
|
64
|
+
/^0\./,
|
|
65
|
+
/^169\.254\./,
|
|
66
|
+
];
|
|
67
|
+
for (const pattern of privatePatterns) {
|
|
68
|
+
if (pattern.test(hostname)) {
|
|
69
|
+
throw new Error(`URL points to private IP range: ${hostname}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (hostname === 'localhost' || hostname.endsWith('.local')) {
|
|
73
|
+
throw new Error(`URL points to local hostname: ${hostname}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Creates axios config with HTTPS agent for self-signed certificates in local development
|
|
78
|
+
*/
|
|
79
|
+
function getAxiosConfig(baseUrl) {
|
|
80
|
+
if (baseUrl.includes('localhost') || baseUrl.includes('127.0.0.1')) {
|
|
81
|
+
return {
|
|
82
|
+
httpsAgent: new https.Agent({
|
|
83
|
+
rejectUnauthorized: false
|
|
84
|
+
})
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
return {};
|
|
88
|
+
}
|
|
89
|
+
class ProofOfAuthenticity {
|
|
90
|
+
constructor() {
|
|
91
|
+
this.description = {
|
|
92
|
+
displayName: 'ProofOfAuthenticity by CHECKHC',
|
|
93
|
+
name: 'proofOfAuthenticity',
|
|
94
|
+
icon: 'file:proofofauthenticity.png',
|
|
95
|
+
group: ['transform'],
|
|
96
|
+
version: 1,
|
|
97
|
+
subtitle: '={{$parameter["operation"]}}',
|
|
98
|
+
description: 'ProofOfAuthenticity by CHECKHC - Blockchain timestamping with AI detection and C2PA authenticity. Learn more: https://www.checkhc.net',
|
|
99
|
+
defaults: {
|
|
100
|
+
name: 'ProofOfAuthenticity by CHECKHC',
|
|
101
|
+
},
|
|
102
|
+
inputs: ['main'],
|
|
103
|
+
outputs: ['main'],
|
|
104
|
+
credentials: [
|
|
105
|
+
{
|
|
106
|
+
name: 'proofOfAuthenticityApi',
|
|
107
|
+
required: true,
|
|
108
|
+
},
|
|
109
|
+
],
|
|
110
|
+
properties: [
|
|
111
|
+
// Operation
|
|
112
|
+
{
|
|
113
|
+
displayName: 'Operation',
|
|
114
|
+
name: 'operation',
|
|
115
|
+
type: 'options',
|
|
116
|
+
noDataExpression: true,
|
|
117
|
+
options: [
|
|
118
|
+
{
|
|
119
|
+
name: 'Create Certificate',
|
|
120
|
+
value: 'createCertificate',
|
|
121
|
+
description: 'Create blockchain certificate with optional AI analysis and C2PA',
|
|
122
|
+
action: 'Create certificate',
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: 'List Certificates',
|
|
126
|
+
value: 'listCertificates',
|
|
127
|
+
description: 'List all your blockchain certificates',
|
|
128
|
+
action: 'List certificates',
|
|
129
|
+
},
|
|
130
|
+
],
|
|
131
|
+
default: 'createCertificate',
|
|
132
|
+
},
|
|
133
|
+
// ============================================
|
|
134
|
+
// CERTIFICATION MODE SELECTOR
|
|
135
|
+
// ============================================
|
|
136
|
+
{
|
|
137
|
+
displayName: 'Certification Mode',
|
|
138
|
+
name: 'certificationMode',
|
|
139
|
+
type: 'options',
|
|
140
|
+
displayOptions: {
|
|
141
|
+
show: {
|
|
142
|
+
operation: ['createCertificate'],
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
options: [
|
|
146
|
+
{
|
|
147
|
+
name: 'Blockchain Hash Only (1 credit)',
|
|
148
|
+
value: 'simple',
|
|
149
|
+
description: 'SHA-256 hash timestamped on Solana blockchain. File stays on your device.',
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
name: 'Blockchain Hash + AI + C2PA (30 credits)',
|
|
153
|
+
value: 'ai',
|
|
154
|
+
description: 'Hash + AI authenticity analysis + C2PA content authenticity metadata',
|
|
155
|
+
},
|
|
156
|
+
],
|
|
157
|
+
default: 'simple',
|
|
158
|
+
required: true,
|
|
159
|
+
},
|
|
160
|
+
// ============================================
|
|
161
|
+
// CREATE CERTIFICATE PARAMETERS
|
|
162
|
+
// ============================================
|
|
163
|
+
{
|
|
164
|
+
displayName: 'Input Type',
|
|
165
|
+
name: 'inputType',
|
|
166
|
+
type: 'options',
|
|
167
|
+
displayOptions: {
|
|
168
|
+
show: {
|
|
169
|
+
operation: ['createCertificate'],
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
options: [
|
|
173
|
+
{
|
|
174
|
+
name: 'URL',
|
|
175
|
+
value: 'url',
|
|
176
|
+
description: 'Download file from URL',
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
name: 'Base64 String',
|
|
180
|
+
value: 'base64',
|
|
181
|
+
description: 'File content as base64 encoded string',
|
|
182
|
+
},
|
|
183
|
+
],
|
|
184
|
+
default: 'url',
|
|
185
|
+
description: 'How to provide the file content',
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
displayName: 'File URL',
|
|
189
|
+
name: 'fileUrl',
|
|
190
|
+
type: 'string',
|
|
191
|
+
displayOptions: {
|
|
192
|
+
show: {
|
|
193
|
+
operation: ['createCertificate'],
|
|
194
|
+
inputType: ['url'],
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
default: '',
|
|
198
|
+
required: true,
|
|
199
|
+
placeholder: 'https://example.com/image.jpg',
|
|
200
|
+
description: 'URL of the file to certify',
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
displayName: 'File Data (Base64)',
|
|
204
|
+
name: 'fileData',
|
|
205
|
+
type: 'string',
|
|
206
|
+
displayOptions: {
|
|
207
|
+
show: {
|
|
208
|
+
operation: ['createCertificate'],
|
|
209
|
+
inputType: ['base64'],
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
default: '',
|
|
213
|
+
required: true,
|
|
214
|
+
placeholder: 'data:image/jpeg;base64,/9j/4AAQ...',
|
|
215
|
+
description: 'Base64 encoded file with data URI prefix',
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
displayName: 'Title',
|
|
219
|
+
name: 'title',
|
|
220
|
+
type: 'string',
|
|
221
|
+
displayOptions: {
|
|
222
|
+
show: {
|
|
223
|
+
operation: ['createCertificate'],
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
default: '',
|
|
227
|
+
required: true,
|
|
228
|
+
description: 'Certificate title',
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
displayName: 'Author',
|
|
232
|
+
name: 'author',
|
|
233
|
+
type: 'string',
|
|
234
|
+
displayOptions: {
|
|
235
|
+
show: {
|
|
236
|
+
operation: ['createCertificate'],
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
default: '',
|
|
240
|
+
description: 'Author name',
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
displayName: 'Description',
|
|
244
|
+
name: 'description',
|
|
245
|
+
type: 'string',
|
|
246
|
+
displayOptions: {
|
|
247
|
+
show: {
|
|
248
|
+
operation: ['createCertificate'],
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
default: '',
|
|
252
|
+
description: 'Certificate description',
|
|
253
|
+
},
|
|
254
|
+
// ============================================
|
|
255
|
+
// LIST CERTIFICATES PARAMETERS
|
|
256
|
+
// ============================================
|
|
257
|
+
{
|
|
258
|
+
displayName: 'Filter by Hash',
|
|
259
|
+
name: 'filterHash',
|
|
260
|
+
type: 'string',
|
|
261
|
+
displayOptions: {
|
|
262
|
+
show: {
|
|
263
|
+
operation: ['listCertificates'],
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
default: '',
|
|
267
|
+
placeholder: '2eb0a0766d04971078ca73e1b9d2281b70fc4ca2...',
|
|
268
|
+
description: 'Filter certificates by hash (partial match)',
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
displayName: 'Filter by Filename',
|
|
272
|
+
name: 'filterFilename',
|
|
273
|
+
type: 'string',
|
|
274
|
+
displayOptions: {
|
|
275
|
+
show: {
|
|
276
|
+
operation: ['listCertificates'],
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
default: '',
|
|
280
|
+
placeholder: 'DSC02158.JPG',
|
|
281
|
+
description: 'Filter certificates by filename (partial match)',
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
displayName: 'Filter by Signature',
|
|
285
|
+
name: 'filterSignature',
|
|
286
|
+
type: 'string',
|
|
287
|
+
displayOptions: {
|
|
288
|
+
show: {
|
|
289
|
+
operation: ['listCertificates'],
|
|
290
|
+
},
|
|
291
|
+
},
|
|
292
|
+
default: '',
|
|
293
|
+
placeholder: '4ZxL8...',
|
|
294
|
+
description: 'Filter certificates by blockchain signature (partial match)',
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
displayName: 'Limit',
|
|
298
|
+
name: 'limit',
|
|
299
|
+
type: 'number',
|
|
300
|
+
displayOptions: {
|
|
301
|
+
show: {
|
|
302
|
+
operation: ['listCertificates'],
|
|
303
|
+
},
|
|
304
|
+
},
|
|
305
|
+
default: 100,
|
|
306
|
+
description: 'Maximum number of results to return',
|
|
307
|
+
},
|
|
308
|
+
],
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
async execute() {
|
|
312
|
+
var _a;
|
|
313
|
+
const items = this.getInputData();
|
|
314
|
+
const returnData = [];
|
|
315
|
+
for (let i = 0; i < items.length; i++) {
|
|
316
|
+
try {
|
|
317
|
+
const operation = this.getNodeParameter('operation', i);
|
|
318
|
+
const credentials = await this.getCredentials('proofOfAuthenticityApi', i);
|
|
319
|
+
const baseUrl = credentials.digiCryptoStoreUrl.replace(/\/$/, '');
|
|
320
|
+
const apiKey = credentials.apiKey;
|
|
321
|
+
let responseData;
|
|
322
|
+
// ============================================
|
|
323
|
+
// CREATE CERTIFICATE OPERATION
|
|
324
|
+
// ============================================
|
|
325
|
+
if (operation === 'createCertificate') {
|
|
326
|
+
const title = this.getNodeParameter('title', i);
|
|
327
|
+
const author = this.getNodeParameter('author', i, '');
|
|
328
|
+
const description = this.getNodeParameter('description', i, '');
|
|
329
|
+
const certificationMode = this.getNodeParameter('certificationMode', i, 'simple');
|
|
330
|
+
const inputType = this.getNodeParameter('inputType', i, 'base64');
|
|
331
|
+
// Map certification mode to API parameters
|
|
332
|
+
const usageType = certificationMode === 'simple' ? 'simple' : 'ai';
|
|
333
|
+
let fileData;
|
|
334
|
+
if (inputType === 'url') {
|
|
335
|
+
const fileUrl = this.getNodeParameter('fileUrl', i);
|
|
336
|
+
// Validate URL to prevent SSRF
|
|
337
|
+
validateUrl(fileUrl);
|
|
338
|
+
const fileResponse = await axios_1.default.get(fileUrl, {
|
|
339
|
+
timeout: DOWNLOAD_TIMEOUT,
|
|
340
|
+
responseType: 'arraybuffer',
|
|
341
|
+
maxContentLength: MAX_FILE_SIZE,
|
|
342
|
+
maxBodyLength: MAX_FILE_SIZE,
|
|
343
|
+
});
|
|
344
|
+
const contentType = fileResponse.headers['content-type'] || 'application/octet-stream';
|
|
345
|
+
const base64Data = Buffer.from(fileResponse.data).toString('base64');
|
|
346
|
+
fileData = `data:${contentType};base64,${base64Data}`;
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
fileData = this.getNodeParameter('fileData', i);
|
|
350
|
+
}
|
|
351
|
+
const requestBody = {
|
|
352
|
+
file_data: fileData,
|
|
353
|
+
title,
|
|
354
|
+
description,
|
|
355
|
+
usage_type: usageType,
|
|
356
|
+
payment_mode: 'credits', // Use subscription credits
|
|
357
|
+
};
|
|
358
|
+
// Add AI options if AI mode is enabled
|
|
359
|
+
if (usageType === 'ai') {
|
|
360
|
+
requestBody.ai_endpoint = 'art';
|
|
361
|
+
requestBody.enable_c2pa = true; // C2PA auto-enabled with AI
|
|
362
|
+
}
|
|
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
|
+
}
|
|
373
|
+
// ============================================
|
|
374
|
+
// LIST CERTIFICATES OPERATION
|
|
375
|
+
// ============================================
|
|
376
|
+
else if (operation === 'listCertificates') {
|
|
377
|
+
// Get filter parameters
|
|
378
|
+
const filterHash = this.getNodeParameter('filterHash', i, '');
|
|
379
|
+
const filterFilename = this.getNodeParameter('filterFilename', i, '');
|
|
380
|
+
const filterSignature = this.getNodeParameter('filterSignature', i, '');
|
|
381
|
+
const limit = this.getNodeParameter('limit', i, 100);
|
|
382
|
+
// Build query string
|
|
383
|
+
const queryParams = new URLSearchParams();
|
|
384
|
+
if (filterHash)
|
|
385
|
+
queryParams.append('hash', filterHash);
|
|
386
|
+
if (filterFilename)
|
|
387
|
+
queryParams.append('filename', filterFilename);
|
|
388
|
+
if (filterSignature)
|
|
389
|
+
queryParams.append('signature', filterSignature);
|
|
390
|
+
queryParams.append('limit', limit.toString());
|
|
391
|
+
const queryString = queryParams.toString();
|
|
392
|
+
const url = `${baseUrl}/api/solmemo/list${queryString ? '?' + queryString : ''}`;
|
|
393
|
+
const response = await axios_1.default.get(url, {
|
|
394
|
+
timeout: REQUEST_TIMEOUT,
|
|
395
|
+
headers: {
|
|
396
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
397
|
+
},
|
|
398
|
+
...getAxiosConfig(baseUrl),
|
|
399
|
+
});
|
|
400
|
+
responseData = response.data;
|
|
401
|
+
}
|
|
402
|
+
// Return data
|
|
403
|
+
returnData.push({
|
|
404
|
+
json: responseData,
|
|
405
|
+
pairedItem: { item: i },
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
catch (error) {
|
|
409
|
+
if (this.continueOnFail()) {
|
|
410
|
+
returnData.push({
|
|
411
|
+
json: {
|
|
412
|
+
error: error.message,
|
|
413
|
+
details: ((_a = error.response) === null || _a === void 0 ? void 0 : _a.data) || {},
|
|
414
|
+
},
|
|
415
|
+
pairedItem: { item: i },
|
|
416
|
+
});
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), error.message, { itemIndex: i });
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return [returnData];
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
exports.ProofOfAuthenticity = ProofOfAuthenticity;
|
|
Binary file
|
package/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "n8n-nodes-proofofauthenticity",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "ProofOfAuthenticity by CHECKHC - Blockchain timestamping with AI detection and C2PA content authenticity.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"n8n",
|
|
7
|
+
"n8n-community-node-package",
|
|
8
|
+
"proofofauthenticity",
|
|
9
|
+
"checkhc",
|
|
10
|
+
"blockchain",
|
|
11
|
+
"solana",
|
|
12
|
+
"certification",
|
|
13
|
+
"c2pa",
|
|
14
|
+
"content-authenticity",
|
|
15
|
+
"ai-detection",
|
|
16
|
+
"timestamp",
|
|
17
|
+
"proof-of-authenticity"
|
|
18
|
+
],
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"homepage": "https://www.checkhc.net",
|
|
21
|
+
"author": "CHECKHC <contact@checkhc.net> (https://checkhc.net)",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://github.com/checkhc/n8n-nodes-proofofauthenticity.git"
|
|
25
|
+
},
|
|
26
|
+
"main": "index.js",
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsc && gulp build:icons",
|
|
29
|
+
"dev": "tsc --watch",
|
|
30
|
+
"format": "prettier credentials nodes --write",
|
|
31
|
+
"lint": "eslint credentials nodes package.json",
|
|
32
|
+
"lintfix": "eslint credentials nodes package.json --fix",
|
|
33
|
+
"prepublishOnly": "npm run build"
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist",
|
|
37
|
+
"LICENSE"
|
|
38
|
+
],
|
|
39
|
+
"n8n": {
|
|
40
|
+
"n8nNodesApiVersion": 1,
|
|
41
|
+
"credentials": [
|
|
42
|
+
"dist/credentials/ProofOfAuthenticityApi.credentials.js"
|
|
43
|
+
],
|
|
44
|
+
"nodes": [
|
|
45
|
+
"dist/nodes/ProofOfAuthenticity/ProofOfAuthenticity.node.js"
|
|
46
|
+
]
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/node": "^20.0.0",
|
|
50
|
+
"eslint": "^8.0.0",
|
|
51
|
+
"gulp": "^4.0.2",
|
|
52
|
+
"n8n-workflow": "^1.0.0",
|
|
53
|
+
"prettier": "^3.0.0",
|
|
54
|
+
"typescript": "^5.0.0"
|
|
55
|
+
},
|
|
56
|
+
"dependencies": {
|
|
57
|
+
"axios": "^1.7.9",
|
|
58
|
+
"form-data": "^4.0.4"
|
|
59
|
+
}
|
|
60
|
+
}
|