Commit 2eae8b83 by Alexander Kryklia

Merge pull request #3981 from edx/alex/fix_matlab_check

Improve escaping in code response.
parents 4eab9cdb 97e8f943
...@@ -50,6 +50,7 @@ import pyparsing ...@@ -50,6 +50,7 @@ import pyparsing
import html5lib import html5lib
import bleach import bleach
from .util import sanitize_html
from .registry import TagRegistry from .registry import TagRegistry
from chem import chemcalc from chem import chemcalc
from calc.preview import latex_preview from calc.preview import latex_preview
...@@ -821,19 +822,7 @@ class MatlabInput(CodeInput): ...@@ -821,19 +822,7 @@ class MatlabInput(CodeInput):
# this is only set if we don't have a graded response # this is only set if we don't have a graded response
# the graded response takes precedence # the graded response takes precedence
if 'queue_msg' in self.input_state and self.status in ['queued', 'incomplete', 'unsubmitted']: if 'queue_msg' in self.input_state and self.status in ['queued', 'incomplete', 'unsubmitted']:
attributes = bleach.ALLOWED_ATTRIBUTES.copy() self.queue_msg = sanitize_html(self.input_state['queue_msg'])
# Yuck! but bleach does not offer the option of passing in allowed_protocols,
# and matlab uses data urls for images
if u'data' not in bleach.BleachSanitizer.allowed_protocols:
bleach.BleachSanitizer.allowed_protocols.append(u'data')
attributes.update({'*': ['class', 'style', 'id'],
'audio': ['controls', 'autobuffer', 'autoplay', 'src'],
'img': ['src', 'width', 'height', 'class']})
self.queue_msg = bleach.clean(self.input_state['queue_msg'],
tags=bleach.ALLOWED_TAGS + ['div', 'p', 'audio', 'pre', 'img', 'span'],
styles=['white-space'],
attributes=attributes
)
if 'queuestate' in self.input_state and self.input_state['queuestate'] == 'queued': if 'queuestate' in self.input_state and self.input_state['queuestate'] == 'queued':
self.status = 'queued' self.status = 'queued'
...@@ -905,6 +894,7 @@ class MatlabInput(CodeInput): ...@@ -905,6 +894,7 @@ class MatlabInput(CodeInput):
'button_enabled': self.button_enabled(), 'button_enabled': self.button_enabled(),
'matlab_editor_js': '{static_url}js/vendor/CodeMirror/octave.js'.format( 'matlab_editor_js': '{static_url}js/vendor/CodeMirror/octave.js'.format(
static_url=self.capa_system.STATIC_URL), static_url=self.capa_system.STATIC_URL),
'msg': sanitize_html(self.msg) # sanitize msg before rendering into template
} }
return extra_context return extra_context
......
...@@ -757,6 +757,16 @@ class MatlabTest(unittest.TestCase): ...@@ -757,6 +757,16 @@ class MatlabTest(unittest.TestCase):
expected = "<script>Test message</script>" expected = "<script>Test message</script>"
self.assertEqual(the_input.queue_msg, expected) self.assertEqual(the_input.queue_msg, expected)
def test_matlab_sanitize_msg(self):
"""
Check that the_input.msg is sanitized.
"""
not_allowed_tag = 'script'
self.the_input.msg = "<{0}>Test message</{0}>".format(not_allowed_tag)
expected = "&lt;script&gt;Test message&lt;/script&gt;"
self.assertEqual(self.the_input._get_render_context()['msg'], expected)
def html_tree_equal(received, expected): def html_tree_equal(received, expected):
""" """
Returns whether two etree Elements are the same, with insensitivity to attribute order. Returns whether two etree Elements are the same, with insensitivity to attribute order.
......
"""Tests capa util""" """
Tests capa util
"""
import unittest import unittest
import textwrap import textwrap
from . import test_capa_system from . import test_capa_system
from capa.util import compare_with_tolerance from capa.util import compare_with_tolerance, sanitize_html
class UtilTest(unittest.TestCase): class UtilTest(unittest.TestCase):
...@@ -80,3 +81,18 @@ class UtilTest(unittest.TestCase): ...@@ -80,3 +81,18 @@ class UtilTest(unittest.TestCase):
self.assertFalse(result) self.assertFalse(result)
result = compare_with_tolerance(infinity, infinity, '1.0', False) result = compare_with_tolerance(infinity, infinity, '1.0', False)
self.assertTrue(result) self.assertTrue(result)
def test_sanitize_html(self):
"""
Test for html sanitization with bleach.
"""
allowed_tags = ['div', 'p', 'audio', 'pre', 'span']
for tag in allowed_tags:
queue_msg = "<{0}>Test message</{0}>".format(tag)
self.assertEqual(sanitize_html(queue_msg), queue_msg)
not_allowed_tag = 'script'
queue_msg = "<{0}>Test message</{0}>".format(not_allowed_tag)
expected = "&lt;script&gt;Test message&lt;/script&gt;"
self.assertEqual(sanitize_html(queue_msg), expected)
"""
Utility functions for capa.
"""
import bleach
from calc import evaluator from calc import evaluator
from cmath import isinf from cmath import isinf
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
# #
# Utility functions used in CAPA responsetypes # Utility functions used in CAPA responsetypes
...@@ -134,3 +138,27 @@ def find_with_default(node, path, default): ...@@ -134,3 +138,27 @@ def find_with_default(node, path, default):
return v.text return v.text
else: else:
return default return default
def sanitize_html(html_code):
"""
Sanitize html_code for safe embed on LMS pages.
Used to sanitize XQueue responses from Matlab.
"""
attributes = bleach.ALLOWED_ATTRIBUTES.copy()
# Yuck! but bleach does not offer the option of passing in allowed_protocols,
# and matlab uses data urls for images
if u'data' not in bleach.BleachSanitizer.allowed_protocols:
bleach.BleachSanitizer.allowed_protocols.append(u'data')
attributes.update({
'*': ['class', 'style', 'id'],
'audio': ['controls', 'autobuffer', 'autoplay', 'src'],
'img': ['src', 'width', 'height', 'class']
})
output = bleach.clean(html_code,
tags=bleach.ALLOWED_TAGS + ['div', 'p', 'audio', 'pre', 'img', 'span'],
styles=['white-space'],
attributes=attributes
)
return output
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