Commit 7a9991e9 by Mushtaq Ali

Studio homepage escaping

parent a26d5764
...@@ -9,6 +9,9 @@ from mock import patch, Mock ...@@ -9,6 +9,9 @@ from mock import patch, Mock
import ddt import ddt
from django.test import RequestFactory from django.test import RequestFactory
from django.test.client import Client
from common.test.utils import XssTestMixin
from xmodule.course_module import CourseSummary from xmodule.course_module import CourseSummary
from contentstore.views.course import (_accessible_courses_list, _accessible_courses_list_from_groups, from contentstore.views.course import (_accessible_courses_list, _accessible_courses_list_from_groups,
...@@ -30,7 +33,7 @@ USER_COURSES_COUNT = 50 ...@@ -30,7 +33,7 @@ USER_COURSES_COUNT = 50
@ddt.ddt @ddt.ddt
class TestCourseListing(ModuleStoreTestCase): class TestCourseListing(ModuleStoreTestCase, XssTestMixin):
""" """
Unit tests for getting the list of courses for a logged in user Unit tests for getting the list of courses for a logged in user
""" """
...@@ -72,6 +75,30 @@ class TestCourseListing(ModuleStoreTestCase): ...@@ -72,6 +75,30 @@ class TestCourseListing(ModuleStoreTestCase):
self.client.logout() self.client.logout()
ModuleStoreTestCase.tearDown(self) ModuleStoreTestCase.tearDown(self)
def test_course_listing_is_escaped(self):
"""
Tests course listing returns escaped data.
"""
escaping_content = "<script>alert('ESCAPE')</script>"
# Make user staff to access course listing
self.user.is_staff = True
self.user.save() # pylint: disable=no-member
self.client = Client()
self.client.login(username=self.user.username, password='test')
# Change 'display_coursenumber' field and update the course.
course = CourseFactory.create()
course.display_coursenumber = escaping_content
course = self.store.update_item(course, self.user.id) # pylint: disable=no-member
self.assertEqual(course.display_coursenumber, escaping_content)
# Check if response is escaped
response = self.client.get('/home')
self.assertEqual(response.status_code, 200)
self.assert_no_xss(response, escaping_content)
def test_get_course_list(self): def test_get_course_list(self):
""" """
Test getting courses with new access group format e.g. 'instructor_edx.course.run' Test getting courses with new access group format e.g. 'instructor_edx.course.run'
......
...@@ -10,6 +10,7 @@ from provider.constants import CONFIDENTIAL ...@@ -10,6 +10,7 @@ from provider.constants import CONFIDENTIAL
from openedx.core.djangoapps.programs.models import ProgramsApiConfig from openedx.core.djangoapps.programs.models import ProgramsApiConfig
from openedx.core.djangoapps.programs.tests.mixins import ProgramsApiConfigMixin, ProgramsDataMixin from openedx.core.djangoapps.programs.tests.mixins import ProgramsApiConfigMixin, ProgramsDataMixin
from openedx.core.djangolib.markup import escape
from student.tests.factories import UserFactory from student.tests.factories import UserFactory
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
...@@ -63,7 +64,7 @@ class TestProgramListing(ProgramsApiConfigMixin, ProgramsDataMixin, SharedModule ...@@ -63,7 +64,7 @@ class TestProgramListing(ProgramsApiConfigMixin, ProgramsDataMixin, SharedModule
self.mock_programs_api(data={'results': []}) self.mock_programs_api(data={'results': []})
response = self.client.get(self.studio_home) response = self.client.get(self.studio_home)
self.assertIn("You haven't created any programs yet.", response.content) self.assertIn(escape("You haven't created any programs yet."), response.content)
# When data is provided, expect a program listing. # When data is provided, expect a program listing.
self.mock_programs_api() self.mock_programs_api()
......
<%! from django.utils.translation import ugettext as _ %> <%! from openedx.core.djangolib.markup import HTML, ugettext as _ %>
<%page expression_filter="h"/>
<%inherit file="base.html" /> <%inherit file="base.html" />
...@@ -79,7 +80,10 @@ ...@@ -79,7 +80,10 @@
## Translators: This is an example for the name of the organization sponsoring a course, seen when filling out the form to create a new course. The organization name cannot contain spaces. ## Translators: This is an example for the name of the organization sponsoring a course, seen when filling out the form to create a new course. The organization name cannot contain spaces.
## Translators: "e.g. UniversityX or OrganizationX" is a placeholder displayed when user put no data into this field. ## Translators: "e.g. UniversityX or OrganizationX" is a placeholder displayed when user put no data into this field.
<input class="new-course-org" id="new-course-org" type="text" name="new-course-org" required placeholder="${_('e.g. UniversityX or OrganizationX')}" aria-describedby="tip-new-course-org tip-error-new-course-org" /> <input class="new-course-org" id="new-course-org" type="text" name="new-course-org" required placeholder="${_('e.g. UniversityX or OrganizationX')}" aria-describedby="tip-new-course-org tip-error-new-course-org" />
<span class="tip" id="tip-new-course-org">${_("The name of the organization sponsoring the course.")} <strong>${_("Note: The organization name is part of the course URL")}</strong> ${_("This cannot be changed, but you can set a different display name in Advanced Settings later.")}</span> <span class="tip" id="tip-new-course-org">${_("The name of the organization sponsoring the course. {strong_start}Note: The organization name is part of the course URL.{strong_end} This cannot be changed, but you can set a different display name in Advanced Settings later.").format(
strong_start=HTML('<strong>'),
strong_end=HTML('</strong>'),
)}</span>
<span class="tip tip-error is-hiding" id="tip-error-new-course-org"></span> <span class="tip tip-error is-hiding" id="tip-error-new-course-org"></span>
</li> </li>
...@@ -89,7 +93,10 @@ ...@@ -89,7 +93,10 @@
## seen when filling out the form to create a new course. The number here is ## seen when filling out the form to create a new course. The number here is
## short for "Computer Science 101". It can contain letters but cannot contain spaces. ## short for "Computer Science 101". It can contain letters but cannot contain spaces.
<input class="new-course-number" id="new-course-number" type="text" name="new-course-number" required placeholder="${_('e.g. CS101')}" aria-describedby="tip-new-course-number tip-error-new-course-number" /> <input class="new-course-number" id="new-course-number" type="text" name="new-course-number" required placeholder="${_('e.g. CS101')}" aria-describedby="tip-new-course-number tip-error-new-course-number" />
<span class="tip" id="tip-new-course-number">${_("The unique number that identifies your course within your organization.")} <strong>${_("Note: This is part of your course URL, so no spaces or special characters are allowed and it cannot be changed.")}</strong></span> <span class="tip" id="tip-new-course-number">${_("The unique number that identifies your course within your organization. {strong_start}Note: This is part of your course URL, so no spaces or special characters are allowed and it cannot be changed.{strong_end}").format(
strong_start=HTML('<strong>'),
strong_end=HTML('</strong>'),
)}</span>
<span class="tip tip-error is-hiding" id="tip-error-new-course-number"></span> <span class="tip tip-error is-hiding" id="tip-error-new-course-number"></span>
</li> </li>
...@@ -98,7 +105,10 @@ ...@@ -98,7 +105,10 @@
## Translators: This is an example for the "run" used to identify different ## Translators: This is an example for the "run" used to identify different
## instances of a course, seen when filling out the form to create a new course. ## instances of a course, seen when filling out the form to create a new course.
<input class="new-course-run" id="new-course-run" type="text" name="new-course-run" required placeholder="${_('e.g. 2014_T1')}" aria-describedby="tip-new-course-run tip-error-new-course-run" /> <input class="new-course-run" id="new-course-run" type="text" name="new-course-run" required placeholder="${_('e.g. 2014_T1')}" aria-describedby="tip-new-course-run tip-error-new-course-run" />
<span class="tip" id="tip-new-course-run">${_("The term in which your course will run.")} <strong>${_("Note: This is part of your course URL, so no spaces or special characters are allowed and it cannot be changed.")}</strong></span> <span class="tip" id="tip-new-course-run">${_("The term in which your course will run. {strong_start}Note: This is part of your course URL, so no spaces or special characters are allowed and it cannot be changed.{strong_end}").format(
strong_start=HTML('<strong>'),
strong_end=HTML('</strong>'),
)}</span>
<span class="tip tip-error is-hiding" id="tip-error-new-course-run"></span> <span class="tip tip-error is-hiding" id="tip-error-new-course-run"></span>
</li> </li>
</ol> </ol>
...@@ -155,7 +165,10 @@ ...@@ -155,7 +165,10 @@
## for "Computer Science Problems". The example number may contain letters ## for "Computer Science Problems". The example number may contain letters
## but must not contain spaces. ## but must not contain spaces.
<input class="new-library-number" id="new-library-number" type="text" name="new-library-number" required placeholder="${_('e.g. CSPROB')}" aria-describedby="tip-new-library-number tip-error-new-library-number" /> <input class="new-library-number" id="new-library-number" type="text" name="new-library-number" required placeholder="${_('e.g. CSPROB')}" aria-describedby="tip-new-library-number tip-error-new-library-number" />
<span class="tip" id="tip-new-library-number">${_("The unique code that identifies this library.")} <strong>${_("Note: This is part of your library URL, so no spaces or special characters are allowed.")}</strong> ${_("This cannot be changed.")}</span> <span class="tip" id="tip-new-library-number">${_("The unique code that identifies this library. {strong_start}Note: This is part of your library URL, so no spaces or special characters are allowed.{strong_end} This cannot be changed.").format(
strong_start=HTML('<strong>'),
strong_end=HTML('</strong>'),
)}</span>
<span class="tip tip-error is-hiding" id="tip-error-new-library-number"></span> <span class="tip tip-error is-hiding" id="tip-error-new-library-number"></span>
</li> </li>
</ol> </ol>
...@@ -181,10 +194,10 @@ ...@@ -181,10 +194,10 @@
%for course_info in sorted(in_process_course_actions, key=lambda s: s['display_name'].lower() if s['display_name'] is not None else ''): %for course_info in sorted(in_process_course_actions, key=lambda s: s['display_name'].lower() if s['display_name'] is not None else ''):
<!-- STATE: re-run is processing --> <!-- STATE: re-run is processing -->
%if course_info['is_in_progress']: %if course_info['is_in_progress']:
<li class="wrapper-course has-status" data-course-key="${course_info['course_key'] | h}"> <li class="wrapper-course has-status" data-course-key="${course_info['course_key']}">
<div class="course-item course-rerun is-processing"> <div class="course-item course-rerun is-processing">
<div class="course-details" href="#"> <div class="course-details" href="#">
<h3 class="course-title">${course_info['display_name'] | h}</h3> <h3 class="course-title">${course_info['display_name']}</h3>
<div class="course-metadata"> <div class="course-metadata">
<span class="course-org metadata-item"> <span class="course-org metadata-item">
...@@ -216,8 +229,8 @@ ...@@ -216,8 +229,8 @@
<div class="status-message"> <div class="status-message">
<p class="copy">${_('The new course will be added to your course list in 5-10 minutes. Return to this page or {link_start}refresh it{link_end} to update the course list. The new course will need some manual configuration.').format( <p class="copy">${_('The new course will be added to your course list in 5-10 minutes. Return to this page or {link_start}refresh it{link_end} to update the course list. The new course will need some manual configuration.').format(
link_start='<a href="#" class="action-reload">', link_start=HTML('<a href="#" class="action-reload">'),
link_end='</a>', link_end=HTML('</a>'),
)}</p> )}</p>
</div> </div>
</li> </li>
...@@ -227,10 +240,10 @@ ...@@ -227,10 +240,10 @@
<!-- STATE: re-run has error --> <!-- STATE: re-run has error -->
%if course_info['is_failed']: %if course_info['is_failed']:
<li class="wrapper-course has-status" data-course-key="${course_info['course_key'] | h}"> <li class="wrapper-course has-status" data-course-key="${course_info['course_key']}">
<div class="course-item course-rerun has-error"> <div class="course-item course-rerun has-error">
<div class="course-details" href="#"> <div class="course-details" href="#">
<h3 class="course-title">${course_info['display_name'] | h}</h3> <h3 class="course-title">${course_info['display_name']}</h3>
<div class="course-metadata"> <div class="course-metadata">
<span class="course-org metadata-item"> <span class="course-org metadata-item">
...@@ -296,9 +309,9 @@ ...@@ -296,9 +309,9 @@
<div class="courses courses-tab active"> <div class="courses courses-tab active">
<ul class="list-courses"> <ul class="list-courses">
%for course_info in sorted(courses, key=lambda s: s['display_name'].lower() if s['display_name'] is not None else ''): %for course_info in sorted(courses, key=lambda s: s['display_name'].lower() if s['display_name'] is not None else ''):
<li class="course-item" data-course-key="${course_info['course_key'] | h}"> <li class="course-item" data-course-key="${course_info['course_key']}">
<a class="course-link" href="${course_info['url']}"> <a class="course-link" href="${course_info['url']}">
<h3 class="course-title">${course_info['display_name'] | h}</h3> <h3 class="course-title">${course_info['display_name']}</h3>
<div class="course-metadata"> <div class="course-metadata">
<span class="course-org metadata-item"> <span class="course-org metadata-item">
...@@ -450,7 +463,7 @@ ...@@ -450,7 +463,7 @@
%for library_info in sorted(libraries, key=lambda s: s['display_name'].lower() if s['display_name'] is not None else ''): %for library_info in sorted(libraries, key=lambda s: s['display_name'].lower() if s['display_name'] is not None else ''):
<li class="course-item"> <li class="course-item">
<a class="library-link" href="${library_info['url']}"> <a class="library-link" href="${library_info['url']}">
<h3 class="course-title">${library_info['display_name'] | h}</h3> <h3 class="course-title">${library_info['display_name']}</h3>
<div class="course-metadata"> <div class="course-metadata">
<span class="course-org metadata-item"> <span class="course-org metadata-item">
...@@ -508,12 +521,12 @@ ...@@ -508,12 +521,12 @@
<li class="course-item"> <li class="course-item">
<a class="program-link" href=${program_authoring_url + str(program['id'])}> <a class="program-link" href=${program_authoring_url + str(program['id'])}>
<h3 class="course-title">${program['name'] | h}</h3> <h3 class="course-title">${program['name']}</h3>
<div class="course-metadata"> <div class="course-metadata">
<span class="course-org metadata-item"> <span class="course-org metadata-item">
<!-- As of this writing, programs can only be owned by one organization. If that constraint is relaxed, this will need to be revisited. --> <!-- As of this writing, programs can only be owned by one organization. If that constraint is relaxed, this will need to be revisited. -->
<span class="label">${_("Organization:")}</span> <span class="value">${program['organizations'][0]['key'] | h}</span> <span class="label">${_("Organization:")}</span> <span class="value">${program['organizations'][0]['key']}</span>
</span> </span>
</div> </div>
</a> </a>
...@@ -565,8 +578,8 @@ ...@@ -565,8 +578,8 @@
<p>${_("In order to create courses in {studio_name}, you must {link_start}contact {platform_name} staff to help you create a course{link_end}.").format( <p>${_("In order to create courses in {studio_name}, you must {link_start}contact {platform_name} staff to help you create a course{link_end}.").format(
studio_name=settings.STUDIO_NAME, studio_name=settings.STUDIO_NAME,
platform_name=settings.PLATFORM_NAME, platform_name=settings.PLATFORM_NAME,
link_start='<a href="mailto:{email}">'.format(email=settings.FEATURES.get('STUDIO_REQUEST_EMAIL','')), link_start=HTML('<a href="mailto:{email}">').format(email=settings.FEATURES.get('STUDIO_REQUEST_EMAIL','')),
link_end="</a>", link_end=HTML("</a>"),
)}</p> )}</p>
</div> </div>
% endif % endif
...@@ -580,17 +593,11 @@ ...@@ -580,17 +593,11 @@
% elif course_creator_status == "denied": % elif course_creator_status == "denied":
<div class="bit"> <div class="bit">
<h3 class="title title-3">${_("Can I create courses in {studio_name}?").format(studio_name=settings.STUDIO_NAME)}</h3> <h3 class="title title-3">${_("Can I create courses in {studio_name}?").format(studio_name=settings.STUDIO_NAME)}</h3>
<%!
from django.conf import settings
help_link_start = '<a href="mailto:{email}">'.format(email=settings.TECH_SUPPORT_EMAIL)
help_link_end = '</a>'
%>
<p>${_("Your request to author courses in {studio_name} has been denied. Please {link_start}contact {platform_name} Staff with further questions{link_end}.").format( <p>${_("Your request to author courses in {studio_name} has been denied. Please {link_start}contact {platform_name} Staff with further questions{link_end}.").format(
studio_name=settings.STUDIO_NAME, studio_name=settings.STUDIO_NAME,
platform_name=settings.PLATFORM_NAME, platform_name=settings.PLATFORM_NAME,
link_start=help_link_start, link_start=HTML('<a href="mailto:{email}">').format(email=settings.TECH_SUPPORT_EMAIL),
link_end=help_link_end, link_end=HTML('</a>'),
)}</p> )}</p>
</div> </div>
...@@ -603,14 +610,14 @@ help_link_end = '</a>' ...@@ -603,14 +610,14 @@ help_link_end = '</a>'
<section class="content"> <section class="content">
<article class="content-primary" role="main"> <article class="content-primary" role="main">
<div class="introduction"> <div class="introduction">
<h2 class="title">${_("Thanks for signing up, %(name)s!") % dict(name= user.username)}</h2> <h2 class="title">${_("Thanks for signing up, {name}!").format(name=user.username)}</h2>
</div> </div>
<div class="notice notice-incontext notice-instruction notice-instruction-verification"> <div class="notice notice-incontext notice-instruction notice-instruction-verification">
<div class="msg"> <div class="msg">
<h3 class="title">${_("We need to verify your email address")}</h3> <h3 class="title">${_("We need to verify your email address")}</h3>
<div class="copy"> <div class="copy">
<p>${_('Almost there! In order to complete your sign up we need you to verify your email address (%(email)s). An activation message and next steps should be waiting for you there.') % dict(email=user.email)}</p> <p>${_('Almost there! In order to complete your sign up we need you to verify your email address ({email}). An activation message and next steps should be waiting for you there.').format(email=user.email)}</p>
</div> </div>
</div> </div>
</div> </div>
......
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