mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 10:02:05 +00:00
fix: Upgrade axios to address CVE-2023-45857 (#7713)
[GH Advisory](https://github.com/advisories/GHSA-wf5p-g6vw-rhxx)
This commit is contained in:
committed by
GitHub
parent
8e6b951a76
commit
64eb9bbc36
@@ -16,6 +16,7 @@ import type {
|
||||
import { ClientOAuth2 } from '@n8n/client-oauth2';
|
||||
import type {
|
||||
AxiosError,
|
||||
AxiosHeaders,
|
||||
AxiosPromise,
|
||||
AxiosProxyConfig,
|
||||
AxiosRequestConfig,
|
||||
@@ -186,23 +187,24 @@ const createFormDataObject = (data: Record<string, unknown>) => {
|
||||
});
|
||||
return formData;
|
||||
};
|
||||
function searchForHeader(headers: IDataObject, headerName: string) {
|
||||
if (headers === undefined) {
|
||||
|
||||
function searchForHeader(config: AxiosRequestConfig, headerName: string) {
|
||||
if (config.headers === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const headerNames = Object.keys(headers);
|
||||
const headerNames = Object.keys(config.headers);
|
||||
headerName = headerName.toLowerCase();
|
||||
return headerNames.find((thisHeader) => thisHeader.toLowerCase() === headerName);
|
||||
}
|
||||
|
||||
async function generateContentLengthHeader(formData: FormData, headers: IDataObject) {
|
||||
if (!formData?.getLength) {
|
||||
async function generateContentLengthHeader(config: AxiosRequestConfig) {
|
||||
if (!(config.data instanceof FormData)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const length = await new Promise((res, rej) => {
|
||||
formData.getLength((error: Error | null, length: number) => {
|
||||
const length = await new Promise<number>((res, rej) => {
|
||||
config.data.getLength((error: Error | null, length: number) => {
|
||||
if (error) {
|
||||
rej(error);
|
||||
return;
|
||||
@@ -210,9 +212,10 @@ async function generateContentLengthHeader(formData: FormData, headers: IDataObj
|
||||
res(length);
|
||||
});
|
||||
});
|
||||
headers = Object.assign(headers, {
|
||||
config.headers = {
|
||||
...config.headers,
|
||||
'content-length': length,
|
||||
});
|
||||
};
|
||||
} catch (error) {
|
||||
Logger.error('Unable to calculate form data length', { error });
|
||||
}
|
||||
@@ -228,7 +231,7 @@ async function parseRequestObject(requestObject: IDataObject) {
|
||||
const axiosConfig: AxiosRequestConfig = {};
|
||||
|
||||
if (requestObject.headers !== undefined) {
|
||||
axiosConfig.headers = requestObject.headers as string;
|
||||
axiosConfig.headers = requestObject.headers as AxiosHeaders;
|
||||
}
|
||||
|
||||
// Let's start parsing the hardest part, which is the request body.
|
||||
@@ -246,7 +249,7 @@ async function parseRequestObject(requestObject: IDataObject) {
|
||||
);
|
||||
const contentType =
|
||||
contentTypeHeaderKeyName &&
|
||||
(axiosConfig.headers[contentTypeHeaderKeyName] as string | undefined);
|
||||
(axiosConfig.headers?.[contentTypeHeaderKeyName] as string | undefined);
|
||||
if (contentType === 'application/x-www-form-urlencoded' && requestObject.formData === undefined) {
|
||||
// there are nodes incorrectly created, informing the content type header
|
||||
// and also using formData. Request lib takes precedence for the formData.
|
||||
@@ -265,7 +268,7 @@ async function parseRequestObject(requestObject: IDataObject) {
|
||||
axiosConfig.data = stringify(allData);
|
||||
}
|
||||
}
|
||||
} else if (contentType && contentType.includes('multipart/form-data') !== false) {
|
||||
} else if (contentType?.includes('multipart/form-data')) {
|
||||
if (requestObject.formData !== undefined && requestObject.formData instanceof FormData) {
|
||||
axiosConfig.data = requestObject.formData;
|
||||
} else {
|
||||
@@ -278,10 +281,10 @@ async function parseRequestObject(requestObject: IDataObject) {
|
||||
}
|
||||
// replace the existing header with a new one that
|
||||
// contains the boundary property.
|
||||
delete axiosConfig.headers[contentTypeHeaderKeyName];
|
||||
delete axiosConfig.headers?.[contentTypeHeaderKeyName!];
|
||||
const headers = axiosConfig.data.getHeaders();
|
||||
axiosConfig.headers = Object.assign(axiosConfig.headers || {}, headers);
|
||||
await generateContentLengthHeader(axiosConfig.data, axiosConfig.headers);
|
||||
await generateContentLengthHeader(axiosConfig);
|
||||
} else {
|
||||
// When using the `form` property it means the content should be x-www-form-urlencoded.
|
||||
if (requestObject.form !== undefined && requestObject.body === undefined) {
|
||||
@@ -291,7 +294,7 @@ async function parseRequestObject(requestObject: IDataObject) {
|
||||
? stringify(requestObject.form, { format: 'RFC3986' })
|
||||
: stringify(requestObject.form).toString();
|
||||
if (axiosConfig.headers !== undefined) {
|
||||
const headerName = searchForHeader(axiosConfig.headers, 'content-type');
|
||||
const headerName = searchForHeader(axiosConfig, 'content-type');
|
||||
if (headerName) {
|
||||
delete axiosConfig.headers[headerName];
|
||||
}
|
||||
@@ -305,9 +308,11 @@ async function parseRequestObject(requestObject: IDataObject) {
|
||||
// remove any "content-type" that might exist.
|
||||
if (axiosConfig.headers !== undefined) {
|
||||
const headers = Object.keys(axiosConfig.headers);
|
||||
headers.forEach((header) =>
|
||||
header.toLowerCase() === 'content-type' ? delete axiosConfig.headers[header] : null,
|
||||
);
|
||||
headers.forEach((header) => {
|
||||
if (header.toLowerCase() === 'content-type') {
|
||||
delete axiosConfig.headers?.[header];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (requestObject.formData instanceof FormData) {
|
||||
@@ -318,7 +323,7 @@ async function parseRequestObject(requestObject: IDataObject) {
|
||||
// Mix in headers as FormData creates the boundary.
|
||||
const headers = axiosConfig.data.getHeaders();
|
||||
axiosConfig.headers = Object.assign(axiosConfig.headers || {}, headers);
|
||||
await generateContentLengthHeader(axiosConfig.data, axiosConfig.headers);
|
||||
await generateContentLengthHeader(axiosConfig);
|
||||
} else if (requestObject.body !== undefined) {
|
||||
// If we have body and possibly form
|
||||
if (requestObject.form !== undefined && requestObject.body) {
|
||||
@@ -755,7 +760,7 @@ export async function proxyRequestToAxios(
|
||||
return configObject.resolveWithFullResponse
|
||||
? {
|
||||
body,
|
||||
headers: response.headers,
|
||||
headers: { ...response.headers },
|
||||
statusCode: response.status,
|
||||
statusMessage: response.statusText,
|
||||
request: response.request,
|
||||
@@ -852,7 +857,7 @@ function convertN8nRequestToAxios(n8nRequest: IHttpRequestOptions): AxiosRequest
|
||||
const { body } = n8nRequest;
|
||||
if (body) {
|
||||
// Let's add some useful header standards here.
|
||||
const existingContentTypeHeaderKey = searchForHeader(axiosRequest.headers, 'content-type');
|
||||
const existingContentTypeHeaderKey = searchForHeader(axiosRequest, 'content-type');
|
||||
if (existingContentTypeHeaderKey === undefined) {
|
||||
axiosRequest.headers = axiosRequest.headers || {};
|
||||
// We are only setting content type headers if the user did
|
||||
@@ -866,7 +871,7 @@ function convertN8nRequestToAxios(n8nRequest: IHttpRequestOptions): AxiosRequest
|
||||
axiosRequest.headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
||||
}
|
||||
} else if (
|
||||
axiosRequest.headers[existingContentTypeHeaderKey] === 'application/x-www-form-urlencoded'
|
||||
axiosRequest.headers?.[existingContentTypeHeaderKey] === 'application/x-www-form-urlencoded'
|
||||
) {
|
||||
axiosRequest.data = new URLSearchParams(n8nRequest.body as Record<string, string>);
|
||||
}
|
||||
@@ -879,19 +884,25 @@ function convertN8nRequestToAxios(n8nRequest: IHttpRequestOptions): AxiosRequest
|
||||
}
|
||||
|
||||
if (n8nRequest.json) {
|
||||
const key = searchForHeader(axiosRequest.headers, 'accept');
|
||||
const key = searchForHeader(axiosRequest, 'accept');
|
||||
// If key exists, then the user has set both accept
|
||||
// header and the json flag. Header should take precedence.
|
||||
if (!key) {
|
||||
axiosRequest.headers.Accept = 'application/json';
|
||||
axiosRequest.headers = {
|
||||
...axiosRequest.headers,
|
||||
Accept: 'application/json',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const userAgentHeader = searchForHeader(axiosRequest.headers, 'user-agent');
|
||||
const userAgentHeader = searchForHeader(axiosRequest, 'user-agent');
|
||||
// If key exists, then the user has set both accept
|
||||
// header and the json flag. Header should take precedence.
|
||||
if (!userAgentHeader) {
|
||||
axiosRequest.headers['User-Agent'] = 'n8n';
|
||||
axiosRequest.headers = {
|
||||
...axiosRequest.headers,
|
||||
'User-Agent': 'n8n',
|
||||
};
|
||||
}
|
||||
|
||||
if (n8nRequest.ignoreHttpStatusErrors) {
|
||||
|
||||
Reference in New Issue
Block a user