瀏覽代碼

feat: wip: Sanitize user input on text panel

Johannes Schill 7 年之前
父節點
當前提交
15d560a1c0

+ 1 - 0
conf/defaults.ini

@@ -570,6 +570,7 @@ callback_url =
 
 [panels]
 enable_alpha = false
+sanitize_input = true
 
 [enterprise]
 license_path =

+ 2 - 1
package.json

@@ -188,7 +188,8 @@
     "slate-react": "^0.12.4",
     "tether": "^1.4.0",
     "tether-drop": "https://github.com/torkelo/drop/tarball/master",
-    "tinycolor2": "^1.4.1"
+    "tinycolor2": "^1.4.1",
+    "xss": "^1.0.3"
   },
   "resolutions": {
     "caniuse-db": "1.0.30000772",

+ 1 - 0
pkg/api/frontendsettings.go

@@ -166,6 +166,7 @@ func (hs *HTTPServer) getFrontendSettingsMap(c *m.ReqContext) (map[string]interf
 		"externalUserMngLinkUrl":     setting.ExternalUserMngLinkUrl,
 		"externalUserMngLinkName":    setting.ExternalUserMngLinkName,
 		"viewersCanEdit":             setting.ViewersCanEdit,
+		"sanitizeInput":              hs.Cfg.SanitizeInput,
 		"buildInfo": map[string]interface{}{
 			"version":       setting.BuildVersion,
 			"commit":        setting.BuildCommit,

+ 4 - 1
pkg/setting/setting.go

@@ -18,7 +18,7 @@ import (
 	"github.com/go-macaron/session"
 	"github.com/grafana/grafana/pkg/log"
 	"github.com/grafana/grafana/pkg/util"
-	"gopkg.in/ini.v1"
+	ini "gopkg.in/ini.v1"
 )
 
 type Scheme string
@@ -90,6 +90,7 @@ var (
 	EmailCodeValidMinutes            int
 	DataProxyWhiteList               map[string]bool
 	DisableBruteForceLoginProtection bool
+	SanitizeInput                    bool
 
 	// Snapshots
 	ExternalSnapshotUrl   string
@@ -222,6 +223,7 @@ type Cfg struct {
 	MetricsEndpointBasicAuthUsername string
 	MetricsEndpointBasicAuthPassword string
 	EnableAlphaPanels                bool
+	SanitizeInput                    bool
 	EnterpriseLicensePath            string
 }
 
@@ -709,6 +711,7 @@ func (cfg *Cfg) Load(args *CommandLineArgs) error {
 
 	panels := iniFile.Section("panels")
 	cfg.EnableAlphaPanels = panels.Key("enable_alpha").MustBool(false)
+	cfg.SanitizeInput = panels.Key("sanitize_input").MustBool(true)
 
 	cfg.readSessionConfig()
 	cfg.readSmtpSettings()

+ 3 - 1
public/app/core/config.ts

@@ -35,8 +35,9 @@ export class Settings {
   loginHint: any;
   loginError: any;
   viewersCanEdit: boolean;
+  sanitizeInput: boolean;
 
-  constructor(options) {
+  constructor(options: Settings) {
     const defaults = {
       datasources: {},
       windowTitlePrefix: 'Grafana - ',
@@ -52,6 +53,7 @@ export class Settings {
         isEnterprise: false,
       },
       viewersCanEdit: false,
+      sanitizeInput: true
     };
 
     _.extend(this, defaults, options);

+ 11 - 1
public/app/core/utils/text.ts

@@ -1,4 +1,5 @@
 import { TextMatch } from 'app/types/explore';
+import xss from 'xss';
 
 /**
  * Adapt findMatchesInText for react-highlight-words findChunks handler.
@@ -22,7 +23,7 @@ export function findMatchesInText(haystack: string, needle: string): TextMatch[]
   }
   const matches = [];
   const cleaned = cleanNeedle(needle);
-  let regexp;
+  let regexp: RegExp;
   try {
     regexp = new RegExp(`(?:${cleaned})`, 'g');
   } catch (error) {
@@ -42,3 +43,12 @@ export function findMatchesInText(haystack: string, needle: string): TextMatch[]
   });
   return matches;
 }
+
+export function sanitize (unsanitizedString: string): string {
+  try {
+    return xss(unsanitizedString);
+  } catch (error) {
+    console.log('String could not be sanitized', unsanitizedString);
+    return unsanitizedString;
+  }
+}

+ 10 - 4
public/app/plugins/panel/text/module.ts

@@ -1,6 +1,8 @@
 import _ from 'lodash';
 import { PanelCtrl } from 'app/plugins/sdk';
 import Remarkable from 'remarkable';
+import { sanitize } from 'app/core/utils/text';
+import config from 'app/core/config';
 
 const defaultContent = `
 # Title
@@ -44,8 +46,9 @@ export class TextPanelCtrl extends PanelCtrl {
     $scope.$watch(
       renderWhenChanged,
       _.throttle(() => {
+        console.log('this.render', new Date());
         this.render();
-      }, 1000, {trailing: true})
+      }, 2000, {trailing: true, leading: true})
     );
   }
 
@@ -70,7 +73,7 @@ export class TextPanelCtrl extends PanelCtrl {
     this.renderingCompleted();
   }
 
-  renderText(content) {
+  renderText(content: string) {
     content = content
       .replace(/&/g, '&')
       .replace(/>/g, '>')
@@ -79,7 +82,7 @@ export class TextPanelCtrl extends PanelCtrl {
     this.updateContent(content);
   }
 
-  renderMarkdown(content) {
+  renderMarkdown(content: string) {
     if (!this.remarkable) {
       this.remarkable = new Remarkable();
     }
@@ -89,7 +92,10 @@ export class TextPanelCtrl extends PanelCtrl {
     });
   }
 
-  updateContent(html) {
+  updateContent(html: string) {
+    const { sanitizeInput } = config;
+    html = sanitizeInput ? sanitize(html) : html;
+    console.log('html', html);
     try {
       this.content = this.$sce.trustAsHtml(this.templateSrv.replace(html, this.panel.scopedVars));
     } catch (e) {

+ 13 - 0
yarn.lock

@@ -3560,6 +3560,11 @@ cssesc@^0.1.0:
   version "0.1.0"
   resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4"
 
+cssfilter@0.0.10:
+  version "0.0.10"
+  resolved "https://registry.yarnpkg.com/cssfilter/-/cssfilter-0.0.10.tgz#c6d2672632a2e5c83e013e6864a42ce8defd20ae"
+  integrity sha1-xtJnJjKi5cg+AT5oZKQs6N79IK4=
+
 cssnano@^3.10.0:
   version "3.10.0"
   resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-3.10.0.tgz#4f38f6cea2b9b17fa01490f23f1dc68ea65c1c38"
@@ -13344,6 +13349,14 @@ xregexp@4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.0.0.tgz#e698189de49dd2a18cc5687b05e17c8e43943020"
 
+xss@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/xss/-/xss-1.0.3.tgz#d04bd2558fd6c29c46113824d5e8b2a910054e23"
+  integrity sha512-LTpz3jXPLUphMMmyufoZRSKnqMj41OVypZ8uYGzvjkMV9C1EdACrhQl/EM8Qfh5htSAuMIQFOejmKAZGkJfaCg==
+  dependencies:
+    commander "^2.9.0"
+    cssfilter "0.0.10"
+
 xtend@^4.0.0, xtend@~4.0.0, xtend@~4.0.1:
   version "4.0.1"
   resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"