Просмотр исходного кода

feat(table): escape html by default

closes #3673
bergquist 10 лет назад
Родитель
Сommit
d750908e36

+ 6 - 0
public/app/plugins/panel/table/editor.html

@@ -103,6 +103,11 @@
 						<metric-segment-model property="style.dateFormat" options="editor.dateFormats" on-change="editor.render()" custom="true"></metric-segment-model>
 					</li>
 				</ul>
+				<ul class="tight-form-list" ng-if="style.type === 'string'">
+					<li class="tight-form-item">
+						<editor-checkbox text="escape html" model="style.escapeHtml" change="editor.render()"></editor-checkbox>
+					</li>
+				</ul>
 				<div class="clearfix"></div>
 			</div>
 			<div class="tight-form" ng-if="style.type === 'number'">
@@ -158,6 +163,7 @@
 				<div class="clearfix"></div>
 			</div>
 
+
 		</div>
 	</div>
 

+ 1 - 0
public/app/plugins/panel/table/editor.ts

@@ -112,6 +112,7 @@ export class TablePanelEditorCtrl {
       pattern: '/.*/',
       dateFormat: 'YYYY-MM-DD HH:mm:ss',
       thresholds: [],
+      escapeHtml: true
     };
 
     this.panel.styles.push(angular.copy(columnStyleDefaults));

+ 36 - 13
public/app/plugins/panel/table/renderer.ts

@@ -4,6 +4,8 @@ import _ from 'lodash';
 import moment from 'moment';
 import kbn from 'app/core/utils/kbn';
 
+
+
 export class TableRenderer {
   formaters: any[];
   colorState: any;
@@ -24,22 +26,27 @@ export class TableRenderer {
     return _.first(style.colors);
   }
 
-  defaultCellFormater(v) {
-    if (v === null || v === void 0) {
-      return '';
-    }
+  defaultCellFormater(escapeHtml = true) {
+    return function(v) {
+      if (v === null || v === void 0 || v === undefined) {
+        return '';
+      }
 
-    if (_.isArray(v)) {
-      v = v.join(',&nbsp;');
-    }
+      if (_.isArray(v)) {
+        v = v.join(',&nbsp;');
+      }
 
-    return v;
-  }
+      if (_.isString(v) && escapeHtml) {
+        v = encodeHtml(v);
+      }
 
+      return v;
+    };
+  }
 
   createColumnFormater(style) {
     if (!style) {
-      return this.defaultCellFormater;
+      return this.defaultCellFormater();
     }
 
     if (style.type === 'date') {
@@ -62,7 +69,7 @@ export class TableRenderer {
         }
 
         if (_.isString(v)) {
-          return v;
+          return encodeHtml(v);
         }
 
         if (style.colorMode) {
@@ -73,7 +80,11 @@ export class TableRenderer {
       };
     }
 
-    return this.defaultCellFormater;
+    if (style.type === 'string') {
+      return this.defaultCellFormater(style.escapeHtml);
+    }
+
+    return this.defaultCellFormater();
   }
 
   formatColumnValue(colIndex, value) {
@@ -91,7 +102,7 @@ export class TableRenderer {
       }
     }
 
-    this.formaters[colIndex] = this.defaultCellFormater;
+    this.formaters[colIndex] = this.defaultCellFormater();
     return this.formaters[colIndex](value);
   }
 
@@ -142,3 +153,15 @@ export class TableRenderer {
     return html;
   }
 }
+
+function encodeHtml(unsafe) {
+  return unsafe.replace(/[&<>"']/g, function(m) {
+    return ({
+      '&': '&amp;',
+      '<': '&lt;',
+      '>': '&gt;',
+      '"': '&quot;',
+      '\'': '&#039;'
+    })[m];
+  });
+}

+ 27 - 0
public/app/plugins/panel/table/specs/renderer_specs.ts

@@ -11,6 +11,8 @@ describe('when rendering table', () => {
       {text: 'Value'},
       {text: 'Colored'},
       {text: 'Undefined'},
+      {text: 'String'},
+      {text: 'UnescapedString' }
     ];
 
     var panel = {
@@ -35,6 +37,16 @@ describe('when rendering table', () => {
           colorMode: 'value',
           thresholds: [50, 80],
           colors: ['green', 'orange', 'red']
+        },
+        {
+          pattern: 'String',
+          type: 'string',
+          escapeHtml: true,
+        },
+        {
+          pattern: 'UnescapedString',
+          type: 'string',
+          escapeHtml: false,
         }
       ]
     };
@@ -76,6 +88,21 @@ describe('when rendering table', () => {
       expect(html).to.be('<td>value</td>');
     });
 
+    it('string style with escape html should return escaped html', () => {
+      var html = renderer.renderCell(4, "&breaking <br /> the <br /> row");
+      expect(html).to.be('<td>&amp;breaking &lt;br /&gt; the &lt;br /&gt; row</td>');
+    });
+
+    it('undefined formater should return escaped html', () => {
+      var html = renderer.renderCell(4, "&breaking <br /> the <br /> row");
+      expect(html).to.be('<td>&amp;breaking &lt;br /&gt; the &lt;br /&gt; row</td>');
+    });
+
+    it('string style with escape html false should return html', () => {
+      var html = renderer.renderCell(5, "&breaking <br /> the <br /> row");
+      expect(html).to.be('<td>&breaking <br /> the <br /> row</td>');
+    });
+
     it('undefined value should render as -', () => {
       var html = renderer.renderCell(3, undefined);
       expect(html).to.be('<td></td>');