This is an automated email from the ASF dual-hosted git repository.

maximebeauchemin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git


The following commit(s) were added to refs/heads/master by this push:
     new 0c5db55  [security] prevent XSS markup viz (#3211)
0c5db55 is described below

commit 0c5db55d55471c1c61c0750733733c157551b2d8
Author: Maxime Beauchemin <maximebeauche...@gmail.com>
AuthorDate: Thu Aug 10 21:38:33 2017 -0700

    [security] prevent XSS markup viz (#3211)
    
    * Prevent XSS in Markup viz
    
    We protect the browser by sandboxing the user code inside an iframe
    
    * Helvetica
---
 superset/__init__.py                               | 27 ++++++++++++++++------
 .../components/controls/TextAreaControl.jsx        |  2 +-
 .../assets/stylesheets/less/cosmo/variables.less   |  2 +-
 superset/assets/stylesheets/superset.less          | 12 ++++------
 superset/assets/visualizations/markup.js           | 22 ++++++++++++++++--
 superset/viz.py                                    |  4 ++--
 6 files changed, 49 insertions(+), 20 deletions(-)

diff --git a/superset/__init__.py b/superset/__init__.py
index 9576458..2e44ebd 100644
--- a/superset/__init__.py
+++ b/superset/__init__.py
@@ -32,22 +32,35 @@ app = Flask(__name__)
 app.config.from_object(CONFIG_MODULE)
 conf = app.config
 
+#################################################################
 # Handling manifest file logic at app start
+#################################################################
 MANIFEST_FILE = APP_DIR + '/static/assets/dist/manifest.json'
-get_manifest_file = lambda x: x
 manifest = {}
-try:
-    with open(MANIFEST_FILE, 'r') as f:
-        manifest = json.load(f)
-    get_manifest_file = lambda x: '/static/assets/dist/' + manifest.get(x, '')
-except Exception:
-    print("no manifest file found at " + MANIFEST_FILE)
 
 
+def parse_manifest_json():
+    global manifest
+    try:
+        with open(MANIFEST_FILE, 'r') as f:
+            manifest = json.load(f)
+    except Exception:
+        print("no manifest file found at " + MANIFEST_FILE)
+
+
+def get_manifest_file(filename):
+    if app.debug:
+        parse_manifest_json()
+    return '/static/assets/dist/' + manifest.get(filename, '')
+
+parse_manifest_json()
+
 @app.context_processor
 def get_js_manifest():
     return dict(js_manifest=get_manifest_file)
 
+#################################################################
+
 
 for bp in conf.get('BLUEPRINTS'):
     try:
diff --git 
a/superset/assets/javascripts/explore/components/controls/TextAreaControl.jsx 
b/superset/assets/javascripts/explore/components/controls/TextAreaControl.jsx
index 4fe9b77..31fe2bb 100644
--- 
a/superset/assets/javascripts/explore/components/controls/TextAreaControl.jsx
+++ 
b/superset/assets/javascripts/explore/components/controls/TextAreaControl.jsx
@@ -76,7 +76,7 @@ export default class TextAreaControl extends React.Component {
           modalTitle={controlHeader}
           triggerNode={
             <Button bsSize="small" className="m-t-5">
-              Edit <b>{this.props.language}</b> in modal
+              Edit <strong>{this.props.language}</strong> in modal
             </Button>
           }
           modalBody={this.renderEditor(true)}
diff --git a/superset/assets/stylesheets/less/cosmo/variables.less 
b/superset/assets/stylesheets/less/cosmo/variables.less
index ce6b85a..fb2abf6 100644
--- a/superset/assets/stylesheets/less/cosmo/variables.less
+++ b/superset/assets/stylesheets/less/cosmo/variables.less
@@ -41,7 +41,7 @@
 //
 //## Font, line-height, and color for body text, headings, and more.
 
-@font-family-sans-serif:  "Roboto", "Helvetica Neue", Helvetica, Arial, 
sans-serif;
+@font-family-sans-serif:  Helvetica, Arial;
 
 @font-family-serif:       Georgia, "Times New Roman", Times, serif;
 //** Default monospace fonts for `<code>`, `<kbd>`, and `<pre>`.
diff --git a/superset/assets/stylesheets/superset.less 
b/superset/assets/stylesheets/superset.less
index aa5678c..bacc18a 100644
--- a/superset/assets/stylesheets/superset.less
+++ b/superset/assets/stylesheets/superset.less
@@ -1,9 +1,3 @@
-@font-face {
-  font-family: "Roboto";
-  src: url("./fonts/Roboto-Regular.woff2") format("woff2"),
-       url("./fonts/Roboto-Regular.woff") format("woff");
-}
-
 body {
     margin: 0px !important;
 }
@@ -255,4 +249,8 @@ div.widget .slice_container {
     .panel .table-responsive{
         width: 98%;
     }
-}
\ No newline at end of file
+}
+iframe {
+    border: none;
+    width: 100%;
+}
diff --git a/superset/assets/visualizations/markup.js 
b/superset/assets/visualizations/markup.js
index ba0ad44..379e2ef 100644
--- a/superset/assets/visualizations/markup.js
+++ b/superset/assets/visualizations/markup.js
@@ -4,11 +4,29 @@ require('./markup.css');
 
 function markupWidget(slice, payload) {
   $('#code').attr('rows', '15');
-  slice.container.css({
+  const jqdiv = slice.container;
+  jqdiv.css({
     overflow: 'auto',
     height: slice.container.height(),
   });
-  slice.container.html(payload.data.html);
+
+  const iframeId = `if__${slice.containerId}`;
+  const html = `
+    <html>
+      <head>
+        <link rel="stylesheet" type="text/css" 
href="${payload.data.theme_css}" />
+      </head>
+      <body style="background-color: transparent;">
+        ${payload.data.html}
+      </body>
+    </html>`;
+  jqdiv.html(`
+    <iframe id="${iframeId}"
+      frameborder="0"
+      height="${slice.height()}"
+      sandbox="allow-scripts">
+    </iframe>`);
+  $('#' + iframeId)[0].srcdoc = html;
 }
 
 module.exports = markupWidget;
diff --git a/superset/viz.py b/superset/viz.py
index c2d65e6..100d8bb 100644
--- a/superset/viz.py
+++ b/superset/viz.py
@@ -28,7 +28,7 @@ import simplejson as json
 from six import string_types, PY3
 from dateutil import relativedelta as rdelta
 
-from superset import app, utils, cache
+from superset import app, utils, cache, get_manifest_file
 from superset.utils import DTTM_ALIAS
 
 config = app.config
@@ -439,7 +439,7 @@ class MarkupViz(BaseViz):
         code = self.form_data.get("code", '')
         if markup_type == "markdown":
             code = markdown(code)
-        return dict(html=code)
+        return dict(html=code, theme_css=get_manifest_file('theme.css'))
 
 
 class SeparatorViz(MarkupViz):

-- 
To stop receiving notification emails like this one, please contact
['"comm...@superset.apache.org" <comm...@superset.apache.org>'].

Reply via email to