From 5b59570f9fb231285e52b9e6e5acf467b7d93674 Mon Sep 17 00:00:00 2001 From: John Schulz Date: Fri, 18 Oct 2019 15:02:48 -0400 Subject: [PATCH 1/2] Replace image path/handler with generic file one --- .../integrations_manager/server/packages/get.ts | 5 +---- .../server/packages/handlers.ts | 14 ++++++-------- .../integrations_manager/server/registry/index.ts | 10 ++-------- .../plugins/integrations_manager/server/routes.ts | 6 ++---- 4 files changed, 11 insertions(+), 24 deletions(-) diff --git a/x-pack/legacy/plugins/integrations_manager/server/packages/get.ts b/x-pack/legacy/plugins/integrations_manager/server/packages/get.ts index 6430a405b8e15..f010277079e5b 100644 --- a/x-pack/legacy/plugins/integrations_manager/server/packages/get.ts +++ b/x-pack/legacy/plugins/integrations_manager/server/packages/get.ts @@ -10,7 +10,7 @@ import { InstallationAttributes } from '../../common/types'; import * as Registry from '../registry'; import { createInstallableFrom } from './index'; -export { SearchParams } from '../registry'; +export { SearchParams, fetchFile as getFile } from '../registry'; function nameAsTitle(name: string) { return name.charAt(0).toUpperCase() + name.substr(1).toLowerCase(); @@ -68,9 +68,6 @@ export async function getPackageInfo(options: { return createInstallableFrom(updated, savedObject); } -export const getImage = async (options: Registry.ImageRequestParams) => - Registry.fetchImage(options); - export async function getInstallationObject(options: { savedObjectsClient: SavedObjectsClientContract; pkgkey: string; diff --git a/x-pack/legacy/plugins/integrations_manager/server/packages/handlers.ts b/x-pack/legacy/plugins/integrations_manager/server/packages/handlers.ts index b66a7c7461830..92607fd79088e 100644 --- a/x-pack/legacy/plugins/integrations_manager/server/packages/handlers.ts +++ b/x-pack/legacy/plugins/integrations_manager/server/packages/handlers.ts @@ -5,19 +5,19 @@ */ import { AssetType, Request, ResponseToolkit } from '../../common/types'; +import { API_ROOT } from '../../common/routes'; import { PluginContext } from '../plugin'; import { getClient } from '../saved_objects'; import { SearchParams, getCategories, getClusterAccessor, - getImage, + getFile, getPackageInfo, getPackages, installPackage, removeInstallation, } from './index'; -import { ImageRequestParams } from '../registry'; interface Extra extends ResponseToolkit { context: PluginContext; @@ -33,10 +33,6 @@ interface PackageRequest extends Request { }; } -interface ImageRequest extends Request { - params: Request['params'] & ImageRequestParams; -} - interface InstallAssetRequest extends Request { params: AssetRequestParams; } @@ -71,8 +67,10 @@ export async function handleGetInfo(req: PackageRequest, extra: Extra) { return packageInfo; } -export const handleGetImage = async (req: ImageRequest, extra: Extra) => { - const response = await getImage(req.params); +export const handleGetFile = async (req: Request, extra: Extra) => { + if (!req.url.path) throw new Error('path is required'); + const filePath = req.url.path.replace(API_ROOT, ''); + const response = await getFile(filePath); const newResponse = extra.response(response.body); // set the content type from the registry response newResponse.header('Content-Type', response.headers.get('content-type') || ''); diff --git a/x-pack/legacy/plugins/integrations_manager/server/registry/index.ts b/x-pack/legacy/plugins/integrations_manager/server/registry/index.ts index c9acf50b8796a..955fd9c9cd265 100644 --- a/x-pack/legacy/plugins/integrations_manager/server/registry/index.ts +++ b/x-pack/legacy/plugins/integrations_manager/server/registry/index.ts @@ -26,11 +26,6 @@ export interface SearchParams { category?: CategoryId; } -export interface ImageRequestParams { - pkgkey: string; - imgPath: string; -} - export async function fetchList(params?: SearchParams): Promise { const { registryUrl } = epmConfigStore.getConfig(); const url = new URL(`${registryUrl}/search`); @@ -46,10 +41,9 @@ export async function fetchInfo(key: string): Promise { return fetchUrl(`${registryUrl}/package/${key}`).then(JSON.parse); } -export async function fetchImage(params: ImageRequestParams): Promise { +export async function fetchFile(filePath: string): Promise { const { registryUrl } = epmConfigStore.getConfig(); - const { pkgkey, imgPath } = params; - return getResponse(`${registryUrl}/package/${pkgkey}/img/${imgPath}`); + return getResponse(`${registryUrl}${filePath}`); } export async function fetchCategories(): Promise { diff --git a/x-pack/legacy/plugins/integrations_manager/server/routes.ts b/x-pack/legacy/plugins/integrations_manager/server/routes.ts index 7dfc39c9b18c3..8e435005c9e50 100644 --- a/x-pack/legacy/plugins/integrations_manager/server/routes.ts +++ b/x-pack/legacy/plugins/integrations_manager/server/routes.ts @@ -8,8 +8,6 @@ import { ServerRoute } from '../common/types'; import * as CommonRoutes from '../common/routes'; import * as Packages from './packages/handlers'; -const API_IMG_PATTERN = `${CommonRoutes.API_ROOT}/package/{pkgkey}/img/{imgPath*}`; - // Manager public API paths export const routes: ServerRoute[] = [ { @@ -26,9 +24,9 @@ export const routes: ServerRoute[] = [ }, { method: 'GET', - path: API_IMG_PATTERN, + path: `${CommonRoutes.API_INFO_PATTERN}/{filePath*}`, options: { tags: [`access:${PLUGIN.ID}`], json: { space: 2 } }, - handler: Packages.handleGetImage, + handler: Packages.handleGetFile, }, { method: 'GET', From d1f5bdeb2aaef3d8e78f2c354d87c36c59e52ca6 Mon Sep 17 00:00:00 2001 From: John Schulz Date: Fri, 18 Oct 2019 17:34:14 -0400 Subject: [PATCH 2/2] Incorporate tests from #48696 --- .../server/packages/handlers.ts | 14 +- .../integrations_manager/server/routes.ts | 2 +- x-pack/test/epm_api_integration/apis/file.ts | 147 ++++++++++++++++++ x-pack/test/epm_api_integration/apis/image.ts | 61 -------- x-pack/test/epm_api_integration/apis/index.js | 2 +- 5 files changed, 158 insertions(+), 68 deletions(-) create mode 100644 x-pack/test/epm_api_integration/apis/file.ts delete mode 100644 x-pack/test/epm_api_integration/apis/image.ts diff --git a/x-pack/legacy/plugins/integrations_manager/server/packages/handlers.ts b/x-pack/legacy/plugins/integrations_manager/server/packages/handlers.ts index 92607fd79088e..4b265e732dac6 100644 --- a/x-pack/legacy/plugins/integrations_manager/server/packages/handlers.ts +++ b/x-pack/legacy/plugins/integrations_manager/server/packages/handlers.ts @@ -70,11 +70,15 @@ export async function handleGetInfo(req: PackageRequest, extra: Extra) { export const handleGetFile = async (req: Request, extra: Extra) => { if (!req.url.path) throw new Error('path is required'); const filePath = req.url.path.replace(API_ROOT, ''); - const response = await getFile(filePath); - const newResponse = extra.response(response.body); - // set the content type from the registry response - newResponse.header('Content-Type', response.headers.get('content-type') || ''); - return newResponse; + const registryResponse = await getFile(filePath); + const epmResponse = extra.response(registryResponse.body); + const proxiedHeaders = ['Content-Type']; + proxiedHeaders.forEach(key => { + const value = registryResponse.headers.get(key); + if (value !== null) epmResponse.header(key, value); + }); + + return epmResponse; }; export async function handleRequestInstall(req: InstallAssetRequest, extra: Extra) { diff --git a/x-pack/legacy/plugins/integrations_manager/server/routes.ts b/x-pack/legacy/plugins/integrations_manager/server/routes.ts index 8e435005c9e50..c3604b8f6557d 100644 --- a/x-pack/legacy/plugins/integrations_manager/server/routes.ts +++ b/x-pack/legacy/plugins/integrations_manager/server/routes.ts @@ -25,7 +25,7 @@ export const routes: ServerRoute[] = [ { method: 'GET', path: `${CommonRoutes.API_INFO_PATTERN}/{filePath*}`, - options: { tags: [`access:${PLUGIN.ID}`], json: { space: 2 } }, + options: { tags: [`access:${PLUGIN.ID}`] }, handler: Packages.handleGetFile, }, { diff --git a/x-pack/test/epm_api_integration/apis/file.ts b/x-pack/test/epm_api_integration/apis/file.ts new file mode 100644 index 0000000000000..10670610d2c0c --- /dev/null +++ b/x-pack/test/epm_api_integration/apis/file.ts @@ -0,0 +1,147 @@ +/* + * 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 ServerMock from 'mock-http-server'; +import { FtrProviderContext } from '../../api_integration/ftr_provider_context'; + +export default function({ getService }: FtrProviderContext) { + describe('package file', () => { + const server = new ServerMock({ host: 'localhost', port: 6666 }); + beforeEach(() => { + server.start(() => {}); + }); + afterEach(() => { + server.stop(() => {}); + }); + it('fetches a .png screenshot image', async () => { + server.on({ + method: 'GET', + path: '/package/auditd-2.0.4/img/screenshots/auditbeat-file-integrity-dashboard.png', + reply: { + headers: { 'content-type': 'image/png' }, + }, + }); + + const supertest = getService('supertest'); + await supertest + .get('/api/epm/package/auditd-2.0.4/img/screenshots/auditbeat-file-integrity-dashboard.png') + .set('kbn-xsrf', 'xxx') + .expect('Content-Type', 'image/png') + .expect(200); + }); + + it('fetches an .svg icon image', async () => { + server.on({ + method: 'GET', + path: '/package/auditd-2.0.4/img/icon.svg', + reply: { + headers: { 'content-type': 'image/svg' }, + }, + }); + + const supertest = getService('supertest'); + await supertest + .get('/api/epm/package/auditd-2.0.4/img/icon.svg') + .set('kbn-xsrf', 'xxx') + .expect('Content-Type', 'image/svg'); + }); + + it('fetches an auditbeat .conf rule file', async () => { + server.on({ + method: 'GET', + path: '/package/auditd-2.0.4/auditbeat/rules/sample-rules-linux-32bit.conf', + }); + + const supertest = getService('supertest'); + await supertest + .get('/api/epm/package/auditd-2.0.4/auditbeat/rules/sample-rules-linux-32bit.conf') + .set('kbn-xsrf', 'xxx') + .expect('Content-Type', 'application/json; charset=utf-8') + .expect(200); + }); + + it('fetches an auditbeat .yml config file', async () => { + server.on({ + method: 'GET', + path: '/package/auditd-2.0.4/auditbeat/config/config.yml', + reply: { + headers: { 'content-type': 'text/yaml; charset=UTF-8' }, + }, + }); + + const supertest = getService('supertest'); + await supertest + .get('/api/epm/package/auditd-2.0.4/auditbeat/config/config.yml') + .set('kbn-xsrf', 'xxx') + .expect('Content-Type', 'text/yaml; charset=UTF-8') + .expect(200); + }); + + it('fetches a .json kibana visualization file', async () => { + server.on({ + method: 'GET', + path: + '/package/auditd-2.0.4/kibana/visualization/b21e0c70-c252-11e7-8692-232bd1143e8a-ecs.json', + }); + + const supertest = getService('supertest'); + await supertest + .get( + '/api/epm/package/auditd-2.0.4/kibana/visualization/b21e0c70-c252-11e7-8692-232bd1143e8a-ecs.json' + ) + .set('kbn-xsrf', 'xxx') + .expect('Content-Type', 'application/json; charset=utf-8') + .expect(200); + }); + + it('fetches a .json kibana dashboard file', async () => { + server.on({ + method: 'GET', + path: + '/package/auditd-2.0.4/kibana/dashboard/7de391b0-c1ca-11e7-8995-936807a28b16-ecs.json', + }); + + const supertest = getService('supertest'); + await supertest + .get( + '/api/epm/package/auditd-2.0.4/kibana/dashboard/7de391b0-c1ca-11e7-8995-936807a28b16-ecs.json' + ) + .set('kbn-xsrf', 'xxx') + .expect('Content-Type', 'application/json; charset=utf-8') + .expect(200); + }); + + it('fetches an .json index pattern file', async () => { + server.on({ + method: 'GET', + path: '/package/auditd-2.0.4/kibana/index-pattern/auditbeat-*.json', + }); + + const supertest = getService('supertest'); + await supertest + .get('/api/epm/package/auditd-2.0.4/kibana/index-pattern/auditbeat-*.json') + .set('kbn-xsrf', 'xxx') + .expect('Content-Type', 'application/json; charset=utf-8') + .expect(200); + }); + + it('fetches a .json search file', async () => { + server.on({ + method: 'GET', + path: '/package/auditd-2.0.4/kibana/search/0f10c430-c1c3-11e7-8995-936807a28b16-ecs.json', + }); + + const supertest = getService('supertest'); + await supertest + .get( + '/api/epm/package/auditd-2.0.4/kibana/search/0f10c430-c1c3-11e7-8995-936807a28b16-ecs.json' + ) + .set('kbn-xsrf', 'xxx') + .expect('Content-Type', 'application/json; charset=utf-8') + .expect(200); + }); + }); +} diff --git a/x-pack/test/epm_api_integration/apis/image.ts b/x-pack/test/epm_api_integration/apis/image.ts deleted file mode 100644 index 073ae637eec5c..0000000000000 --- a/x-pack/test/epm_api_integration/apis/image.ts +++ /dev/null @@ -1,61 +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 ServerMock from 'mock-http-server'; -import { FtrProviderContext } from '../../api_integration/ftr_provider_context'; - -export default function({ getService }: FtrProviderContext) { - describe('images', () => { - const server = new ServerMock({ host: 'localhost', port: 6666 }); - beforeEach(() => { - server.start(() => {}); - }); - afterEach(() => { - server.stop(() => {}); - }); - it('fetches a png screenshot image from the registry', async () => { - server.on({ - method: 'GET', - path: '/package/auditd-2.0.4/img/screenshots/auditbeat-file-integrity-dashboard.png', - reply: { - headers: { 'content-type': 'image/png' }, - }, - }); - - const supertest = getService('supertest'); - const fetchImage = async () => { - await supertest - .get( - '/api/epm/package/auditd-2.0.4/img/screenshots/auditbeat-file-integrity-dashboard.png' - ) - .set('kbn-xsrf', 'xxx') - .expect('Content-Type', 'image/png') - .expect(200); - }; - await fetchImage(); - }); - - it('fetches an icon image from the registry', async () => { - server.on({ - method: 'GET', - path: '/package/auditd-2.0.4/img/icon.svg', - reply: { - headers: { 'content-type': 'image/svg' }, - }, - }); - - const supertest = getService('supertest'); - const fetchImage = async () => { - await supertest - .get('/api/epm/package/auditd-2.0.4/img/icon.svg') - .set('kbn-xsrf', 'xxx') - .expect('Content-Type', 'image/svg') - .expect(200); - }; - await fetchImage(); - }); - }); -} diff --git a/x-pack/test/epm_api_integration/apis/index.js b/x-pack/test/epm_api_integration/apis/index.js index 4354c6a1336c4..422b46803e66a 100644 --- a/x-pack/test/epm_api_integration/apis/index.js +++ b/x-pack/test/epm_api_integration/apis/index.js @@ -8,6 +8,6 @@ export default function ({ loadTestFile }) { describe('EPM Endpoints', function () { this.tags('ciGroup7'); loadTestFile(require.resolve('./list')); - loadTestFile(require.resolve('./image')); + loadTestFile(require.resolve('./file')); }); }