diff --git a/recommender/recommender.py b/recommender/recommender.py index 45a40b4..47ef62b 100644 --- a/recommender/recommender.py +++ b/recommender/recommender.py @@ -7,6 +7,7 @@ import lxml.etree as etree import pkg_resources import bleach +import re from copy import deepcopy @@ -586,7 +587,7 @@ def add_resource(self, data, _suffix=''): # pylint: disable=unused-argument for field in self.resource_content_fields: result[field] = strip_and_clean_html_elements(data[field]) - resource_id = stem_url(data['url']) + resource_id = stem_url(result['url']) self._check_redundant_resource(resource_id, 'add_resource', result) self._check_removed_resource(resource_id, 'add_resource', result) @@ -925,11 +926,12 @@ def student_view(self, _context=None): # pylint: disable=unused-argument # load continues to be as-is, pre-generation is not a performance # issue. If students make substantially more resources, we may want # to paginate, and generate in sets of 5-20 URLs per load. - resources = [{'id': r['id'], + resources = [{ + 'id': strip_and_clean_html_elements(r['id']), 'title': strip_and_clean_html_elements(r['title']), - "votes": r['upvotes'] - r['downvotes'], - 'url': r['url'], - 'description': self._get_onetime_url(r['description']), + "votes": strip_and_clean_html_elements(r['upvotes'] - r['downvotes']), + 'url': strip_and_clean_url(r['url']), + 'description': self._get_onetime_url(strip_and_clean_html_elements(r['description'])), 'descriptionText': strip_and_clean_html_elements(r['descriptionText']) } for r in self.recommendations.values()] @@ -1060,4 +1062,27 @@ def strip_and_clean_html_elements(data): """ Clean an HTML elements and return it """ - return bleach.clean(data, strip=True) + return bleach.clean(data, tags=[], strip=True) + +def strip_and_clean_url(data): + """ + Clean an URL elements of HTML tags and possible javascript and return it for use + Ex of bleach linkify output: + bleach.linkify('google.com') ==> u'google.com' + bleach.linkify(' u'' + Ex of bleach linkify with clean output: + bleach.linkify(bleach.clean(' href="javascript:alert()" google.com', tags=[], strip=True)) + ==> u' href="javascript:alert()" google.com' + """ + clean_url = data or '' + clean_url = strip_and_clean_html_elements(clean_url) + # ensure only exists after linkify call below + if ' + return re.search('href=\"(?P.*?)\"', clean_url).group('href') + else: + return '' diff --git a/recommender/static/js/src/recommender.js b/recommender/static/js/src/recommender.js index c1ed88f..0ae99e1 100644 --- a/recommender/static/js/src/recommender.js +++ b/recommender/static/js/src/recommender.js @@ -396,20 +396,20 @@ function RecommenderXBlock(runtime, element, init_data) { resourceVotes: votes } - var newDiv = $(Mustache.render($("#recommenderResourceTemplate").html(), renderData)); - bindResourceDependentEvent(newDiv); - if (IS_USER_STAFF) { bindStaffLimitedResourceDependentEvent(newDiv); } + var $newDiv = $(Mustache.render($("#recommenderResourceTemplate").html(), renderData)); + bindResourceDependentEvent($newDiv); + if (IS_USER_STAFF) { bindStaffLimitedResourceDependentEvent($newDiv); } if ($('.recommenderResource', element).length === 0) { - $('.noResourceIntro', element).after(newDiv); + $('.noResourceIntro', element).after($newDiv); } else { - if (pos === -1) { $(toDiv).after(newDiv); } - else { $(toDiv).before(newDiv); } + if (pos === -1) { $(toDiv).after($newDiv); } + else { $(toDiv).before($newDiv); } } - addResourceDependentTooltip(newDiv); + addResourceDependentTooltip($newDiv); - return newDiv; + return $newDiv; } /** diff --git a/setup.py b/setup.py index 5a56eeb..b0a3794 100644 --- a/setup.py +++ b/setup.py @@ -46,7 +46,7 @@ def package_data(pkg, root_list): setup( name='recommender-xblock', - version='1.3.1', + version='1.3.2', description='recommender XBlock', # TODO: write a better description. long_description=README, author='edX',