2024-04-24 07:28:02 -07:00
|
|
|
import type { IRequestOptions } from 'n8n-workflow';
|
2024-06-05 00:25:39 -07:00
|
|
|
import {
|
|
|
|
REDACTED,
|
|
|
|
prepareRequestBody,
|
|
|
|
sanitizeUiMessage,
|
|
|
|
setAgentOptions,
|
|
|
|
} from '../../GenericFunctions';
|
2023-03-31 09:31:03 -07:00
|
|
|
import type { BodyParameter, BodyParametersReducer } from '../../GenericFunctions';
|
|
|
|
|
2024-06-05 00:25:39 -07:00
|
|
|
describe('HTTP Node Utils', () => {
|
|
|
|
describe('prepareRequestBody', () => {
|
|
|
|
it('should call default reducer', async () => {
|
|
|
|
const bodyParameters: BodyParameter[] = [
|
|
|
|
{
|
|
|
|
name: 'foo.bar',
|
|
|
|
value: 'baz',
|
|
|
|
},
|
|
|
|
];
|
|
|
|
const defaultReducer: BodyParametersReducer = jest.fn();
|
2023-03-31 09:31:03 -07:00
|
|
|
|
2024-06-05 00:25:39 -07:00
|
|
|
await prepareRequestBody(bodyParameters, 'json', 3, defaultReducer);
|
2023-03-31 09:31:03 -07:00
|
|
|
|
2024-06-05 00:25:39 -07:00
|
|
|
expect(defaultReducer).toBeCalledTimes(1);
|
|
|
|
expect(defaultReducer).toBeCalledWith({}, { name: 'foo.bar', value: 'baz' });
|
|
|
|
});
|
2023-03-31 09:31:03 -07:00
|
|
|
|
2024-06-05 00:25:39 -07:00
|
|
|
it('should call process dot notations', async () => {
|
|
|
|
const bodyParameters: BodyParameter[] = [
|
|
|
|
{
|
|
|
|
name: 'foo.bar.spam',
|
|
|
|
value: 'baz',
|
|
|
|
},
|
|
|
|
];
|
|
|
|
const defaultReducer: BodyParametersReducer = jest.fn();
|
2023-03-31 09:31:03 -07:00
|
|
|
|
2024-06-05 00:25:39 -07:00
|
|
|
const result = await prepareRequestBody(bodyParameters, 'json', 4, defaultReducer);
|
2023-03-31 09:31:03 -07:00
|
|
|
|
2024-06-05 00:25:39 -07:00
|
|
|
expect(defaultReducer).toBeCalledTimes(0);
|
|
|
|
expect(result).toBeDefined();
|
|
|
|
expect(result).toEqual({ foo: { bar: { spam: 'baz' } } });
|
|
|
|
});
|
2023-03-31 09:31:03 -07:00
|
|
|
});
|
2024-04-24 07:28:02 -07:00
|
|
|
|
2024-06-05 00:25:39 -07:00
|
|
|
describe('setAgentOptions', () => {
|
|
|
|
it("should not have agentOptions as it's undefined", async () => {
|
|
|
|
const requestOptions: IRequestOptions = {
|
|
|
|
method: 'GET',
|
|
|
|
uri: 'https://example.com',
|
|
|
|
};
|
2024-04-24 07:28:02 -07:00
|
|
|
|
2024-06-05 00:25:39 -07:00
|
|
|
const sslCertificates = undefined;
|
2024-04-24 07:28:02 -07:00
|
|
|
|
2024-06-05 00:25:39 -07:00
|
|
|
setAgentOptions(requestOptions, sslCertificates);
|
2024-04-24 07:28:02 -07:00
|
|
|
|
2024-06-05 00:25:39 -07:00
|
|
|
expect(requestOptions).toEqual({
|
|
|
|
method: 'GET',
|
|
|
|
uri: 'https://example.com',
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should have agentOptions set', async () => {
|
|
|
|
const requestOptions: IRequestOptions = {
|
|
|
|
method: 'GET',
|
|
|
|
uri: 'https://example.com',
|
|
|
|
};
|
|
|
|
|
|
|
|
const sslCertificates = {
|
|
|
|
ca: 'mock-ca',
|
|
|
|
};
|
|
|
|
|
|
|
|
setAgentOptions(requestOptions, sslCertificates);
|
|
|
|
|
|
|
|
expect(requestOptions).toStrictEqual({
|
|
|
|
method: 'GET',
|
|
|
|
uri: 'https://example.com',
|
|
|
|
agentOptions: {
|
|
|
|
ca: 'mock-ca',
|
|
|
|
},
|
|
|
|
});
|
2024-04-24 07:28:02 -07:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2024-06-05 00:25:39 -07:00
|
|
|
describe('sanitizeUiMessage', () => {
|
|
|
|
it('should remove large Buffers', async () => {
|
|
|
|
const requestOptions: IRequestOptions = {
|
|
|
|
method: 'POST',
|
|
|
|
uri: 'https://example.com',
|
|
|
|
body: Buffer.alloc(900000),
|
|
|
|
};
|
2024-04-24 07:28:02 -07:00
|
|
|
|
2024-06-05 00:25:39 -07:00
|
|
|
expect(sanitizeUiMessage(requestOptions, {}).body).toEqual(
|
|
|
|
'Binary data got replaced with this text. Original was a Buffer with a size of 900000 bytes.',
|
|
|
|
);
|
|
|
|
});
|
2024-04-24 07:28:02 -07:00
|
|
|
|
2024-09-23 01:10:31 -07:00
|
|
|
it('should remove keys that contain sensitive data and do not modify requestOptions', async () => {
|
2024-06-05 00:25:39 -07:00
|
|
|
const requestOptions: IRequestOptions = {
|
|
|
|
method: 'POST',
|
|
|
|
uri: 'https://example.com',
|
|
|
|
body: { sessionToken: 'secret', other: 'foo' },
|
|
|
|
headers: { authorization: 'secret', other: 'foo' },
|
|
|
|
auth: { user: 'user', password: 'secret' },
|
|
|
|
};
|
2024-04-24 07:28:02 -07:00
|
|
|
|
2024-06-05 00:25:39 -07:00
|
|
|
expect(
|
|
|
|
sanitizeUiMessage(requestOptions, {
|
|
|
|
headers: ['authorization'],
|
|
|
|
body: ['sessionToken'],
|
|
|
|
auth: ['password'],
|
|
|
|
}),
|
|
|
|
).toEqual({
|
|
|
|
body: { sessionToken: REDACTED, other: 'foo' },
|
|
|
|
headers: { other: 'foo', authorization: REDACTED },
|
|
|
|
auth: { user: 'user', password: REDACTED },
|
|
|
|
method: 'POST',
|
|
|
|
uri: 'https://example.com',
|
|
|
|
});
|
2024-09-23 01:10:31 -07:00
|
|
|
|
|
|
|
expect(requestOptions).toEqual({
|
|
|
|
method: 'POST',
|
|
|
|
uri: 'https://example.com',
|
|
|
|
body: { sessionToken: 'secret', other: 'foo' },
|
|
|
|
headers: { authorization: 'secret', other: 'foo' },
|
|
|
|
auth: { user: 'user', password: 'secret' },
|
|
|
|
});
|
2024-06-05 00:25:39 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should remove secrets', async () => {
|
|
|
|
const requestOptions: IRequestOptions = {
|
|
|
|
method: 'POST',
|
|
|
|
uri: 'https://example.com',
|
|
|
|
body: { nested: { secret: 'secretAccessToken' } },
|
|
|
|
headers: { authorization: 'secretAccessToken', other: 'foo' },
|
|
|
|
};
|
|
|
|
|
2024-09-23 01:10:31 -07:00
|
|
|
const sanitizedRequest = sanitizeUiMessage(requestOptions, {}, ['secretAccessToken']);
|
|
|
|
|
|
|
|
expect(sanitizedRequest).toEqual({
|
2024-06-05 00:25:39 -07:00
|
|
|
body: {
|
|
|
|
nested: {
|
|
|
|
secret: REDACTED,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
headers: { authorization: REDACTED, other: 'foo' },
|
|
|
|
method: 'POST',
|
|
|
|
uri: 'https://example.com',
|
|
|
|
});
|
2024-04-24 07:28:02 -07:00
|
|
|
});
|
2024-08-29 07:28:03 -07:00
|
|
|
|
|
|
|
const headersToTest = [
|
|
|
|
'authorization',
|
|
|
|
'x-api-key',
|
|
|
|
'x-auth-token',
|
|
|
|
'cookie',
|
|
|
|
'proxy-authorization',
|
|
|
|
'sslclientcert',
|
|
|
|
];
|
|
|
|
|
|
|
|
headersToTest.forEach((header) => {
|
|
|
|
it(`should redact the ${header} header when the key is lowercase`, () => {
|
|
|
|
const requestOptions: IRequestOptions = {
|
|
|
|
method: 'POST',
|
|
|
|
uri: 'https://example.com',
|
|
|
|
body: { sessionToken: 'secret', other: 'foo' },
|
|
|
|
headers: { [header]: 'some-sensitive-token', other: 'foo' },
|
|
|
|
auth: { user: 'user', password: 'secret' },
|
|
|
|
};
|
|
|
|
|
|
|
|
const sanitizedRequest = sanitizeUiMessage(requestOptions, {});
|
|
|
|
|
|
|
|
expect(sanitizedRequest.headers).toEqual({ [header]: REDACTED, other: 'foo' });
|
|
|
|
});
|
|
|
|
|
|
|
|
it(`should redact the ${header} header when the key is uppercase`, () => {
|
|
|
|
const requestOptions: IRequestOptions = {
|
|
|
|
method: 'POST',
|
|
|
|
uri: 'https://example.com',
|
|
|
|
body: { sessionToken: 'secret', other: 'foo' },
|
|
|
|
headers: { [header.toUpperCase()]: 'some-sensitive-token', other: 'foo' },
|
|
|
|
auth: { user: 'user', password: 'secret' },
|
|
|
|
};
|
|
|
|
|
|
|
|
const sanitizedRequest = sanitizeUiMessage(requestOptions, {});
|
|
|
|
|
|
|
|
expect(sanitizedRequest.headers).toEqual({
|
|
|
|
[header.toUpperCase()]: REDACTED,
|
|
|
|
other: 'foo',
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should leave headers unchanged if Authorization header is not present', () => {
|
|
|
|
const requestOptions: IRequestOptions = {
|
|
|
|
method: 'POST',
|
|
|
|
uri: 'https://example.com',
|
|
|
|
body: { sessionToken: 'secret', other: 'foo' },
|
|
|
|
headers: { other: 'foo' },
|
|
|
|
auth: { user: 'user', password: 'secret' },
|
|
|
|
};
|
|
|
|
const sanitizedRequest = sanitizeUiMessage(requestOptions, {});
|
|
|
|
|
|
|
|
expect(sanitizedRequest.headers).toEqual({ other: 'foo' });
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should handle case when headers are undefined', () => {
|
|
|
|
const requestOptions: IRequestOptions = {};
|
|
|
|
|
|
|
|
const sanitizedRequest = sanitizeUiMessage(requestOptions, {});
|
|
|
|
|
|
|
|
expect(sanitizedRequest.headers).toBeUndefined();
|
|
|
|
});
|
2024-04-24 07:28:02 -07:00
|
|
|
});
|
|
|
|
});
|