Commit ba5a0023 by Victor Cinaglia

Mitigate XSS vulnerabilities in Singlestat panel

Sanitize `prefix` and `postfix` fields. Re-arrange code slightly in order to handle variable
interpolation.
parent 435079c6
...@@ -77,7 +77,7 @@ class SingleStatCtrl extends MetricsPanelCtrl { ...@@ -77,7 +77,7 @@ class SingleStatCtrl extends MetricsPanelCtrl {
}; };
/** @ngInject */ /** @ngInject */
constructor($scope, $injector, private linkSrv) { constructor($scope, $injector, private linkSrv, private $sanitize) {
super($scope, $injector); super($scope, $injector);
_.defaults(this.panel, this.panelDefaults); _.defaults(this.panel, this.panelDefaults);
...@@ -398,14 +398,15 @@ class SingleStatCtrl extends MetricsPanelCtrl { ...@@ -398,14 +398,15 @@ class SingleStatCtrl extends MetricsPanelCtrl {
const $location = this.$location; const $location = this.$location;
const linkSrv = this.linkSrv; const linkSrv = this.linkSrv;
const $timeout = this.$timeout; const $timeout = this.$timeout;
const $sanitize = this.$sanitize;
const panel = ctrl.panel; const panel = ctrl.panel;
const templateSrv = this.templateSrv; const templateSrv = this.templateSrv;
let data, linkInfo; let data, linkInfo;
const $panelContainer = elem.find('.panel-container'); const $panelContainer = elem.find('.panel-container');
elem = elem.find('.singlestat-panel'); elem = elem.find('.singlestat-panel');
function applyColoringThresholds(value, valueString) { function applyColoringThresholds(valueString) {
const color = getColorForValue(data, value); const color = getColorForValue(data, data.value);
if (color) { if (color) {
return '<span style="color:' + color + '">' + valueString + '</span>'; return '<span style="color:' + color + '">' + valueString + '</span>';
} }
...@@ -413,8 +414,9 @@ class SingleStatCtrl extends MetricsPanelCtrl { ...@@ -413,8 +414,9 @@ class SingleStatCtrl extends MetricsPanelCtrl {
return valueString; return valueString;
} }
function getSpan(className, fontSize, value) { function getSpan(className, fontSize, applyColoring, value) {
value = templateSrv.replace(value, data.scopedVars); value = $sanitize(templateSrv.replace(value, data.scopedVars));
value = applyColoring ? applyColoringThresholds(value) : value;
return '<span class="' + className + '" style="font-size:' + fontSize + '">' + value + '</span>'; return '<span class="' + className + '" style="font-size:' + fontSize + '">' + value + '</span>';
} }
...@@ -422,25 +424,13 @@ class SingleStatCtrl extends MetricsPanelCtrl { ...@@ -422,25 +424,13 @@ class SingleStatCtrl extends MetricsPanelCtrl {
let body = '<div class="singlestat-panel-value-container">'; let body = '<div class="singlestat-panel-value-container">';
if (panel.prefix) { if (panel.prefix) {
let prefix = panel.prefix; body += getSpan('singlestat-panel-prefix', panel.prefixFontSize, panel.colorPrefix, panel.prefix);
if (panel.colorPrefix) {
prefix = applyColoringThresholds(data.value, panel.prefix);
}
body += getSpan('singlestat-panel-prefix', panel.prefixFontSize, prefix);
} }
let value = data.valueFormatted; body += getSpan('singlestat-panel-value', panel.valueFontSize, panel.colorValue, data.valueFormatted);
if (panel.colorValue) {
value = applyColoringThresholds(data.value, value);
}
body += getSpan('singlestat-panel-value', panel.valueFontSize, value);
if (panel.postfix) { if (panel.postfix) {
let postfix = panel.postfix; body += getSpan('singlestat-panel-postfix', panel.postfixFontSize, panel.colorPostfix, panel.postfix);
if (panel.colorPostfix) {
postfix = applyColoringThresholds(data.value, panel.postfix);
}
body += getSpan('singlestat-panel-postfix', panel.postfixFontSize, postfix);
} }
body += '</div>'; body += '</div>';
......
...@@ -14,6 +14,8 @@ describe('SingleStatCtrl', () => { ...@@ -14,6 +14,8 @@ describe('SingleStatCtrl', () => {
get: () => {}, get: () => {},
}; };
const $sanitize = {};
SingleStatCtrl.prototype.panel = { SingleStatCtrl.prototype.panel = {
events: { events: {
on: () => {}, on: () => {},
...@@ -31,7 +33,7 @@ describe('SingleStatCtrl', () => { ...@@ -31,7 +33,7 @@ describe('SingleStatCtrl', () => {
describe(desc, () => { describe(desc, () => {
ctx.setup = setupFunc => { ctx.setup = setupFunc => {
beforeEach(() => { beforeEach(() => {
ctx.ctrl = new SingleStatCtrl($scope, $injector, {}); ctx.ctrl = new SingleStatCtrl($scope, $injector, {}, $sanitize);
setupFunc(); setupFunc();
ctx.ctrl.onDataReceived(ctx.data); ctx.ctrl.onDataReceived(ctx.data);
ctx.data = ctx.ctrl.data; ctx.data = ctx.ctrl.data;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment