def clean_upload(self): upload = self.cleaned_data['upload'] errors = [] if upload.size > self.max_size: errors.append({ 'type': 'error', 'message': _('Packaged app too large for submission. Packages ' 'must be smaller than %s.' % filesizeformat( self.max_size)), 'tier': 1, }) # Immediately raise an error, do not process the rest of the view, # which would read the file. raise self.persist_errors(errors, upload) manifest = None try: # Be careful to keep this as in-memory zip reading. safe_zip = SafeUnzip(upload, 'r') safe_zip.is_valid() # Will throw ValidationError if necessary. manifest = safe_zip.extract_path('manifest.webapp') except forms.ValidationError as e: errors.append({ 'type': 'error', 'message': ''.join(e.messages), 'tier': 1, }) except Exception as e: errors.append({ 'type': 'error', 'message': _('Error extracting manifest from zip file.'), 'tier': 1, }) finally: safe_zip.close() origin = None if manifest: try: origin = WebAppParser.decode_manifest(manifest).get('origin') except forms.ValidationError as e: errors.append({ 'type': 'error', 'message': ''.join(e.messages), 'tier': 1, }) if origin: try: verify_app_domain(origin, packaged=True, exclude=self.addon) except forms.ValidationError, e: errors.append({ 'type': 'error', 'message': ''.join(e.messages), 'tier': 1, })
def test_is_broken(self): zip = SafeUnzip(self.packaged_app_path('signed.zip')) zip.is_valid() sf_re = re.compile('^META\-INF/(\w+)\.sf$') for info in zip.info: if sf_re.match(info.filename): info.filename = 'META-INF/foo.foo' break assert not zip.is_signed()
def manifest_contents(self): fp = get_file(self.fileorpath) if zipfile.is_zipfile(fp): zf = SafeUnzip(fp) zf.is_valid() # Raises forms.ValidationError if problems. try: data = zf.extract_path('manifest.json') except KeyError: raise forms.ValidationError( _('The file "manifest.json" was not found at the root ' 'of the zip archive.')) else: raise forms.ValidationError( _('Addons need to be packaged into a valid zip archive.')) return self.decode_manifest(data)
def validate_file(self, file_obj): """ Verify that the upload is a valid zip file that contains a manifest.json file. """ if file_obj.content_type not in self.valid_content_types: self.error('BAD_CONTENT_TYPE') try: self.zipfile = SafeUnzip(file_obj) try: # Will throw ValidationError if necessary. self.zipfile.is_valid() except ValidationError as e: raise ParseError(unicode(e)) except (BadZipfile, IOError): self.error('INVALID_ZIP') manifest = self.zipfile.extract_path('manifest.json') except KeyError: self.error('NO_MANIFEST') return manifest
def test_unzip_total_file_size_limit(self): # There are no files over 100 kb in that zip, but the total is over. zip = SafeUnzip(self.packaged_app_path('full-tpa.zip')) self.assertRaises(forms.ValidationError, zip.is_valid)
def test_is_secure(self): zip = SafeUnzip(self.packaged_app_path('signed.zip')) zip.is_valid() assert zip.is_signed()
def test_not_secure(self): zip = SafeUnzip(self.packaged_app_path('mozball.zip')) zip.is_valid() assert not zip.is_signed()
def test_extract_path(self): zip = SafeUnzip(self.packaged_app_path('mozball.zip')) assert zip.is_valid() desc_string = '"description": "Exciting Open Web development action!"' assert desc_string in zip.extract_path('manifest.webapp')
def test_unzip_not_fatal(self): zip = SafeUnzip(self.manifest_path('mozball.webapp')) assert not zip.is_valid(fatal=False)
def test_unzip_fatal(self): zip = SafeUnzip(self.manifest_path('mozball.webapp')) self.assertRaises(zipfile.BadZipfile, zip.is_valid)
def test_unzip_limit(self): zip = SafeUnzip(self.packaged_app_path('full-tpa.zip')) self.assertRaises(forms.ValidationError, zip.is_valid)
def fetch_icon(pk, file_pk=None, **kw): """ Downloads a webapp icon from the location specified in the manifest. Returns False if icon was not able to be retrieved If `file_pk` is not provided it will use the file from the app's `current_version`. """ webapp = Webapp.objects.get(pk=pk) log.info(u'[1@None] Fetching icon for webapp %s.' % webapp.name) if file_pk: file_obj = File.objects.get(pk=file_pk) else: file_obj = (webapp.current_version and webapp.current_version.all_files[0]) manifest = webapp.get_manifest_json(file_obj) if not manifest or 'icons' not in manifest: # Set the icon type to empty. webapp.update(icon_type='') return try: biggest = max(int(size) for size in manifest['icons']) except ValueError: log.error('No icon to fetch for webapp "%s"' % webapp.name) return False icon_url = manifest['icons'][str(biggest)] if icon_url.startswith('data:image'): image_string = icon_url.split('base64,')[1] content = base64.decodestring(image_string) else: if webapp.is_packaged: # Get icons from package. if icon_url.startswith('/'): icon_url = icon_url[1:] try: zf = SafeUnzip(private_storage.open(file_obj.file_path)) zf.is_valid() content = zf.extract_path(icon_url) except (KeyError, forms.ValidationError): # Not found in archive. log.error(u'[Webapp:%s] Icon %s not found in archive' % (webapp, icon_url)) return False else: if not urlparse.urlparse(icon_url).scheme: icon_url = webapp.origin + icon_url try: response = _fetch_content(icon_url) except Exception, e: log.error(u'[Webapp:%s] Failed to fetch icon for webapp: %s' % (webapp, e)) # Set the icon type to empty. webapp.update(icon_type='') return False try: content = get_content_and_check_size( response, settings.MAX_ICON_UPLOAD_SIZE) except ResponseTooLargeException: log.warning(u'[Webapp:%s] Icon exceeds maximum size.' % webapp) return False
def test_unzip_fatal(self): zip = SafeUnzip(self.xpi_path('search.xml')) self.assertRaises(zipfile.BadZipfile, zip.is_valid)
def test_unzip_limit(self): zip = SafeUnzip(self.xpi_path('langpack-localepicker')) self.assertRaises(forms.ValidationError, zip.is_valid)
def test_is_broken(self): zip = SafeUnzip(self.xpi_path('signed')) zip.is_valid() zip.info[2].filename = 'META-INF/foo.sf' assert not zip.is_signed()
def test_is_secure(self): zip = SafeUnzip(self.xpi_path('signed')) zip.is_valid() assert zip.is_signed()
def test_not_secure(self): zip = SafeUnzip(self.xpi_path('extension')) zip.is_valid() assert not zip.is_signed()
def test_extract_path(self): zip = SafeUnzip(self.xpi_path('langpack-localepicker')) assert zip.is_valid() assert 'locale browser de' in zip.extract_path('chrome.manifest')
def test_unzip_not_fatal(self): zip = SafeUnzip(self.xpi_path('search.xml')) assert not zip.is_valid(fatal=False)