fix(plugin-chart-echarts): sanitize series from html tags (#1126)

* fix(plugin-chart-echarts): sanitize series from html tags

* use echarts html encoder
This commit is contained in:
Ville Brofeldt
2021-07-02 14:45:40 +03:00
committed by Yongjie Zhao
parent c160a4abde
commit 895d9d325d
7 changed files with 35 additions and 10 deletions

View File

@@ -30,7 +30,7 @@ import {
BoxPlotQueryFormData,
EchartsBoxPlotChartProps,
} from './types';
import { extractGroupbyLabel, getColtypesMapping } from '../utils/series';
import { extractGroupbyLabel, getColtypesMapping, sanitizeHtml } from '../utils/series';
import { defaultGrid, defaultTooltip, defaultYAxis } from '../defaults';
export default function transformProps(
@@ -103,7 +103,9 @@ export default function transformProps(
tooltip: {
formatter: (param: { data: [string, number] }) => {
const [outlierName, stats] = param.data;
const headline = groupby ? `<p><strong>${outlierName}</strong></p>` : '';
const headline = groupby
? `<p><strong>${sanitizeHtml(outlierName)}</strong></p>`
: '';
return `${headline}${numberFormatter(stats)}`;
},
},
@@ -161,7 +163,7 @@ export default function transformProps(
value: [number, number, number, number, number, number, number, number, number[]];
name: string;
} = param;
const headline = name ? `<p><strong>${name}</strong></p>` : '';
const headline = name ? `<p><strong>${sanitizeHtml(name)}</strong></p>` : '';
const stats = [
`Max: ${numberFormatter(value[5])}`,
`3rd Quartile: ${numberFormatter(value[4])}`,

View File

@@ -35,7 +35,12 @@ import {
FunnelChartTransformedProps,
} from './types';
import { DEFAULT_LEGEND_FORM_DATA } from '../types';
import { extractGroupbyLabel, getChartPadding, getLegendProps } from '../utils/series';
import {
extractGroupbyLabel,
getChartPadding,
getLegendProps,
sanitizeHtml,
} from '../utils/series';
import { defaultGrid, defaultTooltip } from '../defaults';
const percentFormatter = getNumberFormatter(NumberFormats.PERCENT_2_POINT);
@@ -49,7 +54,8 @@ export function formatFunnelLabel({
labelType: EchartsFunnelLabelTypeType;
numberFormatter: NumberFormatter;
}): string {
const { name = '', value, percent } = params;
const { name: rawName = '', value, percent } = params;
const name = sanitizeHtml(rawName);
const formattedValue = numberFormatter(value as number);
const formattedPercent = percentFormatter((percent as number) / 100);
switch (labelType) {

View File

@@ -34,7 +34,7 @@ import {
} from './types';
import { DEFAULT_GRAPH_SERIES_OPTION } from './constants';
import { EchartsProps } from '../types';
import { getChartPadding, getLegendProps } from '../utils/series';
import { getChartPadding, getLegendProps, sanitizeHtml } from '../utils/series';
type EdgeWithStyles = GraphEdgeItemOption & {
lineStyle: Exclude<GraphEdgeItemOption['lineStyle'], undefined>;
@@ -127,7 +127,9 @@ function edgeFormatter(
): string {
const source = Number(sourceIndex);
const target = Number(targetIndex);
return `${getKeyByValue(nodes, source)} > ${getKeyByValue(nodes, target)} : ${value}`;
return `${sanitizeHtml(getKeyByValue(nodes, source))} > ${sanitizeHtml(
getKeyByValue(nodes, target),
)} : ${value}`;
}
function getCategoryName(columnName: string, name?: DataRecordValue) {

View File

@@ -40,6 +40,7 @@ import {
getChartPadding,
getColtypesMapping,
getLegendProps,
sanitizeHtml,
} from '../utils/series';
import { defaultGrid, defaultTooltip } from '../defaults';
@@ -54,7 +55,8 @@ export function formatPieLabel({
labelType: EchartsPieLabelType;
numberFormatter: NumberFormatter;
}): string {
const { name = '', value, percent } = params;
const { name: rawName = '', value, percent } = params;
const name = sanitizeHtml(rawName);
const formattedValue = numberFormatter(value as number);
const formattedPercent = percentFormatter((percent as number) / 100);

View File

@@ -20,6 +20,7 @@ import { TimeseriesDataRecord, NumberFormatter } from '@superset-ui/core';
import { CallbackDataParams, OptionName } from 'echarts/types/src/util/types';
import { TooltipMarker } from 'echarts/types/src/util/format';
import { ForecastSeriesContext, ForecastSeriesEnum, ProphetValue } from '../types';
import { sanitizeHtml } from './series';
const seriesTypeRegex = new RegExp(
`(.+)(${ForecastSeriesEnum.ForecastLower}|${ForecastSeriesEnum.ForecastTrend}|${ForecastSeriesEnum.ForecastUpper})$`,
@@ -73,7 +74,7 @@ export const formatProphetTooltipSeries = ({
marker: TooltipMarker;
formatter: NumberFormatter;
}): string => {
let row = `${marker}${seriesName}: `;
let row = `${marker}${sanitizeHtml(seriesName)}: `;
let isObservation = false;
if (observation) {
isObservation = true;

View File

@@ -26,7 +26,7 @@ import {
TimeFormatter,
TimeseriesDataRecord,
} from '@superset-ui/core';
import { LegendComponentOption, SeriesOption } from 'echarts';
import { format, LegendComponentOption, SeriesOption } from 'echarts';
import { NULL_STRING, TIMESERIES_CONSTANTS } from '../constants';
import { LegendOrientation, LegendType } from '../types';
import { defaultLegendPadding } from '../defaults';
@@ -200,3 +200,7 @@ export function dedupSeries(series: SeriesOption[]): SeriesOption[] {
};
});
}
export function sanitizeHtml(text: string): string {
return format.encodeHTML(text);
}

View File

@@ -24,9 +24,11 @@ import {
formatSeriesName,
getChartPadding,
getLegendProps,
sanitizeHtml,
} from '../../src/utils/series';
import { LegendOrientation, LegendType } from '../../src/types';
import { defaultLegendPadding } from '../../src/defaults';
import { NULL_STRING } from '../../lib/constants';
describe('extractTimeseriesSeries', () => {
it('should generate a valid ECharts timeseries series object', () => {
@@ -350,4 +352,10 @@ describe('formatSeriesName', () => {
).toEqual([{ id: 'foo' }, { id: 'bar' }, { id: 'foo (1)' }, { id: 'foo (2)' }]);
});
});
describe('sanitizeHtml', () => {
it('should remove html tags from series name', () => {
expect(sanitizeHtml(NULL_STRING)).toEqual('&lt;NULL&gt;');
});
});
});