mirror of
https://github.com/n8n-io/n8n.git
synced 2024-09-20 01:19:07 +03:00
fix(core): Use hostname from URL instead of Host header for SNI (#8562)
This commit is contained in:
parent
76f317074e
commit
7531f34386
@ -31,7 +31,7 @@ import FormData from 'form-data';
|
||||
import { createReadStream } from 'fs';
|
||||
import { access as fsAccess, writeFile as fsWriteFile } from 'fs/promises';
|
||||
import { IncomingMessage, type IncomingHttpHeaders } from 'http';
|
||||
import { Agent } from 'https';
|
||||
import { Agent, type AgentOptions } from 'https';
|
||||
import get from 'lodash/get';
|
||||
import pick from 'lodash/pick';
|
||||
import { extension, lookup } from 'mime-types';
|
||||
@ -229,7 +229,22 @@ async function generateContentLengthHeader(config: AxiosRequestConfig) {
|
||||
}
|
||||
}
|
||||
|
||||
async function parseRequestObject(requestObject: IDataObject) {
|
||||
const getHostFromRequestObject = (
|
||||
requestObject: Partial<{
|
||||
url: string;
|
||||
uri: string;
|
||||
baseURL: string;
|
||||
}>,
|
||||
): string | null => {
|
||||
try {
|
||||
const url = (requestObject.url ?? requestObject.uri) as string;
|
||||
return new URL(url, requestObject.baseURL).hostname;
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export async function parseRequestObject(requestObject: IDataObject) {
|
||||
// This function is a temporary implementation
|
||||
// That translates all http requests done via
|
||||
// the request library to axios directly
|
||||
@ -468,6 +483,17 @@ async function parseRequestObject(requestObject: IDataObject) {
|
||||
});
|
||||
}
|
||||
|
||||
const host = getHostFromRequestObject(requestObject);
|
||||
const agentOptions: AgentOptions = {};
|
||||
if (host) {
|
||||
agentOptions.servername = host;
|
||||
}
|
||||
if (requestObject.rejectUnauthorized === false) {
|
||||
agentOptions.rejectUnauthorized = false;
|
||||
agentOptions.secureOptions = crypto.constants.SSL_OP_LEGACY_SERVER_CONNECT;
|
||||
}
|
||||
axiosConfig.httpsAgent = new Agent(agentOptions);
|
||||
|
||||
if (requestObject.timeout !== undefined) {
|
||||
axiosConfig.timeout = requestObject.timeout as number;
|
||||
}
|
||||
@ -732,14 +758,11 @@ export async function proxyRequestToAxios(
|
||||
maxBodyLength: Infinity,
|
||||
maxContentLength: Infinity,
|
||||
};
|
||||
let configObject: ConfigObject;
|
||||
if (uriOrObject !== undefined && typeof uriOrObject === 'string') {
|
||||
axiosConfig.url = uriOrObject;
|
||||
}
|
||||
if (uriOrObject !== undefined && typeof uriOrObject === 'object') {
|
||||
configObject = uriOrObject;
|
||||
let configObject: ConfigObject & { uri?: string };
|
||||
if (typeof uriOrObject === 'string') {
|
||||
configObject = { uri: uriOrObject, ...options };
|
||||
} else {
|
||||
configObject = options || {};
|
||||
configObject = uriOrObject ?? {};
|
||||
}
|
||||
|
||||
axiosConfig = Object.assign(axiosConfig, await parseRequestObject(configObject));
|
||||
@ -859,11 +882,15 @@ function convertN8nRequestToAxios(n8nRequest: IHttpRequestOptions): AxiosRequest
|
||||
axiosRequest.responseType = n8nRequest.encoding;
|
||||
}
|
||||
|
||||
if (n8nRequest.skipSslCertificateValidation === true) {
|
||||
axiosRequest.httpsAgent = new Agent({
|
||||
rejectUnauthorized: false,
|
||||
});
|
||||
const host = getHostFromRequestObject(n8nRequest);
|
||||
const agentOptions: AgentOptions = {};
|
||||
if (host) {
|
||||
agentOptions.servername = host;
|
||||
}
|
||||
if (n8nRequest.skipSslCertificateValidation === true) {
|
||||
agentOptions.rejectUnauthorized = false;
|
||||
}
|
||||
axiosRequest.httpsAgent = new Agent(agentOptions);
|
||||
|
||||
if (n8nRequest.arrayFormat !== undefined) {
|
||||
axiosRequest.paramsSerializer = (params) => {
|
||||
|
@ -2,6 +2,7 @@ import {
|
||||
copyInputItems,
|
||||
getBinaryDataBuffer,
|
||||
parseIncomingMessage,
|
||||
parseRequestObject,
|
||||
proxyRequestToAxios,
|
||||
setBinaryDataBuffer,
|
||||
} from '@/NodeExecuteFunctions';
|
||||
@ -21,6 +22,7 @@ import nock from 'nock';
|
||||
import { tmpdir } from 'os';
|
||||
import { join } from 'path';
|
||||
import Container from 'typedi';
|
||||
import type { Agent } from 'https';
|
||||
|
||||
const temporaryDir = mkdtempSync(join(tmpdir(), 'n8n'));
|
||||
|
||||
@ -358,6 +360,16 @@ describe('NodeExecuteFunctions', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseRequestObject', () => {
|
||||
test('should not use Host header for SNI', async () => {
|
||||
const axiosOptions = await parseRequestObject({
|
||||
url: 'https://example.de/foo/bar',
|
||||
headers: { Host: 'other.host.com' },
|
||||
});
|
||||
expect((axiosOptions.httpsAgent as Agent).options.servername).toEqual('example.de');
|
||||
});
|
||||
});
|
||||
|
||||
describe('copyInputItems', () => {
|
||||
it('should pick only selected properties', () => {
|
||||
const output = copyInputItems(
|
||||
|
Loading…
Reference in New Issue
Block a user