From bf8d7e8cdadfe5a175ac0622e3eb6a886400e1e6 Mon Sep 17 00:00:00 2001 From: Brian Date: Thu, 8 Nov 2018 11:57:09 -0500 Subject: [PATCH] Typescripted the common functions and broke out tests to individual test files --- .../add_force_now_query_string.test.ts | 94 ++++++ ...tring.js => add_force_now_query_string.ts} | 39 ++- .../execute_job/decrypt_job_headers.test.ts | 77 +++++ ..._job_headers.js => decrypt_job_headers.ts} | 14 +- ...e_url.test.js => get_absolute_url.test.ts} | 37 ++- ...et_absolute_url.js => get_absolute_url.ts} | 14 +- .../get_conditional_headers.test.ts | 213 +++++++++++++ ..._headers.js => get_conditional_headers.ts} | 19 +- .../execute_job/get_custom_logo.test.ts | 68 +++++ ...{get_custom_logo.js => get_custom_logo.ts} | 24 +- .../common/execute_job/index.test.js | 288 ------------------ .../common/execute_job/{index.js => index.ts} | 4 +- .../omit_blacklisted_headers.test.ts | 71 +++++ ...headers.js => omit_blacklisted_headers.ts} | 18 +- x-pack/plugins/reporting/types.d.ts | 32 +- 15 files changed, 662 insertions(+), 350 deletions(-) create mode 100644 x-pack/plugins/reporting/export_types/common/execute_job/add_force_now_query_string.test.ts rename x-pack/plugins/reporting/export_types/common/execute_job/{add_forcenow_querystring.js => add_force_now_query_string.ts} (57%) create mode 100644 x-pack/plugins/reporting/export_types/common/execute_job/decrypt_job_headers.test.ts rename x-pack/plugins/reporting/export_types/common/execute_job/{decrypt_job_headers.js => decrypt_job_headers.ts} (51%) rename x-pack/plugins/reporting/export_types/common/execute_job/{get_absolute_url.test.js => get_absolute_url.test.ts} (83%) rename x-pack/plugins/reporting/export_types/common/execute_job/{get_absolute_url.js => get_absolute_url.ts} (79%) create mode 100644 x-pack/plugins/reporting/export_types/common/execute_job/get_conditional_headers.test.ts rename x-pack/plugins/reporting/export_types/common/execute_job/{get_conditional_headers.js => get_conditional_headers.ts} (64%) create mode 100644 x-pack/plugins/reporting/export_types/common/execute_job/get_custom_logo.test.ts rename x-pack/plugins/reporting/export_types/common/execute_job/{get_custom_logo.js => get_custom_logo.ts} (63%) delete mode 100644 x-pack/plugins/reporting/export_types/common/execute_job/index.test.js rename x-pack/plugins/reporting/export_types/common/execute_job/{index.js => index.ts} (88%) create mode 100644 x-pack/plugins/reporting/export_types/common/execute_job/omit_blacklisted_headers.test.ts rename x-pack/plugins/reporting/export_types/common/execute_job/{omit_blacklisted_headers.js => omit_blacklisted_headers.ts} (52%) diff --git a/x-pack/plugins/reporting/export_types/common/execute_job/add_force_now_query_string.test.ts b/x-pack/plugins/reporting/export_types/common/execute_job/add_force_now_query_string.test.ts new file mode 100644 index 000000000000000..ca544fb325f3e59 --- /dev/null +++ b/x-pack/plugins/reporting/export_types/common/execute_job/add_force_now_query_string.test.ts @@ -0,0 +1,94 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { memoize } from 'lodash'; +// import { KbnServer } from '../../../types'; +import { addForceNowQuerystring } from './index'; + +let config: any; +let mockServer: any; +beforeEach(() => { + config = { + 'xpack.reporting.encryptionKey': 'testencryptionkey', + 'server.basePath': '/sbp', + 'server.host': 'localhost', + 'server.port': 5601, + }; + mockServer = { + expose: () => { + ' '; + }, + config: memoize(() => ({ get: jest.fn() })), + info: { + protocol: 'http', + }, + plugins: { + elasticsearch: { + getCluster: memoize(() => { + return { + callWithRequest: jest.fn(), + }; + }), + }, + }, + savedObjects: { + getScopedSavedObjectsClient: jest.fn(), + }, + uiSettingsServiceFactory: jest.fn().mockReturnValue({ get: jest.fn() }), + }; + + mockServer.config().get.mockImplementation((key: any) => { + return config[key]; + }); +}); + +test(`fails if no URL is passed`, async () => { + await expect( + addForceNowQuerystring({ + job: {}, + server: mockServer, + }) + ).rejects.toBeDefined(); +}); + +test(`adds forceNow to hash's query, if it exists`, async () => { + const forceNow = '2000-01-01T00:00:00.000Z'; + const { urls } = await addForceNowQuerystring({ + job: { relativeUrl: '/app/kibana#/something', forceNow }, + server: mockServer, + }); + + expect(urls[0]).toEqual( + 'http://localhost:5601/sbp/app/kibana#/something?forceNow=2000-01-01T00%3A00%3A00.000Z' + ); +}); + +test(`appends forceNow to hash's query, if it exists`, async () => { + const forceNow = '2000-01-01T00:00:00.000Z'; + + const { urls } = await addForceNowQuerystring({ + job: { + relativeUrl: '/app/kibana#/something?_g=something', + forceNow, + }, + server: mockServer, + }); + + expect(urls[0]).toEqual( + 'http://localhost:5601/sbp/app/kibana#/something?_g=something&forceNow=2000-01-01T00%3A00%3A00.000Z' + ); +}); + +test(`doesn't append forceNow query to url, if it doesn't exists`, async () => { + const { urls } = await addForceNowQuerystring({ + job: { + relativeUrl: '/app/kibana#/something', + }, + server: mockServer, + }); + + expect(urls[0]).toEqual('http://localhost:5601/sbp/app/kibana#/something'); +}); diff --git a/x-pack/plugins/reporting/export_types/common/execute_job/add_forcenow_querystring.js b/x-pack/plugins/reporting/export_types/common/execute_job/add_force_now_query_string.ts similarity index 57% rename from x-pack/plugins/reporting/export_types/common/execute_job/add_forcenow_querystring.js rename to x-pack/plugins/reporting/export_types/common/execute_job/add_force_now_query_string.ts index 980831fcfce6efe..33fe23510f0dfb7 100644 --- a/x-pack/plugins/reporting/export_types/common/execute_job/add_forcenow_querystring.js +++ b/x-pack/plugins/reporting/export_types/common/execute_job/add_force_now_query_string.ts @@ -3,11 +3,13 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +// @ts-ignore import url from 'url'; +import { ConditionalHeaders, KbnServer, ReportingJob } from '../../../types'; import { getAbsoluteUrlFactory } from './get_absolute_url'; -function getSavedObjectAbsoluteUrl(job, relativeUrl, server) { - const getAbsoluteUrl = getAbsoluteUrlFactory(server); +function getSavedObjectAbsoluteUrl(job: ReportingJob, relativeUrl: string, server: KbnServer) { + const getAbsoluteUrl: any = getAbsoluteUrlFactory(server); if (relativeUrl) { const { pathname: path, hash, search } = url.parse(relativeUrl); @@ -17,37 +19,46 @@ function getSavedObjectAbsoluteUrl(job, relativeUrl, server) { throw new Error(`Unable to generate report. Url is not defined.`); } -export const addForceNowQuerystring = async ({ job, conditionalHeaders, logo, server }) => { - - //if no URLS then its from PNG which should only have one so put it in the array and process as PDF does +export const addForceNowQuerystring = async ({ + job, + conditionalHeaders, + logo, + server, +}: { + job: ReportingJob; + conditionalHeaders?: ConditionalHeaders; + logo?: any; + server: KbnServer; +}) => { + // if no URLS then its from PNG which should only have one so put it in the array and process as PDF does if (!job.urls) { if (!job.relativeUrl) { - throw new Error(`Unable to generate report. Url is not defined.`);} + throw new Error(`Unable to generate report. Url is not defined.`); + } job.urls = [getSavedObjectAbsoluteUrl(job, job.relativeUrl, server)]; } const urls = job.urls.map(jobUrl => { if (!job.forceNow) { - return jobUrl; + return jobUrl; } - const parsed = url.parse(jobUrl, true); - const hash = url.parse(parsed.hash.replace(/^#/, ''), true); + const parsed: any = url.parse(jobUrl, true); + const hash: any = url.parse(parsed.hash.replace(/^#/, ''), true); const transformedHash = url.format({ pathname: hash.pathname, query: { ...hash.query, - forceNow: job.forceNow - } + forceNow: job.forceNow, + }, }); return url.format({ ...parsed, - hash: transformedHash + hash: transformedHash, }); }); return { job, conditionalHeaders, logo, urls, server }; - -}; \ No newline at end of file +}; diff --git a/x-pack/plugins/reporting/export_types/common/execute_job/decrypt_job_headers.test.ts b/x-pack/plugins/reporting/export_types/common/execute_job/decrypt_job_headers.test.ts new file mode 100644 index 000000000000000..68ef3beac735d1b --- /dev/null +++ b/x-pack/plugins/reporting/export_types/common/execute_job/decrypt_job_headers.test.ts @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { memoize } from 'lodash'; +// @ts-ignore +import { cryptoFactory } from '../../../server/lib/crypto'; +import { decryptJobHeaders } from './index'; + +let config: any; +let mockServer: any; +beforeEach(() => { + config = { + 'xpack.reporting.encryptionKey': 'testencryptionkey', + 'server.basePath': '/sbp', + 'server.host': 'localhost', + 'server.port': 5601, + }; + mockServer = { + expose: () => { + ' '; + }, + config: memoize(() => ({ get: jest.fn() })), + info: { + protocol: 'http', + }, + plugins: { + elasticsearch: { + getCluster: memoize(() => { + return { + callWithRequest: jest.fn(), + }; + }), + }, + }, + savedObjects: { + getScopedSavedObjectsClient: jest.fn(), + }, + uiSettingsServiceFactory: jest.fn().mockReturnValue({ get: jest.fn() }), + }; + + mockServer.config().get.mockImplementation((key: any) => { + return config[key]; + }); +}); + +const encryptHeaders = async (headers: Record) => { + const crypto = cryptoFactory(mockServer); + return await crypto.encrypt(headers); +}; + +describe('headers', () => { + test(`fails if it can't decrypt headers`, async () => { + await expect( + decryptJobHeaders({ + job: { relativeUrl: '/app/kibana#/something', timeRange: {} }, + server: mockServer, + }) + ).rejects.toBeDefined(); + }); + + test(`passes back decrypted headers that were passed in`, async () => { + const headers = { + foo: 'bar', + baz: 'quix', + }; + + const encryptedHeaders = await encryptHeaders(headers); + const { decryptedHeaders } = await decryptJobHeaders({ + job: { relativeUrl: '/app/kibana#/something', headers: encryptedHeaders }, + server: mockServer, + }); + expect(decryptedHeaders).toEqual(headers); + }); +}); diff --git a/x-pack/plugins/reporting/export_types/common/execute_job/decrypt_job_headers.js b/x-pack/plugins/reporting/export_types/common/execute_job/decrypt_job_headers.ts similarity index 51% rename from x-pack/plugins/reporting/export_types/common/execute_job/decrypt_job_headers.js rename to x-pack/plugins/reporting/export_types/common/execute_job/decrypt_job_headers.ts index 814afc323dc3fe8..d10d8b51f84eccb 100644 --- a/x-pack/plugins/reporting/export_types/common/execute_job/decrypt_job_headers.js +++ b/x-pack/plugins/reporting/export_types/common/execute_job/decrypt_job_headers.ts @@ -3,10 +3,18 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +// @ts-ignore import { cryptoFactory } from '../../../server/lib/crypto'; +import { CryptoFactory, KbnServer, ReportingJob } from '../../../types'; -export const decryptJobHeaders = async ({ job, server }) => { - const crypto = cryptoFactory(server); - const decryptedHeaders = await crypto.decrypt(job.headers); +export const decryptJobHeaders = async ({ + job, + server, +}: { + job: ReportingJob; + server: KbnServer; +}) => { + const crypto: CryptoFactory = cryptoFactory(server); + const decryptedHeaders: string = await crypto.decrypt(job.headers); return { job, decryptedHeaders, server }; }; diff --git a/x-pack/plugins/reporting/export_types/common/execute_job/get_absolute_url.test.js b/x-pack/plugins/reporting/export_types/common/execute_job/get_absolute_url.test.ts similarity index 83% rename from x-pack/plugins/reporting/export_types/common/execute_job/get_absolute_url.test.js rename to x-pack/plugins/reporting/export_types/common/execute_job/get_absolute_url.test.ts index 39ca6fd52f51e1c..0f87922ba717d63 100644 --- a/x-pack/plugins/reporting/export_types/common/execute_job/get_absolute_url.test.js +++ b/x-pack/plugins/reporting/export_types/common/execute_job/get_absolute_url.test.ts @@ -7,24 +7,26 @@ import { memoize } from 'lodash'; import { getAbsoluteUrlFactory } from './get_absolute_url'; -const createMockServer = ({ settings = {} } = {}) => { +const createMockServer = ({ settings = {} }: any) => { const mockServer = { - expose: () => {}, + expose: () => { + ''; + }, config: memoize(() => { return { - get: jest.fn() + get: jest.fn(), }; }), info: { - protocol: 'http' - } + protocol: 'http', + }, }; - const defaultSettings = { + const defaultSettings: any = { 'server.host': 'something', 'server.port': 8080, 'server.basePath': '/tst', - 'xpack.reporting.kibanaServer': {} + 'xpack.reporting.kibanaServer': {}, }; mockServer.config().get.mockImplementation(key => { return key in settings ? settings[key] : defaultSettings[key]; @@ -34,8 +36,7 @@ const createMockServer = ({ settings = {} } = {}) => { }; test(`by default it builds url using information from server.info.protocol and the server.config`, () => { - const mockServer = createMockServer(); - + const mockServer = createMockServer(''); const getAbsoluteUrl = getAbsoluteUrlFactory(mockServer); const absoluteUrl = getAbsoluteUrl(); expect(absoluteUrl).toBe(`http://something:8080/tst/app/kibana`); @@ -43,7 +44,7 @@ test(`by default it builds url using information from server.info.protocol and t test(`uses kibanaServer.protocol if specified`, () => { const settings = { - 'xpack.reporting.kibanaServer.protocol': 'https' + 'xpack.reporting.kibanaServer.protocol': 'https', }; const mockServer = createMockServer({ settings }); @@ -54,7 +55,7 @@ test(`uses kibanaServer.protocol if specified`, () => { test(`uses kibanaServer.hostname if specified`, () => { const settings = { - 'xpack.reporting.kibanaServer.hostname': 'something-else' + 'xpack.reporting.kibanaServer.hostname': 'something-else', }; const mockServer = createMockServer({ settings }); @@ -65,7 +66,7 @@ test(`uses kibanaServer.hostname if specified`, () => { test(`uses kibanaServer.port if specified`, () => { const settings = { - 'xpack.reporting.kibanaServer.port': 8008 + 'xpack.reporting.kibanaServer.port': 8008, }; const mockServer = createMockServer({ settings }); @@ -75,7 +76,7 @@ test(`uses kibanaServer.port if specified`, () => { }); test(`uses the provided hash`, () => { - const mockServer = createMockServer(); + const mockServer = createMockServer(''); const getAbsoluteUrl = getAbsoluteUrlFactory(mockServer); const hash = '/hash'; @@ -84,7 +85,7 @@ test(`uses the provided hash`, () => { }); test(`uses the provided hash with queryString`, () => { - const mockServer = createMockServer(); + const mockServer = createMockServer(''); const getAbsoluteUrl = getAbsoluteUrlFactory(mockServer); const hash = '/hash?querystring'; @@ -93,7 +94,7 @@ test(`uses the provided hash with queryString`, () => { }); test(`uses the provided basePath`, () => { - const mockServer = createMockServer(); + const mockServer = createMockServer(''); const getAbsoluteUrl = getAbsoluteUrlFactory(mockServer); const absoluteUrl = getAbsoluteUrl({ basePath: '/s/marketing' }); @@ -101,7 +102,7 @@ test(`uses the provided basePath`, () => { }); test(`uses the path`, () => { - const mockServer = createMockServer(); + const mockServer = createMockServer(''); const getAbsoluteUrl = getAbsoluteUrlFactory(mockServer); const path = '/app/canvas'; @@ -110,12 +111,10 @@ test(`uses the path`, () => { }); test(`uses the search`, () => { - const mockServer = createMockServer(); + const mockServer = createMockServer(''); const getAbsoluteUrl = getAbsoluteUrlFactory(mockServer); const search = '_t=123456789'; const absoluteUrl = getAbsoluteUrl({ search }); expect(absoluteUrl).toBe(`http://something:8080/tst/app/kibana?${search}`); }); - - diff --git a/x-pack/plugins/reporting/export_types/common/execute_job/get_absolute_url.js b/x-pack/plugins/reporting/export_types/common/execute_job/get_absolute_url.ts similarity index 79% rename from x-pack/plugins/reporting/export_types/common/execute_job/get_absolute_url.js rename to x-pack/plugins/reporting/export_types/common/execute_job/get_absolute_url.ts index bc3fefe36f04978..04bdb2bc70465e3 100644 --- a/x-pack/plugins/reporting/export_types/common/execute_job/get_absolute_url.js +++ b/x-pack/plugins/reporting/export_types/common/execute_job/get_absolute_url.ts @@ -5,24 +5,26 @@ */ import url from 'url'; +// @ts-ignore import { oncePerServer } from '../../../server/lib/once_per_server'; +import { ConfigObject, KbnServer } from '../../../types'; -function getAbsoluteUrlFn(server) { - const config = server.config(); +function getAbsoluteUrlFn(server: KbnServer) { + const config: ConfigObject = server.config(); return function getAbsoluteUrl({ basePath = config.get('server.basePath'), - hash, + hash = '', path = '/app/kibana', - search + search = '', } = {}) { return url.format({ protocol: config.get('xpack.reporting.kibanaServer.protocol') || server.info.protocol, hostname: config.get('xpack.reporting.kibanaServer.hostname') || config.get('server.host'), port: config.get('xpack.reporting.kibanaServer.port') || config.get('server.port'), pathname: basePath + path, - hash: hash, - search + hash, + search, }); }; } diff --git a/x-pack/plugins/reporting/export_types/common/execute_job/get_conditional_headers.test.ts b/x-pack/plugins/reporting/export_types/common/execute_job/get_conditional_headers.test.ts new file mode 100644 index 000000000000000..be13ce2aebf9e38 --- /dev/null +++ b/x-pack/plugins/reporting/export_types/common/execute_job/get_conditional_headers.test.ts @@ -0,0 +1,213 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { memoize } from 'lodash'; +import { getConditionalHeaders, getCustomLogo } from './index'; + +let config: any; +let mockServer: any; +beforeEach(() => { + config = { + 'xpack.reporting.encryptionKey': 'testencryptionkey', + 'server.basePath': '/sbp', + 'server.host': 'localhost', + 'server.port': 5601, + }; + mockServer = { + expose: () => { + ' '; + }, + config: memoize(() => ({ get: jest.fn() })), + info: { + protocol: 'http', + }, + plugins: { + elasticsearch: { + getCluster: memoize(() => { + return { + callWithRequest: jest.fn(), + }; + }), + }, + }, + savedObjects: { + getScopedSavedObjectsClient: jest.fn(), + }, + uiSettingsServiceFactory: jest.fn().mockReturnValue({ get: jest.fn() }), + }; + + mockServer.config().get.mockImplementation((key: any) => { + return config[key]; + }); +}); + +describe('conditions', () => { + test(`uses hostname from reporting config if set`, async () => { + config['xpack.reporting.kibanaServer.hostname'] = 'custom-hostname'; + const permittedHeaders = { + foo: 'bar', + baz: 'quix', + }; + + const { conditionalHeaders } = await getConditionalHeaders({ + job: {}, + filteredHeaders: permittedHeaders, + server: mockServer, + }); + + expect(conditionalHeaders.conditions.hostname).toEqual( + config['xpack.reporting.kibanaServer.hostname'] + ); + }); + + test(`uses hostname from server.config if reporting config not set`, async () => { + const permittedHeaders = { + foo: 'bar', + baz: 'quix', + }; + + const { conditionalHeaders } = await getConditionalHeaders({ + job: {}, + filteredHeaders: permittedHeaders, + server: mockServer, + }); + + expect(conditionalHeaders.conditions.hostname).toEqual(config['server.host']); + }); + + test(`uses port from reporting config if set`, async () => { + config['xpack.reporting.kibanaServer.port'] = 443; + + const permittedHeaders = { + foo: 'bar', + baz: 'quix', + }; + + const { conditionalHeaders } = await getConditionalHeaders({ + job: {}, + filteredHeaders: permittedHeaders, + server: mockServer, + }); + + expect(conditionalHeaders.conditions.port).toEqual(config['xpack.reporting.kibanaServer.port']); + }); + + test(`uses port from server if reporting config not set`, async () => { + const permittedHeaders = { + foo: 'bar', + baz: 'quix', + }; + + const { conditionalHeaders } = await getConditionalHeaders({ + job: {}, + filteredHeaders: permittedHeaders, + server: mockServer, + }); + + expect(conditionalHeaders.conditions.port).toEqual(config['server.port']); + }); + + test(`uses basePath from server config`, async () => { + const permittedHeaders = { + foo: 'bar', + baz: 'quix', + }; + + const { conditionalHeaders } = await getConditionalHeaders({ + job: {}, + filteredHeaders: permittedHeaders, + server: mockServer, + }); + + expect(conditionalHeaders.conditions.basePath).toEqual(config['server.basePath']); + }); + + test(`uses protocol from reporting config if set`, async () => { + config['xpack.reporting.kibanaServer.protocol'] = 'https'; + const permittedHeaders = { + foo: 'bar', + baz: 'quix', + }; + + const { conditionalHeaders } = await getConditionalHeaders({ + job: {}, + filteredHeaders: permittedHeaders, + server: mockServer, + }); + + expect(conditionalHeaders.conditions.protocol).toEqual( + config['xpack.reporting.kibanaServer.protocol'] + ); + }); + + test(`uses protocol from server.info`, async () => { + const permittedHeaders = { + foo: 'bar', + baz: 'quix', + }; + + const { conditionalHeaders } = await getConditionalHeaders({ + job: {}, + filteredHeaders: permittedHeaders, + server: mockServer, + }); + + expect(conditionalHeaders.conditions.protocol).toEqual(mockServer.info.protocol); + }); +}); + +test('uses basePath from job when creating saved object service', async () => { + const permittedHeaders = { + foo: 'bar', + baz: 'quix', + }; + + const { conditionalHeaders } = await getConditionalHeaders({ + job: {}, + filteredHeaders: permittedHeaders, + server: mockServer, + }); + + const logo = 'custom-logo'; + mockServer.uiSettingsServiceFactory().get.mockReturnValue(logo); + + const jobBasePath = '/sbp/s/marketing'; + await getCustomLogo({ + job: { basePath: jobBasePath }, + conditionalHeaders, + server: mockServer, + }); + + expect(mockServer.savedObjects.getScopedSavedObjectsClient.mock.calls[0][0].getBasePath()).toBe( + jobBasePath + ); +}); + +test(`uses basePath from server if job doesn't have a basePath when creating saved object service`, async () => { + const permittedHeaders = { + foo: 'bar', + baz: 'quix', + }; + + const { conditionalHeaders } = await getConditionalHeaders({ + job: {}, + filteredHeaders: permittedHeaders, + server: mockServer, + }); + + const logo = 'custom-logo'; + mockServer.uiSettingsServiceFactory().get.mockReturnValue(logo); + + await getCustomLogo({ + job: {}, + conditionalHeaders, + server: mockServer, + }); + + expect(mockServer.savedObjects.getScopedSavedObjectsClient.mock.calls[0][0].getBasePath()).toBe( + '/sbp' + ); +}); diff --git a/x-pack/plugins/reporting/export_types/common/execute_job/get_conditional_headers.js b/x-pack/plugins/reporting/export_types/common/execute_job/get_conditional_headers.ts similarity index 64% rename from x-pack/plugins/reporting/export_types/common/execute_job/get_conditional_headers.js rename to x-pack/plugins/reporting/export_types/common/execute_job/get_conditional_headers.ts index e029499ebcdf663..155e38fbdff4651 100644 --- a/x-pack/plugins/reporting/export_types/common/execute_job/get_conditional_headers.js +++ b/x-pack/plugins/reporting/export_types/common/execute_job/get_conditional_headers.ts @@ -3,19 +3,28 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import { ConditionalHeaders, ConfigObject, KbnServer, ReportingJob } from '../../../types'; -export const getConditionalHeaders = ({ job, filteredHeaders, server }) => { - const config = server.config(); +export const getConditionalHeaders = ({ + job, + filteredHeaders, + server, +}: { + job: ReportingJob; + filteredHeaders: Record; + server: KbnServer; +}) => { + const config: ConfigObject = server.config(); - const conditionalHeaders = { + const conditionalHeaders: ConditionalHeaders = { headers: filteredHeaders, conditions: { hostname: config.get('xpack.reporting.kibanaServer.hostname') || config.get('server.host'), port: config.get('xpack.reporting.kibanaServer.port') || config.get('server.port'), basePath: config.get('server.basePath'), protocol: config.get('xpack.reporting.kibanaServer.protocol') || server.info.protocol, - } + }, }; return { job, conditionalHeaders, server }; -}; \ No newline at end of file +}; diff --git a/x-pack/plugins/reporting/export_types/common/execute_job/get_custom_logo.test.ts b/x-pack/plugins/reporting/export_types/common/execute_job/get_custom_logo.test.ts new file mode 100644 index 000000000000000..7615f1448706468 --- /dev/null +++ b/x-pack/plugins/reporting/export_types/common/execute_job/get_custom_logo.test.ts @@ -0,0 +1,68 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { memoize } from 'lodash'; +import { getConditionalHeaders, getCustomLogo } from './index'; + +let config: any; +let mockServer: any; +beforeEach(() => { + config = { + 'xpack.reporting.encryptionKey': 'testencryptionkey', + 'server.basePath': '/sbp', + 'server.host': 'localhost', + 'server.port': 5601, + }; + mockServer = { + expose: () => { + ' '; + }, + config: memoize(() => ({ get: jest.fn() })), + info: { + protocol: 'http', + }, + plugins: { + elasticsearch: { + getCluster: memoize(() => { + return { + callWithRequest: jest.fn(), + }; + }), + }, + }, + savedObjects: { + getScopedSavedObjectsClient: jest.fn(), + }, + uiSettingsServiceFactory: jest.fn().mockReturnValue({ get: jest.fn() }), + }; + + mockServer.config().get.mockImplementation((key: any) => { + return config[key]; + }); +}); + +test(`gets logo from uiSettings`, async () => { + const permittedHeaders = { + foo: 'bar', + baz: 'quix', + }; + + const { conditionalHeaders } = await getConditionalHeaders({ + job: {}, + filteredHeaders: permittedHeaders, + server: mockServer, + }); + + const { logo } = await getCustomLogo({ + job: {}, + conditionalHeaders, + server: mockServer, + }); + + mockServer.uiSettingsServiceFactory().get.mockReturnValue(logo); + + expect(mockServer.uiSettingsServiceFactory().get).toBeCalledWith('xpackReporting:customPdfLogo'); +}); diff --git a/x-pack/plugins/reporting/export_types/common/execute_job/get_custom_logo.js b/x-pack/plugins/reporting/export_types/common/execute_job/get_custom_logo.ts similarity index 63% rename from x-pack/plugins/reporting/export_types/common/execute_job/get_custom_logo.js rename to x-pack/plugins/reporting/export_types/common/execute_job/get_custom_logo.ts index 16f3e86cf40e348..0b25187a938aea9 100644 --- a/x-pack/plugins/reporting/export_types/common/execute_job/get_custom_logo.js +++ b/x-pack/plugins/reporting/export_types/common/execute_job/get_custom_logo.ts @@ -4,26 +4,34 @@ * you may not use this file except in compliance with the Elastic License. */ import { UI_SETTINGS_CUSTOM_PDF_LOGO } from '../../../common/constants'; +import { ConditionalHeaders, KbnServer, ReportingJob } from '../../../types'; -export const getCustomLogo = async ({ job, conditionalHeaders, server }) => { - const serverBasePath = server.config().get('server.basePath'); +export const getCustomLogo = async ({ + job, + conditionalHeaders, + server, +}: { + job: ReportingJob; + conditionalHeaders: ConditionalHeaders; + server: KbnServer; +}) => { + const serverBasePath: string = server.config().get('server.basePath'); - const fakeRequest = { + const fakeRequest: any = { headers: conditionalHeaders.headers, // This is used by the spaces SavedObjectClientWrapper to determine the existing space. // We use the basePath from the saved job, which we'll have post spaces being implemented; // or we use the server base path, which uses the default space - getBasePath: () => job.basePath || serverBasePath + getBasePath: () => job.basePath || serverBasePath, }; const savedObjects = server.savedObjects; const savedObjectsClient = savedObjects.getScopedSavedObjectsClient(fakeRequest); - const uiSettings = server.uiSettingsServiceFactory({ - savedObjectsClient - }); + + const uiSettings = server.uiSettingsServiceFactory({ savedObjectsClient }); const logo = await uiSettings.get(UI_SETTINGS_CUSTOM_PDF_LOGO); return { job, conditionalHeaders, logo, server }; -}; \ No newline at end of file +}; diff --git a/x-pack/plugins/reporting/export_types/common/execute_job/index.test.js b/x-pack/plugins/reporting/export_types/common/execute_job/index.test.js deleted file mode 100644 index 088e7ebc744d3a5..000000000000000 --- a/x-pack/plugins/reporting/export_types/common/execute_job/index.test.js +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { memoize } from 'lodash'; -import { cryptoFactory } from '../../../server/lib/crypto'; -import { decryptJobHeaders, addForceNowQuerystring, omitBlacklistedHeaders, getConditionalHeaders, getCustomLogo } from './index'; - -let config; -let mockServer; -beforeEach(() => { - config = { - 'xpack.reporting.encryptionKey': 'testencryptionkey', - 'server.basePath': '/sbp', - 'server.host': 'localhost', - 'server.port': 5601 - }; - mockServer = { - expose: () => { }, - config: memoize(() => ({ get: jest.fn() })), - info: { - protocol: 'http', - }, - plugins: { - elasticsearch: { - getCluster: memoize(() => { - return { - callWithRequest: jest.fn() - }; - }) - } - }, - savedObjects: { - getScopedSavedObjectsClient: jest.fn(), - }, - uiSettingsServiceFactory: jest.fn().mockReturnValue({ get: jest.fn() }), - }; - - mockServer.config().get.mockImplementation((key) => { - return config[key]; - }); - -}); - -const encryptHeaders = async (headers) => { - const crypto = cryptoFactory(mockServer); - return await crypto.encrypt(headers); -}; - -describe('headers', () => { - test(`fails if no URL is passed`, async () => { - await expect(addForceNowQuerystring({ job: { timeRange: {} }, server: mockServer })).rejects.toBeDefined(); - }); - - - test(`fails if it can't decrypt headers`, async () => { - await expect(decryptJobHeaders({ job: { relativeUrl: '/app/kibana#/something', timeRange: {} }, - server: mockServer })).rejects.toBeDefined(); - }); - - test(`passes back decrypted headers that were passed in`, async () => { - const headers = { - foo: 'bar', - baz: 'quix', - }; - - const encryptedHeaders = await encryptHeaders(headers); - const { decryptedHeaders } = await decryptJobHeaders({ job: { relativeUrl: '/app/kibana#/something', headers: encryptedHeaders }, - server: mockServer }); - expect(decryptedHeaders).toEqual(headers); - }); - test(`omits blacklisted headers`, async () => { - const permittedHeaders = { - foo: 'bar', - baz: 'quix', - }; - - const blacklistedHeaders = { - 'accept-encoding': '', - 'content-length': '', - 'content-type': '', - 'host': '', - 'transfer-encoding': '', - }; - - const { filteredHeaders } = await omitBlacklistedHeaders({ job: { }, decryptedHeaders: { - ...permittedHeaders, - ...blacklistedHeaders - }, server: mockServer }); - - expect(filteredHeaders).toEqual(permittedHeaders); - - }); - - - describe('conditions', () => { - test(`uses hostname from reporting config if set`, async () => { - config['xpack.reporting.kibanaServer.hostname'] = 'custom-hostname'; - const permittedHeaders = { - foo: 'bar', - baz: 'quix', - }; - - const { conditionalHeaders } = await getConditionalHeaders({ job: { }, - filteredHeaders: permittedHeaders, - server: mockServer }); - - expect(conditionalHeaders.conditions.hostname).toEqual(config['xpack.reporting.kibanaServer.hostname']); - - }); - - test(`uses hostname from server.config if reporting config not set`, async () => { - const permittedHeaders = { - foo: 'bar', - baz: 'quix', - }; - - const { conditionalHeaders } = await getConditionalHeaders({ job: { }, - filteredHeaders: permittedHeaders, - server: mockServer }); - - expect(conditionalHeaders.conditions.hostname).toEqual(config['server.host']); - - }); - - test(`uses port from reporting config if set`, async () => { - config['xpack.reporting.kibanaServer.port'] = 443; - - const permittedHeaders = { - foo: 'bar', - baz: 'quix', - }; - - const { conditionalHeaders } = await getConditionalHeaders({ job: { }, - filteredHeaders: permittedHeaders, - server: mockServer }); - - expect(conditionalHeaders.conditions.port).toEqual(config['xpack.reporting.kibanaServer.port']); - - }); - - test(`uses port from server if reporting config not set`, async () => { - const permittedHeaders = { - foo: 'bar', - baz: 'quix', - }; - - const { conditionalHeaders } = await getConditionalHeaders({ job: { }, - filteredHeaders: permittedHeaders, - server: mockServer }); - - expect(conditionalHeaders.conditions.port).toEqual(config['server.port']); - - }); - - test(`uses basePath from server config`, async () => { - const permittedHeaders = { - foo: 'bar', - baz: 'quix', - }; - - const { conditionalHeaders } = await getConditionalHeaders({ job: { }, - filteredHeaders: permittedHeaders, - server: mockServer }); - - expect(conditionalHeaders.conditions.basePath).toEqual(config['server.basePath']); - - }); - - test(`uses protocol from reporting config if set`, async () => { - config['xpack.reporting.kibanaServer.protocol'] = 'https'; - const permittedHeaders = { - foo: 'bar', - baz: 'quix', - }; - - const { conditionalHeaders } = await getConditionalHeaders({ job: { }, - filteredHeaders: permittedHeaders, - server: mockServer }); - - expect(conditionalHeaders.conditions.protocol).toEqual(config['xpack.reporting.kibanaServer.protocol']); - - }); - - test(`uses protocol from server.info`, async () => { - const permittedHeaders = { - foo: 'bar', - baz: 'quix', - }; - - const { conditionalHeaders } = await getConditionalHeaders({ job: { }, - filteredHeaders: permittedHeaders, - server: mockServer }); - - expect(conditionalHeaders.conditions.protocol).toEqual(mockServer.info.protocol); - - }); - - test(`adds forceNow to hash's query, if it exists`, async () => { - - const forceNow = '2000-01-01T00:00:00.000Z'; - - const { urls } = await addForceNowQuerystring({ job: { relativeUrl: '/app/kibana#/something', forceNow }, server: mockServer }); - - expect(urls[0]).toEqual('http://localhost:5601/sbp/app/kibana#/something?forceNow=2000-01-01T00%3A00%3A00.000Z'); - - }); - - test(`appends forceNow to hash's query, if it exists`, async () => { - const forceNow = '2000-01-01T00:00:00.000Z'; - - const { urls } = await addForceNowQuerystring({ job: { relativeUrl: '/app/kibana#/something?_g=something', - forceNow }, server: mockServer }); - - expect(urls[0]).toEqual('http://localhost:5601/sbp/app/kibana#/something?_g=something&forceNow=2000-01-01T00%3A00%3A00.000Z'); - }); - - test(`doesn't append forceNow query to url, if it doesn't exists`, async () => { - const { urls } = await addForceNowQuerystring({ job: { relativeUrl: '/app/kibana#/something' - }, server: mockServer }); - - expect(urls[0]).toEqual('http://localhost:5601/sbp/app/kibana#/something'); - - }); - }); -}); - -test('uses basePath from job when creating saved object service', async () => { - - const permittedHeaders = { - foo: 'bar', - baz: 'quix', - }; - - const { conditionalHeaders } = await getConditionalHeaders({ job: { }, - filteredHeaders: permittedHeaders, - server: mockServer }); - - const logo = 'custom-logo'; - mockServer.uiSettingsServiceFactory().get.mockReturnValue(logo); - - const jobBasePath = '/sbp/s/marketing'; - await getCustomLogo({ job: { objects: [], basePath: jobBasePath }, - conditionalHeaders: conditionalHeaders, server: mockServer }); - - expect(mockServer.savedObjects.getScopedSavedObjectsClient.mock.calls[0][0].getBasePath()).toBe(jobBasePath); -}); - -test(`uses basePath from server if job doesn't have a basePath when creating saved object service`, async () => { - const permittedHeaders = { - foo: 'bar', - baz: 'quix', - }; - - const { conditionalHeaders } = await getConditionalHeaders({ job: { }, - filteredHeaders: permittedHeaders, - server: mockServer }); - - const logo = 'custom-logo'; - mockServer.uiSettingsServiceFactory().get.mockReturnValue(logo); - - await getCustomLogo({ job: { objects: [] }, - conditionalHeaders: conditionalHeaders, server: mockServer }); - - expect(mockServer.savedObjects.getScopedSavedObjectsClient.mock.calls[0][0].getBasePath()).toBe('/sbp'); -}); - -test(`gets logo from uiSettings`, async () => { - - const permittedHeaders = { - foo: 'bar', - baz: 'quix', - }; - - const { conditionalHeaders } = await getConditionalHeaders({ job: { }, - filteredHeaders: permittedHeaders, - server: mockServer }); - - const { logo } = await getCustomLogo({ job: { objects: [] }, - conditionalHeaders: conditionalHeaders, server: mockServer }); - - mockServer.uiSettingsServiceFactory().get.mockReturnValue(logo); - - expect(mockServer.uiSettingsServiceFactory().get).toBeCalledWith('xpackReporting:customPdfLogo'); -}); - diff --git a/x-pack/plugins/reporting/export_types/common/execute_job/index.js b/x-pack/plugins/reporting/export_types/common/execute_job/index.ts similarity index 88% rename from x-pack/plugins/reporting/export_types/common/execute_job/index.js rename to x-pack/plugins/reporting/export_types/common/execute_job/index.ts index af414b1b25f5752..33e61f57e9fe3cf 100644 --- a/x-pack/plugins/reporting/export_types/common/execute_job/index.js +++ b/x-pack/plugins/reporting/export_types/common/execute_job/index.ts @@ -4,11 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ - -export { addForceNowQuerystring } from './add_forcenow_querystring'; +export { addForceNowQuerystring } from './add_force_now_query_string'; export { decryptJobHeaders } from './decrypt_job_headers'; export { getConditionalHeaders } from './get_conditional_headers'; export { getCustomLogo } from './get_custom_logo'; export { omitBlacklistedHeaders } from './omit_blacklisted_headers'; export { getAbsoluteUrlFactory } from './get_absolute_url'; - diff --git a/x-pack/plugins/reporting/export_types/common/execute_job/omit_blacklisted_headers.test.ts b/x-pack/plugins/reporting/export_types/common/execute_job/omit_blacklisted_headers.test.ts new file mode 100644 index 000000000000000..f46dd6a9bf650e0 --- /dev/null +++ b/x-pack/plugins/reporting/export_types/common/execute_job/omit_blacklisted_headers.test.ts @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { memoize } from 'lodash'; +import { omitBlacklistedHeaders } from './index'; + +let config: any; +let mockServer: any; +beforeEach(() => { + config = { + 'xpack.reporting.encryptionKey': 'testencryptionkey', + 'server.basePath': '/sbp', + 'server.host': 'localhost', + 'server.port': 5601, + }; + mockServer = { + expose: () => { + ' '; + }, + config: memoize(() => ({ get: jest.fn() })), + info: { + protocol: 'http', + }, + plugins: { + elasticsearch: { + getCluster: memoize(() => { + return { + callWithRequest: jest.fn(), + }; + }), + }, + }, + savedObjects: { + getScopedSavedObjectsClient: jest.fn(), + }, + uiSettingsServiceFactory: jest.fn().mockReturnValue({ get: jest.fn() }), + }; + + mockServer.config().get.mockImplementation((key: any) => { + return config[key]; + }); +}); + +test(`omits blacklisted headers`, async () => { + const permittedHeaders = { + foo: 'bar', + baz: 'quix', + }; + + const blacklistedHeaders = { + 'accept-encoding': '', + 'content-length': '', + 'content-type': '', + host: '', + 'transfer-encoding': '', + }; + + const { filteredHeaders } = await omitBlacklistedHeaders({ + job: {}, + decryptedHeaders: { + ...permittedHeaders, + ...blacklistedHeaders, + }, + server: mockServer, + }); + + expect(filteredHeaders).toEqual(permittedHeaders); +}); diff --git a/x-pack/plugins/reporting/export_types/common/execute_job/omit_blacklisted_headers.js b/x-pack/plugins/reporting/export_types/common/execute_job/omit_blacklisted_headers.ts similarity index 52% rename from x-pack/plugins/reporting/export_types/common/execute_job/omit_blacklisted_headers.js rename to x-pack/plugins/reporting/export_types/common/execute_job/omit_blacklisted_headers.ts index b21035cd3ade905..a334d57a73f68e7 100644 --- a/x-pack/plugins/reporting/export_types/common/execute_job/omit_blacklisted_headers.js +++ b/x-pack/plugins/reporting/export_types/common/execute_job/omit_blacklisted_headers.ts @@ -5,8 +5,20 @@ */ import { omit } from 'lodash'; import { KBN_SCREENSHOT_HEADER_BLACKLIST } from '../../../common/constants'; +import { KbnServer, ReportingJob } from '../../../types'; -export const omitBlacklistedHeaders = ({ job, decryptedHeaders, server }) => { - const filteredHeaders = omit(decryptedHeaders, KBN_SCREENSHOT_HEADER_BLACKLIST); +export const omitBlacklistedHeaders = ({ + job, + decryptedHeaders, + server, +}: { + job: ReportingJob; + decryptedHeaders: Record; + server: KbnServer; +}) => { + const filteredHeaders: Record = omit( + decryptedHeaders, + KBN_SCREENSHOT_HEADER_BLACKLIST + ); return { job, filteredHeaders, server }; -}; \ No newline at end of file +}; diff --git a/x-pack/plugins/reporting/types.d.ts b/x-pack/plugins/reporting/types.d.ts index cca035d6d5e52e6..c12d03dc2990eb5 100644 --- a/x-pack/plugins/reporting/types.d.ts +++ b/x-pack/plugins/reporting/types.d.ts @@ -3,12 +3,29 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ + +interface UiSettings { + get: (value: string) => string; +} + +type SavedObjectClient = any; + +// these types shoud be in core kibana and are only here temporarily export interface KbnServer { + info: { protocol: string }; config: () => ConfigObject; + savedObjects: { + getScopedSavedObjectsClient: ( + fakeRequest: { headers: object; getBasePath: () => string } + ) => SavedObjectClient; + }; + uiSettingsServiceFactory: ( + { savedObjectsClient }: { savedObjectsClient: SavedObjectClient } + ) => UiSettings; } export interface ConfigObject { - get: (path: string) => any; + get: (path?: string) => any; } export interface Size { @@ -65,3 +82,16 @@ export interface ConditionalHeadersConditions { port: number; basePath: string; } + +export interface CryptoFactory { + decrypt: (headers?: Record) => string; +} +export interface ReportingJob { + headers?: Record; + basePath?: string; + urls?: string[]; + relativeUrl?: string; + forceNow?: string; + timeRange?: any; + objects?: [any]; +}