Extra validation of the uploaded ZIP #73

Merged
Anna Sirota merged 13 commits from validation-single-theme-xml into main 2024-04-11 12:32:50 +02:00
6 changed files with 53 additions and 6 deletions
Showing only changes of commit a64eb5b9ad - Show all commits

View File

@ -58,7 +58,7 @@ EXTENSION_TYPE_PLURAL = {
EXTENSION_TYPE_CHOICES.THEME: _('Themes'), EXTENSION_TYPE_CHOICES.THEME: _('Themes'),
} }
EXTENSION_SLUGS_PATH = '|'.join(EXTENSION_TYPE_SLUGS.values()) EXTENSION_SLUGS_PATH = '|'.join(EXTENSION_TYPE_SLUGS.values())
EXTENSION_TYPES = {v: k for k, v in EXTENSION_TYPE_SLUGS_SINGULAR.items()} EXTENSION_SLUG_TYPES = {v: k for k, v in EXTENSION_TYPE_SLUGS_SINGULAR.items()}
ALLOWED_EXTENSION_MIMETYPES = ('application/zip', ) ALLOWED_EXTENSION_MIMETYPES = ('application/zip', )
# FIXME: this controls the initial widget rendered server-side, and server-side validation # FIXME: this controls the initial widget rendered server-side, and server-side validation

Binary file not shown.

Binary file not shown.

View File

@ -168,7 +168,21 @@ class SubmitFileTest(TestCase):
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertDictEqual( self.assertDictEqual(
response.context['form'].errors, response.context['form'].errors,
{'source': ['A theme ZIP archive should contain a single XML file']}, {'source': ['A theme ZIP archive should only have one XML file']},
)
def test_validation_errors_no_init(self):
self.assertEqual(Extension.objects.count(), 0)
user = UserFactory()
self.client.force_login(user)
with open(TEST_FILES_DIR / 'addon-without-init.zip', 'rb') as fp:
response = self.client.post(self.url, {'source': fp, 'agreed_with_terms': True})
self.assertEqual(response.status_code, 200)
self.assertDictEqual(
response.context['form'].errors,
{'source': ['An add-on directory should contain an __init__.py file']},
) )
def test_theme_file(self): def test_theme_file(self):
@ -218,6 +232,31 @@ class SubmitFileTest(TestCase):
self.assertEqual(response.status_code, 200, _get_all_form_errors(response)) self.assertEqual(response.status_code, 200, _get_all_form_errors(response))
self.assertEqual(File.objects.count(), 0) self.assertEqual(File.objects.count(), 0)
def test_addon_single_py(self):
self.assertEqual(File.objects.count(), 0)
user = UserFactory()
self.client.force_login(user)
with open(TEST_FILES_DIR / 'addon-single-py-module.zip', 'rb') as fp:
response = self.client.post(self.url, {'source': fp, 'agreed_with_terms': True})
self.assertEqual(response.status_code, 302, _get_all_form_errors(response))
self.assertEqual(File.objects.count(), 1)
file = File.objects.first()
self.assertEqual(response['Location'], file.get_submit_url())
self.assertEqual(file.user, user)
self.assertEqual(file.original_name, 'addon-single-py-module.zip')
self.assertEqual(file.size_bytes, 558)
self.assertEqual(
file.original_hash,
'sha256:21408edc82b70a16fd332311faf297b86a29c96cea554b206a162394033c2451',
)
self.assertEqual(
file.hash, 'sha256:21408edc82b70a16fd332311faf297b86a29c96cea554b206a162394033c2451',
)
self.assertEqual(file.get_type_display(), 'Add-on')
self.assertEqual(file.metadata['name'], 'Some Add-on')
for file_name, data in EXPECTED_EXTENSION_DATA.items(): for file_name, data in EXPECTED_EXTENSION_DATA.items():

View File

@ -13,7 +13,7 @@ from .validators import (
FileMIMETypeValidator, FileMIMETypeValidator,
ManifestValidator, ManifestValidator,
) )
from constants.base import EXTENSION_TYPES, ALLOWED_EXTENSION_MIMETYPES from constants.base import EXTENSION_SLUG_TYPES, ALLOWED_EXTENSION_MIMETYPES
import files.models import files.models
import files.utils as utils import files.utils as utils
@ -31,7 +31,8 @@ class FileForm(forms.ModelForm):
error_messages = { error_messages = {
'invalid_manifest_toml': _('A valid manifest file could not be found'), 'invalid_manifest_toml': _('A valid manifest file could not be found'),
'invalid_zip_archive': msg_only_zip_files, 'invalid_zip_archive': msg_only_zip_files,
'invalid_theme_multiple_xmls': _('A theme ZIP archive should contain a single XML file'), 'invalid_theme_multiple_xmls': _('A theme ZIP archive should only have one XML file'),
'invalid_missing_init': _('An add-on directory should contain an __init__.py file'),
} }
class Meta: class Meta:
@ -151,6 +152,6 @@ class FileForm(forms.ModelForm):
self.cleaned_data['metadata'] = manifest self.cleaned_data['metadata'] = manifest
# TODO: Error handling # TODO: Error handling
self.cleaned_data['type'] = EXTENSION_TYPES[manifest['type']] self.cleaned_data['type'] = EXTENSION_SLUG_TYPES[manifest['type']]
return self.cleaned_data return self.cleaned_data

View File

@ -89,11 +89,18 @@ def read_manifest_from_zip(archive_path):
with myzip.open(manifest_filepath) as file_content: with myzip.open(manifest_filepath) as file_content:
toml_content = toml.loads(file_content.read().decode()) toml_content = toml.loads(file_content.read().decode())
is_a_directory = '/' in manifest_filepath
# In case manifest TOML was successfully parsed, do additional type-specific validation # In case manifest TOML was successfully parsed, do additional type-specific validation
if toml_content['type'] == 'theme': type_slug = toml_content['type']
if type_slug == 'theme':
theme_xmls = filter_file_paths_by_ext(file_list, '.xml') theme_xmls = filter_file_paths_by_ext(file_list, '.xml')
if len(list(theme_xmls)) != 1: if len(list(theme_xmls)) != 1:
error_codes.append('invalid_theme_multiple_xmls') error_codes.append('invalid_theme_multiple_xmls')
elif type_slug == 'add-on':
if is_a_directory:
init_filepath = find_file_inside_zip_list('__init__.py', file_list)
if not init_filepath:
error_codes.append('invalid_missing_init')
return toml_content, error_codes return toml_content, error_codes