n8n-core 1.78.0 → 1.79.1
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/dist/build.tsbuildinfo +1 -1
- package/dist/credentials.d.ts +1 -0
- package/dist/credentials.js +7 -0
- package/dist/credentials.js.map +1 -1
- package/dist/execution-engine/active-workflows.d.ts +2 -1
- package/dist/execution-engine/active-workflows.js.map +1 -1
- package/dist/execution-engine/execution-lifecycle-hooks.d.ts +24 -0
- package/dist/execution-engine/execution-lifecycle-hooks.js +30 -0
- package/dist/execution-engine/execution-lifecycle-hooks.js.map +1 -0
- package/dist/execution-engine/index.d.ts +2 -0
- package/dist/execution-engine/index.js +4 -0
- package/dist/execution-engine/index.js.map +1 -1
- package/dist/execution-engine/interfaces.d.ts +7 -0
- package/dist/execution-engine/interfaces.js +3 -0
- package/dist/execution-engine/interfaces.js.map +1 -0
- package/dist/execution-engine/node-execution-context/credentials-test-context.js +4 -3
- package/dist/execution-engine/node-execution-context/credentials-test-context.js.map +1 -1
- package/dist/execution-engine/node-execution-context/execute-context.d.ts +3 -1
- package/dist/execution-engine/node-execution-context/execute-context.js +27 -15
- package/dist/execution-engine/node-execution-context/execute-context.js.map +1 -1
- package/dist/execution-engine/node-execution-context/execute-single-context.d.ts +1 -1
- package/dist/execution-engine/node-execution-context/execute-single-context.js +9 -7
- package/dist/execution-engine/node-execution-context/execute-single-context.js.map +1 -1
- package/dist/execution-engine/node-execution-context/hook-context.js +5 -4
- package/dist/execution-engine/node-execution-context/hook-context.js.map +1 -1
- package/dist/execution-engine/node-execution-context/index.d.ts +6 -0
- package/dist/execution-engine/node-execution-context/index.js +26 -1
- package/dist/execution-engine/node-execution-context/index.js.map +1 -1
- package/dist/execution-engine/node-execution-context/load-options-context.js +4 -3
- package/dist/execution-engine/node-execution-context/load-options-context.js.map +1 -1
- package/dist/execution-engine/node-execution-context/node-execution-context.d.ts +1 -1
- package/dist/execution-engine/node-execution-context/poll-context.js +8 -5
- package/dist/execution-engine/node-execution-context/poll-context.js.map +1 -1
- package/dist/execution-engine/node-execution-context/supply-data-context.js +23 -15
- package/dist/execution-engine/node-execution-context/supply-data-context.js.map +1 -1
- package/dist/execution-engine/node-execution-context/trigger-context.js +10 -6
- package/dist/execution-engine/node-execution-context/trigger-context.js.map +1 -1
- package/dist/execution-engine/node-execution-context/utils/binary-helper-functions.d.ts +10 -0
- package/dist/execution-engine/node-execution-context/utils/binary-helper-functions.js +183 -0
- package/dist/execution-engine/node-execution-context/utils/binary-helper-functions.js.map +1 -0
- package/dist/execution-engine/node-execution-context/utils/construct-execution-metadata.d.ts +4 -0
- package/dist/execution-engine/node-execution-context/utils/construct-execution-metadata.js +11 -0
- package/dist/execution-engine/node-execution-context/utils/construct-execution-metadata.js.map +1 -0
- package/dist/execution-engine/node-execution-context/utils/copy-input-items.d.ts +2 -0
- package/dist/execution-engine/node-execution-context/utils/copy-input-items.js +19 -0
- package/dist/execution-engine/node-execution-context/utils/copy-input-items.js.map +1 -0
- package/dist/execution-engine/node-execution-context/utils/deduplication-helper-functions.d.ts +2 -0
- package/dist/execution-engine/node-execution-context/utils/deduplication-helper-functions.js +38 -0
- package/dist/execution-engine/node-execution-context/utils/deduplication-helper-functions.js.map +1 -0
- package/dist/execution-engine/node-execution-context/utils/file-system-helper-functions.d.ts +3 -0
- package/dist/execution-engine/node-execution-context/utils/file-system-helper-functions.js +98 -0
- package/dist/execution-engine/node-execution-context/utils/file-system-helper-functions.js.map +1 -0
- package/dist/execution-engine/node-execution-context/utils/get-input-connection-data.d.ts +1 -1
- package/dist/execution-engine/node-execution-context/utils/get-input-connection-data.js +2 -2
- package/dist/execution-engine/node-execution-context/utils/get-input-connection-data.js.map +1 -1
- package/dist/execution-engine/node-execution-context/utils/normalize-items.d.ts +2 -0
- package/dist/execution-engine/node-execution-context/utils/normalize-items.js +36 -0
- package/dist/execution-engine/node-execution-context/utils/normalize-items.js.map +1 -0
- package/dist/execution-engine/node-execution-context/utils/parse-incoming-message.d.ts +16 -0
- package/dist/execution-engine/node-execution-context/utils/parse-incoming-message.js +57 -0
- package/dist/execution-engine/node-execution-context/utils/parse-incoming-message.js.map +1 -0
- package/dist/execution-engine/node-execution-context/utils/request-helper-functions.d.ts +16 -0
- package/dist/execution-engine/node-execution-context/utils/request-helper-functions.js +1158 -0
- package/dist/execution-engine/node-execution-context/utils/request-helper-functions.js.map +1 -0
- package/dist/execution-engine/node-execution-context/utils/return-json-array.d.ts +2 -0
- package/dist/execution-engine/node-execution-context/utils/return-json-array.js +19 -0
- package/dist/execution-engine/node-execution-context/utils/return-json-array.js.map +1 -0
- package/dist/execution-engine/node-execution-context/utils/scheduling-helper-functions.d.ts +2 -0
- package/dist/execution-engine/node-execution-context/utils/scheduling-helper-functions.js +13 -0
- package/dist/execution-engine/node-execution-context/utils/scheduling-helper-functions.js.map +1 -0
- package/dist/execution-engine/node-execution-context/utils/ssh-tunnel-helper-functions.d.ts +2 -0
- package/dist/execution-engine/node-execution-context/utils/ssh-tunnel-helper-functions.js +13 -0
- package/dist/execution-engine/node-execution-context/utils/ssh-tunnel-helper-functions.js.map +1 -0
- package/dist/execution-engine/node-execution-context/utils/webhook-helper-functions.d.ts +3 -0
- package/dist/execution-engine/node-execution-context/utils/webhook-helper-functions.js +31 -0
- package/dist/execution-engine/node-execution-context/utils/webhook-helper-functions.js.map +1 -0
- package/dist/execution-engine/node-execution-context/webhook-context.js +9 -6
- package/dist/execution-engine/node-execution-context/webhook-context.js.map +1 -1
- package/dist/execution-engine/triggers-and-pollers.d.ts +2 -1
- package/dist/execution-engine/triggers-and-pollers.js +19 -23
- package/dist/execution-engine/triggers-and-pollers.js.map +1 -1
- package/dist/execution-engine/workflow-execute.d.ts +0 -1
- package/dist/execution-engine/workflow-execute.js +21 -23
- package/dist/execution-engine/workflow-execute.js.map +1 -1
- package/dist/node-execute-functions.d.ts +1 -62
- package/dist/node-execute-functions.js +0 -1626
- package/dist/node-execute-functions.js.map +1 -1
- package/package.json +4 -4
|
@@ -1,1634 +1,8 @@
|
|
|
1
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
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.getCheckProcessedHelperFunctions = exports.getBinaryHelperFunctions = exports.getNodeHelperFunctions = exports.getFileSystemHelperFunctions = exports.getSchedulingFunctions = exports.getSSHTunnelFunctions = exports.getRequestHelperFunctions = exports.removeEmptyBody = exports.validateUrl = void 0;
|
|
40
|
-
exports.parseRequestObject = parseRequestObject;
|
|
41
|
-
exports.parseContentType = parseContentType;
|
|
42
|
-
exports.parseContentDisposition = parseContentDisposition;
|
|
43
|
-
exports.parseIncomingMessage = parseIncomingMessage;
|
|
44
|
-
exports.binaryToString = binaryToString;
|
|
45
|
-
exports.invokeAxios = invokeAxios;
|
|
46
|
-
exports.proxyRequestToAxios = proxyRequestToAxios;
|
|
47
|
-
exports.httpRequest = httpRequest;
|
|
48
|
-
exports.getBinaryPath = getBinaryPath;
|
|
49
|
-
exports.getBinaryMetadata = getBinaryMetadata;
|
|
50
|
-
exports.getBinaryStream = getBinaryStream;
|
|
51
|
-
exports.assertBinaryData = assertBinaryData;
|
|
52
|
-
exports.getBinaryDataBuffer = getBinaryDataBuffer;
|
|
53
|
-
exports.detectBinaryEncoding = detectBinaryEncoding;
|
|
54
|
-
exports.setBinaryDataBuffer = setBinaryDataBuffer;
|
|
55
|
-
exports.copyBinaryFile = copyBinaryFile;
|
|
56
|
-
exports.prepareBinaryData = prepareBinaryData;
|
|
57
|
-
exports.checkProcessedAndRecord = checkProcessedAndRecord;
|
|
58
|
-
exports.checkProcessedItemsAndRecord = checkProcessedItemsAndRecord;
|
|
59
|
-
exports.removeProcessed = removeProcessed;
|
|
60
|
-
exports.clearAllProcessedItems = clearAllProcessedItems;
|
|
61
|
-
exports.getProcessedDataCount = getProcessedDataCount;
|
|
62
|
-
exports.applyPaginationRequestData = applyPaginationRequestData;
|
|
63
|
-
exports.requestOAuth2 = requestOAuth2;
|
|
64
|
-
exports.requestOAuth1 = requestOAuth1;
|
|
65
|
-
exports.httpRequestWithAuthentication = httpRequestWithAuthentication;
|
|
66
|
-
exports.returnJsonArray = returnJsonArray;
|
|
67
|
-
exports.constructExecutionMetaData = constructExecutionMetaData;
|
|
68
|
-
exports.normalizeItems = normalizeItems;
|
|
69
|
-
exports.requestWithAuthentication = requestWithAuthentication;
|
|
70
|
-
exports.getNodeWebhookUrl = getNodeWebhookUrl;
|
|
71
|
-
exports.getWebhookDescription = getWebhookDescription;
|
|
72
|
-
exports.isFilePathBlocked = isFilePathBlocked;
|
|
73
|
-
exports.copyInputItems = copyInputItems;
|
|
74
3
|
exports.getExecutePollFunctions = getExecutePollFunctions;
|
|
75
4
|
exports.getExecuteTriggerFunctions = getExecuteTriggerFunctions;
|
|
76
|
-
const client_oauth2_1 = require("@n8n/client-oauth2");
|
|
77
|
-
const di_1 = require("@n8n/di");
|
|
78
|
-
const axios_1 = __importDefault(require("axios"));
|
|
79
|
-
const chardet_1 = __importDefault(require("chardet"));
|
|
80
|
-
const crypto_1 = __importStar(require("crypto"));
|
|
81
|
-
const file_type_1 = __importDefault(require("file-type"));
|
|
82
|
-
const form_data_1 = __importDefault(require("form-data"));
|
|
83
|
-
const fs_1 = require("fs");
|
|
84
|
-
const promises_1 = require("fs/promises");
|
|
85
|
-
const http_1 = require("http");
|
|
86
|
-
const https_1 = require("https");
|
|
87
|
-
const iconv_lite_1 = __importDefault(require("iconv-lite"));
|
|
88
|
-
const get_1 = __importDefault(require("lodash/get"));
|
|
89
|
-
const isEmpty_1 = __importDefault(require("lodash/isEmpty"));
|
|
90
|
-
const merge_1 = __importDefault(require("lodash/merge"));
|
|
91
|
-
const pick_1 = __importDefault(require("lodash/pick"));
|
|
92
|
-
const mime_types_1 = require("mime-types");
|
|
93
|
-
const n8n_workflow_1 = require("n8n-workflow");
|
|
94
|
-
const oauth_1_0a_1 = __importDefault(require("oauth-1.0a"));
|
|
95
|
-
const path_1 = __importDefault(require("path"));
|
|
96
|
-
const qs_1 = require("qs");
|
|
97
|
-
const stream_1 = require("stream");
|
|
98
|
-
const url_1 = __importStar(require("url"));
|
|
99
|
-
const logger_1 = require("./logging/logger");
|
|
100
|
-
const binary_data_service_1 = require("./binary-data/binary-data.service");
|
|
101
|
-
const utils_1 = require("./binary-data/utils");
|
|
102
|
-
const constants_1 = require("./constants");
|
|
103
|
-
const data_deduplication_service_1 = require("./data-deduplication-service");
|
|
104
5
|
const node_execution_context_1 = require("./execution-engine/node-execution-context");
|
|
105
|
-
const scheduled_task_manager_1 = require("./execution-engine/scheduled-task-manager");
|
|
106
|
-
const ssh_clients_manager_1 = require("./execution-engine/ssh-clients-manager");
|
|
107
|
-
const instance_settings_1 = require("./instance-settings");
|
|
108
|
-
axios_1.default.defaults.timeout = 300000;
|
|
109
|
-
axios_1.default.defaults.headers.post = {};
|
|
110
|
-
axios_1.default.defaults.headers.put = {};
|
|
111
|
-
axios_1.default.defaults.headers.patch = {};
|
|
112
|
-
axios_1.default.defaults.paramsSerializer = (params) => {
|
|
113
|
-
if (params instanceof url_1.URLSearchParams) {
|
|
114
|
-
return params.toString();
|
|
115
|
-
}
|
|
116
|
-
return (0, qs_1.stringify)(params, { arrayFormat: 'indices' });
|
|
117
|
-
};
|
|
118
|
-
axios_1.default.interceptors.request.use((config) => {
|
|
119
|
-
if (config.data === undefined) {
|
|
120
|
-
config.headers.setContentType(false, false);
|
|
121
|
-
}
|
|
122
|
-
return config;
|
|
123
|
-
});
|
|
124
|
-
const pushFormDataValue = (form, key, value) => {
|
|
125
|
-
if (value?.hasOwnProperty('value') && value.hasOwnProperty('options')) {
|
|
126
|
-
form.append(key, value.value, value.options);
|
|
127
|
-
}
|
|
128
|
-
else {
|
|
129
|
-
form.append(key, value);
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
const createFormDataObject = (data) => {
|
|
133
|
-
const formData = new form_data_1.default();
|
|
134
|
-
const keys = Object.keys(data);
|
|
135
|
-
keys.forEach((key) => {
|
|
136
|
-
const formField = data[key];
|
|
137
|
-
if (formField instanceof Array) {
|
|
138
|
-
formField.forEach((item) => {
|
|
139
|
-
pushFormDataValue(formData, key, item);
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
else {
|
|
143
|
-
pushFormDataValue(formData, key, formField);
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
return formData;
|
|
147
|
-
};
|
|
148
|
-
const validateUrl = (url) => {
|
|
149
|
-
if (!url)
|
|
150
|
-
return false;
|
|
151
|
-
try {
|
|
152
|
-
new url_1.URL(url);
|
|
153
|
-
return true;
|
|
154
|
-
}
|
|
155
|
-
catch (error) {
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
};
|
|
159
|
-
exports.validateUrl = validateUrl;
|
|
160
|
-
function searchForHeader(config, headerName) {
|
|
161
|
-
if (config.headers === undefined) {
|
|
162
|
-
return undefined;
|
|
163
|
-
}
|
|
164
|
-
const headerNames = Object.keys(config.headers);
|
|
165
|
-
headerName = headerName.toLowerCase();
|
|
166
|
-
return headerNames.find((thisHeader) => thisHeader.toLowerCase() === headerName);
|
|
167
|
-
}
|
|
168
|
-
async function generateContentLengthHeader(config) {
|
|
169
|
-
if (!(config.data instanceof form_data_1.default)) {
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
try {
|
|
173
|
-
const length = await new Promise((res, rej) => {
|
|
174
|
-
config.data.getLength((error, length) => {
|
|
175
|
-
if (error) {
|
|
176
|
-
rej(error);
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
res(length);
|
|
180
|
-
});
|
|
181
|
-
});
|
|
182
|
-
config.headers = {
|
|
183
|
-
...config.headers,
|
|
184
|
-
'content-length': length,
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
catch (error) {
|
|
188
|
-
di_1.Container.get(logger_1.Logger).error('Unable to calculate form data length', { error });
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
const getHostFromRequestObject = (requestObject) => {
|
|
192
|
-
try {
|
|
193
|
-
const url = (requestObject.url ?? requestObject.uri);
|
|
194
|
-
return new url_1.URL(url, requestObject.baseURL).hostname;
|
|
195
|
-
}
|
|
196
|
-
catch (error) {
|
|
197
|
-
return null;
|
|
198
|
-
}
|
|
199
|
-
};
|
|
200
|
-
const getBeforeRedirectFn = (agentOptions, axiosConfig) => (redirectedRequest) => {
|
|
201
|
-
const redirectAgent = new https_1.Agent({
|
|
202
|
-
...agentOptions,
|
|
203
|
-
servername: redirectedRequest.hostname,
|
|
204
|
-
});
|
|
205
|
-
redirectedRequest.agent = redirectAgent;
|
|
206
|
-
redirectedRequest.agents.https = redirectAgent;
|
|
207
|
-
if (axiosConfig.headers?.Authorization) {
|
|
208
|
-
redirectedRequest.headers.Authorization = axiosConfig.headers.Authorization;
|
|
209
|
-
}
|
|
210
|
-
if (axiosConfig.auth) {
|
|
211
|
-
redirectedRequest.auth = `${axiosConfig.auth.username}:${axiosConfig.auth.password}`;
|
|
212
|
-
}
|
|
213
|
-
};
|
|
214
|
-
async function parseRequestObject(requestObject) {
|
|
215
|
-
const axiosConfig = {};
|
|
216
|
-
if (requestObject.headers !== undefined) {
|
|
217
|
-
axiosConfig.headers = requestObject.headers;
|
|
218
|
-
}
|
|
219
|
-
const contentTypeHeaderKeyName = axiosConfig.headers &&
|
|
220
|
-
Object.keys(axiosConfig.headers).find((headerName) => headerName.toLowerCase() === 'content-type');
|
|
221
|
-
const contentType = contentTypeHeaderKeyName &&
|
|
222
|
-
axiosConfig.headers?.[contentTypeHeaderKeyName];
|
|
223
|
-
if (contentType === 'application/x-www-form-urlencoded' && requestObject.formData === undefined) {
|
|
224
|
-
if (typeof requestObject.body === 'string') {
|
|
225
|
-
axiosConfig.data = requestObject.body;
|
|
226
|
-
}
|
|
227
|
-
else {
|
|
228
|
-
const allData = Object.assign(requestObject.body || {}, requestObject.form || {});
|
|
229
|
-
if (requestObject.useQuerystring === true) {
|
|
230
|
-
axiosConfig.data = (0, qs_1.stringify)(allData, { arrayFormat: 'repeat' });
|
|
231
|
-
}
|
|
232
|
-
else {
|
|
233
|
-
axiosConfig.data = (0, qs_1.stringify)(allData);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
else if (contentType?.includes('multipart/form-data')) {
|
|
238
|
-
if (requestObject.formData !== undefined && requestObject.formData instanceof form_data_1.default) {
|
|
239
|
-
axiosConfig.data = requestObject.formData;
|
|
240
|
-
}
|
|
241
|
-
else {
|
|
242
|
-
const allData = {
|
|
243
|
-
...requestObject.body,
|
|
244
|
-
...requestObject.formData,
|
|
245
|
-
};
|
|
246
|
-
axiosConfig.data = createFormDataObject(allData);
|
|
247
|
-
}
|
|
248
|
-
delete axiosConfig.headers?.[contentTypeHeaderKeyName];
|
|
249
|
-
const headers = axiosConfig.data.getHeaders();
|
|
250
|
-
axiosConfig.headers = Object.assign(axiosConfig.headers || {}, headers);
|
|
251
|
-
await generateContentLengthHeader(axiosConfig);
|
|
252
|
-
}
|
|
253
|
-
else {
|
|
254
|
-
if (requestObject.form !== undefined && requestObject.body === undefined) {
|
|
255
|
-
axiosConfig.data =
|
|
256
|
-
typeof requestObject.form === 'string'
|
|
257
|
-
? (0, qs_1.stringify)(requestObject.form, { format: 'RFC3986' })
|
|
258
|
-
: (0, qs_1.stringify)(requestObject.form).toString();
|
|
259
|
-
if (axiosConfig.headers !== undefined) {
|
|
260
|
-
const headerName = searchForHeader(axiosConfig, 'content-type');
|
|
261
|
-
if (headerName) {
|
|
262
|
-
delete axiosConfig.headers[headerName];
|
|
263
|
-
}
|
|
264
|
-
axiosConfig.headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
|
265
|
-
}
|
|
266
|
-
else {
|
|
267
|
-
axiosConfig.headers = {
|
|
268
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
269
|
-
};
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
else if (requestObject.formData !== undefined) {
|
|
273
|
-
if (axiosConfig.headers !== undefined) {
|
|
274
|
-
const headers = Object.keys(axiosConfig.headers);
|
|
275
|
-
headers.forEach((header) => {
|
|
276
|
-
if (header.toLowerCase() === 'content-type') {
|
|
277
|
-
delete axiosConfig.headers?.[header];
|
|
278
|
-
}
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
|
-
if (requestObject.formData instanceof form_data_1.default) {
|
|
282
|
-
axiosConfig.data = requestObject.formData;
|
|
283
|
-
}
|
|
284
|
-
else {
|
|
285
|
-
axiosConfig.data = createFormDataObject(requestObject.formData);
|
|
286
|
-
}
|
|
287
|
-
const headers = axiosConfig.data.getHeaders();
|
|
288
|
-
axiosConfig.headers = Object.assign(axiosConfig.headers || {}, headers);
|
|
289
|
-
await generateContentLengthHeader(axiosConfig);
|
|
290
|
-
}
|
|
291
|
-
else if (requestObject.body !== undefined) {
|
|
292
|
-
if (requestObject.form !== undefined && requestObject.body) {
|
|
293
|
-
requestObject.body = Object.assign(requestObject.body, requestObject.form);
|
|
294
|
-
}
|
|
295
|
-
axiosConfig.data = requestObject.body;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
if (requestObject.uri !== undefined) {
|
|
299
|
-
axiosConfig.url = requestObject.uri?.toString();
|
|
300
|
-
}
|
|
301
|
-
if (requestObject.url !== undefined) {
|
|
302
|
-
axiosConfig.url = requestObject.url?.toString();
|
|
303
|
-
}
|
|
304
|
-
if (requestObject.baseURL !== undefined) {
|
|
305
|
-
axiosConfig.baseURL = requestObject.baseURL?.toString();
|
|
306
|
-
}
|
|
307
|
-
if (requestObject.method !== undefined) {
|
|
308
|
-
axiosConfig.method = requestObject.method;
|
|
309
|
-
}
|
|
310
|
-
if (requestObject.qs !== undefined && Object.keys(requestObject.qs).length > 0) {
|
|
311
|
-
axiosConfig.params = requestObject.qs;
|
|
312
|
-
}
|
|
313
|
-
function hasArrayFormatOptions(arg) {
|
|
314
|
-
if (typeof arg.qsStringifyOptions === 'object' &&
|
|
315
|
-
arg.qsStringifyOptions !== null &&
|
|
316
|
-
!Array.isArray(arg.qsStringifyOptions) &&
|
|
317
|
-
'arrayFormat' in arg.qsStringifyOptions) {
|
|
318
|
-
return true;
|
|
319
|
-
}
|
|
320
|
-
return false;
|
|
321
|
-
}
|
|
322
|
-
if (requestObject.useQuerystring === true ||
|
|
323
|
-
(hasArrayFormatOptions(requestObject) &&
|
|
324
|
-
requestObject.qsStringifyOptions.arrayFormat === 'repeat')) {
|
|
325
|
-
axiosConfig.paramsSerializer = (params) => {
|
|
326
|
-
return (0, qs_1.stringify)(params, { arrayFormat: 'repeat' });
|
|
327
|
-
};
|
|
328
|
-
}
|
|
329
|
-
else if (requestObject.useQuerystring === false) {
|
|
330
|
-
axiosConfig.paramsSerializer = (params) => {
|
|
331
|
-
return (0, qs_1.stringify)(params, { arrayFormat: 'indices' });
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
if (hasArrayFormatOptions(requestObject) &&
|
|
335
|
-
requestObject.qsStringifyOptions.arrayFormat === 'brackets') {
|
|
336
|
-
axiosConfig.paramsSerializer = (params) => {
|
|
337
|
-
return (0, qs_1.stringify)(params, { arrayFormat: 'brackets' });
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
if (requestObject.auth !== undefined) {
|
|
341
|
-
if (requestObject.auth.bearer !== undefined) {
|
|
342
|
-
axiosConfig.headers = Object.assign(axiosConfig.headers || {}, {
|
|
343
|
-
Authorization: `Bearer ${requestObject.auth.bearer}`,
|
|
344
|
-
});
|
|
345
|
-
}
|
|
346
|
-
else {
|
|
347
|
-
const authObj = requestObject.auth;
|
|
348
|
-
axiosConfig.auth = {
|
|
349
|
-
username: (authObj.user || authObj.username),
|
|
350
|
-
password: (authObj.password || authObj.pass),
|
|
351
|
-
};
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
if (requestObject.json === true) {
|
|
355
|
-
const acceptHeaderExists = axiosConfig.headers === undefined
|
|
356
|
-
? false
|
|
357
|
-
: Object.keys(axiosConfig.headers)
|
|
358
|
-
.map((headerKey) => headerKey.toLowerCase())
|
|
359
|
-
.includes('accept');
|
|
360
|
-
if (!acceptHeaderExists) {
|
|
361
|
-
axiosConfig.headers = Object.assign(axiosConfig.headers || {}, {
|
|
362
|
-
Accept: 'application/json',
|
|
363
|
-
});
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
if (requestObject.json === false || requestObject.json === undefined) {
|
|
367
|
-
axiosConfig.transformResponse = (res) => res;
|
|
368
|
-
}
|
|
369
|
-
const { method } = requestObject;
|
|
370
|
-
if ((requestObject.followRedirect !== false &&
|
|
371
|
-
(!method || method === 'GET' || method === 'HEAD')) ||
|
|
372
|
-
requestObject.followAllRedirects) {
|
|
373
|
-
axiosConfig.maxRedirects = requestObject.maxRedirects;
|
|
374
|
-
}
|
|
375
|
-
else {
|
|
376
|
-
axiosConfig.maxRedirects = 0;
|
|
377
|
-
}
|
|
378
|
-
const host = getHostFromRequestObject(requestObject);
|
|
379
|
-
const agentOptions = { ...requestObject.agentOptions };
|
|
380
|
-
if (host) {
|
|
381
|
-
agentOptions.servername = host;
|
|
382
|
-
}
|
|
383
|
-
if (requestObject.rejectUnauthorized === false) {
|
|
384
|
-
agentOptions.rejectUnauthorized = false;
|
|
385
|
-
agentOptions.secureOptions = crypto_1.default.constants.SSL_OP_LEGACY_SERVER_CONNECT;
|
|
386
|
-
}
|
|
387
|
-
axiosConfig.httpsAgent = new https_1.Agent(agentOptions);
|
|
388
|
-
axiosConfig.beforeRedirect = getBeforeRedirectFn(agentOptions, axiosConfig);
|
|
389
|
-
if (requestObject.timeout !== undefined) {
|
|
390
|
-
axiosConfig.timeout = requestObject.timeout;
|
|
391
|
-
}
|
|
392
|
-
if (requestObject.proxy !== undefined) {
|
|
393
|
-
if (typeof requestObject.proxy === 'string') {
|
|
394
|
-
try {
|
|
395
|
-
const url = new url_1.URL(requestObject.proxy);
|
|
396
|
-
const host = url.hostname.startsWith('[') ? url.hostname.slice(1, -1) : url.hostname;
|
|
397
|
-
axiosConfig.proxy = {
|
|
398
|
-
host,
|
|
399
|
-
port: parseInt(url.port, 10),
|
|
400
|
-
protocol: url.protocol,
|
|
401
|
-
};
|
|
402
|
-
if (!url.port) {
|
|
403
|
-
if (url.protocol === 'http') {
|
|
404
|
-
axiosConfig.proxy.port = 80;
|
|
405
|
-
}
|
|
406
|
-
else if (url.protocol === 'https') {
|
|
407
|
-
axiosConfig.proxy.port = 443;
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
if (url.username || url.password) {
|
|
411
|
-
axiosConfig.proxy.auth = {
|
|
412
|
-
username: url.username,
|
|
413
|
-
password: url.password,
|
|
414
|
-
};
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
catch (error) {
|
|
418
|
-
if (requestObject.proxy.includes('@')) {
|
|
419
|
-
const [userpass, hostport] = requestObject.proxy.split('@');
|
|
420
|
-
const [username, password] = userpass.split(':');
|
|
421
|
-
const [hostname, port] = hostport.split(':');
|
|
422
|
-
const host = hostname.startsWith('[') ? hostname.slice(1, -1) : hostname;
|
|
423
|
-
axiosConfig.proxy = {
|
|
424
|
-
host,
|
|
425
|
-
port: parseInt(port, 10),
|
|
426
|
-
protocol: 'http',
|
|
427
|
-
auth: {
|
|
428
|
-
username,
|
|
429
|
-
password,
|
|
430
|
-
},
|
|
431
|
-
};
|
|
432
|
-
}
|
|
433
|
-
else if (requestObject.proxy.includes(':')) {
|
|
434
|
-
const [hostname, port] = requestObject.proxy.split(':');
|
|
435
|
-
axiosConfig.proxy = {
|
|
436
|
-
host: hostname,
|
|
437
|
-
port: parseInt(port, 10),
|
|
438
|
-
protocol: 'http',
|
|
439
|
-
};
|
|
440
|
-
}
|
|
441
|
-
else {
|
|
442
|
-
axiosConfig.proxy = {
|
|
443
|
-
host: requestObject.proxy,
|
|
444
|
-
port: 80,
|
|
445
|
-
protocol: 'http',
|
|
446
|
-
};
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
else {
|
|
451
|
-
axiosConfig.proxy = requestObject.proxy;
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
if (requestObject.useStream) {
|
|
455
|
-
axiosConfig.responseType = 'stream';
|
|
456
|
-
}
|
|
457
|
-
else if (requestObject.encoding === null) {
|
|
458
|
-
axiosConfig.responseType = 'arraybuffer';
|
|
459
|
-
}
|
|
460
|
-
const allHeaders = axiosConfig.headers ? Object.keys(axiosConfig.headers) : [];
|
|
461
|
-
if (!allHeaders.some((headerKey) => headerKey.toLowerCase() === 'accept')) {
|
|
462
|
-
axiosConfig.headers = Object.assign(axiosConfig.headers || {}, { accept: '*/*' });
|
|
463
|
-
}
|
|
464
|
-
if (requestObject.json !== false &&
|
|
465
|
-
axiosConfig.data !== undefined &&
|
|
466
|
-
axiosConfig.data !== '' &&
|
|
467
|
-
!(axiosConfig.data instanceof Buffer) &&
|
|
468
|
-
!allHeaders.some((headerKey) => headerKey.toLowerCase() === 'content-type')) {
|
|
469
|
-
axiosConfig.headers = Object.assign(axiosConfig.headers || {}, {
|
|
470
|
-
'content-type': 'application/json',
|
|
471
|
-
});
|
|
472
|
-
}
|
|
473
|
-
if (requestObject.simple === false) {
|
|
474
|
-
axiosConfig.validateStatus = () => true;
|
|
475
|
-
}
|
|
476
|
-
return axiosConfig;
|
|
477
|
-
}
|
|
478
|
-
function digestAuthAxiosConfig(axiosConfig, response, auth) {
|
|
479
|
-
const authDetails = response.headers['www-authenticate']
|
|
480
|
-
.split(',')
|
|
481
|
-
.map((v) => v.split('='));
|
|
482
|
-
if (authDetails) {
|
|
483
|
-
const nonceCount = '000000001';
|
|
484
|
-
const cnonce = crypto_1.default.randomBytes(24).toString('hex');
|
|
485
|
-
const realm = authDetails
|
|
486
|
-
.find((el) => el[0].toLowerCase().indexOf('realm') > -1)[1]
|
|
487
|
-
.replace(/"/g, '');
|
|
488
|
-
const opaqueKV = authDetails.find((el) => el[0].toLowerCase().indexOf('opaque') > -1);
|
|
489
|
-
const opaque = opaqueKV ? opaqueKV[1].replace(/"/g, '') : undefined;
|
|
490
|
-
const nonce = authDetails
|
|
491
|
-
.find((el) => el[0].toLowerCase().indexOf('nonce') > -1)[1]
|
|
492
|
-
.replace(/"/g, '');
|
|
493
|
-
const ha1 = crypto_1.default
|
|
494
|
-
.createHash('md5')
|
|
495
|
-
.update(`${auth?.username}:${realm}:${auth?.password}`)
|
|
496
|
-
.digest('hex');
|
|
497
|
-
const urlURL = new url_1.default.URL(axios_1.default.getUri(axiosConfig));
|
|
498
|
-
const path = urlURL.pathname + urlURL.search;
|
|
499
|
-
const ha2 = crypto_1.default
|
|
500
|
-
.createHash('md5')
|
|
501
|
-
.update(`${axiosConfig.method ?? 'GET'}:${path}`)
|
|
502
|
-
.digest('hex');
|
|
503
|
-
const response = crypto_1.default
|
|
504
|
-
.createHash('md5')
|
|
505
|
-
.update(`${ha1}:${nonce}:${nonceCount}:${cnonce}:auth:${ha2}`)
|
|
506
|
-
.digest('hex');
|
|
507
|
-
let authorization = `Digest username="${auth?.username}",realm="${realm}",` +
|
|
508
|
-
`nonce="${nonce}",uri="${path}",qop="auth",algorithm="MD5",` +
|
|
509
|
-
`response="${response}",nc="${nonceCount}",cnonce="${cnonce}"`;
|
|
510
|
-
if (opaque) {
|
|
511
|
-
authorization += `,opaque="${opaque}"`;
|
|
512
|
-
}
|
|
513
|
-
if (axiosConfig.headers) {
|
|
514
|
-
axiosConfig.headers.authorization = authorization;
|
|
515
|
-
}
|
|
516
|
-
else {
|
|
517
|
-
axiosConfig.headers = { authorization };
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
return axiosConfig;
|
|
521
|
-
}
|
|
522
|
-
function parseHeaderParameters(parameters) {
|
|
523
|
-
return parameters.reduce((acc, param) => {
|
|
524
|
-
const [key, value] = param.split('=');
|
|
525
|
-
let decodedValue = decodeURIComponent(value).trim();
|
|
526
|
-
if (decodedValue.startsWith('"') && decodedValue.endsWith('"')) {
|
|
527
|
-
decodedValue = decodedValue.slice(1, -1);
|
|
528
|
-
}
|
|
529
|
-
acc[key.toLowerCase().trim()] = decodedValue;
|
|
530
|
-
return acc;
|
|
531
|
-
}, {});
|
|
532
|
-
}
|
|
533
|
-
function parseContentType(contentType) {
|
|
534
|
-
if (!contentType) {
|
|
535
|
-
return null;
|
|
536
|
-
}
|
|
537
|
-
const [type, ...parameters] = contentType.split(';');
|
|
538
|
-
return {
|
|
539
|
-
type: type.toLowerCase(),
|
|
540
|
-
parameters: { charset: 'utf-8', ...parseHeaderParameters(parameters) },
|
|
541
|
-
};
|
|
542
|
-
}
|
|
543
|
-
function parseContentDisposition(contentDisposition) {
|
|
544
|
-
if (!contentDisposition) {
|
|
545
|
-
return null;
|
|
546
|
-
}
|
|
547
|
-
if (!contentDisposition.startsWith('attachment') && !contentDisposition.startsWith('inline')) {
|
|
548
|
-
contentDisposition = `attachment; ${contentDisposition}`;
|
|
549
|
-
}
|
|
550
|
-
const [type, ...parameters] = contentDisposition.split(';');
|
|
551
|
-
const parsedParameters = parseHeaderParameters(parameters);
|
|
552
|
-
let { filename } = parsedParameters;
|
|
553
|
-
const wildcard = parsedParameters['filename*'];
|
|
554
|
-
if (wildcard) {
|
|
555
|
-
const [_encoding, _locale, content] = wildcard?.split("'") ?? [];
|
|
556
|
-
filename = content;
|
|
557
|
-
}
|
|
558
|
-
return { type, filename };
|
|
559
|
-
}
|
|
560
|
-
function parseIncomingMessage(message) {
|
|
561
|
-
const contentType = parseContentType(message.headers['content-type']);
|
|
562
|
-
if (contentType) {
|
|
563
|
-
const { type, parameters } = contentType;
|
|
564
|
-
message.contentType = type;
|
|
565
|
-
message.encoding = parameters.charset.toLowerCase();
|
|
566
|
-
}
|
|
567
|
-
const contentDisposition = parseContentDisposition(message.headers['content-disposition']);
|
|
568
|
-
if (contentDisposition) {
|
|
569
|
-
message.contentDisposition = contentDisposition;
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
async function binaryToString(body, encoding) {
|
|
573
|
-
if (!encoding && body instanceof http_1.IncomingMessage) {
|
|
574
|
-
parseIncomingMessage(body);
|
|
575
|
-
encoding = body.encoding;
|
|
576
|
-
}
|
|
577
|
-
const buffer = await (0, utils_1.binaryToBuffer)(body);
|
|
578
|
-
return iconv_lite_1.default.decode(buffer, encoding ?? 'utf-8');
|
|
579
|
-
}
|
|
580
|
-
async function invokeAxios(axiosConfig, authOptions = {}) {
|
|
581
|
-
try {
|
|
582
|
-
return await (0, axios_1.default)(axiosConfig);
|
|
583
|
-
}
|
|
584
|
-
catch (error) {
|
|
585
|
-
if (authOptions.sendImmediately !== false || !(error instanceof axios_1.default.AxiosError))
|
|
586
|
-
throw error;
|
|
587
|
-
const { response } = error;
|
|
588
|
-
if (response?.status !== 401 || !response.headers['www-authenticate']?.includes('nonce')) {
|
|
589
|
-
throw error;
|
|
590
|
-
}
|
|
591
|
-
const { auth } = axiosConfig;
|
|
592
|
-
delete axiosConfig.auth;
|
|
593
|
-
axiosConfig = digestAuthAxiosConfig(axiosConfig, response, auth);
|
|
594
|
-
return await (0, axios_1.default)(axiosConfig);
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
async function proxyRequestToAxios(workflow, additionalData, node, uriOrObject, options) {
|
|
598
|
-
let axiosConfig = {
|
|
599
|
-
maxBodyLength: Infinity,
|
|
600
|
-
maxContentLength: Infinity,
|
|
601
|
-
};
|
|
602
|
-
let configObject;
|
|
603
|
-
if (typeof uriOrObject === 'string') {
|
|
604
|
-
configObject = { uri: uriOrObject, ...options };
|
|
605
|
-
}
|
|
606
|
-
else {
|
|
607
|
-
configObject = uriOrObject ?? {};
|
|
608
|
-
}
|
|
609
|
-
axiosConfig = Object.assign(axiosConfig, await parseRequestObject(configObject));
|
|
610
|
-
try {
|
|
611
|
-
const response = await invokeAxios(axiosConfig, configObject.auth);
|
|
612
|
-
let body = response.data;
|
|
613
|
-
if (body instanceof http_1.IncomingMessage && axiosConfig.responseType === 'stream') {
|
|
614
|
-
parseIncomingMessage(body);
|
|
615
|
-
}
|
|
616
|
-
else if (body === '') {
|
|
617
|
-
body = axiosConfig.responseType === 'arraybuffer' ? Buffer.alloc(0) : undefined;
|
|
618
|
-
}
|
|
619
|
-
await additionalData?.hooks?.executeHookFunctions('nodeFetchedData', [workflow?.id, node]);
|
|
620
|
-
return configObject.resolveWithFullResponse
|
|
621
|
-
? {
|
|
622
|
-
body,
|
|
623
|
-
headers: { ...response.headers },
|
|
624
|
-
statusCode: response.status,
|
|
625
|
-
statusMessage: response.statusText,
|
|
626
|
-
request: response.request,
|
|
627
|
-
}
|
|
628
|
-
: body;
|
|
629
|
-
}
|
|
630
|
-
catch (error) {
|
|
631
|
-
const { config, response } = error;
|
|
632
|
-
if (error.isAxiosError) {
|
|
633
|
-
error.config = error.request = undefined;
|
|
634
|
-
error.options = (0, pick_1.default)(config ?? {}, ['url', 'method', 'data', 'headers']);
|
|
635
|
-
if (response) {
|
|
636
|
-
di_1.Container.get(logger_1.Logger).debug('Request proxied to Axios failed', { status: response.status });
|
|
637
|
-
let responseData = response.data;
|
|
638
|
-
if (Buffer.isBuffer(responseData) || responseData instanceof stream_1.Readable) {
|
|
639
|
-
responseData = await binaryToString(responseData);
|
|
640
|
-
}
|
|
641
|
-
if (configObject.simple === false) {
|
|
642
|
-
if (configObject.resolveWithFullResponse) {
|
|
643
|
-
return {
|
|
644
|
-
body: responseData,
|
|
645
|
-
headers: response.headers,
|
|
646
|
-
statusCode: response.status,
|
|
647
|
-
statusMessage: response.statusText,
|
|
648
|
-
};
|
|
649
|
-
}
|
|
650
|
-
else {
|
|
651
|
-
return responseData;
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
error.message = `${response.status} - ${JSON.stringify(responseData)}`;
|
|
655
|
-
throw Object.assign(error, {
|
|
656
|
-
statusCode: response.status,
|
|
657
|
-
status: response.status,
|
|
658
|
-
error: responseData,
|
|
659
|
-
response: (0, pick_1.default)(response, ['headers', 'status', 'statusText']),
|
|
660
|
-
});
|
|
661
|
-
}
|
|
662
|
-
else if ('rejectUnauthorized' in configObject && error.code?.includes('CERT')) {
|
|
663
|
-
throw new n8n_workflow_1.NodeSslError(error);
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
throw error;
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
function convertN8nRequestToAxios(n8nRequest) {
|
|
670
|
-
const { headers, method, timeout, auth, proxy, url } = n8nRequest;
|
|
671
|
-
const axiosRequest = {
|
|
672
|
-
headers: headers ?? {},
|
|
673
|
-
method,
|
|
674
|
-
timeout,
|
|
675
|
-
auth,
|
|
676
|
-
proxy,
|
|
677
|
-
url,
|
|
678
|
-
maxBodyLength: Infinity,
|
|
679
|
-
maxContentLength: Infinity,
|
|
680
|
-
};
|
|
681
|
-
axiosRequest.params = n8nRequest.qs;
|
|
682
|
-
if (n8nRequest.abortSignal) {
|
|
683
|
-
axiosRequest.signal = n8nRequest.abortSignal;
|
|
684
|
-
}
|
|
685
|
-
if (n8nRequest.baseURL !== undefined) {
|
|
686
|
-
axiosRequest.baseURL = n8nRequest.baseURL;
|
|
687
|
-
}
|
|
688
|
-
if (n8nRequest.disableFollowRedirect === true) {
|
|
689
|
-
axiosRequest.maxRedirects = 0;
|
|
690
|
-
}
|
|
691
|
-
if (n8nRequest.encoding !== undefined) {
|
|
692
|
-
axiosRequest.responseType = n8nRequest.encoding;
|
|
693
|
-
}
|
|
694
|
-
const host = getHostFromRequestObject(n8nRequest);
|
|
695
|
-
const agentOptions = {};
|
|
696
|
-
if (host) {
|
|
697
|
-
agentOptions.servername = host;
|
|
698
|
-
}
|
|
699
|
-
if (n8nRequest.skipSslCertificateValidation === true) {
|
|
700
|
-
agentOptions.rejectUnauthorized = false;
|
|
701
|
-
}
|
|
702
|
-
axiosRequest.httpsAgent = new https_1.Agent(agentOptions);
|
|
703
|
-
axiosRequest.beforeRedirect = getBeforeRedirectFn(agentOptions, axiosRequest);
|
|
704
|
-
if (n8nRequest.arrayFormat !== undefined) {
|
|
705
|
-
axiosRequest.paramsSerializer = (params) => {
|
|
706
|
-
return (0, qs_1.stringify)(params, { arrayFormat: n8nRequest.arrayFormat });
|
|
707
|
-
};
|
|
708
|
-
}
|
|
709
|
-
const { body } = n8nRequest;
|
|
710
|
-
if (body) {
|
|
711
|
-
const existingContentTypeHeaderKey = searchForHeader(axiosRequest, 'content-type');
|
|
712
|
-
if (existingContentTypeHeaderKey === undefined) {
|
|
713
|
-
axiosRequest.headers = axiosRequest.headers || {};
|
|
714
|
-
if (body instanceof form_data_1.default) {
|
|
715
|
-
axiosRequest.headers = {
|
|
716
|
-
...axiosRequest.headers,
|
|
717
|
-
...body.getHeaders(),
|
|
718
|
-
};
|
|
719
|
-
}
|
|
720
|
-
else if (body instanceof url_1.URLSearchParams) {
|
|
721
|
-
axiosRequest.headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
else if (axiosRequest.headers?.[existingContentTypeHeaderKey] === 'application/x-www-form-urlencoded') {
|
|
725
|
-
axiosRequest.data = new url_1.URLSearchParams(n8nRequest.body);
|
|
726
|
-
}
|
|
727
|
-
if (typeof body === 'string' || (typeof body === 'object' && !(0, n8n_workflow_1.isObjectEmpty)(body))) {
|
|
728
|
-
axiosRequest.data = body;
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
if (n8nRequest.json) {
|
|
732
|
-
const key = searchForHeader(axiosRequest, 'accept');
|
|
733
|
-
if (!key) {
|
|
734
|
-
axiosRequest.headers = {
|
|
735
|
-
...axiosRequest.headers,
|
|
736
|
-
Accept: 'application/json',
|
|
737
|
-
};
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
const userAgentHeader = searchForHeader(axiosRequest, 'user-agent');
|
|
741
|
-
if (!userAgentHeader) {
|
|
742
|
-
axiosRequest.headers = {
|
|
743
|
-
...axiosRequest.headers,
|
|
744
|
-
'User-Agent': 'n8n',
|
|
745
|
-
};
|
|
746
|
-
}
|
|
747
|
-
if (n8nRequest.ignoreHttpStatusErrors) {
|
|
748
|
-
axiosRequest.validateStatus = () => true;
|
|
749
|
-
}
|
|
750
|
-
return axiosRequest;
|
|
751
|
-
}
|
|
752
|
-
const NoBodyHttpMethods = ['GET', 'HEAD', 'OPTIONS'];
|
|
753
|
-
const removeEmptyBody = (requestOptions) => {
|
|
754
|
-
const method = requestOptions.method || 'GET';
|
|
755
|
-
if (NoBodyHttpMethods.includes(method) && (0, isEmpty_1.default)(requestOptions.body)) {
|
|
756
|
-
delete requestOptions.body;
|
|
757
|
-
}
|
|
758
|
-
};
|
|
759
|
-
exports.removeEmptyBody = removeEmptyBody;
|
|
760
|
-
async function httpRequest(requestOptions) {
|
|
761
|
-
(0, exports.removeEmptyBody)(requestOptions);
|
|
762
|
-
const axiosRequest = convertN8nRequestToAxios(requestOptions);
|
|
763
|
-
if (axiosRequest.data === undefined ||
|
|
764
|
-
(axiosRequest.method !== undefined && axiosRequest.method.toUpperCase() === 'GET')) {
|
|
765
|
-
delete axiosRequest.data;
|
|
766
|
-
}
|
|
767
|
-
const result = await invokeAxios(axiosRequest, requestOptions.auth);
|
|
768
|
-
if (requestOptions.returnFullResponse) {
|
|
769
|
-
return {
|
|
770
|
-
body: result.data,
|
|
771
|
-
headers: result.headers,
|
|
772
|
-
statusCode: result.status,
|
|
773
|
-
statusMessage: result.statusText,
|
|
774
|
-
};
|
|
775
|
-
}
|
|
776
|
-
return result.data;
|
|
777
|
-
}
|
|
778
|
-
function getBinaryPath(binaryDataId) {
|
|
779
|
-
return di_1.Container.get(binary_data_service_1.BinaryDataService).getPath(binaryDataId);
|
|
780
|
-
}
|
|
781
|
-
async function getBinaryMetadata(binaryDataId) {
|
|
782
|
-
return await di_1.Container.get(binary_data_service_1.BinaryDataService).getMetadata(binaryDataId);
|
|
783
|
-
}
|
|
784
|
-
async function getBinaryStream(binaryDataId, chunkSize) {
|
|
785
|
-
return await di_1.Container.get(binary_data_service_1.BinaryDataService).getAsStream(binaryDataId, chunkSize);
|
|
786
|
-
}
|
|
787
|
-
function assertBinaryData(inputData, node, itemIndex, propertyName, inputIndex) {
|
|
788
|
-
const binaryKeyData = inputData.main[inputIndex][itemIndex].binary;
|
|
789
|
-
if (binaryKeyData === undefined) {
|
|
790
|
-
throw new n8n_workflow_1.NodeOperationError(node, `This operation expects the node's input data to contain a binary file '${propertyName}', but none was found [item ${itemIndex}]`, {
|
|
791
|
-
itemIndex,
|
|
792
|
-
description: 'Make sure that the previous node outputs a binary file',
|
|
793
|
-
});
|
|
794
|
-
}
|
|
795
|
-
const binaryPropertyData = binaryKeyData[propertyName];
|
|
796
|
-
if (binaryPropertyData === undefined) {
|
|
797
|
-
throw new n8n_workflow_1.NodeOperationError(node, `The item has no binary field '${propertyName}' [item ${itemIndex}]`, {
|
|
798
|
-
itemIndex,
|
|
799
|
-
description: 'Check that the parameter where you specified the input binary field name is correct, and that it matches a field in the binary input',
|
|
800
|
-
});
|
|
801
|
-
}
|
|
802
|
-
return binaryPropertyData;
|
|
803
|
-
}
|
|
804
|
-
async function getBinaryDataBuffer(inputData, itemIndex, propertyName, inputIndex) {
|
|
805
|
-
const binaryData = inputData.main[inputIndex][itemIndex].binary[propertyName];
|
|
806
|
-
return await di_1.Container.get(binary_data_service_1.BinaryDataService).getAsBuffer(binaryData);
|
|
807
|
-
}
|
|
808
|
-
function detectBinaryEncoding(buffer) {
|
|
809
|
-
return chardet_1.default.detect(buffer);
|
|
810
|
-
}
|
|
811
|
-
async function setBinaryDataBuffer(binaryData, bufferOrStream, workflowId, executionId) {
|
|
812
|
-
return await di_1.Container.get(binary_data_service_1.BinaryDataService).store(workflowId, executionId, bufferOrStream, binaryData);
|
|
813
|
-
}
|
|
814
|
-
async function copyBinaryFile(workflowId, executionId, filePath, fileName, mimeType) {
|
|
815
|
-
let fileExtension;
|
|
816
|
-
if (!mimeType) {
|
|
817
|
-
if (filePath) {
|
|
818
|
-
const mimeTypeLookup = (0, mime_types_1.lookup)(filePath);
|
|
819
|
-
if (mimeTypeLookup) {
|
|
820
|
-
mimeType = mimeTypeLookup;
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
if (!mimeType) {
|
|
824
|
-
const fileTypeData = await file_type_1.default.fromFile(filePath);
|
|
825
|
-
if (fileTypeData) {
|
|
826
|
-
mimeType = fileTypeData.mime;
|
|
827
|
-
fileExtension = fileTypeData.ext;
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
if (!fileExtension && mimeType) {
|
|
832
|
-
fileExtension = (0, mime_types_1.extension)(mimeType) || undefined;
|
|
833
|
-
}
|
|
834
|
-
if (!mimeType) {
|
|
835
|
-
mimeType = 'text/plain';
|
|
836
|
-
}
|
|
837
|
-
const returnData = {
|
|
838
|
-
mimeType,
|
|
839
|
-
fileType: (0, n8n_workflow_1.fileTypeFromMimeType)(mimeType),
|
|
840
|
-
fileExtension,
|
|
841
|
-
data: '',
|
|
842
|
-
};
|
|
843
|
-
if (fileName) {
|
|
844
|
-
returnData.fileName = fileName;
|
|
845
|
-
}
|
|
846
|
-
else if (filePath) {
|
|
847
|
-
returnData.fileName = path_1.default.parse(filePath).base;
|
|
848
|
-
}
|
|
849
|
-
return await di_1.Container.get(binary_data_service_1.BinaryDataService).copyBinaryFile(workflowId, executionId, returnData, filePath);
|
|
850
|
-
}
|
|
851
|
-
async function prepareBinaryData(binaryData, executionId, workflowId, filePath, mimeType) {
|
|
852
|
-
let fileExtension;
|
|
853
|
-
if (binaryData instanceof http_1.IncomingMessage) {
|
|
854
|
-
if (!filePath) {
|
|
855
|
-
try {
|
|
856
|
-
const { responseUrl } = binaryData;
|
|
857
|
-
filePath =
|
|
858
|
-
binaryData.contentDisposition?.filename ??
|
|
859
|
-
((responseUrl && new url_1.URL(responseUrl).pathname) ?? binaryData.req?.path)?.slice(1);
|
|
860
|
-
}
|
|
861
|
-
catch { }
|
|
862
|
-
}
|
|
863
|
-
if (!mimeType) {
|
|
864
|
-
mimeType = binaryData.contentType;
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
if (!mimeType) {
|
|
868
|
-
if (filePath) {
|
|
869
|
-
const mimeTypeLookup = (0, mime_types_1.lookup)(filePath);
|
|
870
|
-
if (mimeTypeLookup) {
|
|
871
|
-
mimeType = mimeTypeLookup;
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
if (!mimeType) {
|
|
875
|
-
if (Buffer.isBuffer(binaryData)) {
|
|
876
|
-
const fileTypeData = await file_type_1.default.fromBuffer(binaryData);
|
|
877
|
-
if (fileTypeData) {
|
|
878
|
-
mimeType = fileTypeData.mime;
|
|
879
|
-
fileExtension = fileTypeData.ext;
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
else if (binaryData instanceof http_1.IncomingMessage) {
|
|
883
|
-
mimeType = binaryData.headers['content-type'];
|
|
884
|
-
}
|
|
885
|
-
else {
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
|
-
}
|
|
889
|
-
if (!fileExtension && mimeType) {
|
|
890
|
-
fileExtension = (0, mime_types_1.extension)(mimeType) || undefined;
|
|
891
|
-
}
|
|
892
|
-
if (!mimeType) {
|
|
893
|
-
mimeType = 'text/plain';
|
|
894
|
-
}
|
|
895
|
-
const returnData = {
|
|
896
|
-
mimeType,
|
|
897
|
-
fileType: (0, n8n_workflow_1.fileTypeFromMimeType)(mimeType),
|
|
898
|
-
fileExtension,
|
|
899
|
-
data: '',
|
|
900
|
-
};
|
|
901
|
-
if (filePath) {
|
|
902
|
-
const filePathParts = path_1.default.parse(filePath);
|
|
903
|
-
if (filePathParts.dir !== '') {
|
|
904
|
-
returnData.directory = filePathParts.dir;
|
|
905
|
-
}
|
|
906
|
-
returnData.fileName = filePathParts.base;
|
|
907
|
-
const fileExtension = filePathParts.ext.slice(1);
|
|
908
|
-
if (fileExtension) {
|
|
909
|
-
returnData.fileExtension = fileExtension;
|
|
910
|
-
}
|
|
911
|
-
}
|
|
912
|
-
return await setBinaryDataBuffer(returnData, binaryData, workflowId, executionId);
|
|
913
|
-
}
|
|
914
|
-
async function checkProcessedAndRecord(items, scope, contextData, options) {
|
|
915
|
-
return await data_deduplication_service_1.DataDeduplicationService.getInstance().checkProcessedAndRecord(items, scope, contextData, options);
|
|
916
|
-
}
|
|
917
|
-
async function checkProcessedItemsAndRecord(key, items, scope, contextData, options) {
|
|
918
|
-
return await data_deduplication_service_1.DataDeduplicationService.getInstance().checkProcessedItemsAndRecord(key, items, scope, contextData, options);
|
|
919
|
-
}
|
|
920
|
-
async function removeProcessed(items, scope, contextData, options) {
|
|
921
|
-
return await data_deduplication_service_1.DataDeduplicationService.getInstance().removeProcessed(items, scope, contextData, options);
|
|
922
|
-
}
|
|
923
|
-
async function clearAllProcessedItems(scope, contextData, options) {
|
|
924
|
-
return await data_deduplication_service_1.DataDeduplicationService.getInstance().clearAllProcessedItems(scope, contextData, options);
|
|
925
|
-
}
|
|
926
|
-
async function getProcessedDataCount(scope, contextData, options) {
|
|
927
|
-
return await data_deduplication_service_1.DataDeduplicationService.getInstance().getProcessedDataCount(scope, contextData, options);
|
|
928
|
-
}
|
|
929
|
-
function applyPaginationRequestData(requestData, paginationRequestData) {
|
|
930
|
-
const preparedPaginationData = {
|
|
931
|
-
...paginationRequestData,
|
|
932
|
-
uri: paginationRequestData.url,
|
|
933
|
-
};
|
|
934
|
-
if ('formData' in requestData) {
|
|
935
|
-
preparedPaginationData.formData = paginationRequestData.body;
|
|
936
|
-
delete preparedPaginationData.body;
|
|
937
|
-
}
|
|
938
|
-
else if ('form' in requestData) {
|
|
939
|
-
preparedPaginationData.form = paginationRequestData.body;
|
|
940
|
-
delete preparedPaginationData.body;
|
|
941
|
-
}
|
|
942
|
-
return (0, merge_1.default)({}, requestData, preparedPaginationData);
|
|
943
|
-
}
|
|
944
|
-
async function requestOAuth2(credentialsType, requestOptions, node, additionalData, oAuth2Options, isN8nRequest = false) {
|
|
945
|
-
(0, exports.removeEmptyBody)(requestOptions);
|
|
946
|
-
const credentials = (await this.getCredentials(credentialsType));
|
|
947
|
-
if (credentials.grantType === 'authorizationCode' && credentials.oauthTokenData === undefined) {
|
|
948
|
-
throw new n8n_workflow_1.ApplicationError('OAuth credentials not connected');
|
|
949
|
-
}
|
|
950
|
-
const oAuthClient = new client_oauth2_1.ClientOAuth2({
|
|
951
|
-
clientId: credentials.clientId,
|
|
952
|
-
clientSecret: credentials.clientSecret,
|
|
953
|
-
accessTokenUri: credentials.accessTokenUrl,
|
|
954
|
-
scopes: credentials.scope.split(' '),
|
|
955
|
-
ignoreSSLIssues: credentials.ignoreSSLIssues,
|
|
956
|
-
authentication: credentials.authentication ?? 'header',
|
|
957
|
-
});
|
|
958
|
-
let oauthTokenData = credentials.oauthTokenData;
|
|
959
|
-
if (credentials.grantType === 'clientCredentials' &&
|
|
960
|
-
(oauthTokenData === undefined ||
|
|
961
|
-
Object.keys(oauthTokenData).length === 0 ||
|
|
962
|
-
oauthTokenData.access_token === '')) {
|
|
963
|
-
const { data } = await oAuthClient.credentials.getToken();
|
|
964
|
-
if (!node.credentials?.[credentialsType]) {
|
|
965
|
-
throw new n8n_workflow_1.ApplicationError('Node does not have credential type', {
|
|
966
|
-
extra: { nodeName: node.name },
|
|
967
|
-
tags: { credentialType: credentialsType },
|
|
968
|
-
});
|
|
969
|
-
}
|
|
970
|
-
const nodeCredentials = node.credentials[credentialsType];
|
|
971
|
-
credentials.oauthTokenData = data;
|
|
972
|
-
await additionalData.credentialsHelper.updateCredentials(nodeCredentials, credentialsType, credentials);
|
|
973
|
-
oauthTokenData = data;
|
|
974
|
-
}
|
|
975
|
-
const accessToken = (0, get_1.default)(oauthTokenData, oAuth2Options?.property) || oauthTokenData.accessToken;
|
|
976
|
-
const refreshToken = oauthTokenData.refreshToken;
|
|
977
|
-
const token = oAuthClient.createToken({
|
|
978
|
-
...oauthTokenData,
|
|
979
|
-
...(accessToken ? { access_token: accessToken } : {}),
|
|
980
|
-
...(refreshToken ? { refresh_token: refreshToken } : {}),
|
|
981
|
-
}, oAuth2Options?.tokenType || oauthTokenData.tokenType);
|
|
982
|
-
requestOptions.rejectUnauthorized = !credentials.ignoreSSLIssues;
|
|
983
|
-
const newRequestOptions = token.sign(requestOptions);
|
|
984
|
-
const newRequestHeaders = (newRequestOptions.headers = newRequestOptions.headers ?? {});
|
|
985
|
-
if (oAuth2Options?.keepBearer === false && typeof newRequestHeaders.Authorization === 'string') {
|
|
986
|
-
newRequestHeaders.Authorization = newRequestHeaders.Authorization.split(' ')[1];
|
|
987
|
-
}
|
|
988
|
-
if (oAuth2Options?.keyToIncludeInAccessTokenHeader) {
|
|
989
|
-
Object.assign(newRequestHeaders, {
|
|
990
|
-
[oAuth2Options.keyToIncludeInAccessTokenHeader]: token.accessToken,
|
|
991
|
-
});
|
|
992
|
-
}
|
|
993
|
-
if (isN8nRequest) {
|
|
994
|
-
return await this.helpers.httpRequest(newRequestOptions).catch(async (error) => {
|
|
995
|
-
if (error.response?.status === 401) {
|
|
996
|
-
this.logger.debug(`OAuth2 token for "${credentialsType}" used by node "${node.name}" expired. Should revalidate.`);
|
|
997
|
-
const tokenRefreshOptions = {};
|
|
998
|
-
if (oAuth2Options?.includeCredentialsOnRefreshOnBody) {
|
|
999
|
-
const body = {
|
|
1000
|
-
client_id: credentials.clientId,
|
|
1001
|
-
...(credentials.grantType === 'authorizationCode' && {
|
|
1002
|
-
client_secret: credentials.clientSecret,
|
|
1003
|
-
}),
|
|
1004
|
-
};
|
|
1005
|
-
tokenRefreshOptions.body = body;
|
|
1006
|
-
tokenRefreshOptions.headers = {
|
|
1007
|
-
Authorization: '',
|
|
1008
|
-
};
|
|
1009
|
-
}
|
|
1010
|
-
let newToken;
|
|
1011
|
-
this.logger.debug(`OAuth2 token for "${credentialsType}" used by node "${node.name}" has been renewed.`);
|
|
1012
|
-
if (credentials.grantType === 'clientCredentials') {
|
|
1013
|
-
newToken = await token.client.credentials.getToken();
|
|
1014
|
-
}
|
|
1015
|
-
else {
|
|
1016
|
-
newToken = await token.refresh(tokenRefreshOptions);
|
|
1017
|
-
}
|
|
1018
|
-
this.logger.debug(`OAuth2 token for "${credentialsType}" used by node "${node.name}" has been renewed.`);
|
|
1019
|
-
credentials.oauthTokenData = newToken.data;
|
|
1020
|
-
if (!node.credentials?.[credentialsType]) {
|
|
1021
|
-
throw new n8n_workflow_1.ApplicationError('Node does not have credential type', {
|
|
1022
|
-
extra: { nodeName: node.name, credentialType: credentialsType },
|
|
1023
|
-
});
|
|
1024
|
-
}
|
|
1025
|
-
const nodeCredentials = node.credentials[credentialsType];
|
|
1026
|
-
await additionalData.credentialsHelper.updateCredentials(nodeCredentials, credentialsType, credentials);
|
|
1027
|
-
const refreshedRequestOption = newToken.sign(requestOptions);
|
|
1028
|
-
if (oAuth2Options?.keyToIncludeInAccessTokenHeader) {
|
|
1029
|
-
Object.assign(newRequestHeaders, {
|
|
1030
|
-
[oAuth2Options.keyToIncludeInAccessTokenHeader]: token.accessToken,
|
|
1031
|
-
});
|
|
1032
|
-
}
|
|
1033
|
-
return await this.helpers.httpRequest(refreshedRequestOption);
|
|
1034
|
-
}
|
|
1035
|
-
throw error;
|
|
1036
|
-
});
|
|
1037
|
-
}
|
|
1038
|
-
const tokenExpiredStatusCode = oAuth2Options?.tokenExpiredStatusCode === undefined
|
|
1039
|
-
? 401
|
|
1040
|
-
: oAuth2Options?.tokenExpiredStatusCode;
|
|
1041
|
-
return await this.helpers
|
|
1042
|
-
.request(newRequestOptions)
|
|
1043
|
-
.then((response) => {
|
|
1044
|
-
const requestOptions = newRequestOptions;
|
|
1045
|
-
if (requestOptions.resolveWithFullResponse === true &&
|
|
1046
|
-
requestOptions.simple === false &&
|
|
1047
|
-
response.statusCode === tokenExpiredStatusCode) {
|
|
1048
|
-
throw response;
|
|
1049
|
-
}
|
|
1050
|
-
return response;
|
|
1051
|
-
})
|
|
1052
|
-
.catch(async (error) => {
|
|
1053
|
-
if (error.statusCode === tokenExpiredStatusCode) {
|
|
1054
|
-
const tokenRefreshOptions = {};
|
|
1055
|
-
if (oAuth2Options?.includeCredentialsOnRefreshOnBody) {
|
|
1056
|
-
const body = {
|
|
1057
|
-
client_id: credentials.clientId,
|
|
1058
|
-
client_secret: credentials.clientSecret,
|
|
1059
|
-
};
|
|
1060
|
-
tokenRefreshOptions.body = body;
|
|
1061
|
-
tokenRefreshOptions.headers = {
|
|
1062
|
-
Authorization: '',
|
|
1063
|
-
};
|
|
1064
|
-
}
|
|
1065
|
-
this.logger.debug(`OAuth2 token for "${credentialsType}" used by node "${node.name}" expired. Should revalidate.`);
|
|
1066
|
-
let newToken;
|
|
1067
|
-
if (credentials.grantType === 'clientCredentials') {
|
|
1068
|
-
newToken = await token.client.credentials.getToken();
|
|
1069
|
-
}
|
|
1070
|
-
else {
|
|
1071
|
-
newToken = await token.refresh(tokenRefreshOptions);
|
|
1072
|
-
}
|
|
1073
|
-
this.logger.debug(`OAuth2 token for "${credentialsType}" used by node "${node.name}" has been renewed.`);
|
|
1074
|
-
credentials.oauthTokenData = newToken.data;
|
|
1075
|
-
if (!node.credentials?.[credentialsType]) {
|
|
1076
|
-
throw new n8n_workflow_1.ApplicationError('Node does not have credential type', {
|
|
1077
|
-
tags: { credentialType: credentialsType },
|
|
1078
|
-
extra: { nodeName: node.name },
|
|
1079
|
-
});
|
|
1080
|
-
}
|
|
1081
|
-
const nodeCredentials = node.credentials[credentialsType];
|
|
1082
|
-
await additionalData.credentialsHelper.updateCredentials(nodeCredentials, credentialsType, credentials);
|
|
1083
|
-
this.logger.debug(`OAuth2 token for "${credentialsType}" used by node "${node.name}" has been saved to database successfully.`);
|
|
1084
|
-
const newRequestOptions = newToken.sign(requestOptions);
|
|
1085
|
-
newRequestOptions.headers = newRequestOptions.headers ?? {};
|
|
1086
|
-
if (oAuth2Options?.keyToIncludeInAccessTokenHeader) {
|
|
1087
|
-
Object.assign(newRequestOptions.headers, {
|
|
1088
|
-
[oAuth2Options.keyToIncludeInAccessTokenHeader]: token.accessToken,
|
|
1089
|
-
});
|
|
1090
|
-
}
|
|
1091
|
-
return await this.helpers.request(newRequestOptions);
|
|
1092
|
-
}
|
|
1093
|
-
throw error;
|
|
1094
|
-
});
|
|
1095
|
-
}
|
|
1096
|
-
async function requestOAuth1(credentialsType, requestOptions, isN8nRequest = false) {
|
|
1097
|
-
(0, exports.removeEmptyBody)(requestOptions);
|
|
1098
|
-
const credentials = await this.getCredentials(credentialsType);
|
|
1099
|
-
if (credentials === undefined) {
|
|
1100
|
-
throw new n8n_workflow_1.ApplicationError('No credentials were returned');
|
|
1101
|
-
}
|
|
1102
|
-
if (credentials.oauthTokenData === undefined) {
|
|
1103
|
-
throw new n8n_workflow_1.ApplicationError('OAuth credentials not connected');
|
|
1104
|
-
}
|
|
1105
|
-
const oauth = new oauth_1_0a_1.default({
|
|
1106
|
-
consumer: {
|
|
1107
|
-
key: credentials.consumerKey,
|
|
1108
|
-
secret: credentials.consumerSecret,
|
|
1109
|
-
},
|
|
1110
|
-
signature_method: credentials.signatureMethod,
|
|
1111
|
-
hash_function(base, key) {
|
|
1112
|
-
let algorithm;
|
|
1113
|
-
switch (credentials.signatureMethod) {
|
|
1114
|
-
case 'HMAC-SHA256':
|
|
1115
|
-
algorithm = 'sha256';
|
|
1116
|
-
break;
|
|
1117
|
-
case 'HMAC-SHA512':
|
|
1118
|
-
algorithm = 'sha512';
|
|
1119
|
-
break;
|
|
1120
|
-
default:
|
|
1121
|
-
algorithm = 'sha1';
|
|
1122
|
-
break;
|
|
1123
|
-
}
|
|
1124
|
-
return (0, crypto_1.createHmac)(algorithm, key).update(base).digest('base64');
|
|
1125
|
-
},
|
|
1126
|
-
});
|
|
1127
|
-
const oauthTokenData = credentials.oauthTokenData;
|
|
1128
|
-
const token = {
|
|
1129
|
-
key: oauthTokenData.oauth_token,
|
|
1130
|
-
secret: oauthTokenData.oauth_token_secret,
|
|
1131
|
-
};
|
|
1132
|
-
requestOptions.data = { ...requestOptions.qs, ...requestOptions.form };
|
|
1133
|
-
if ('uri' in requestOptions && !requestOptions.url) {
|
|
1134
|
-
requestOptions.url = requestOptions.uri;
|
|
1135
|
-
delete requestOptions.uri;
|
|
1136
|
-
}
|
|
1137
|
-
requestOptions.headers = oauth.toHeader(oauth.authorize(requestOptions, token));
|
|
1138
|
-
if (isN8nRequest) {
|
|
1139
|
-
return await this.helpers.httpRequest(requestOptions);
|
|
1140
|
-
}
|
|
1141
|
-
return await this.helpers
|
|
1142
|
-
.request(requestOptions)
|
|
1143
|
-
.catch(async (error) => {
|
|
1144
|
-
throw error;
|
|
1145
|
-
});
|
|
1146
|
-
}
|
|
1147
|
-
async function httpRequestWithAuthentication(credentialsType, requestOptions, workflow, node, additionalData, additionalCredentialOptions) {
|
|
1148
|
-
(0, exports.removeEmptyBody)(requestOptions);
|
|
1149
|
-
if ('getExecutionCancelSignal' in this) {
|
|
1150
|
-
requestOptions.abortSignal = this.getExecutionCancelSignal();
|
|
1151
|
-
}
|
|
1152
|
-
let credentialsDecrypted;
|
|
1153
|
-
try {
|
|
1154
|
-
const parentTypes = additionalData.credentialsHelper.getParentTypes(credentialsType);
|
|
1155
|
-
if (parentTypes.includes('oAuth1Api')) {
|
|
1156
|
-
return await requestOAuth1.call(this, credentialsType, requestOptions, true);
|
|
1157
|
-
}
|
|
1158
|
-
if (parentTypes.includes('oAuth2Api')) {
|
|
1159
|
-
return await requestOAuth2.call(this, credentialsType, requestOptions, node, additionalData, additionalCredentialOptions?.oauth2, true);
|
|
1160
|
-
}
|
|
1161
|
-
if (additionalCredentialOptions?.credentialsDecrypted) {
|
|
1162
|
-
credentialsDecrypted = additionalCredentialOptions.credentialsDecrypted.data;
|
|
1163
|
-
}
|
|
1164
|
-
else {
|
|
1165
|
-
credentialsDecrypted =
|
|
1166
|
-
await this.getCredentials(credentialsType);
|
|
1167
|
-
}
|
|
1168
|
-
if (credentialsDecrypted === undefined) {
|
|
1169
|
-
throw new n8n_workflow_1.NodeOperationError(node, `Node "${node.name}" does not have any credentials of type "${credentialsType}" set`, { level: 'warning' });
|
|
1170
|
-
}
|
|
1171
|
-
const data = await additionalData.credentialsHelper.preAuthentication({ helpers: this.helpers }, credentialsDecrypted, credentialsType, node, false);
|
|
1172
|
-
if (data) {
|
|
1173
|
-
Object.assign(credentialsDecrypted, data);
|
|
1174
|
-
}
|
|
1175
|
-
requestOptions = await additionalData.credentialsHelper.authenticate(credentialsDecrypted, credentialsType, requestOptions, workflow, node);
|
|
1176
|
-
return await httpRequest(requestOptions);
|
|
1177
|
-
}
|
|
1178
|
-
catch (error) {
|
|
1179
|
-
if (error.response?.status === 401 &&
|
|
1180
|
-
additionalData.credentialsHelper.preAuthentication !== undefined) {
|
|
1181
|
-
try {
|
|
1182
|
-
if (credentialsDecrypted !== undefined) {
|
|
1183
|
-
const data = await additionalData.credentialsHelper.preAuthentication({ helpers: this.helpers }, credentialsDecrypted, credentialsType, node, true);
|
|
1184
|
-
if (data) {
|
|
1185
|
-
Object.assign(credentialsDecrypted, data);
|
|
1186
|
-
}
|
|
1187
|
-
requestOptions = await additionalData.credentialsHelper.authenticate(credentialsDecrypted, credentialsType, requestOptions, workflow, node);
|
|
1188
|
-
}
|
|
1189
|
-
return await httpRequest(requestOptions);
|
|
1190
|
-
}
|
|
1191
|
-
catch (error) {
|
|
1192
|
-
throw new n8n_workflow_1.NodeApiError(this.getNode(), error);
|
|
1193
|
-
}
|
|
1194
|
-
}
|
|
1195
|
-
throw new n8n_workflow_1.NodeApiError(this.getNode(), error);
|
|
1196
|
-
}
|
|
1197
|
-
}
|
|
1198
|
-
function returnJsonArray(jsonData) {
|
|
1199
|
-
const returnData = [];
|
|
1200
|
-
if (!Array.isArray(jsonData)) {
|
|
1201
|
-
jsonData = [jsonData];
|
|
1202
|
-
}
|
|
1203
|
-
jsonData.forEach((data) => {
|
|
1204
|
-
if (data?.json) {
|
|
1205
|
-
returnData.push({ ...data, json: data.json });
|
|
1206
|
-
}
|
|
1207
|
-
else {
|
|
1208
|
-
returnData.push({ json: data });
|
|
1209
|
-
}
|
|
1210
|
-
});
|
|
1211
|
-
return returnData;
|
|
1212
|
-
}
|
|
1213
|
-
function constructExecutionMetaData(inputData, options) {
|
|
1214
|
-
const { itemData } = options;
|
|
1215
|
-
return inputData.map((data) => {
|
|
1216
|
-
const { json, ...rest } = data;
|
|
1217
|
-
return { json, pairedItem: itemData, ...rest };
|
|
1218
|
-
});
|
|
1219
|
-
}
|
|
1220
|
-
function normalizeItems(executionData) {
|
|
1221
|
-
if (typeof executionData === 'object' && !Array.isArray(executionData)) {
|
|
1222
|
-
executionData = executionData.json ? [executionData] : [{ json: executionData }];
|
|
1223
|
-
}
|
|
1224
|
-
if (executionData.every((item) => typeof item === 'object' && 'json' in item))
|
|
1225
|
-
return executionData;
|
|
1226
|
-
if (executionData.some((item) => typeof item === 'object' && 'json' in item)) {
|
|
1227
|
-
throw new n8n_workflow_1.ApplicationError('Inconsistent item format');
|
|
1228
|
-
}
|
|
1229
|
-
if (executionData.every((item) => typeof item === 'object' && 'binary' in item)) {
|
|
1230
|
-
const normalizedItems = [];
|
|
1231
|
-
executionData.forEach((item) => {
|
|
1232
|
-
const json = Object.keys(item).reduce((acc, key) => {
|
|
1233
|
-
if (key === 'binary')
|
|
1234
|
-
return acc;
|
|
1235
|
-
return { ...acc, [key]: item[key] };
|
|
1236
|
-
}, {});
|
|
1237
|
-
normalizedItems.push({
|
|
1238
|
-
json,
|
|
1239
|
-
binary: item.binary,
|
|
1240
|
-
});
|
|
1241
|
-
});
|
|
1242
|
-
return normalizedItems;
|
|
1243
|
-
}
|
|
1244
|
-
if (executionData.some((item) => typeof item === 'object' && 'binary' in item)) {
|
|
1245
|
-
throw new n8n_workflow_1.ApplicationError('Inconsistent item format');
|
|
1246
|
-
}
|
|
1247
|
-
return executionData.map((item) => {
|
|
1248
|
-
return { json: item };
|
|
1249
|
-
});
|
|
1250
|
-
}
|
|
1251
|
-
async function requestWithAuthentication(credentialsType, requestOptions, workflow, node, additionalData, additionalCredentialOptions, itemIndex) {
|
|
1252
|
-
(0, exports.removeEmptyBody)(requestOptions);
|
|
1253
|
-
let credentialsDecrypted;
|
|
1254
|
-
try {
|
|
1255
|
-
const parentTypes = additionalData.credentialsHelper.getParentTypes(credentialsType);
|
|
1256
|
-
if (credentialsType === 'oAuth1Api' || parentTypes.includes('oAuth1Api')) {
|
|
1257
|
-
return await requestOAuth1.call(this, credentialsType, requestOptions, false);
|
|
1258
|
-
}
|
|
1259
|
-
if (credentialsType === 'oAuth2Api' || parentTypes.includes('oAuth2Api')) {
|
|
1260
|
-
return await requestOAuth2.call(this, credentialsType, requestOptions, node, additionalData, additionalCredentialOptions?.oauth2, false);
|
|
1261
|
-
}
|
|
1262
|
-
if (additionalCredentialOptions?.credentialsDecrypted) {
|
|
1263
|
-
credentialsDecrypted = additionalCredentialOptions.credentialsDecrypted.data;
|
|
1264
|
-
}
|
|
1265
|
-
else {
|
|
1266
|
-
credentialsDecrypted = await this.getCredentials(credentialsType, itemIndex);
|
|
1267
|
-
}
|
|
1268
|
-
if (credentialsDecrypted === undefined) {
|
|
1269
|
-
throw new n8n_workflow_1.NodeOperationError(node, `Node "${node.name}" does not have any credentials of type "${credentialsType}" set`, { level: 'warning' });
|
|
1270
|
-
}
|
|
1271
|
-
const data = await additionalData.credentialsHelper.preAuthentication({ helpers: this.helpers }, credentialsDecrypted, credentialsType, node, false);
|
|
1272
|
-
if (data) {
|
|
1273
|
-
Object.assign(credentialsDecrypted, data);
|
|
1274
|
-
}
|
|
1275
|
-
requestOptions = (await additionalData.credentialsHelper.authenticate(credentialsDecrypted, credentialsType, requestOptions, workflow, node));
|
|
1276
|
-
return await proxyRequestToAxios(workflow, additionalData, node, requestOptions);
|
|
1277
|
-
}
|
|
1278
|
-
catch (error) {
|
|
1279
|
-
try {
|
|
1280
|
-
if (credentialsDecrypted !== undefined) {
|
|
1281
|
-
const data = await additionalData.credentialsHelper.preAuthentication({ helpers: this.helpers }, credentialsDecrypted, credentialsType, node, true);
|
|
1282
|
-
if (data) {
|
|
1283
|
-
Object.assign(credentialsDecrypted, data);
|
|
1284
|
-
requestOptions = (await additionalData.credentialsHelper.authenticate(credentialsDecrypted, credentialsType, requestOptions, workflow, node));
|
|
1285
|
-
return await proxyRequestToAxios(workflow, additionalData, node, requestOptions);
|
|
1286
|
-
}
|
|
1287
|
-
}
|
|
1288
|
-
throw error;
|
|
1289
|
-
}
|
|
1290
|
-
catch (error) {
|
|
1291
|
-
if (error instanceof n8n_workflow_1.ExecutionBaseError)
|
|
1292
|
-
throw error;
|
|
1293
|
-
throw new n8n_workflow_1.NodeApiError(this.getNode(), error);
|
|
1294
|
-
}
|
|
1295
|
-
}
|
|
1296
|
-
}
|
|
1297
|
-
function getNodeWebhookUrl(name, workflow, node, additionalData, mode, additionalKeys, isTest) {
|
|
1298
|
-
let baseUrl = additionalData.webhookBaseUrl;
|
|
1299
|
-
if (isTest === true) {
|
|
1300
|
-
baseUrl = additionalData.webhookTestBaseUrl;
|
|
1301
|
-
}
|
|
1302
|
-
const webhookDescription = getWebhookDescription(name, workflow, node);
|
|
1303
|
-
if (webhookDescription === undefined) {
|
|
1304
|
-
return undefined;
|
|
1305
|
-
}
|
|
1306
|
-
const path = workflow.expression.getSimpleParameterValue(node, webhookDescription.path, mode, additionalKeys);
|
|
1307
|
-
if (path === undefined) {
|
|
1308
|
-
return undefined;
|
|
1309
|
-
}
|
|
1310
|
-
const isFullPath = workflow.expression.getSimpleParameterValue(node, webhookDescription.isFullPath, mode, additionalKeys, undefined, false);
|
|
1311
|
-
return n8n_workflow_1.NodeHelpers.getNodeWebhookUrl(baseUrl, workflow.id, node, path.toString(), isFullPath);
|
|
1312
|
-
}
|
|
1313
|
-
function getWebhookDescription(name, workflow, node) {
|
|
1314
|
-
const nodeType = workflow.nodeTypes.getByNameAndVersion(node.type, node.typeVersion);
|
|
1315
|
-
if (nodeType.description.webhooks === undefined) {
|
|
1316
|
-
return undefined;
|
|
1317
|
-
}
|
|
1318
|
-
for (const webhookDescription of nodeType.description.webhooks) {
|
|
1319
|
-
if (webhookDescription.name === name) {
|
|
1320
|
-
return webhookDescription;
|
|
1321
|
-
}
|
|
1322
|
-
}
|
|
1323
|
-
return undefined;
|
|
1324
|
-
}
|
|
1325
|
-
const getRequestHelperFunctions = (workflow, node, additionalData, runExecutionData = null, connectionInputData = []) => {
|
|
1326
|
-
const getResolvedValue = (parameterValue, itemIndex, runIndex, executeData, additionalKeys, returnObjectAsString = false) => {
|
|
1327
|
-
const mode = 'internal';
|
|
1328
|
-
if (typeof parameterValue === 'object' ||
|
|
1329
|
-
(typeof parameterValue === 'string' && parameterValue.charAt(0) === '=')) {
|
|
1330
|
-
return workflow.expression.getParameterValue(parameterValue, runExecutionData, runIndex, itemIndex, node.name, connectionInputData, mode, additionalKeys ?? {}, executeData, returnObjectAsString);
|
|
1331
|
-
}
|
|
1332
|
-
return parameterValue;
|
|
1333
|
-
};
|
|
1334
|
-
return {
|
|
1335
|
-
httpRequest,
|
|
1336
|
-
async requestWithAuthenticationPaginated(requestOptions, itemIndex, paginationOptions, credentialsType, additionalCredentialOptions) {
|
|
1337
|
-
const responseData = [];
|
|
1338
|
-
if (!requestOptions.qs) {
|
|
1339
|
-
requestOptions.qs = {};
|
|
1340
|
-
}
|
|
1341
|
-
requestOptions.resolveWithFullResponse = true;
|
|
1342
|
-
requestOptions.simple = false;
|
|
1343
|
-
let tempResponseData;
|
|
1344
|
-
let makeAdditionalRequest;
|
|
1345
|
-
let paginateRequestData;
|
|
1346
|
-
const runIndex = 0;
|
|
1347
|
-
const additionalKeys = {
|
|
1348
|
-
$request: requestOptions,
|
|
1349
|
-
$response: {},
|
|
1350
|
-
$version: node.typeVersion,
|
|
1351
|
-
$pageCount: 0,
|
|
1352
|
-
};
|
|
1353
|
-
const executeData = {
|
|
1354
|
-
data: {},
|
|
1355
|
-
node,
|
|
1356
|
-
source: null,
|
|
1357
|
-
};
|
|
1358
|
-
const hashData = {
|
|
1359
|
-
identicalCount: 0,
|
|
1360
|
-
previousLength: 0,
|
|
1361
|
-
previousHash: '',
|
|
1362
|
-
};
|
|
1363
|
-
do {
|
|
1364
|
-
paginateRequestData = getResolvedValue(paginationOptions.request, itemIndex, runIndex, executeData, additionalKeys, false);
|
|
1365
|
-
const tempRequestOptions = applyPaginationRequestData(requestOptions, paginateRequestData);
|
|
1366
|
-
if (!(0, exports.validateUrl)(tempRequestOptions.uri)) {
|
|
1367
|
-
throw new n8n_workflow_1.NodeOperationError(node, `'${paginateRequestData.url}' is not a valid URL.`, {
|
|
1368
|
-
itemIndex,
|
|
1369
|
-
runIndex,
|
|
1370
|
-
type: 'invalid_url',
|
|
1371
|
-
});
|
|
1372
|
-
}
|
|
1373
|
-
if (credentialsType) {
|
|
1374
|
-
tempResponseData = await this.helpers.requestWithAuthentication.call(this, credentialsType, tempRequestOptions, additionalCredentialOptions);
|
|
1375
|
-
}
|
|
1376
|
-
else {
|
|
1377
|
-
tempResponseData = await this.helpers.request(tempRequestOptions);
|
|
1378
|
-
}
|
|
1379
|
-
const newResponse = Object.assign({
|
|
1380
|
-
body: {},
|
|
1381
|
-
headers: {},
|
|
1382
|
-
statusCode: 0,
|
|
1383
|
-
}, (0, pick_1.default)(tempResponseData, ['body', 'headers', 'statusCode']));
|
|
1384
|
-
let contentBody;
|
|
1385
|
-
if (newResponse.body instanceof stream_1.Readable && paginationOptions.binaryResult !== true) {
|
|
1386
|
-
contentBody = await binaryToString(newResponse.body);
|
|
1387
|
-
const responseContentType = newResponse.headers['content-type']?.toString() ?? '';
|
|
1388
|
-
if (responseContentType.includes('application/json')) {
|
|
1389
|
-
newResponse.body = (0, n8n_workflow_1.jsonParse)(contentBody, { fallbackValue: {} });
|
|
1390
|
-
}
|
|
1391
|
-
else {
|
|
1392
|
-
newResponse.body = contentBody;
|
|
1393
|
-
}
|
|
1394
|
-
tempResponseData.__bodyResolved = true;
|
|
1395
|
-
tempResponseData.body = newResponse.body;
|
|
1396
|
-
}
|
|
1397
|
-
else {
|
|
1398
|
-
contentBody = newResponse.body;
|
|
1399
|
-
}
|
|
1400
|
-
if (paginationOptions.binaryResult !== true || tempResponseData.headers.etag) {
|
|
1401
|
-
let contentLength = 0;
|
|
1402
|
-
if ('content-length' in tempResponseData.headers) {
|
|
1403
|
-
contentLength = parseInt(tempResponseData.headers['content-length']) || 0;
|
|
1404
|
-
}
|
|
1405
|
-
if (hashData.previousLength === contentLength) {
|
|
1406
|
-
let hash;
|
|
1407
|
-
if (tempResponseData.headers.etag) {
|
|
1408
|
-
hash = tempResponseData.headers.etag;
|
|
1409
|
-
}
|
|
1410
|
-
else {
|
|
1411
|
-
if (typeof contentBody !== 'string') {
|
|
1412
|
-
contentBody = JSON.stringify(contentBody);
|
|
1413
|
-
}
|
|
1414
|
-
hash = crypto_1.default.createHash('md5').update(contentBody).digest('base64');
|
|
1415
|
-
}
|
|
1416
|
-
if (hashData.previousHash === hash) {
|
|
1417
|
-
hashData.identicalCount += 1;
|
|
1418
|
-
if (hashData.identicalCount > 2) {
|
|
1419
|
-
throw new n8n_workflow_1.NodeOperationError(node, 'The returned response was identical 5x, so requests got stopped', {
|
|
1420
|
-
itemIndex,
|
|
1421
|
-
description: 'Check if "Pagination Completed When" has been configured correctly.',
|
|
1422
|
-
});
|
|
1423
|
-
}
|
|
1424
|
-
}
|
|
1425
|
-
else {
|
|
1426
|
-
hashData.identicalCount = 0;
|
|
1427
|
-
}
|
|
1428
|
-
hashData.previousHash = hash;
|
|
1429
|
-
}
|
|
1430
|
-
else {
|
|
1431
|
-
hashData.identicalCount = 0;
|
|
1432
|
-
}
|
|
1433
|
-
hashData.previousLength = contentLength;
|
|
1434
|
-
}
|
|
1435
|
-
responseData.push(tempResponseData);
|
|
1436
|
-
additionalKeys.$response = newResponse;
|
|
1437
|
-
additionalKeys.$pageCount = (additionalKeys.$pageCount ?? 0) + 1;
|
|
1438
|
-
const maxRequests = getResolvedValue(paginationOptions.maxRequests, itemIndex, runIndex, executeData, additionalKeys, false);
|
|
1439
|
-
if (maxRequests && additionalKeys.$pageCount >= maxRequests) {
|
|
1440
|
-
break;
|
|
1441
|
-
}
|
|
1442
|
-
makeAdditionalRequest = getResolvedValue(paginationOptions.continue, itemIndex, runIndex, executeData, additionalKeys, false);
|
|
1443
|
-
if (makeAdditionalRequest) {
|
|
1444
|
-
if (paginationOptions.requestInterval) {
|
|
1445
|
-
const requestInterval = getResolvedValue(paginationOptions.requestInterval, itemIndex, runIndex, executeData, additionalKeys, false);
|
|
1446
|
-
await (0, n8n_workflow_1.sleep)(requestInterval);
|
|
1447
|
-
}
|
|
1448
|
-
if (tempResponseData.statusCode < 200 || tempResponseData.statusCode >= 300) {
|
|
1449
|
-
let data = tempResponseData.body;
|
|
1450
|
-
if (data instanceof stream_1.Readable && paginationOptions.binaryResult !== true) {
|
|
1451
|
-
data = await binaryToString(data);
|
|
1452
|
-
}
|
|
1453
|
-
else if (typeof data === 'object') {
|
|
1454
|
-
data = JSON.stringify(data);
|
|
1455
|
-
}
|
|
1456
|
-
throw Object.assign(new Error(`${tempResponseData.statusCode} - "${data?.toString()}"`), {
|
|
1457
|
-
statusCode: tempResponseData.statusCode,
|
|
1458
|
-
error: data,
|
|
1459
|
-
isAxiosError: true,
|
|
1460
|
-
response: {
|
|
1461
|
-
headers: tempResponseData.headers,
|
|
1462
|
-
status: tempResponseData.statusCode,
|
|
1463
|
-
statusText: tempResponseData.statusMessage,
|
|
1464
|
-
},
|
|
1465
|
-
});
|
|
1466
|
-
}
|
|
1467
|
-
}
|
|
1468
|
-
} while (makeAdditionalRequest);
|
|
1469
|
-
return responseData;
|
|
1470
|
-
},
|
|
1471
|
-
async httpRequestWithAuthentication(credentialsType, requestOptions, additionalCredentialOptions) {
|
|
1472
|
-
return await httpRequestWithAuthentication.call(this, credentialsType, requestOptions, workflow, node, additionalData, additionalCredentialOptions);
|
|
1473
|
-
},
|
|
1474
|
-
request: async (uriOrObject, options) => await proxyRequestToAxios(workflow, additionalData, node, uriOrObject, options),
|
|
1475
|
-
async requestWithAuthentication(credentialsType, requestOptions, additionalCredentialOptions, itemIndex) {
|
|
1476
|
-
return await requestWithAuthentication.call(this, credentialsType, requestOptions, workflow, node, additionalData, additionalCredentialOptions, itemIndex);
|
|
1477
|
-
},
|
|
1478
|
-
async requestOAuth1(credentialsType, requestOptions) {
|
|
1479
|
-
return await requestOAuth1.call(this, credentialsType, requestOptions);
|
|
1480
|
-
},
|
|
1481
|
-
async requestOAuth2(credentialsType, requestOptions, oAuth2Options) {
|
|
1482
|
-
return await requestOAuth2.call(this, credentialsType, requestOptions, node, additionalData, oAuth2Options);
|
|
1483
|
-
},
|
|
1484
|
-
};
|
|
1485
|
-
};
|
|
1486
|
-
exports.getRequestHelperFunctions = getRequestHelperFunctions;
|
|
1487
|
-
const getSSHTunnelFunctions = () => ({
|
|
1488
|
-
getSSHClient: async (credentials) => await di_1.Container.get(ssh_clients_manager_1.SSHClientsManager).getClient(credentials),
|
|
1489
|
-
});
|
|
1490
|
-
exports.getSSHTunnelFunctions = getSSHTunnelFunctions;
|
|
1491
|
-
const getSchedulingFunctions = (workflow) => {
|
|
1492
|
-
const scheduledTaskManager = di_1.Container.get(scheduled_task_manager_1.ScheduledTaskManager);
|
|
1493
|
-
return {
|
|
1494
|
-
registerCron: (cronExpression, onTick) => scheduledTaskManager.registerCron(workflow, cronExpression, onTick),
|
|
1495
|
-
};
|
|
1496
|
-
};
|
|
1497
|
-
exports.getSchedulingFunctions = getSchedulingFunctions;
|
|
1498
|
-
const getAllowedPaths = () => {
|
|
1499
|
-
const restrictFileAccessTo = process.env[constants_1.RESTRICT_FILE_ACCESS_TO];
|
|
1500
|
-
if (!restrictFileAccessTo) {
|
|
1501
|
-
return [];
|
|
1502
|
-
}
|
|
1503
|
-
const allowedPaths = restrictFileAccessTo
|
|
1504
|
-
.split(';')
|
|
1505
|
-
.map((path) => path.trim())
|
|
1506
|
-
.filter((path) => path);
|
|
1507
|
-
return allowedPaths;
|
|
1508
|
-
};
|
|
1509
|
-
function isFilePathBlocked(filePath) {
|
|
1510
|
-
const allowedPaths = getAllowedPaths();
|
|
1511
|
-
const resolvedFilePath = path_1.default.resolve(filePath);
|
|
1512
|
-
const blockFileAccessToN8nFiles = process.env[constants_1.BLOCK_FILE_ACCESS_TO_N8N_FILES] !== 'false';
|
|
1513
|
-
if (allowedPaths.length) {
|
|
1514
|
-
for (const path of allowedPaths) {
|
|
1515
|
-
if (resolvedFilePath.startsWith(path)) {
|
|
1516
|
-
return false;
|
|
1517
|
-
}
|
|
1518
|
-
}
|
|
1519
|
-
return true;
|
|
1520
|
-
}
|
|
1521
|
-
if (blockFileAccessToN8nFiles) {
|
|
1522
|
-
const { n8nFolder, staticCacheDir } = di_1.Container.get(instance_settings_1.InstanceSettings);
|
|
1523
|
-
const restrictedPaths = [n8nFolder, staticCacheDir];
|
|
1524
|
-
if (process.env[constants_1.CONFIG_FILES]) {
|
|
1525
|
-
restrictedPaths.push(...process.env[constants_1.CONFIG_FILES].split(','));
|
|
1526
|
-
}
|
|
1527
|
-
if (process.env[constants_1.CUSTOM_EXTENSION_ENV]) {
|
|
1528
|
-
const customExtensionFolders = process.env[constants_1.CUSTOM_EXTENSION_ENV].split(';');
|
|
1529
|
-
restrictedPaths.push(...customExtensionFolders);
|
|
1530
|
-
}
|
|
1531
|
-
if (process.env[constants_1.BINARY_DATA_STORAGE_PATH]) {
|
|
1532
|
-
restrictedPaths.push(process.env[constants_1.BINARY_DATA_STORAGE_PATH]);
|
|
1533
|
-
}
|
|
1534
|
-
if (process.env[constants_1.UM_EMAIL_TEMPLATES_INVITE]) {
|
|
1535
|
-
restrictedPaths.push(process.env[constants_1.UM_EMAIL_TEMPLATES_INVITE]);
|
|
1536
|
-
}
|
|
1537
|
-
if (process.env[constants_1.UM_EMAIL_TEMPLATES_PWRESET]) {
|
|
1538
|
-
restrictedPaths.push(process.env[constants_1.UM_EMAIL_TEMPLATES_PWRESET]);
|
|
1539
|
-
}
|
|
1540
|
-
for (const path of restrictedPaths) {
|
|
1541
|
-
if (resolvedFilePath.startsWith(path)) {
|
|
1542
|
-
return true;
|
|
1543
|
-
}
|
|
1544
|
-
}
|
|
1545
|
-
}
|
|
1546
|
-
return false;
|
|
1547
|
-
}
|
|
1548
|
-
const getFileSystemHelperFunctions = (node) => ({
|
|
1549
|
-
async createReadStream(filePath) {
|
|
1550
|
-
try {
|
|
1551
|
-
await (0, promises_1.access)(filePath);
|
|
1552
|
-
}
|
|
1553
|
-
catch (error) {
|
|
1554
|
-
throw error.code === 'ENOENT'
|
|
1555
|
-
? new n8n_workflow_1.NodeOperationError(node, error, {
|
|
1556
|
-
message: `The file "${String(filePath)}" could not be accessed.`,
|
|
1557
|
-
level: 'warning',
|
|
1558
|
-
})
|
|
1559
|
-
: error;
|
|
1560
|
-
}
|
|
1561
|
-
if (isFilePathBlocked(filePath)) {
|
|
1562
|
-
const allowedPaths = getAllowedPaths();
|
|
1563
|
-
const message = allowedPaths.length ? ` Allowed paths: ${allowedPaths.join(', ')}` : '';
|
|
1564
|
-
throw new n8n_workflow_1.NodeOperationError(node, `Access to the file is not allowed.${message}`, {
|
|
1565
|
-
level: 'warning',
|
|
1566
|
-
});
|
|
1567
|
-
}
|
|
1568
|
-
return (0, fs_1.createReadStream)(filePath);
|
|
1569
|
-
},
|
|
1570
|
-
getStoragePath() {
|
|
1571
|
-
return path_1.default.join(di_1.Container.get(instance_settings_1.InstanceSettings).n8nFolder, `storage/${node.type}`);
|
|
1572
|
-
},
|
|
1573
|
-
async writeContentToFile(filePath, content, flag) {
|
|
1574
|
-
if (isFilePathBlocked(filePath)) {
|
|
1575
|
-
throw new n8n_workflow_1.NodeOperationError(node, `The file "${String(filePath)}" is not writable.`, {
|
|
1576
|
-
level: 'warning',
|
|
1577
|
-
});
|
|
1578
|
-
}
|
|
1579
|
-
return await (0, promises_1.writeFile)(filePath, content, { encoding: 'binary', flag });
|
|
1580
|
-
},
|
|
1581
|
-
});
|
|
1582
|
-
exports.getFileSystemHelperFunctions = getFileSystemHelperFunctions;
|
|
1583
|
-
const getNodeHelperFunctions = ({ executionId }, workflowId) => ({
|
|
1584
|
-
copyBinaryFile: async (filePath, fileName, mimeType) => await copyBinaryFile(workflowId, executionId, filePath, fileName, mimeType),
|
|
1585
|
-
});
|
|
1586
|
-
exports.getNodeHelperFunctions = getNodeHelperFunctions;
|
|
1587
|
-
const getBinaryHelperFunctions = ({ executionId }, workflowId) => ({
|
|
1588
|
-
getBinaryPath,
|
|
1589
|
-
getBinaryStream,
|
|
1590
|
-
getBinaryMetadata,
|
|
1591
|
-
binaryToBuffer: utils_1.binaryToBuffer,
|
|
1592
|
-
binaryToString,
|
|
1593
|
-
prepareBinaryData: async (binaryData, filePath, mimeType) => await prepareBinaryData(binaryData, executionId, workflowId, filePath, mimeType),
|
|
1594
|
-
setBinaryDataBuffer: async (data, binaryData) => await setBinaryDataBuffer(data, binaryData, workflowId, executionId),
|
|
1595
|
-
copyBinaryFile: async () => {
|
|
1596
|
-
throw new n8n_workflow_1.ApplicationError('`copyBinaryFile` has been removed. Please upgrade this node.');
|
|
1597
|
-
},
|
|
1598
|
-
});
|
|
1599
|
-
exports.getBinaryHelperFunctions = getBinaryHelperFunctions;
|
|
1600
|
-
const getCheckProcessedHelperFunctions = (workflow, node) => ({
|
|
1601
|
-
async checkProcessedAndRecord(items, scope, options) {
|
|
1602
|
-
return await checkProcessedAndRecord(items, scope, { node, workflow }, options);
|
|
1603
|
-
},
|
|
1604
|
-
async checkProcessedItemsAndRecord(propertyName, items, scope, options) {
|
|
1605
|
-
return await checkProcessedItemsAndRecord(propertyName, items, scope, { node, workflow }, options);
|
|
1606
|
-
},
|
|
1607
|
-
async removeProcessed(items, scope, options) {
|
|
1608
|
-
return await removeProcessed(items, scope, { node, workflow }, options);
|
|
1609
|
-
},
|
|
1610
|
-
async clearAllProcessedItems(scope, options) {
|
|
1611
|
-
return await clearAllProcessedItems(scope, { node, workflow }, options);
|
|
1612
|
-
},
|
|
1613
|
-
async getProcessedDataCount(scope, options) {
|
|
1614
|
-
return await getProcessedDataCount(scope, { node, workflow }, options);
|
|
1615
|
-
},
|
|
1616
|
-
});
|
|
1617
|
-
exports.getCheckProcessedHelperFunctions = getCheckProcessedHelperFunctions;
|
|
1618
|
-
function copyInputItems(items, properties) {
|
|
1619
|
-
return items.map((item) => {
|
|
1620
|
-
const newItem = {};
|
|
1621
|
-
for (const property of properties) {
|
|
1622
|
-
if (item.json[property] === undefined) {
|
|
1623
|
-
newItem[property] = null;
|
|
1624
|
-
}
|
|
1625
|
-
else {
|
|
1626
|
-
newItem[property] = (0, n8n_workflow_1.deepCopy)(item.json[property]);
|
|
1627
|
-
}
|
|
1628
|
-
}
|
|
1629
|
-
return newItem;
|
|
1630
|
-
});
|
|
1631
|
-
}
|
|
1632
6
|
function getExecutePollFunctions(workflow, node, additionalData, mode, activation) {
|
|
1633
7
|
return new node_execution_context_1.PollContext(workflow, node, additionalData, mode, activation);
|
|
1634
8
|
}
|