-
Notifications
You must be signed in to change notification settings - Fork 8.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Reporting/UI Settings] Validation for the Reporting UI Setting Custo…
…m Logo (#94746) * Validation for the Reporting UI Setting Custom Logo * add more validations * check if image is too large * fix i18n * clean redundant * large test strings not necessary Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
- Loading branch information
1 parent
37ff43b
commit 0d1a1af
Showing
4 changed files
with
166 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
x-pack/plugins/reporting/server/config/ui_settings.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import { range } from 'lodash'; | ||
import { PdfLogoSchema } from './ui_settings'; | ||
|
||
test('validates when provided with image data', () => { | ||
const jpgString = | ||
`data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHCBcUFBUUExUYGRUaGRsZGxsZHB8bIh0iGhgbGxkbGx8dIy0kGx0rIiIbJTcoKi8xNDU0ISY6Pzo2` + | ||
`+8snFz9eWgvYKS4ZsvS05zRQsDveIzH4Er4iDtr6iICIiAiIgIiICIiD//2Q==`; | ||
expect(PdfLogoSchema.validate(jpgString)).toBe(jpgString); | ||
|
||
const pngString = | ||
`data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAO4AAADUCAMAAACs0e/bAAAAjVBMVEX////8/Pz4+Pj5+fnb29vz8/Px8fFeXl7r6+u/v79nZ` + | ||
`tcAAAAASUVORK5CYII=`; | ||
expect(PdfLogoSchema.validate(pngString)).toBe(pngString); | ||
|
||
const gifString = | ||
`data:image/gif;base64,R0lGODlhoADIAPYAAO/w7wgFBwsLCxMTExsbGyMjI5SUlLS0tLu7u9vb2+Hh4e/v7/Ds7////0NDQ2RkZCkXJO/w8PLy8g8QD` + | ||
`53IIefTH3WR4N8lXzvKWu/zlMI+5zGdO85rb/OY4z7nOd87znvv850APutCHTvSiG/3oSE+60pfO9KY7/elQj7rU5xIIADs=`; | ||
expect(PdfLogoSchema.validate(gifString)).toBe(gifString); | ||
|
||
const svgString = | ||
`data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXR` + | ||
`AgPC9nPgogIDwvZz4KPC9zdmc+Cg==`; | ||
expect(PdfLogoSchema.validate(svgString)).toBe(svgString); | ||
}); | ||
|
||
test('validates if provided with null / undefined value', () => { | ||
expect(() => PdfLogoSchema.validate(undefined)).not.toThrow(); | ||
expect(() => PdfLogoSchema.validate(null)).not.toThrow(); | ||
}); | ||
|
||
test('throws validation error if provided with data over max size', () => { | ||
const largeJpgMock = | ||
`data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHCBcUFBUUExUYGRUaGRsZGxsZHB8bIh0iGhgbGxkbGx8dIy0kGx0rIiIbJTcoKi8xNDU0ISY6Pzo2` + | ||
range(0, 2050) | ||
.map( | ||
() => | ||
`Pi0zNDMBCwsLBgYGEAYGEDEcFRwxMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMf/AABEIAOgA2gMBIgACEQEDEQH/xAAcAAEAAgMBAQE` | ||
) | ||
.join('') + | ||
`+8snFz9eWgvYKS4ZsvS05zRQsDveIzH4Er4iDtr6iICIiAiIgIiICIiD//2Q==`; | ||
expect(() => PdfLogoSchema.validate(largeJpgMock)).toThrowError(/too large/); | ||
}); | ||
|
||
test('throws validation error if provided with non-image data', () => { | ||
const invalidErrorMatcher = /try a different image/; | ||
|
||
expect(() => PdfLogoSchema.validate('')).toThrowError(invalidErrorMatcher); | ||
expect(() => PdfLogoSchema.validate(true)).toThrow(invalidErrorMatcher); | ||
expect(() => PdfLogoSchema.validate(false)).toThrow(invalidErrorMatcher); | ||
expect(() => PdfLogoSchema.validate({})).toThrow(invalidErrorMatcher); | ||
expect(() => PdfLogoSchema.validate([])).toThrow(invalidErrorMatcher); | ||
expect(() => PdfLogoSchema.validate(0)).toThrow(invalidErrorMatcher); | ||
expect(() => PdfLogoSchema.validate(0x00f)).toThrow(invalidErrorMatcher); | ||
|
||
const csvString = | ||
`data:text/csv;base64,Il9pZCIsIl9pbmRleCIsIl9zY29yZSIsIl90eXBlIiwiZm9vLmJhciIsImZvby5iYXIua2V5d29yZCIKZjY1QU9IZ0J5bFZmWW04W` + | ||
`TRvb1EsYmVlLDEsIi0iLGJheixiYXoKbks1QU9IZ0J5bFZmWW04WTdZcUcsYmVlLDEsIi0iLGJvbyxib28K`; | ||
expect(() => PdfLogoSchema.validate(csvString)).toThrow(invalidErrorMatcher); | ||
|
||
const scriptString = | ||
`data:application/octet-stream;base64,QEVDSE8gT0ZGCldFRUtPRllSLkNPTSB8IEZJTkQgIlRoaXMgaXMiID4gVEVNUC5CQV` + | ||
`QKRUNITz5USElTLkJBVCBTRVQgV0VFSz0lJTMKQ0FMTCBURU1QLkJBVApERUwgIFRFTVAuQkFUCkRFTCAgVEhJUy5CQVQKRUNITyBXZWVrICVXRUVLJQo=`; | ||
expect(() => PdfLogoSchema.validate(scriptString)).toThrow(invalidErrorMatcher); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import { schema } from '@kbn/config-schema'; | ||
import { i18n } from '@kbn/i18n'; | ||
import { CoreSetup, UiSettingsParams } from 'kibana/server'; | ||
import { PLUGIN_ID, UI_SETTINGS_CUSTOM_PDF_LOGO } from '../../common/constants'; | ||
|
||
const kbToBase64Length = (kb: number) => Math.floor((kb * 1024 * 8) / 6); | ||
const maxLogoSizeInKilobytes = kbToBase64Length(200); | ||
|
||
// inspired by x-pack/plugins/canvas/common/lib/dataurl.ts | ||
const dataurlRegex = /^data:([a-z]+\/[a-z0-9-+.]+)(;[a-z-]+=[a-z0-9-]+)?(;([a-z0-9]+))?,/; | ||
const imageTypes = ['image/svg+xml', 'image/jpeg', 'image/png', 'image/gif']; | ||
|
||
const isImageData = (str: any): boolean => { | ||
const matches = str.match(dataurlRegex); | ||
|
||
if (!matches) { | ||
return false; | ||
} | ||
|
||
const [, mimetype, , , encoding] = matches; | ||
const imageTypeIndex = imageTypes.indexOf(mimetype); | ||
if (imageTypeIndex < 0 || encoding !== 'base64') { | ||
return false; | ||
} | ||
|
||
return true; | ||
}; | ||
|
||
const isLessThanMaxSize = (str: any) => { | ||
if (str.length > maxLogoSizeInKilobytes) { | ||
return false; | ||
} | ||
|
||
return true; | ||
}; | ||
|
||
const validatePdfLogoBase64String = (str: any) => { | ||
if (typeof str !== 'string' || !isImageData(str)) { | ||
return i18n.translate('xpack.reporting.uiSettings.validate.customLogo.badFile', { | ||
defaultMessage: `Sorry, that file will not work. Please try a different image file.`, | ||
}); | ||
} | ||
if (!isLessThanMaxSize(str)) { | ||
return i18n.translate('xpack.reporting.uiSettings.validate.customLogo.tooLarge', { | ||
defaultMessage: `Sorry, that file is too large. The image file must be less than 200 kilobytes.`, | ||
}); | ||
} | ||
}; | ||
|
||
export const PdfLogoSchema = schema.nullable(schema.any({ validate: validatePdfLogoBase64String })); | ||
|
||
export function registerUiSettings(core: CoreSetup<object, unknown>) { | ||
core.uiSettings.register({ | ||
[UI_SETTINGS_CUSTOM_PDF_LOGO]: { | ||
name: i18n.translate('xpack.reporting.pdfFooterImageLabel', { | ||
defaultMessage: 'PDF footer image', | ||
}), | ||
value: null, | ||
description: i18n.translate('xpack.reporting.pdfFooterImageDescription', { | ||
defaultMessage: `Custom image to use in the PDF's footer`, | ||
}), | ||
sensitive: true, | ||
type: 'image', | ||
schema: PdfLogoSchema, | ||
category: [PLUGIN_ID], | ||
validation: { | ||
maxSize: { | ||
length: maxLogoSizeInKilobytes, | ||
description: '200 kB', | ||
}, | ||
}, | ||
}, | ||
} as Record<string, UiSettingsParams<null>>); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters