diff --git a/extensions/tests/test_submit.py b/extensions/tests/test_submit.py
index 687726bd..58add202 100644
--- a/extensions/tests/test_submit.py
+++ b/extensions/tests/test_submit.py
@@ -118,12 +118,14 @@ EXPECTED_VALIDATION_ERRORS = {
'source': ['The manifest file is missing.'],
},
'invalid-manifest-toml.zip': {'source': ['Manifest file contains invalid code.']},
- 'invalid-theme-multiple-xmls.zip': {'source': ['Themes can only contain one XML file.']},
- 'invalid-theme-multiple-xmls-macosx.zip': {'source': ['Archive contains forbidden files or directories: __MACOSX/']},
+ 'invalid-theme-multiple-xmls.zip': {
+ 'source': ['Themes can only contain one XML file.']
+ },
+ 'invalid-theme-multiple-xmls-macosx.zip': {
+ 'source': ['Archive contains forbidden files or directories: __MACOSX/']
+ },
'invalid-missing-wheels.zip': {
- 'source': [
- 'Python wheel missing: addon/wheels/test-wheel-whatever.whl'
- ]
+ 'source': ['Python wheel missing: addon/wheels/test-wheel-whatever.whl']
},
}
POST_DATA = {
@@ -224,6 +226,16 @@ class SubmitFileTest(TestCase):
self.assertEqual(response.status_code, 200)
self.assertDictEqual(response.context['form'].errors, expected_errors)
+ def test_validation_errors_with_html(self):
+ self.assertEqual(Extension.objects.count(), 0)
+ user = UserFactory()
+ self.client.force_login(user)
+
+ with open(TEST_FILES_DIR / 'invalid-theme-multiple-xmls-macosx.zip', 'rb') as fp:
+ response = self.client.post(self.url, {'source': fp, 'agreed_with_terms': True})
+
+ self.assertNotContains(response, "<", html=False)
+
def test_addon_without_top_level_directory(self):
self.assertEqual(Extension.objects.count(), 0)
user = UserFactory()
diff --git a/files/forms.py b/files/forms.py
index f8e2e254..9b1642b8 100644
--- a/files/forms.py
+++ b/files/forms.py
@@ -4,6 +4,7 @@ import zipfile
import tempfile
from django import forms
+from django.utils.html import escape
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
@@ -36,11 +37,15 @@ class FileForm(forms.ModelForm):
# TODO: surface TOML parsing errors?
'invalid_manifest_toml': _('Manifest file contains invalid code.'),
'invalid_missing_init': mark_safe(_('Add-on file missing: __init__.py.')),
- 'missing_or_multiple_theme_xml': mark_safe(_('Themes can only contain one XML file.')),
+ 'missing_or_multiple_theme_xml': mark_safe(
+ _('Themes can only contain one XML file.')
+ ),
'invalid_zip_archive': msg_only_zip_files,
'missing_manifest_toml': _('The manifest file is missing.'),
- 'missing_wheel': _('Python wheel missing: %(path)s'), # TODO %(path)s
- 'forbidden_filepaths': _('Archive contains forbidden files or directories: %(paths)s'), #TODO %(paths)s
+ 'missing_wheel': _('Python wheel missing: %(path)s'),
+ 'forbidden_filepaths': mark_safe(
+ _('Archive contains forbidden files or directories: %(paths)s')
+ ),
}
class Meta:
@@ -145,12 +150,10 @@ class FileForm(forms.ModelForm):
manifest, error_codes = utils.read_manifest_from_zip(file_path)
for code in error_codes:
if isinstance(code, dict):
- errors.append(
- forms.ValidationError(
- self.error_messages[code['code']],
- params=code['params'],
- )
- )
+ error_message = str(self.error_messages[code['code']])
+ sanitized_params = {k: escape(v) for k, v in code['params'].items()}
+ error_message = mark_safe(error_message % sanitized_params)
+ errors.append(forms.ValidationError(error_message))
else:
errors.append(forms.ValidationError(self.error_messages[code]))
if errors: