diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/BoxPlot/transformProps.ts b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/BoxPlot/transformProps.ts index 70129bebf55..420287c7a9b 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/BoxPlot/transformProps.ts +++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/BoxPlot/transformProps.ts @@ -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 ? `

${outlierName}

` : ''; + const headline = groupby + ? `

${sanitizeHtml(outlierName)}

` + : ''; 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 ? `

${name}

` : ''; + const headline = name ? `

${sanitizeHtml(name)}

` : ''; const stats = [ `Max: ${numberFormatter(value[5])}`, `3rd Quartile: ${numberFormatter(value[4])}`, diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Funnel/transformProps.ts b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Funnel/transformProps.ts index 5f15d849988..ee1772de204 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Funnel/transformProps.ts +++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Funnel/transformProps.ts @@ -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) { diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Graph/transformProps.ts b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Graph/transformProps.ts index bfcf04b91a1..e3465512287 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Graph/transformProps.ts +++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Graph/transformProps.ts @@ -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; @@ -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) { diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Pie/transformProps.ts b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Pie/transformProps.ts index bfc240380bf..7cd47187cb1 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Pie/transformProps.ts +++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Pie/transformProps.ts @@ -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); diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/utils/prophet.ts b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/utils/prophet.ts index 86af47b19c6..2c23113864f 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/utils/prophet.ts +++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/utils/prophet.ts @@ -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; diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/utils/series.ts b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/utils/series.ts index 2cb7ad4b9a5..0e1db573ba8 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/utils/series.ts +++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/utils/series.ts @@ -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); +} diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/test/utils/series.test.ts b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/test/utils/series.test.ts index c0f3a3b87d5..d5d3dd89fa2 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/test/utils/series.test.ts +++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/test/utils/series.test.ts @@ -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('<NULL>'); + }); + }); });