From f42d2edd29d420672a963a6d3fd4f1041d8667b0 Mon Sep 17 00:00:00 2001 From: Alex Wang <awang@edx.org> Date: Tue, 26 Nov 2019 20:15:33 -0500 Subject: [PATCH] Fix xss warnings (#22408) --- .../teams/static/teams/js/views/edit_team.js | 18 +++-- .../static/teams/js/views/instructor_tools.js | 8 +-- .../teams/static/teams/js/views/my_teams.js | 8 +-- .../teams/static/teams/js/views/team_card.js | 67 +++++++++++-------- .../js/views/team_profile_header_actions.js | 19 +++--- .../teams/static/teams/js/views/team_utils.js | 11 ++- .../teams/static/teams/js/views/topic_card.js | 30 ++++++--- 7 files changed, 91 insertions(+), 70 deletions(-) diff --git a/lms/djangoapps/teams/static/teams/js/views/edit_team.js b/lms/djangoapps/teams/static/teams/js/views/edit_team.js index 9dd906940f0..c2fd38c144f 100644 --- a/lms/djangoapps/teams/static/teams/js/views/edit_team.js +++ b/lms/djangoapps/teams/static/teams/js/views/edit_team.js @@ -7,8 +7,9 @@ 'js/views/fields', 'teams/js/models/team', 'common/js/components/utils/view_utils', - 'text!teams/templates/edit-team.underscore'], - function(Backbone, _, gettext, FieldViews, TeamModel, ViewUtils, editTeamTemplate) { + 'text!teams/templates/edit-team.underscore', + 'edx-ui-toolkit/js/utils/html-utils'], + function(Backbone, _, gettext, FieldViews, TeamModel, ViewUtils, editTeamTemplate, HtmlUtils) { return Backbone.View.extend({ maxTeamNameLength: 255, @@ -81,11 +82,14 @@ }, render: function() { - this.$el.html(_.template(editTeamTemplate)({ // xss-lint: disable=javascript-jquery-html - primaryButtonTitle: this.primaryButtonTitle, - action: this.action, - totalMembers: _.isUndefined(this.teamModel) ? 0 : this.teamModel.get('membership').length - })); + HtmlUtils.setHtml( + this.$el, + HtmlUtils.template(editTeamTemplate)({ + primaryButtonTitle: this.primaryButtonTitle, + action: this.action, + totalMembers: _.isUndefined(this.teamModel) ? 0 : this.teamModel.get('membership').length + }) + ); this.set(this.teamNameField, '.team-required-fields'); this.set(this.teamDescriptionField, '.team-required-fields'); this.set(this.teamLanguageField, '.team-optional-fields'); diff --git a/lms/djangoapps/teams/static/teams/js/views/instructor_tools.js b/lms/djangoapps/teams/static/teams/js/views/instructor_tools.js index 27df329ae85..55c287a4fbd 100644 --- a/lms/djangoapps/teams/static/teams/js/views/instructor_tools.js +++ b/lms/djangoapps/teams/static/teams/js/views/instructor_tools.js @@ -7,8 +7,9 @@ 'edx-ui-toolkit/js/utils/string-utils', 'teams/js/views/team_utils', 'common/js/components/utils/view_utils', - 'text!teams/templates/instructor-tools.underscore'], - function(Backbone, _, gettext, StringUtils, TeamUtils, ViewUtils, instructorToolbarTemplate) { + 'text!teams/templates/instructor-tools.underscore', + 'edx-ui-toolkit/js/utils/html-utils'], + function(Backbone, _, gettext, StringUtils, TeamUtils, ViewUtils, instructorToolbarTemplate, HtmlUtils) { return Backbone.View.extend({ events: { @@ -17,13 +18,12 @@ }, initialize: function(options) { - this.template = _.template(instructorToolbarTemplate); this.team = options.team; this.teamEvents = options.teamEvents; }, render: function() { - this.$el.html(this.template); // xss-lint: disable=javascript-jquery-html + HtmlUtils.setHtml(this.$el, HtmlUtils.template(instructorToolbarTemplate)({})); return this; }, diff --git a/lms/djangoapps/teams/static/teams/js/views/my_teams.js b/lms/djangoapps/teams/static/teams/js/views/my_teams.js index 35b520f9623..f95819a20fe 100644 --- a/lms/djangoapps/teams/static/teams/js/views/my_teams.js +++ b/lms/djangoapps/teams/static/teams/js/views/my_teams.js @@ -1,8 +1,8 @@ (function(define) { 'use strict'; - define(['backbone', 'gettext', 'teams/js/views/teams'], - function(Backbone, gettext, TeamsView) { + define(['backbone', 'gettext', 'teams/js/views/teams', 'edx-ui-toolkit/js/utils/html-utils'], + function(Backbone, gettext, TeamsView, HtmlUtils) { var MyTeamsView = TeamsView.extend({ render: function() { var view = this; @@ -13,9 +13,7 @@ .done(function() { TeamsView.prototype.render.call(view); if (view.collection.length === 0) { - view.$el.append( // xss-lint: disable=javascript-jquery-append - // eslint-disable-next-line max-len - '<p>' + gettext('You are not currently a member of any team.') + '</p>'); // xss-lint: disable=javascript-concat-html + HtmlUtils.append(view.$el, gettext('You are not currently a member of any team.')); } }); return this; diff --git a/lms/djangoapps/teams/static/teams/js/views/team_card.js b/lms/djangoapps/teams/static/teams/js/views/team_card.js index 65ca6941899..35dcebb8043 100644 --- a/lms/djangoapps/teams/static/teams/js/views/team_card.js +++ b/lms/djangoapps/teams/static/teams/js/views/team_card.js @@ -10,7 +10,9 @@ 'teams/js/views/team_utils', 'text!teams/templates/team-membership-details.underscore', 'text!teams/templates/team-country-language.underscore', - 'text!teams/templates/date.underscore' + 'text!teams/templates/date.underscore', + 'edx-ui-toolkit/js/utils/html-utils', + 'edx-ui-toolkit/js/utils/string-utils' ], function( $, Backbone, @@ -21,14 +23,15 @@ TeamUtils, teamMembershipDetailsTemplate, teamCountryLanguageTemplate, - dateTemplate + dateTemplate, + HtmlUtils, + StringUtils ) { var TeamMembershipView, TeamCountryLanguageView, TeamActivityView, TeamCardView; TeamMembershipView = Backbone.View.extend({ tagName: 'div', className: 'team-members', - template: _.template(teamMembershipDetailsTemplate), initialize: function(options) { this.maxTeamSize = options.maxTeamSize; @@ -41,21 +44,23 @@ }).reverse(), displayableMemberships = allMemberships.slice(0, 5), maxMemberCount = this.maxTeamSize; - this.$el.html(this.template({ // xss-lint: disable=javascript-jquery-html - membership_message: TeamUtils.teamCapacityText(allMemberships.length, maxMemberCount), - memberships: displayableMemberships, - has_additional_memberships: displayableMemberships.length < allMemberships.length, - /* Translators: "and others" refers to fact that additional - * members of a team exist that are not displayed. */ - sr_message: gettext('and others') - })); + HtmlUtils.setHtml( + this.$el, + HtmlUtils.template(teamMembershipDetailsTemplate)({ + membership_message: TeamUtils.teamCapacityText(allMemberships.length, maxMemberCount), + memberships: displayableMemberships, + has_additional_memberships: displayableMemberships.length < allMemberships.length, + /* Translators: "and others" refers to fact that additional + * members of a team exist that are not displayed. */ + sr_message: gettext('and others') + + }) + ); return this; } }); TeamCountryLanguageView = Backbone.View.extend({ - template: _.template(teamCountryLanguageTemplate), - initialize: function(options) { this.countries = options.countries; this.languages = options.languages; @@ -63,10 +68,13 @@ render: function() { // this.$el should be the card meta div - this.$el.append(this.template({ // xss-lint: disable=javascript-jquery-append - country: this.countries[this.model.get('country')], - language: this.languages[this.model.get('language')] - })); + HtmlUtils.append( + this.$el, + HtmlUtils.template(teamCountryLanguageTemplate)({ + country: this.countries[this.model.get('country')], + language: this.languages[this.model.get('language')] + }) + ); } }); @@ -83,15 +91,17 @@ var lastActivity = moment(this.date), currentLanguage = $('html').attr('lang'); lastActivity.locale(currentLanguage); - this.$el.html( // xss-lint: disable=javascript-jquery-html - // eslint-disable-next-line no-undef - interpolate( // xss-lint: disable=javascript-interpolate - /* Translators: 'date' is a placeholder for a fuzzy, - * relative timestamp (see: http://momentjs.com/) - */ - gettext('Last activity %(date)s'), - {date: this.template({date: lastActivity.format('MMMM Do YYYY, h:mm:ss a')})}, - true + HtmlUtils.setHtml( + this.$el, + HtmlUtils.HTML( + StringUtils.interpolate( + /* Translators: 'date' is a placeholder for a fuzzy, + * relative timestamp (see: http://momentjs.com/) + */ + gettext('Last activity {date}'), + {date: this.template({date: lastActivity.format('MMMM Do YYYY, h:mm:ss a')})}, + true + ) ) ); this.$('abbr').text(lastActivity.fromNow()); @@ -123,9 +133,8 @@ details: function() { return this.detailViews; }, actionClass: 'action-view', actionContent: function() { - // eslint-disable-next-line no-undef - return interpolate( // xss-lint: disable=javascript-interpolate - gettext('View %(span_start)s %(team_name)s %(span_end)s'), + return StringUtils.interpolate( + gettext('View {span_start} {team_name} {span_end}'), {span_start: '<span class="sr">', team_name: _.escape(this.model.get('name')), span_end: '</span>'}, true ); diff --git a/lms/djangoapps/teams/static/teams/js/views/team_profile_header_actions.js b/lms/djangoapps/teams/static/teams/js/views/team_profile_header_actions.js index 1a4bfbbeff4..66780676fa4 100644 --- a/lms/djangoapps/teams/static/teams/js/views/team_profile_header_actions.js +++ b/lms/djangoapps/teams/static/teams/js/views/team_profile_header_actions.js @@ -6,8 +6,9 @@ 'underscore', 'gettext', 'teams/js/views/team_utils', - 'text!teams/templates/team-profile-header-actions.underscore'], - function(Backbone, $, _, gettext, TeamUtils, teamProfileHeaderActionsTemplate) { + 'text!teams/templates/team-profile-header-actions.underscore', + 'edx-ui-toolkit/js/utils/html-utils'], + function(Backbone, $, _, gettext, TeamUtils, teamProfileHeaderActionsTemplate, HtmlUtils) { return Backbone.View.extend({ errorMessage: gettext('An error occurred. Try again.'), @@ -53,12 +54,14 @@ showJoinButton = true; } } - - view.$el.html(view.template({ // xss-lint: disable=javascript-jquery-html - showJoinButton: showJoinButton, - message: message, - showEditButton: view.showEditButton - })); + HtmlUtils.setHtml( + view.$el, + HtmlUtils.template(teamProfileHeaderActionsTemplate)({ + showJoinButton: showJoinButton, + message: message, + showEditButton: view.showEditButton + }) + ); }); return view; }, diff --git a/lms/djangoapps/teams/static/teams/js/views/team_utils.js b/lms/djangoapps/teams/static/teams/js/views/team_utils.js index 4c3e09ca8ba..723b583abdc 100644 --- a/lms/djangoapps/teams/static/teams/js/views/team_utils.js +++ b/lms/djangoapps/teams/static/teams/js/views/team_utils.js @@ -1,8 +1,8 @@ /* Team utility methods*/ (function(define) { 'use strict'; - define(['jquery', 'underscore'], - function($, _) { + define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/string-utils'], + function($, _, StringUtils) { return { /** @@ -20,12 +20,11 @@ }, teamCapacityText: function(memberCount, maxMemberCount) { - // eslint-disable-next-line no-undef - return interpolate( // xss-lint: disable=javascript-interpolate + return StringUtils.interpolate( // Translators: The following message displays the number of members on a team. ngettext( - '%(memberCount)s / %(maxMemberCount)s Member', - '%(memberCount)s / %(maxMemberCount)s Members', + '{memberCount} / {maxMemberCount} Member', + '{memberCount} / {maxMemberCount} Members', maxMemberCount ), {memberCount: memberCount, maxMemberCount: maxMemberCount}, true diff --git a/lms/djangoapps/teams/static/teams/js/views/topic_card.js b/lms/djangoapps/teams/static/teams/js/views/topic_card.js index a65ffe1b457..34734773b3f 100644 --- a/lms/djangoapps/teams/static/teams/js/views/topic_card.js +++ b/lms/djangoapps/teams/static/teams/js/views/topic_card.js @@ -3,8 +3,14 @@ */ (function(define) { 'use strict'; - define(['backbone', 'underscore', 'gettext', 'js/components/card/views/card'], - function(Backbone, _, gettext, CardView) { + define([ + 'backbone', + 'underscore', + 'gettext', + 'js/components/card/views/card', + 'edx-ui-toolkit/js/utils/html-utils', + 'edx-ui-toolkit/js/utils/string-utils'], + function(Backbone, _, gettext, CardView, HtmlUtils, StringUtils) { var TeamCountDetailView = Backbone.View.extend({ tagName: 'p', className: 'team-count', @@ -15,12 +21,15 @@ render: function() { var team_count = this.model.get('team_count'); // eslint-disable-line camelcase - // eslint-disable-next-line no-undef, max-len - this.$el.html(_.escape(interpolate( // xss-lint: disable=javascript-jquery-html,javascript-interpolate - ngettext('%(team_count)s Team', '%(team_count)s Teams', team_count), - {team_count: team_count}, - true - ))); + HtmlUtils.setHtml( + this.$el, + HtmlUtils.HTML(_.escape(StringUtils.interpolate( + ngettext('{team_count} Team', '{team_count} Teams', team_count), + {team_count: team_count}, + true + ))) + ); + return this; } }); @@ -43,9 +52,8 @@ details: function() { return this.detailViews; }, actionClass: 'action-view', actionContent: function() { - // eslint-disable-next-line no-undef - var screenReaderText = _.escape(interpolate( // xss-lint: disable=javascript-interpolate - gettext('View Teams in the %(topic_name)s Topic'), + var screenReaderText = _.escape(StringUtils.interpolate( + gettext('View Teams in the {topic_name} Topic'), {topic_name: this.model.get('name')}, true )); // eslint-disable-next-line max-len -- GitLab