Skip to content

Commit

Permalink
Move HTML sanitization from client to server side (opensearch-project…
Browse files Browse the repository at this point in the history
…#382)

Move HTML sanitization to server, store markdown over HTML, remove unused imports

Signed-off-by: David Cui <davidcui@amazon.com>
  • Loading branch information
davidcui1225 authored and joshuali925 committed Jul 5, 2022
1 parent 7c92fc8 commit 64420b1
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 34 deletions.
4 changes: 2 additions & 2 deletions dashboards-reports/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"async-mutex": "^0.2.6",
"babel-polyfill": "^6.26.0",
"cron-validator": "^1.1.1",
"dompurify": "^2.1.1",
"dompurify": "^2.3.8",
"elastic-builder": "^2.7.1",
"enzyme-adapter-react-16": "^1.15.2",
"jest-fetch-mock": "^3.0.3",
Expand All @@ -41,7 +41,7 @@
},
"devDependencies": {
"@elastic/eslint-import-resolver-kibana": "link:../../packages/osd-eslint-import-resolver-opensearch-dashboards",
"@types/dompurify": "^2.0.4",
"@types/dompurify": "^2.3.3",
"@types/enzyme-adapter-react-16": "^1.0.6",
"@types/jsdom": "^16.2.3",
"@types/puppeteer-core": "^2.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import {
} from '../main_utils';
import { ReportDefinitionSchemaType } from '../../../../server/model';
import moment from 'moment';
import { converter } from '../../report_definitions/utils';
import {
permissionsMissingToast,
permissionsMissingActions,
Expand Down Expand Up @@ -426,12 +425,12 @@ export function ReportDefinitionDetails(props: { match?: any; setBreadcrumbs?: a
reportHeader:
reportParams.core_params.hasOwnProperty('header') &&
reportParams.core_params.header != ''
? converter.makeMarkdown(reportParams.core_params.header)
? reportParams.core_params.header
: `\u2014`,
reportFooter:
reportParams.core_params.hasOwnProperty('footer') &&
reportParams.core_params.footer != ''
? converter.makeMarkdown(reportParams.core_params.footer)
? reportParams.core_params.footer
: `\u2014`,
triggerType: triggerType,
scheduleDetails: triggerParams
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import {
import { fileFormatsUpper, generateReportById } from '../main_utils';
import { GenerateReportLoadingModal } from '../loading_modal';
import { ReportSchemaType } from '../../../../server/model';
import { converter } from '../../report_definitions/utils';
import dateMath from '@elastic/datemath';
import {
permissionsMissingActions,
Expand Down Expand Up @@ -229,12 +228,12 @@ export function ReportDetails(props: { match?: any; setBreadcrumbs?: any; httpCl
reportHeader:
reportParams.core_params.hasOwnProperty('header') &&
reportParams.core_params.header != ''
? converter.makeMarkdown(reportParams.core_params.header)
? reportParams.core_params.header
: `\u2014`,
reportFooter:
reportParams.core_params.hasOwnProperty('footer') &&
reportParams.core_params.footer != ''
? converter.makeMarkdown(reportParams.core_params.footer)
? reportParams.core_params.footer
: `\u2014`,
triggerType: triggerType,
scheduleType: triggerParams ? triggerParams.schedule_type : `\u2014`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,17 +250,6 @@ export function CreateReport(props: { [x: string]: any; setBreadcrumbs?: any; ht
setPreErrorData(metadata);
setComingFromError(true);
} else {
// convert header and footer to html
if ('header' in metadata.report_params.core_params) {
metadata.report_params.core_params.header = converter.makeHtml(
metadata.report_params.core_params.header
);
}
if ('footer' in metadata.report_params.core_params) {
metadata.report_params.core_params.footer = converter.makeHtml(
metadata.report_params.core_params.footer
);
}
httpClient
.post('../api/reporting/reportDefinition', {
body: JSON.stringify(metadata),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -374,13 +374,13 @@ export function ReportSettings(props: ReportSettingProps) {
if (header) {
checkboxIdSelectHeaderFooter.header = true;
if (!unmounted) {
setHeader(converter.makeMarkdown(header));
setHeader(header);
}
}
if (footer) {
checkboxIdSelectHeaderFooter.footer = true;
if (!unmounted) {
setFooter(converter.makeMarkdown(footer));
setFooter(footer);
}
}
})
Expand Down
28 changes: 28 additions & 0 deletions dashboards-reports/server/routes/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

import { CountersType } from './types';
import Showdown from 'showdown';

export enum FORMAT {
pdf = 'pdf',
Expand Down Expand Up @@ -78,7 +79,34 @@ export const EXTRA_HEADERS = [
'x-forwarded-for',
];

export const converter = new Showdown.Converter({
tables: true,
simplifiedAutoLink: true,
strikethrough: true,
tasklists: true,
noHeaderId: true,
});

const BLOCKED_KEYWORD = 'BLOCKED_KEYWORD';
const ipv4Regex = /(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?):([1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])/g
const ipv6Regex = /(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/g;
const localhostRegex = /localhost:([1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])/g;
const iframeRegex = /iframe/g;

export const replaceBlockedKeywords = (htmlString: string) => {
// replace <ipv4>:<port>
htmlString = htmlString.replace(ipv4Regex, BLOCKED_KEYWORD);
// replace ipv6 addresses
htmlString = htmlString.replace(ipv6Regex, BLOCKED_KEYWORD);
// replace iframe keyword
htmlString = htmlString.replace(iframeRegex, BLOCKED_KEYWORD);
// replace localhost:<port>
htmlString = htmlString.replace(localhostRegex, BLOCKED_KEYWORD);
return htmlString;
}

export const CHROMIUM_PATH = `${__dirname}/../../../.chromium/headless_shell`;


/**
* Metric constants
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
import { getFileName } from '../helpers';
import { CreateReportResultType } from '../types';
import { ReportParamsSchemaType, VisualReportSchemaType } from 'server/model';
import { converter, replaceBlockedKeywords } from '../constants';
import fs from 'fs';
import _ from 'lodash';

Expand Down Expand Up @@ -45,10 +46,21 @@ export const createVisualReport = async (
const window = new JSDOM('').window;
const DOMPurify = createDOMPurify(window);

const reportHeader = header
? DOMPurify.sanitize(header)
let keywordFilteredHeader = header
? converter.makeHtml(header)
: DEFAULT_REPORT_HEADER;
const reportFooter = footer ? DOMPurify.sanitize(footer) : '';
let keywordFilteredFooter = footer ? converter.makeHtml(footer) : '';

keywordFilteredHeader = DOMPurify.sanitize(keywordFilteredHeader);
keywordFilteredFooter = DOMPurify.sanitize(keywordFilteredFooter);

// filter blocked keywords in header and footer
if (keywordFilteredHeader !== '') {
keywordFilteredHeader = replaceBlockedKeywords(keywordFilteredHeader);
}
if (keywordFilteredFooter !== '') {
keywordFilteredFooter = replaceBlockedKeywords(keywordFilteredFooter);
}

// set up puppeteer
const browser = await puppeteer.launch({
Expand Down Expand Up @@ -151,8 +163,8 @@ export const createVisualReport = async (
await waitForDynamicContent(page);

await addReportStyle(page);
await addReportHeader(page, reportHeader);
await addReportFooter(page, reportFooter);
await addReportHeader(page, keywordFilteredHeader);
await addReportFooter(page, keywordFilteredFooter);

// create pdf or png accordingly
if (reportFormat === FORMAT.pdf) {
Expand Down
16 changes: 8 additions & 8 deletions dashboards-reports/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -568,10 +568,10 @@
resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==

"@types/dompurify@^2.0.4":
version "2.0.4"
resolved "https://registry.yarnpkg.com/@types/dompurify/-/dompurify-2.0.4.tgz#25fce15f1f4b1bc0df0ad957040cf226416ac2d7"
integrity sha512-y6K7NyXTQvjr8hJNsAFAD8yshCsIJ0d+OYEFzULuIqWyWOKL2hRru1I+rorI5U0K4SLAROTNuSUFXPDTu278YA==
"@types/dompurify@^2.3.3":
version "2.3.3"
resolved "https://registry.yarnpkg.com/@types/dompurify/-/dompurify-2.3.3.tgz#c24c92f698f77ed9cc9d9fa7888f90cf2bfaa23f"
integrity sha512-nnVQSgRVuZ/843oAfhA25eRSNzUFcBPk/LOiw5gm8mD9/X7CNcbRkQu/OsjCewO8+VIYfPxUnXvPEVGenw14+w==
dependencies:
"@types/trusted-types" "*"

Expand Down Expand Up @@ -2207,10 +2207,10 @@ domhandler@^3.0, domhandler@^3.0.0:
dependencies:
domelementtype "^2.0.1"

dompurify@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.1.1.tgz#b5aa988676b093a9c836d8b855680a8598af25fe"
integrity sha512-NijiNVkS/OL8mdQL1hUbCD6uty/cgFpmNiuFxrmJ5YPH2cXrPKIewoixoji56rbZ6XBPmtM8GA8/sf9unlSuwg==
dompurify@^2.3.8:
version "2.3.8"
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.8.tgz#224fe9ae57d7ebd9a1ae1ac18c1c1ca3f532226f"
integrity sha512-eVhaWoVibIzqdGYjwsBWodIQIaXFSB+cKDf4cfxLMsK0xiud6SE+/WCVx/Xw/UwQsa4cS3T2eITcdtmTg2UKcw==

domutils@^2.0.0:
version "2.2.0"
Expand Down

0 comments on commit 64420b1

Please sign in to comment.