1
1
mirror of https://github.com/n8n-io/n8n.git synced 2024-09-19 17:07:18 +03:00

fix(core): Use hostname from URL instead of Host header for SNI (#8562)

This commit is contained in:
Elias Meire 2024-02-06 19:38:36 +01:00 committed by GitHub
parent 76f317074e
commit 7531f34386
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 52 additions and 13 deletions

View File

@ -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) => {

View File

@ -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(