Example #1
0
def json_upload_detail(request, upload, addon=None):
    result = upload_validation_context(request, upload, addon=addon)
    if result["validation"]:
        if result["validation"]["errors"] == 0:
            try:
                parse_addon(upload, addon=addon)
            except django_forms.ValidationError, exc:
                m = []
                for msg in exc.messages:
                    # Simulate a validation error so the UI displays it.
                    m.append({"type": "error", "message": msg, "tier": 1})
                v = make_validation_result(dict(error="", validation=dict(messages=m)))
                return json_view.error(v)
Example #2
0
def json_upload_detail(request, upload, addon=None):
    result = upload_validation_context(request, upload, addon=addon)
    if result['validation']:
        if result['validation']['errors'] == 0:
            try:
                parse_addon(upload, addon=addon)
            except django_forms.ValidationError, exc:
                m = []
                for msg in exc.messages:
                    # Simulate a validation error so the UI displays it.
                    m.append({'type': 'error', 'message': msg, 'tier': 1})
                v = make_validation_result(dict(error='',
                                                validation=dict(messages=m)))
                return json_view.error(v)
Example #3
0
def test_parse_addon(webapp_mock, search_mock, xpi_mock):
    parse_addon('file.xpi', None)
    xpi_mock.assert_called_with('file.xpi', None)

    parse_addon('file.xml', None)
    search_mock.assert_called_with('file.xml', None)

    parse_addon('file.jar', None)
    xpi_mock.assert_called_with('file.jar', None)

    parse_addon('file.webapp', None)
    webapp_mock.assert_called_with('file.webapp', None)

    parse_addon('file.json', None)
    webapp_mock.assert_called_with('file.json', None)
Example #4
0
 def test_public_to_unreviewed(self):
     upload = self.upload('extension')
     d = parse_addon(upload.path)
     self.addon.update(status=amo.STATUS_PUBLIC)
     eq_(self.addon.status, amo.STATUS_PUBLIC)
     f = File.from_upload(upload, self.version, self.platform, parse_data=d)
     eq_(f.status, amo.STATUS_UNREVIEWED)
Example #5
0
    def manifest_updated(self, manifest, upload):
        """The manifest has updated, update the version and file.

        This is intended to be used for hosted apps only, which have only a
        single version and a single file.
        """
        data = parse_addon(upload, self)
        version = self.versions.latest()
        version.update(version=data['version'])
        path = smart_path(nfd_str(upload.path))
        file = version.files.latest()
        file.filename = file.generate_filename(extension='.webapp')
        file.size = int(max(1, round(storage.size(path) / 1024, 0)))
        file.hash = (file.generate_hash(path) if
                     waffle.switch_is_active('file-hash-paranoia') else
                     upload.hash)
        log.info('Updated file hash to %s' % file.hash)
        file.save()

        # Move the uploaded file from the temp location.
        copy_stored_file(path, os.path.join(version.path_prefix,
                                            nfd_str(file.filename)))
        log.info('[Webapp:%s] Copied updated manifest to %s' % (
            self, version.path_prefix))

        amo.log(amo.LOG.MANIFEST_UPDATED, self)
Example #6
0
    def put(self, request, addon, version):
        if 'upload' in request.FILES:
            filedata = request.FILES['upload']
        else:
            return Response(
                {'error': _('Missing "upload" key in multipart file data.')},
                status=status.HTTP_400_BAD_REQUEST)

        try:
            # Parse the file to get and validate package data with the addon.
            pkg = parse_addon(filedata, addon)
        except forms.ValidationError as e:
            return Response({'error': e.message},
                            status=status.HTTP_400_BAD_REQUEST)
        if pkg['version'] != version:
            return Response(
                {'error': _('Version does not match install.rdf.')},
                status=status.HTTP_400_BAD_REQUEST)
        elif addon.versions.filter(version=version).exists():
            return Response({'error': _('Version already exists.')},
                            status=status.HTTP_409_CONFLICT)

        file_upload = handle_upload(
            filedata=filedata, user=request.user, addon=addon, submit=True)

        return Response(FileUploadSerializer(file_upload).data,
                        status=status.HTTP_202_ACCEPTED)
Example #7
0
 def test_trusted_lite_to_lite(self):
     upload = self.upload('extension')
     data = parse_addon(upload.path)
     self.addon.update(status=amo.STATUS_LITE, trusted=True)
     eq_(self.addon.status, amo.STATUS_LITE)
     f = File.from_upload(upload, self.version, self.platform, data)
     eq_(f.status, amo.STATUS_LITE)
Example #8
0
def json_upload_detail(upload):
    if not settings.VALIDATE_ADDONS:
        upload.task_error = ''
        upload.validation = json.dumps({'errors': 0, 'messages': [],
                                        'notices': 0, 'warnings': 0})
        upload.save()

    validation = json.loads(upload.validation) if upload.validation else ""
    url = reverse('devhub.upload_detail', args=[upload.uuid, 'json'])
    full_report_url = reverse('devhub.upload_detail', args=[upload.uuid])
    plat_exclude = []

    if validation:
        prepare_validation_results(validation)
        if validation['errors'] == 0:
            try:
                apps = parse_addon(upload.path).get('apps', [])
                app_ids = set([a.id for a in apps])
                supported_platforms = []
                if amo.MOBILE.id in app_ids:
                    supported_platforms.extend(amo.MOBILE_PLATFORMS.keys())
                    app_ids.remove(amo.MOBILE.id)
                if len(app_ids):
                    # Targets any other non-mobile app:
                    supported_platforms.extend(amo.DESKTOP_PLATFORMS.keys())
                s = amo.SUPPORTED_PLATFORMS.keys()
                plat_exclude = set(s) - set(supported_platforms)
                plat_exclude = [str(p) for p in plat_exclude]
            except django_forms.ValidationError, exc:
                # XPI parsing errors will be reported in the form submission
                # (next request).
                # TODO(Kumar) It would be nicer to present errors to the user
                # right here to avoid confusion about platform selection.
                log.error("XPI parsing error, ignored: %s" % exc)
Example #9
0
 def clean(self):
     if not self.errors:
         xpi = parse_addon(self.cleaned_data["upload"], self.addon)
         if self.addon.versions.filter(version=xpi["version"]):
             raise forms.ValidationError(_(u"Version %s already exists") % xpi["version"])
         self._clean_all_platforms()
     return self.cleaned_data
Example #10
0
    def clean(self):

        data = self.cleaned_data
        if 'upload' not in self.cleaned_data:
            self._errors['upload'] = self.upload_error
            return

        # Packaged apps are only valid for firefox os.
        if self.is_packaged():
            # Now run the packaged app check, done in clean, because
            # clean_packaged needs to be processed first.
            try:
                pkg = parse_addon(data['upload'], self.addon)
            except forms.ValidationError, e:
                self._errors['upload'] = self.error_class(e.messages)
                return

            ver = pkg.get('version')
            if (ver and self.addon and
                self.addon.versions.filter(version=ver).exists()):
                self._errors['upload'] = _(u'Version %s already exists') % ver
                return

            origin = pkg.get('origin')
            if origin:
                try:
                    validate_origin(origin)
                    origin = verify_app_domain(origin, packaged=True)
                except forms.ValidationError, e:
                    self._errors['upload'] = self.error_class(e.messages)
                    return
                if origin:
                    data['origin'] = origin
Example #11
0
def json_upload_detail(request, upload, addon_slug=None):
    addon = None
    if addon_slug:
        addon = get_object_or_404(Addon, slug=addon_slug)
    result = upload_validation_context(request, upload, addon=addon)
    plat_exclude = []
    if result['validation']:
        if result['validation']['errors'] == 0:
            try:
                pkg = parse_addon(upload, addon=addon)
                app_ids = set([a.id for a in pkg.get('apps', [])])
                supported_platforms = []
                for app in (amo.MOBILE, amo.ANDROID):
                    if app.id in app_ids:
                        supported_platforms.extend(amo.MOBILE_PLATFORMS.keys())
                        app_ids.remove(app.id)
                if len(app_ids):
                    # Targets any other non-mobile app:
                    supported_platforms.extend(amo.DESKTOP_PLATFORMS.keys())
                s = amo.SUPPORTED_PLATFORMS.keys()
                plat_exclude = set(s) - set(supported_platforms)
                plat_exclude = [str(p) for p in plat_exclude]
            except django_forms.ValidationError, exc:
                m = []
                for msg in exc.messages:
                    # Simulate a validation error so the UI displays
                    # it as such
                    m.append({'type': 'error',
                              'message': msg, 'tier': 1})
                v = make_validation_result(
                        dict(error='', validation=dict(messages=m)))
                return json_view.error(v)
Example #12
0
 def test_lite_to_unreviewed(self):
     upload = self.upload('extension')
     data = parse_addon(upload.path)
     self.addon.update(status=amo.STATUS_LITE)
     eq_(self.addon.status, amo.STATUS_LITE)
     f = File.from_upload(upload, self.version, self.platform, data)
     eq_(f.status, amo.STATUS_UNREVIEWED)
Example #13
0
 def clean(self):
     if not self.errors:
         xpi = parse_addon(self.cleaned_data['upload'].path, self.addon)
         if self.addon.versions.filter(version=xpi['version']):
             raise forms.ValidationError(
                 _('Version %s already exists') % xpi['version'])
     return self.cleaned_data
Example #14
0
 def test_lite_to_unreviewed(self):
     upload = self.upload('extension')
     data = parse_addon(upload.path)
     self.addon.update(status=amo.STATUS_LITE)
     eq_(self.addon.status, amo.STATUS_LITE)
     f = File.from_upload(upload, self.version, self.platform, data)
     eq_(f.status, amo.STATUS_UNREVIEWED)
Example #15
0
 def test_trusted_lite_to_lite(self):
     upload = self.upload('extension')
     data = parse_addon(upload.path)
     self.addon.update(status=amo.STATUS_LITE, trusted=True)
     eq_(self.addon.status, amo.STATUS_LITE)
     f = File.from_upload(upload, self.version, self.platform, data)
     eq_(f.status, amo.STATUS_LITE)
Example #16
0
def json_upload_detail(request, upload, addon_slug=None):
    addon = None
    if addon_slug:
        addon = get_object_or_404(Addon, slug=addon_slug)
    result = upload_validation_context(request, upload, addon=addon)
    plat_exclude = []
    if result['validation']:
        if result['validation']['errors'] == 0:
            try:
                pkg = parse_addon(upload, addon=addon)
                app_ids = set([a.id for a in pkg.get('apps', [])])
                supported_platforms = []
                for app in (amo.MOBILE, amo.ANDROID):
                    if app.id in app_ids:
                        supported_platforms.extend(amo.MOBILE_PLATFORMS.keys())
                        app_ids.remove(app.id)
                if len(app_ids):
                    # Targets any other non-mobile app:
                    supported_platforms.extend(amo.DESKTOP_PLATFORMS.keys())
                s = amo.SUPPORTED_PLATFORMS.keys()
                plat_exclude = set(s) - set(supported_platforms)
                plat_exclude = [str(p) for p in plat_exclude]
            except django_forms.ValidationError, exc:
                m = []
                for msg in exc.messages:
                    # Simulate a validation error so the UI displays
                    # it as such
                    m.append({'type': 'error', 'message': msg, 'tier': 1})
                v = make_validation_result(
                    dict(error='', validation=dict(messages=m)))
                return json_view.error(v)
Example #17
0
 def test_trusted_public_to_beta(self):
     upload = self.upload('beta-extension')
     data = parse_addon(upload.path)
     self.addon.update(status=amo.STATUS_PUBLIC, trusted=True)
     eq_(self.addon.status, amo.STATUS_PUBLIC)
     f = File.from_upload(upload, self.version, self.platform, data)
     eq_(f.status, amo.STATUS_BETA)
Example #18
0
    def manifest_updated(self, manifest, upload):
        """The manifest has updated, update the version and file.

        This is intended to be used for hosted apps only, which have only a
        single version and a single file.
        """
        data = parse_addon(upload, self)
        version = self.versions.latest()
        version.update(version=data['version'])
        path = smart_path(nfd_str(upload.path))
        file = version.files.latest()
        file.filename = file.generate_filename(extension='.webapp')
        file.size = storage.size(path)
        file.hash = (file.generate_hash(path)
                     if waffle.switch_is_active('file-hash-paranoia') else
                     upload.hash)
        log.info('Updated file hash to %s' % file.hash)
        file.save()

        # Move the uploaded file from the temp location.
        copy_stored_file(
            path, os.path.join(version.path_prefix, nfd_str(file.filename)))
        log.info('[Webapp:%s] Copied updated manifest to %s' %
                 (self, version.path_prefix))

        amo.log(amo.LOG.MANIFEST_UPDATED, self)
Example #19
0
 def test_trusted_public_to_public(self):
     upload = self.upload('extension')
     d = parse_addon(upload.path)
     self.addon.update(status=amo.STATUS_PUBLIC, trusted=True)
     eq_(self.addon.status, amo.STATUS_PUBLIC)
     f = File.from_upload(upload, self.version, self.platform, parse_data=d)
     eq_(f.status, amo.STATUS_PUBLIC)
Example #20
0
 def test_beta_version_non_public(self):
     # Only public add-ons can get beta versions.
     upload = self.upload('beta-extension')
     data = parse_addon(upload.path)
     self.addon.update(status=amo.STATUS_LITE)
     f = File.from_upload(upload, self.version, self.platform, data)
     eq_(f.status, amo.STATUS_UNREVIEWED)
Example #21
0
 def clean(self):
     if not self.errors:
         self._clean_upload()
         xpi = parse_addon(self.cleaned_data['upload'])
         addons.forms.clean_name(xpi['name'])
         self._clean_all_platforms()
     return self.cleaned_data
 def test_rdf_parse_errors_are_ignored(self, run_validator,
                                       flag_is_active):
     run_validator.return_value = json.dumps({
         "errors": 0,
         "success": True,
         "warnings": 0,
         "notices": 0,
         "message_tree": {},
         "messages": [],
         "metadata": {}
     })
     flag_is_active.return_value = True
     addon = Addon.objects.get(pk=3615)
     xpi = self.get_upload('extension.xpi')
     d = parse_addon(xpi.path)
     # Set up a duplicate upload:
     addon.update(guid=d['guid'])
     res = self.client.get(reverse('devhub.validate_addon'))
     doc = pq(res.content)
     upload_url = doc('#upload-addon').attr('data-upload-url')
     with storage.open(xpi.path, 'rb') as f:
         # Simulate JS file upload
         res = self.client.post(upload_url, {'upload': f}, follow=True)
     data = json.loads(res.content)
     # Simulate JS result polling:
     res = self.client.get(data['url'])
     data = json.loads(res.content)
     # Make sure we don't see a dupe UUID error:
     eq_(data['validation']['messages'], [])
     # Simulate JS result polling on detail page:
     res = self.client.get(data['full_report_url'], follow=True)
     res = self.client.get(res.context['validate_url'], follow=True)
     data = json.loads(res.content)
     # Again, make sure we don't see a dupe UUID error:
     eq_(data['validation']['messages'], [])
Example #23
0
    def clean(self):

        data = self.cleaned_data
        if 'upload' not in self.cleaned_data:
            self._errors['upload'] = self.upload_error
            return

        # Packaged apps are only valid for firefox os.
        if self.is_packaged():
            # Now run the packaged app check, done in clean, because
            # clean_packaged needs to be processed first.
            try:
                pkg = parse_addon(data['upload'], self.addon)
            except forms.ValidationError, e:
                self._errors['upload'] = self.error_class(e.messages)
                return

            ver = pkg.get('version')
            if (ver and self.addon
                    and self.addon.versions.filter(version=ver).exists()):
                self._errors['upload'] = _(u'Version %s already exists') % ver
                return

            origin = pkg.get('origin')
            if origin:
                try:
                    origin = verify_app_domain(origin,
                                               packaged=True,
                                               exclude=self.addon)
                except forms.ValidationError, e:
                    self._errors['upload'] = self.error_class(e.messages)
                    return
                if origin:
                    data['origin'] = origin
Example #24
0
 def test_public_to_beta(self):
     upload = self.upload('beta-extension')
     data = parse_addon(upload.path)
     self.addon.update(status=amo.STATUS_PUBLIC)
     eq_(self.addon.status, amo.STATUS_PUBLIC)
     f = File.from_upload(upload, self.version, self.platform, data)
     eq_(f.status, amo.STATUS_BETA)
 def test_rdf_parse_errors_are_ignored(self, run_validator,
                                       flag_is_active):
     run_validator.return_value = json.dumps({
         "errors": 0,
         "success": True,
         "warnings": 0,
         "notices": 0,
         "message_tree": {},
         "messages": [],
         "metadata": {}
     })
     flag_is_active.return_value = True
     addon = Addon.objects.get(pk=3615)
     xpi = self.get_upload('extension.xpi')
     d = parse_addon(xpi.path)
     # Set up a duplicate upload:
     addon.update(guid=d['guid'])
     res = self.client.get(reverse('devhub.validate_addon'))
     doc = pq(res.content)
     upload_url = doc('#upload-addon').attr('data-upload-url')
     with storage.open(xpi.path, 'rb') as f:
         # Simulate JS file upload
         res = self.client.post(upload_url, {'upload': f}, follow=True)
     data = json.loads(res.content)
     # Simulate JS result polling:
     res = self.client.get(data['url'])
     data = json.loads(res.content)
     # Make sure we don't see a dupe UUID error:
     eq_(data['validation']['messages'], [])
     # Simulate JS result polling on detail page:
     res = self.client.get(data['full_report_url'], follow=True)
     res = self.client.get(res.context['validate_url'], follow=True)
     data = json.loads(res.content)
     # Again, make sure we don't see a dupe UUID error:
     eq_(data['validation']['messages'], [])
Example #26
0
 def test_public_to_unreviewed(self):
     upload = self.upload('extension')
     d = parse_addon(upload.path)
     self.addon.update(status=amo.STATUS_PUBLIC)
     eq_(self.addon.status, amo.STATUS_PUBLIC)
     f = File.from_upload(upload, self.version, self.platform, parse_data=d)
     eq_(f.status, amo.STATUS_UNREVIEWED)
Example #27
0
def json_upload_detail(upload):
    if not settings.VALIDATE_ADDONS:
        upload.task_error = ''
        upload.validation = json.dumps({'errors': 0, 'messages': [],
                                        'notices': 0, 'warnings': 0})
        upload.save()

    validation = json.loads(upload.validation) if upload.validation else ""
    url = reverse('devhub.upload_detail', args=[upload.uuid, 'json'])
    full_report_url = reverse('devhub.upload_detail', args=[upload.uuid])
    plat_exclude = []

    if validation:
        if validation['errors'] == 0:
            try:
                apps = parse_addon(upload.path).get('apps', [])
                app_ids = set([a.id for a in apps])
                supported_platforms = []
                if amo.MOBILE.id in app_ids:
                    supported_platforms.extend(amo.MOBILE_PLATFORMS.keys())
                    app_ids.remove(amo.MOBILE.id)
                if len(app_ids):
                    # Targets any other non-mobile app:
                    supported_platforms.extend(amo.DESKTOP_PLATFORMS.keys())
                s = amo.SUPPORTED_PLATFORMS.keys()
                plat_exclude = set(s) - set(supported_platforms)
                plat_exclude = [str(p) for p in plat_exclude]
            except django_forms.ValidationError, exc:
                # XPI parsing errors will be reported in the form submission
                # (next request).
                # TODO(Kumar) It would be nicer to present errors to the user
                # right here to avoid confusion about platform selection.
                log.error("XPI parsing error, ignored: %s" % exc)
Example #28
0
 def test_beta_version_non_public(self):
     # Only public add-ons can get beta versions.
     upload = self.upload('beta-extension')
     data = parse_addon(upload.path)
     self.addon.update(status=amo.STATUS_LITE)
     f = File.from_upload(upload, self.version, self.platform, data)
     eq_(f.status, amo.STATUS_UNREVIEWED)
Example #29
0
 def clean(self):
     if not self.errors:
         self._clean_upload()
         xpi = parse_addon(self.cleaned_data['upload'])
         addons.forms.clean_name(xpi['name'])
         self._clean_all_platforms()
     return self.cleaned_data
Example #30
0
def json_upload_detail(request, upload, addon_slug=None):
    addon = None
    if addon_slug:
        addon = get_object_or_404(Addon, slug=addon_slug)
    result = upload_validation_context(request, upload, addon=addon)
    if result['validation']:
        if result['validation']['errors'] == 0:
            try:
                parse_addon(upload, addon=addon)
            except django_forms.ValidationError, exc:
                m = []
                for msg in exc.messages:
                    # Simulate a validation error so the UI displays it.
                    m.append({'type': 'error', 'message': msg, 'tier': 1})
                v = make_validation_result(
                    dict(error='', validation=dict(messages=m)))
                return json_view.error(v)
Example #31
0
 def clean(self):
     if not self.errors:
         self._clean_upload()
         xpi = parse_addon(self.cleaned_data['upload'])
         # We don't enforce name uniqueness for unlisted add-ons.
         if not self.cleaned_data.get('is_unlisted', False):
             addons.forms.clean_name(xpi['name'], addon_type=xpi['type'])
     return self.cleaned_data
Example #32
0
 def clean(self):
     if not self.errors:
         self._clean_upload()
         xpi = parse_addon(self.cleaned_data['upload'])
         # We don't enforce name uniqueness for unlisted add-ons.
         if not self.cleaned_data.get('is_unlisted', False):
             addons.forms.clean_name(xpi['name'], addon_type=xpi['type'])
     return self.cleaned_data
Example #33
0
 def clean(self):
     if not self.errors:
         xpi = parse_addon(self.cleaned_data['upload'], self.addon)
         if self.addon.versions.filter(version=xpi['version']):
             raise forms.ValidationError(
                 _(u'Version %s already exists') % xpi['version'])
         self._clean_all_platforms()
     return self.cleaned_data
Example #34
0
 def clean(self):
     if not self.errors:
         self._clean_upload()
         xpi = parse_addon(self.cleaned_data['upload'], self.addon)
         if self.addon.versions.filter(version=xpi['version']):
             raise forms.ValidationError(
                 _(u'Version %s already exists') % xpi['version'])
         self._clean_all_platforms()
     return self.cleaned_data
Example #35
0
 def test_trusted_litenominated_to_litenominated(self):
     upload = self.upload("extension")
     data = parse_addon(upload.path)
     with mock.patch("addons.models.Addon.update_status"):
         # mock update_status because it doesn't like Addons without files.
         self.addon.update(status=amo.STATUS_LITE_AND_NOMINATED, trusted=True)
     eq_(self.addon.status, amo.STATUS_LITE_AND_NOMINATED)
     f = File.from_upload(upload, self.version, self.platform, data)
     eq_(f.status, amo.STATUS_LITE_AND_NOMINATED)
Example #36
0
 def test_litenominated_to_unreviewed(self):
     upload = self.upload('extension')
     data = parse_addon(upload.path)
     with mock.patch('addons.models.Addon.update_status'):
         # mock update_status because it doesn't like Addons without files.
         self.addon.update(status=amo.STATUS_LITE_AND_NOMINATED)
     eq_(self.addon.status, amo.STATUS_LITE_AND_NOMINATED)
     f = File.from_upload(upload, self.version, self.platform, data)
     eq_(f.status, amo.STATUS_UNREVIEWED)
Example #37
0
 def test_litenominated_to_unreviewed(self):
     upload = self.upload('extension')
     d = parse_addon(upload.path)
     with mock.patch('addons.models.Addon.update_status'):
         # mock update_status because it doesn't like Addons without files.
         self.addon.update(status=amo.STATUS_LITE_AND_NOMINATED)
     eq_(self.addon.status, amo.STATUS_LITE_AND_NOMINATED)
     f = File.from_upload(upload, self.version, self.platform, parse_data=d)
     eq_(f.status, amo.STATUS_UNREVIEWED)
Example #38
0
    def __init__(self, file_, addon=None, listed=None):
        self.addon = addon
        self.file = None

        if isinstance(file_, FileUpload):
            save = tasks.handle_upload_validation_result
            validate = self.validate_upload(file_, listed)

            # We're dealing with a bare file upload. Try to extract the
            # metadata that we need to match it against a previous upload
            # from the file itself.
            try:
                addon_data = parse_addon(file_, check=False)
            except ValidationError:
                addon_data = None
        elif isinstance(file_, File):
            # The listed flag for a File object should always come from
            # the status of its owner Addon. If the caller tries to override
            # this, something is wrong.
            assert listed is None

            save = tasks.handle_file_validation_result
            validate = self.validate_file(file_)

            self.file = file_
            self.addon = self.file.version.addon
            addon_data = {'guid': self.addon.id,
                          'version': self.file.version.version}
        else:
            raise ValueError

        if addon_data:
            # If we have a valid file, try to find an associated Addon
            # object, and a valid former submission to compare against.
            try:
                self.addon = (self.addon or
                              Addon.with_unlisted.get(guid=addon_data['guid']))
            except Addon.DoesNotExist:
                pass

            self.prev_file = self.find_previous_version(addon_data['version'])
            if self.prev_file:
                # Group both tasks so the results can be merged when
                # the jobs complete.
                validate = group((validate,
                                  self.validate_file(self.prev_file)))

        # Fallback error handler to save a set of exception results, in case
        # anything unexpected happens during processing.
        on_error = save.subtask([amo.VALIDATOR_SKELETON_EXCEPTION, file_.pk],
                                {'annotate': False}, immutable=True)

        # When the validation jobs complete, pass the results to the
        # appropriate annotate/save task for the object type.
        self.task = chain(validate, save.subtask([file_.pk],
                                                 link_error=on_error))
Example #39
0
 def clean(self):
     if not self.errors:
         self._clean_upload()
         xpi = parse_addon(self.cleaned_data['upload'], self.addon)
         # Make sure we don't already have the same non-rejected version.
         if self.addon.versions.filter(version=xpi['version']).exclude(
                 files__status=amo.STATUS_DISABLED):
             raise forms.ValidationError(
                 _(u'Version %s already exists') % xpi['version'])
     return self.cleaned_data
Example #40
0
    def clean(self):
        if not self.version.is_allowed_upload():
            raise forms.ValidationError(_("You cannot upload any more files for this version."))

        # Check for errors in the xpi.
        if not self.errors:
            xpi = parse_addon(self.cleaned_data["upload"], self.addon)
            if xpi["version"] != self.version.version:
                raise forms.ValidationError(_("Version doesn't match"))
        return self.cleaned_data
Example #41
0
 def clean(self):
     if not self.errors:
         self._clean_upload()
         xpi = parse_addon(self.cleaned_data['upload'], self.addon)
         # Make sure we don't already have the same non-rejected version.
         if self.addon.versions.filter(version=xpi['version']).exclude(
                 files__status=amo.STATUS_DISABLED):
             raise forms.ValidationError(
                 _(u'Version %s already exists') % xpi['version'])
     return self.cleaned_data
Example #42
0
 def test_rdf_parse_errors_are_ignored(self, run_validator, flag_is_active):
     run_validator.return_value = self.compatibility_result
     flag_is_active.return_value = True
     addon = Addon.objects.get(pk=3615)
     dupe_xpi = self.get_upload("extension.xpi")
     d = parse_addon(dupe_xpi)
     # Set up a duplicate upload:
     addon.update(guid=d["guid"])
     data = self.upload(filename=dupe_xpi.path)
     # Make sure we don't see a dupe UUID error:
     eq_(data["validation"]["messages"], [])
Example #43
0
    def test_trusted_litenominated_to_litenominated(self):
        upload = self.upload('extension')
        d = parse_addon(upload.path)
        with mock.patch('addons.models.Addon.update_status'):
            # mock update_status because it doesn't like Addons without files.
            self.addon.update(status=amo.STATUS_LITE_AND_NOMINATED,
                              trusted=True)

        assert self.addon.status == amo.STATUS_LITE_AND_NOMINATED
        f = File.from_upload(upload, self.version, self.platform, parse_data=d)
        assert f.status == amo.STATUS_LITE
Example #44
0
    def clean(self):
        if not self.version.is_allowed_upload():
            raise forms.ValidationError(
                _('You cannot upload any more files for this version.'))

        # Check for errors in the xpi.
        if not self.errors:
            xpi = parse_addon(self.cleaned_data['upload'], self.addon)
            if xpi['version'] != self.version.version:
                raise forms.ValidationError(_("Version doesn't match"))
        return self.cleaned_data
Example #45
0
    def test_trusted_litenominated_to_litenominated(self):
        upload = self.upload('extension')
        d = parse_addon(upload.path)
        with mock.patch('addons.models.Addon.update_status'):
            # mock update_status because it doesn't like Addons without files.
            self.addon.update(status=amo.STATUS_LITE_AND_NOMINATED,
                              trusted=True)

        assert self.addon.status == amo.STATUS_LITE_AND_NOMINATED
        f = File.from_upload(upload, self.version, self.platform, parse_data=d)
        assert f.status == amo.STATUS_LITE
 def test_rdf_parse_errors_are_ignored(self, run_validator, flag_is_active):
     run_validator.return_value = self.compatibility_result
     flag_is_active.return_value = True
     addon = Addon.objects.get(pk=3615)
     dupe_xpi = self.get_upload('extension.xpi')
     d = parse_addon(dupe_xpi)
     # Set up a duplicate upload:
     addon.update(guid=d['guid'])
     data = self.upload(filename=dupe_xpi.path)
     # Make sure we don't see a dupe UUID error:
     eq_(data['validation']['messages'], [])
Example #47
0
 def from_upload(cls, upload, platforms):
     from files.utils import parse_addon
     data = parse_addon(upload.path)
     fields = cls._meta.get_all_field_names()
     addon = Addon(**dict((k, v) for k, v in data.items() if k in fields))
     addon.status = amo.STATUS_NULL
     addon.default_locale = to_language(translation.get_language())
     addon.save()
     Version.from_upload(upload, addon, platforms)
     amo.log(amo.LOG.CREATE_ADDON, addon)
     log.debug('New addon %r from %r' % (addon, upload))
     return addon
Example #48
0
    def __init__(self, file_, addon=None, listed=None):
        self.addon = addon
        self.file = None

        if isinstance(file_, FileUpload):
            save = tasks.handle_upload_validation_result
            validate = self.validate_upload(file_, listed)

            # We're dealing with a bare file upload. Try to extract the
            # metadata that we need to match it against a previous upload
            # from the file itself.
            try:
                addon_data = parse_addon(file_, check=False)
            except ValidationError:
                addon_data = None
        elif isinstance(file_, File):
            # The listed flag for a File object should always come from
            # the status of its owner Addon. If the caller tries to override
            # this, something is wrong.
            assert listed is None

            save = tasks.handle_file_validation_result
            validate = self.validate_file(file_)

            self.file = file_
            self.addon = self.file.version.addon
            addon_data = {
                'guid': self.addon.id,
                'version': self.file.version.version
            }
        else:
            raise ValueError

        if addon_data:
            # If we have a valid file, try to find an associated Addon
            # object, and a valid former submission to compare against.
            try:
                self.addon = (self.addon or
                              Addon.with_unlisted.get(guid=addon_data['guid']))
            except Addon.DoesNotExist:
                pass

            self.prev_file = self.find_previous_version(addon_data['version'])
            if self.prev_file:
                # Group both tasks so the results can be merged when
                # the jobs complete.
                validate = group(
                    (validate, self.validate_file(self.prev_file)))

        # When the validation jobs complete, pass the results to the
        # appropriate annotate/save task for the object type.
        self.task = chain(validate, save.subtask([file_.pk]))
Example #49
0
 def clean_upload(self):
     upload = self.cleaned_data['upload']
     if self.is_packaged:
         pkg = parse_addon(upload, self.addon)
         ver = pkg.get('version')
         if (ver and self.addon and
             self.addon.versions.filter(version=ver).exists()):
             raise forms.ValidationError(
                 _(u'Version %s already exists') % ver)
     else:
         # Throw an error if this is a dupe.
         verify_app_domain(upload.name)  # JS sets manifest as `upload.name`.
     return upload
Example #50
0
    def test_dupe_uuid(self, flag_is_active):
        flag_is_active.return_value = True
        addon = Addon.objects.get(pk=3615)
        d = parse_addon(self.get_upload('extension.xpi'))
        addon.update(guid=d['guid'])

        dupe_xpi = self.get_upload('extension.xpi')
        res = self.client.get(reverse('devhub.upload_detail',
                                      args=[dupe_xpi.uuid, 'json']))
        eq_(res.status_code, 400)
        data = json.loads(res.content)
        eq_(data['validation']['messages'],
            [{'tier': 1, 'message': 'Duplicate UUID found.',
              'type': 'error'}])
Example #51
0
 def clean_upload(self):
     upload = self.cleaned_data['upload']
     if self.is_packaged:
         pkg = parse_addon(upload, self.addon)
         ver = pkg.get('version')
         if (ver and self.addon
                 and self.addon.versions.filter(version=ver).exists()):
             raise forms.ValidationError(
                 _(u'Version %s already exists') % ver)
     else:
         # Throw an error if this is a dupe.
         # (JS sets manifest as `upload.name`.)
         verify_app_domain(upload.name)
     return upload
Example #52
0
    def test_dupe_uuid(self, flag_is_active):
        flag_is_active.return_value = True
        addon = Addon.objects.get(pk=3615)
        d = parse_addon(self.get_upload('extension.xpi'))
        addon.update(guid=d['guid'])

        dupe_xpi = self.get_upload('extension.xpi')
        res = self.client.get(reverse('devhub.upload_detail',
                                      args=[dupe_xpi.uuid, 'json']))
        eq_(res.status_code, 400)
        data = json.loads(res.content)
        eq_(data['validation']['messages'],
            [{'tier': 1, 'message': 'Duplicate UUID found.',
              'type': 'error'}])
Example #53
0
def test_parse_addon(search_mock, xpi_mock):
    parse_addon('file.xpi', None)
    xpi_mock.assert_called_with('file.xpi', None)

    parse_addon('file.xml', None)
    search_mock.assert_called_with('file.xml', None)

    parse_addon('file.jar', None)
    xpi_mock.assert_called_with('file.jar', None)
Example #54
0
    def put(self, request, addon, version_string):
        if 'upload' in request.FILES:
            filedata = request.FILES['upload']
        else:
            return Response(
                {'error': _('Missing "upload" key in multipart file data.')},
                status=status.HTTP_400_BAD_REQUEST)

        try:
            # Parse the file to get and validate package data with the addon.
            pkg = parse_addon(filedata, addon)
            if not acl.submission_allowed(request.user, pkg):
                raise forms.ValidationError(
                    _(u'You cannot submit this type of add-ons'))
        except forms.ValidationError as e:
            return Response({'error': e.message},
                            status=status.HTTP_400_BAD_REQUEST)
        if pkg['version'] != version_string:
            return Response(
                {'error': _('Version does not match install.rdf.')},
                status=status.HTTP_400_BAD_REQUEST)
        elif (addon is not None
              and addon.versions.filter(
                  version=version_string,
                  files__status__in=amo.REVIEWED_STATUSES).exists()):
            return Response({'error': _('Version already exists.')},
                            status=status.HTTP_409_CONFLICT)

        if addon is None:
            addon = Addon.create_addon_from_upload_data(data=pkg,
                                                        user=request.user,
                                                        is_listed=False)
            status_code = status.HTTP_201_CREATED
        else:
            status_code = status.HTTP_202_ACCEPTED

        file_upload = handle_upload(filedata=filedata,
                                    user=request.user,
                                    addon=addon,
                                    submit=True)

        return Response(FileUploadSerializer(file_upload).data,
                        status=status_code)
Example #55
0
def run():
    """Walk the themes and addons files to check if they're multi-package XPIs.

    https://developer.mozilla.org/en-US/docs/Multiple_Item_Packaging

    If they are, set File.is_multi_package = True
    """
    # Disable this as a migration, it's taking too long, move it to a
    # standalone script.
    return
    # Only (complete) themes and addons can have multi-package XPIs.
    for file_ in File.objects.filter(
            version__addon__type__in=[amo.ADDON_EXTENSION, amo.ADDON_THEME]):
        try:
            data = parse_addon(file_.file_path, addon=file_.version.addon)
            if data.get('is_multi_package'):
                file_.update(is_multi_package=True)
        except:
            log.error('Failed checking file {0}'.format(file_.pk))
Example #56
0
    def __init__(self, file_, addon=None, listed=None):
        self.addon = addon
        self.file = None
        self.prev_file = None

        if isinstance(file_, FileUpload):
            save = tasks.handle_upload_validation_result
            validate = self.validate_upload(file_, listed)

            # We're dealing with a bare file upload. Try to extract the
            # metadata that we need to match it against a previous upload
            # from the file itself.
            try:
                addon_data = parse_addon(file_, check=False)
            except ValidationError, form_error:
                log.info('could not parse addon for upload {}: {}'.format(
                    file_.pk, form_error))
                addon_data = None
            else:
                file_.update(version=addon_data.get('version'))
Example #57
0
 def parse(self, filename='search.xml'):
     return parse_addon(open(self.file_fixture_path(filename)))
Example #58
0
 def test_strict_compat(self):
     upload = self.upload('strict-compat')
     data = parse_addon(upload.path)
     f = File.from_upload(upload, self.version, self.platform, data)
     eq_(f.strict_compatibility, True)
Example #59
0
 def test_no_restart_false(self):
     upload = self.upload('extension')
     d = parse_addon(upload.path)
     f = File.from_upload(upload, self.version, self.platform, parse_data=d)
     assert not f.no_restart
Example #60
0
 def test_no_restart_true(self):
     upload = self.upload('jetpack')
     d = parse_addon(upload.path)
     f = File.from_upload(upload, self.version, self.platform, parse_data=d)
     assert f.no_restart