Skip to content
Snippets Groups Projects
Commit ef0d56aa authored by Adeel Khan's avatar Adeel Khan
Browse files

Fix lms templates to prevent xss attacks.

This patch is part of multiple PR's.

LEARNER-4632
parent b4649edf
No related branches found
No related tags found
No related merge requests found
<%page expression_filter="h"/>
<%!
from django.urls import reverse
from django.utils.translation import ugettext as _
from openedx.core.djangolib.markup import HTML, Text
from six import text_type
%>
<%
def _message(reqm, message):
return message.format(link="<a href={url}>{url_name}</a>".format(
return Text(message).format(link=HTML("<a href={url}>{url_name}</a>").format(
url = reverse('jump_to', kwargs=dict(course_id=text_type(reqm.course_id),
location=text_type(reqm.location))),
url_name = reqm.display_name_with_default_escaped))
url_name = reqm.display_name_with_default))
%>
% if message:
% for reqm in module.required_modules:
......
......@@ -11,7 +11,7 @@ from third_party_auth import provider, pipeline
%>
<%!
from openedx.core.djangolib.js_utils import js_escaped_string
from openedx.core.djangolib.js_utils import js_escaped_string, dump_js_escaped_json
%>
<%block name="pagetitle">${_("Log into your {platform_name} Account").format(platform_name=platform_name)}</%block>
......@@ -60,7 +60,7 @@ from openedx.core.djangolib.js_utils import js_escaped_string
if (request.status === 403) {
$('.message.submission-error').removeClass('is-shown');
$('.third-party-signin.message').addClass('is-shown').focus();
$('.third-party-signin.message .instructions').HtmlUtils.setHtml(request.responseText);
$('.third-party-signin.message .instructions').text(request.responseText);
} else {
$('.third-party-signin.message').removeClass('is-shown');
$('.message.submission-error').addClass('is-shown').focus();
......@@ -70,7 +70,7 @@ from openedx.core.djangolib.js_utils import js_escaped_string
$('#login-form').on('ajax:success', function(event, json, xhr) {
if(json.success) {
var nextUrl = "${login_redirect_url | n}"; // xss-lint: disable=mako-invalid-js-filter
var nextUrl = "${login_redirect_url | n, js_escaped_string}";
if (json.redirect_url) {
nextUrl = json.redirect_url; // Most likely third party auth completion. This trumps 'nextUrl' above.
}
......@@ -89,7 +89,7 @@ from openedx.core.djangolib.js_utils import js_escaped_string
} else {
toggleSubmitButton(true);
$('.message.submission-error').addClass('is-shown').focus();
$('.message.submission-error .message-copy').HtmlUtils.setHtml(json.value);
$('.message.submission-error .message-copy').text(json.value);
}
});
$("#forgot-password-link").click(function() {
......@@ -101,15 +101,22 @@ from openedx.core.djangolib.js_utils import js_escaped_string
function toggleSubmitButton(enable) {
var $submitButton = $('form .form-actions #submit');
var $var1 = '${_('Log into My {platform_name} Account').format(platform_name=platform_name) | n, js_escaped_string}'
var $var2 = '${_('Access My Courses') | n, js_escaped_string}'
if(enable) {
var platform = "${_('Log into My {platform_name} Account').format(platform_name=platform_name) | n, js_escaped_string}";
var msg = "${_('Access My Courses') | n, js_escaped_string}";
var content = edx.HtmlUtils.interpolateHtml(
edx.HtmlUtils.HTML("{platform}<span class='orn-plus'>+</span>{msg}"),
{
platform:platform,
msg:msg
});
$submitButton.
removeClass('is-disabled').
attr('aria-disabled', false).
prop('disabled', false).
HtmlUtils.setHtml("$var1 <span class='orn-plus'>+</span> $var2");
html(HtmlUtils.ensureHtml(content).toString());
}
else {
$submitButton.
......@@ -133,7 +140,7 @@ from openedx.core.djangolib.js_utils import js_escaped_string
if (pipeline_running) {
$('#login-form').submit();
}
})('${pipeline_running | n, js_escaped_string}')
})(${pipeline_running | n, dump_js_escaped_json})
</script>
</%block>
......@@ -178,7 +185,10 @@ from openedx.core.djangolib.js_utils import js_escaped_string
% endif
<p class="instructions sr">
${HTML(_('Please provide the following information to log into your {platform_name} account. Required fields are noted by <strong class="indicator">bold text and an asterisk (*)</strong>.')).format(platform_name=platform_name)}
${Text(_('Please provide the following information to log into your {platform_name} account. Required fields are noted by {strong_start}bold text and an asterisk (*){strong_end}.')).format(
strong_start=HTML('<strong class="indicator">'),
strong_end=HTML('</strong>'),
platform_name=platform_name)}
</p>
<div class="group group-form group-form-requiredinformation">
......
<%page expression_filter="h"/>
<%inherit file="main.html" />
<%!
from django.urls import reverse
from django.utils.translation import ugettext as _
from openedx.core.djangolib.js_utils import js_escaped_string
%>
<h2>${_("Manage student accounts")}</h2>
......@@ -62,14 +64,14 @@ PLACEHOLDER_USERNAME = '__PLACEHOLDER_USERNAME'
<script type="text/javascript">
$(function() {
var form = $(".manage-accounts-form"),
profileUrl = "${reverse('accounts_api', kwargs={'username': PLACEHOLDER_USERNAME})}",
removeProfileUrl = "${reverse('profile_image_remove', kwargs={'username': PLACEHOLDER_USERNAME})}",
profileUrl = "${reverse('accounts_api', kwargs={'username': PLACEHOLDER_USERNAME}) | n, js_escaped_string}",
removeProfileUrl = "${reverse('profile_image_remove', kwargs={'username': PLACEHOLDER_USERNAME}) | n, js_escaped_string}",
refreshProfile;
refreshProfile = function(username) {
return $.ajax({
type: "GET",
url: profileUrl.replace('${PLACEHOLDER_USERNAME}', username),
url: profileUrl.replace('${PLACEHOLDER_USERNAME | n, js_escaped_string}', username),
success: function(response) {
var imageUrl = response["profile_image"]["image_url_medium"];
$("#profile-image", form).attr("src", imageUrl);
......@@ -86,10 +88,10 @@ $(function() {
var username = $('#username', form).val(),
action = $("input:radio[name=account_action]:checked", form).val();
if (action === 'remove_profile_image') {
$(".account-change-status").text("${_('working')}");
$(".account-change-status").text("${_('working') | n, js_escaped_string}");
$.ajax({
type: "POST",
url: removeProfileUrl.replace('${PLACEHOLDER_USERNAME}', username),
url: removeProfileUrl.replace('${PLACEHOLDER_USERNAME | n, js_escaped_string}', username),
success: function(response) {
refreshProfile(username).always(function() {
$("#profile-image", form).focus();
......@@ -98,13 +100,13 @@ $(function() {
}
});
} else if (action) {
$(".account-change-status").text("${_('working')}");
$(".account-change-status").text("${_('working') | n, js_escaped_string}");
$.ajax({
type: "POST",
url: form.attr('action'),
data: form.serialize(),
success: function(response) {
$(".account-change-status").html(response.message);
$(".account-change-status").text(response.message);
}
});
} else {
......
<%page expression_filter="h"/>
<%inherit file="shopping_cart_flow.html" />
<%!
from openedx.core.djangolib.js_utils import js_escaped_string
from django.utils.translation import ugettext as _
from django.urls import reverse
%>
......@@ -44,7 +46,7 @@ from django.urls import reverse
<div class="col-two">
<div class="col-2">
${form_html}
${form_html | n, decode.utf8}
<p>
${_('If no additional billing details are populated the payment confirmation will be sent to the user making the purchase.')}
</p>
......@@ -74,7 +76,7 @@ from django.urls import reverse
var recipient_email = $('input[name="recipient_email"]').val();
var company_contact_email = $('input[name="company_contact_email"]').val();
if ( recipient_email != '' && !(validateEmail(recipient_email))) {
$('span#recipient_email_error').html('Please enter valid email address');
$('span#recipient_email_error').text('Please enter valid email address');
$('input[name="recipient_email"]').addClass('error');
is_valid_email = false;
}
......@@ -83,7 +85,7 @@ from django.urls import reverse
$('span#recipient_email_error').html('');
}
if ( company_contact_email != '' && !(validateEmail(company_contact_email))) {
$('span#company_contact_email_error').html('Please enter valid email address');
$('span#company_contact_email_error').text('Please enter valid email address');
$('input[name="company_contact_email"]').addClass('error');
is_valid_email = false;
}
......@@ -97,7 +99,7 @@ from django.urls import reverse
event.preventDefault();
// Disable the submit button to prevent duplicate submissions
$(this).addClass("disabled");
var post_url = "${reverse('billing_details')}";
var post_url = "${reverse('billing_details') | n, js_escaped_string}";
var data = {
"company_name" : $('input[name="company_name"]').val(),
"company_contact_name" : $('input[name="company_contact_name"]').val(),
......@@ -109,7 +111,7 @@ from django.urls import reverse
$.post(post_url, data)
.success(function(data) {
if (data.is_course_enrollment_closed == true) {
location.href = "${reverse('shoppingcart.views.show_cart')}";
location.href = "${reverse('shoppingcart.views.show_cart') | n, js_escaped_string}";
}
else {
payment_form.submit();
......
<%page expression_filter="h"/>
<%inherit file="shopping_cart_flow.html" />
<%block name="review_highlight">class="active"</%block>
<%!
from openedx.core.djangolib.js_utils import js_escaped_string
from django.urls import reverse
from edxmako.shortcuts import marketing_link
from django.utils.translation import ugettext as _
from openedx.core.djangolib.markup import HTML, Text
from django.utils.translation import ungettext
from openedx.core.lib.courses import course_image_url
%>
......@@ -66,7 +69,7 @@ from openedx.core.lib.courses import course_image_url
<div class="clearfix">
<div class="image">
<img class="item-image" src="${course_image_url(course)}"
alt="${course.display_number_with_default | h} ${course.display_name_with_default_escaped} ${_('Cover Image')}" />
alt="${course.display_number_with_default} ${course.display_name_with_default} ${_('Cover Image')}" />
</div>
<div class="data-input">
## Translators: "Registration for:" is followed by a course name
......@@ -169,17 +172,19 @@ from openedx.core.lib.courses import course_image_url
</div>
<div name="payment" class="hidden">
<div id="processor_form" aria-describedby="payment_business_helper_text">
${form_html}
${form_html | n, decode.utf8}
</div>
<p id="payment_business_helper_text">
${_('After this purchase is complete, {username} will be enrolled in this course.').format(username=u'<br/><b>{username}</b>'.format(username=order.user.username))}
${Text(_('After this purchase is complete, {username} will be enrolled in this course.')).format( \
username=HTML(u'<br/><b>{username}</b>').format(username=order.user.username))}
</p>
</div>
% else:
<div name="payment" aria-describedby="payment_helper_text">
${form_html}
${form_html | n, decode.utf8}
<p id="payment_helper_text">
${_('After this purchase is complete, {username} will be enrolled in this course.').format(username=u'<br/><b>{username}</b>'.format(username=order.user.username))}
${Text(_('After this purchase is complete, {username} will be enrolled in this course.')).format( \
username=HTML(u'<br/><b>{username}</b>').format(username=order.user.username))}
</p>
</div>
<div name="billing" class="hidden">
......@@ -235,7 +240,7 @@ from openedx.core.lib.courses import course_image_url
$('button.btn-remove').click(function(event) {
event.preventDefault();
var post_url = "${reverse('shoppingcart.views.remove_item')}";
var post_url = "${reverse('shoppingcart.views.remove_item') | n, js_escaped_string}";
$.post(post_url, {id:$(this).data('item-id')})
.always(function(data){
location.reload(true);
......@@ -244,7 +249,7 @@ from openedx.core.lib.courses import course_image_url
$('#submit-code').click(function(event){
event.preventDefault();
var post_url = "${reverse('shoppingcart.views.use_code')}";
var post_url = "${reverse('shoppingcart.views.use_code') | n, js_escaped_string}";
if($('#input_code').val() == "") {
showErrorMsgs('Must enter a valid code','code');
return;
......@@ -273,7 +278,7 @@ from openedx.core.lib.courses import course_image_url
$('#submit-reset-redemption').click(function(event){
event.preventDefault();
var post_url = "${reverse('shoppingcart.views.reset_code_redemption')}";
var post_url = "${reverse('shoppingcart.views.reset_code_redemption') | n, js_escaped_string}";
$.post(post_url)
.success(function(data) {
location.reload(true);
......@@ -297,7 +302,7 @@ from openedx.core.lib.courses import course_image_url
return false;
}
event.preventDefault();
location.href = "${reverse('billing_details')}";
location.href = "${reverse('billing_details') | n, js_escaped_string}";
});
......@@ -353,7 +358,7 @@ from openedx.core.lib.courses import course_image_url
function showErrorMsgs(msg, msg_area){
$( "span.error-text#"+ msg_area +"" ).removeClass("hidden");
$( "span.error-text#"+ msg_area +"" ).html(msg).show();
$( "span.error-text#"+ msg_area +"" ).text(msg).show();
if(msg_area=='code'){
$("#input_code").addClass('error');
......@@ -375,11 +380,11 @@ from openedx.core.lib.courses import course_image_url
function update_user_cart(ItemId, newQty, prevQty, unit_cost, wasbusinessType, isbusinessType){
var post_url = "${reverse('shoppingcart.views.update_user_cart')}";
var post_url = "${reverse('shoppingcart.views.update_user_cart') | n, js_escaped_string}";
var typeChanged = false;
var prevTotal = $('#total-amount').data('amount');
var newTotal = getNewTotal(prevQty, newQty, unit_cost, prevTotal);
$('#total-amount').html('$'+newTotal.toFixed(2)+' USD');
$('#total-amount').text('$'+newTotal.toFixed(2)+' USD');
$('#total-amount').data('amount', newTotal);
if(isbusinessType != wasbusinessType){
......@@ -401,7 +406,7 @@ from openedx.core.lib.courses import course_image_url
var prevTotal = data['total_cost'];
$('html').css({'cursor':'default'});
$(".button").css({'cursor':'default'});
$("#processor_form").html(data['form_html']);
$("#processor_form").html(edx.HtmlUtils.HTML(data['form_html']).toString());
if(typeChanged){
var submit_button = $('.col-2.relative').find("button[type='submit']");
submit_button.removeAttr('disabled');
......
<%page expression_filter="h"/>
<%inherit file="/main.html" />
<%!
from django.urls import reverse
......@@ -21,9 +22,9 @@
duration: 200
});
if (self.html() === "[ + ]") {
self.html("[ &#8722; ]");
self.html(edx.HtmlUtils.HTML("[ &#8722; ]").toString());
} else {
self.html("[ + ]");
self.text("[ + ]");
}
e.preventDefault();
});
......@@ -130,7 +131,7 @@ textarea {
%if course_id is not None:
## Translators: Git is a version-control system; see http://git-scm.com/about
<h2>${_('Recent git load activity for {course_id}').format(course_id=course_id) | h}</h2>
<h2>${_('Recent git load activity for {course_id}').format(course_id=course_id)}</h2>
%if error_msg:
<h3>${_('Error')}:</h3>
<p>${error_msg}</p>
......@@ -160,7 +161,7 @@ textarea {
<td>${date}</td>
<td>
<a href="${reverse('gitlogs_detail', kwargs={'course_id': unicode(cil.course_id)})}">
${cil.course_id | h}
${cil.course_id}
</a>
</td>
<td>
......@@ -176,7 +177,7 @@ textarea {
<tr class="import-log" id="import-log-${index}">
<td colspan="3">
<pre>
${cil.import_log | h}
${cil.import_log}
</pre>
</td>
</tr>
......
......@@ -150,7 +150,7 @@ class LoginFormTest(ThirdPartyAuthTestMixin, UrlResetMixin, SharedModuleStoreTes
# Verify that the parameters are sent on to the next page correctly
post_login_handler = _finish_auth_url(params)
js_success_var = u'var nextUrl = "{}";'.format(post_login_handler)
js_success_var = u'var nextUrl = "{}";'.format(js_escaped_string(post_login_handler))
self.assertContains(response, js_success_var)
# Verify that the login link preserves the querystring params
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment