コード例 #1
0
ファイル: test_models.py プロジェクト: st333v/addons-server
 def test_ip_log(self):
     addon = Addon.objects.get()
     assert IPLog.objects.count() == 0
     # Creating an activity log for an action without store_ip=True doesn't
     # create an IPLog.
     action = amo.LOG.REJECT_VERSION
     assert not getattr(action, 'store_ip', False)
     with core.override_remote_addr('127.0.4.8'):
         activity = ActivityLog.create(
             action,
             addon,
             addon.current_version,
             user=self.request.user,
         )
     assert IPLog.objects.count() == 0
     # Creating an activity log for an action *with* store_ip=True *does*
     # create an IPLog.
     action = amo.LOG.ADD_VERSION
     assert getattr(action, 'store_ip', False)
     with core.override_remote_addr('15.16.23.42'):
         activity = ActivityLog.create(
             action,
             addon,
             addon.current_version,
             user=self.request.user,
         )
     assert IPLog.objects.count() == 1
     ip_log = IPLog.objects.get()
     assert ip_log.activity_log == activity
     assert ip_log.ip_address == '15.16.23.42'
コード例 #2
0
ファイル: test_init.py プロジェクト: wagnerand/addons-server
def test_override_remote_addr():
    original = core.get_remote_addr()

    with core.override_remote_addr('some other value'):
        assert core.get_remote_addr() == 'some other value'

    assert core.get_remote_addr() == original
コード例 #3
0
 def test_to_string_num_queries_model_depending_on_addon(self):
     addon = Addon.objects.get()
     addon2 = addon_factory()
     with core.override_remote_addr('1.1.1.1'):
         ActivityLog.create(
             amo.LOG.ADD_VERSION,
             addon,
             addon.current_version,
             user=self.request.user,
         )
         ActivityLog.create(
             amo.LOG.ADD_VERSION,
             addon2,
             addon2.current_version,
             user=user_factory(),
         )
     with self.assertNumQueries(6):
         # - 1 for all activities
         # - 1 for all users
         # - 1 for all addons
         # - 1 for all add-on translations
         # - 1 for all versions
         # - 1 for all versions translations
         activities = ActivityLog.objects.for_addons([addon, addon2
                                                      ]).order_by('pk')
         assert len(activities) == 2
         addon_url = 'http://testserver/en-US/firefox/addon/a3615/'
         assert activities[0].to_string() == (
             f'<a href="{addon_url}versions/">Version 2.1.072</a> added to '
             f'<a href="{addon_url}">Delicious Bookmarks</a>.')
         assert activities[1].to_string()
コード例 #4
0
    def log_updates(self, num, version_string='1'):
        version = Version.objects.create(version=version_string,
                                         addon=self.addon)

        for i in range(num):
            with core.override_remote_addr('127.0.0.1'):
                ActivityLog.create(amo.LOG.ADD_VERSION, self.addon, version)
コード例 #5
0
    def from_upload(cls,
                    upload,
                    addon,
                    selected_apps,
                    channel,
                    parsed_data=None):
        """
        Create a Version instance and corresponding File(s) from a
        FileUpload, an Addon, a list of compatible app ids, a channel id and
        the parsed_data generated by parse_addon().

        Note that it's the caller's responsability to ensure the file is valid.
        We can't check for that here because an admin may have overridden the
        validation results.
        """
        from olympia.addons.models import AddonReviewerFlags
        from olympia.addons.utils import RestrictionChecker
        from olympia.git.utils import create_git_extraction_entry

        assert parsed_data is not None

        if addon.status == amo.STATUS_DISABLED:
            raise VersionCreateError(
                'Addon is Mozilla Disabled; no new versions are allowed.')

        if upload.addon and upload.addon != addon:
            raise VersionCreateError(
                'FileUpload was made for a different Addon')

        if not upload.user or not upload.ip_address or not upload.source:
            raise VersionCreateError(
                'FileUpload does not have some required fields')

        if not upload.user.last_login_ip or not upload.user.email:
            raise VersionCreateError(
                'FileUpload user does not have some required fields')

        license_id = None
        if channel == amo.RELEASE_CHANNEL_LISTED:
            previous_version = addon.find_latest_version(channel=channel,
                                                         exclude=())
            if previous_version and previous_version.license_id:
                license_id = previous_version.license_id
        approval_notes = None
        if parsed_data.get('is_mozilla_signed_extension'):
            approval_notes = (
                'This version has been signed with Mozilla internal certificate.'
            )
        version = cls.objects.create(
            addon=addon,
            approval_notes=approval_notes,
            version=parsed_data['version'],
            license_id=license_id,
            channel=channel,
        )
        email = upload.user.email if upload.user and upload.user.email else ''
        with core.override_remote_addr(upload.ip_address):
            # The following log statement is used by foxsec-pipeline.
            # We override the IP because it might be called from a task and we
            # want the original IP from the submitter.
            log.info(
                f'New version: {version!r} ({version.id}) from {upload!r}',
                extra={
                    'email': email,
                    'guid': addon.guid,
                    'upload': upload.uuid.hex,
                    'user_id': upload.user_id,
                    'from_api': upload.source == amo.UPLOAD_SOURCE_API,
                },
            )
            activity.log_create(amo.LOG.ADD_VERSION,
                                version,
                                addon,
                                user=upload.user or get_task_user())

        if addon.type == amo.ADDON_STATICTHEME:
            # We don't let developers select apps for static themes
            selected_apps = [app.id for app in amo.APP_USAGE]

        compatible_apps = {}
        for app in parsed_data.get('apps', []):
            if app.id not in selected_apps:
                # If the user chose to explicitly deselect Firefox for Android
                # we're not creating the respective `ApplicationsVersions`
                # which will have this add-on then be listed only for
                # Firefox specifically.
                continue

            compatible_apps[app.appdata] = ApplicationsVersions(
                version=version, min=app.min, max=app.max, application=app.id)
            compatible_apps[app.appdata].save()

        # Pre-generate _compatible_apps property to avoid accidentally
        # triggering queries with that instance later.
        version._compatible_apps = compatible_apps

        # Create relevant file and update the all_files cached property on the
        # Version, because we might need it afterwards.
        version.all_files = [
            File.from_upload(
                upload=upload,
                version=version,
                parsed_data=parsed_data,
            )
        ]

        version.inherit_nomination(from_statuses=[amo.STATUS_AWAITING_REVIEW])
        version.disable_old_files()

        # After the upload has been copied to its permanent location, delete it
        # from storage. Keep the FileUpload instance (it gets cleaned up by a
        # cron eventually some time after its creation, in amo.cron.gc()),
        # making sure it's associated with the add-on instance.
        storage.delete(upload.path)
        upload.path = ''
        if upload.addon is None:
            upload.addon = addon
        upload.save()

        version_uploaded.send(instance=version, sender=Version)

        if version.is_webextension:
            if (waffle.switch_is_active('enable-yara')
                    or waffle.switch_is_active('enable-customs')
                    or waffle.switch_is_active('enable-wat')):
                ScannerResult.objects.filter(upload_id=upload.id).update(
                    version=version)

        if waffle.switch_is_active('enable-uploads-commit-to-git-storage'):
            # Schedule this version for git extraction.
            transaction.on_commit(
                lambda: create_git_extraction_entry(version=version))

        # Generate a preview and icon for listed static themes
        if (addon.type == amo.ADDON_STATICTHEME
                and channel == amo.RELEASE_CHANNEL_LISTED):
            theme_data = parsed_data.get('theme', {})
            generate_static_theme_preview(theme_data, version.pk)

        # Reset add-on reviewer flags to disable auto-approval and require
        # admin code review if the package has already been signed by mozilla.
        reviewer_flags_defaults = {}
        is_mozilla_signed = parsed_data.get('is_mozilla_signed_extension')
        if upload.validation_timeout:
            reviewer_flags_defaults['needs_admin_code_review'] = True
        if is_mozilla_signed and addon.type != amo.ADDON_LPAPP:
            reviewer_flags_defaults['needs_admin_code_review'] = True
            reviewer_flags_defaults['auto_approval_disabled'] = True

        # Check if the approval should be restricted
        if not RestrictionChecker(upload=upload).is_auto_approval_allowed():
            flag = ('auto_approval_disabled'
                    if channel == amo.RELEASE_CHANNEL_LISTED else
                    'auto_approval_disabled_unlisted')
            reviewer_flags_defaults[flag] = True

        if reviewer_flags_defaults:
            AddonReviewerFlags.objects.update_or_create(
                addon=addon, defaults=reviewer_flags_defaults)

        # Authors need to be notified about auto-approval delay again since
        # they are submitting a new version.
        addon.reset_notified_about_auto_approval_delay()

        # Track the time it took from first upload through validation
        # (and whatever else) until a version was created.
        upload_start = utc_millesecs_from_epoch(upload.created)
        now = datetime.datetime.now()
        now_ts = utc_millesecs_from_epoch(now)
        upload_time = now_ts - upload_start

        log.info('Time for version {version} creation from upload: {delta}; '
                 'created={created}; now={now}'.format(delta=upload_time,
                                                       version=version,
                                                       created=upload.created,
                                                       now=now))
        statsd.timing('devhub.version_created_from_upload', upload_time)

        return version
コード例 #6
0
ファイル: models.py プロジェクト: raman934/addons-server
    def from_upload(cls, upload, addon, selected_apps, channel,
                    parsed_data=None):
        """
        Create a Version instance and corresponding File(s) from a
        FileUpload, an Addon, a list of compatible app ids, a channel id and
        the parsed_data generated by parse_addon().

        Note that it's the caller's responsability to ensure the file is valid.
        We can't check for that here because an admin may have overridden the
        validation results.
        """
        from olympia.git.utils import create_git_extraction_entry

        assert parsed_data is not None

        if addon.status == amo.STATUS_DISABLED:
            raise VersionCreateError(
                'Addon is Mozilla Disabled; no new versions are allowed.')

        license_id = None
        if channel == amo.RELEASE_CHANNEL_LISTED:
            previous_version = addon.find_latest_version(
                channel=channel, exclude=())
            if previous_version and previous_version.license_id:
                license_id = previous_version.license_id
        approval_notes = None
        if parsed_data.get('is_mozilla_signed_extension'):
            approval_notes = (u'This version has been signed with '
                              u'Mozilla internal certificate.')
        version = cls.objects.create(
            addon=addon,
            approval_notes=approval_notes,
            version=parsed_data['version'],
            license_id=license_id,
            channel=channel,
        )
        email = upload.user.email if upload.user and upload.user.email else ''
        with core.override_remote_addr(upload.ip_address):
            log.info(
                'New version: %r (%s) from %r' % (version, version.id, upload),
                extra={
                    'email': email,
                    'guid': addon.guid,
                    'upload': upload.uuid.hex,
                    'user_id': upload.user_id,
                    'from_api': upload.source == amo.UPLOAD_SOURCE_API,
                }
            )
            activity.log_create(
                amo.LOG.ADD_VERSION, version, addon,
                user=upload.user or get_task_user())

        if addon.type == amo.ADDON_STATICTHEME:
            # We don't let developers select apps for static themes
            selected_apps = [app.id for app in amo.APP_USAGE]

        compatible_apps = {}
        for app in parsed_data.get('apps', []):
            if app.id not in selected_apps:
                # If the user chose to explicitly deselect Firefox for Android
                # we're not creating the respective `ApplicationsVersions`
                # which will have this add-on then be listed only for
                # Firefox specifically.
                continue

            compatible_apps[app.appdata] = ApplicationsVersions(
                version=version, min=app.min, max=app.max, application=app.id)
            compatible_apps[app.appdata].save()

        # See #2828: sometimes when we generate the filename(s) below, in
        # File.from_upload(), cache-machine is confused and has trouble
        # fetching the ApplicationsVersions that were just created. To work
        # around this we pre-generate version.compatible_apps and avoid the
        # queries completely.
        version._compatible_apps = compatible_apps

        # For backwards compatibility. We removed specific platform
        # support during submission but we don't handle it any different
        # beyond that yet. That means, we're going to simply set it
        # to `PLATFORM_ALL` and also have the backend create separate
        # files for each platform. Cleaning that up is another step.
        # Given the timing on this, we don't care about updates to legacy
        # add-ons as well.
        # Create relevant file and update the all_files cached property on the
        # Version, because we might need it afterwards.
        version.all_files = [File.from_upload(
            upload=upload, version=version, platform=amo.PLATFORM_ALL.id,
            parsed_data=parsed_data
        )]

        version.inherit_nomination(from_statuses=[amo.STATUS_AWAITING_REVIEW])
        version.disable_old_files()

        # After the upload has been copied to all platforms, remove the upload.
        storage.delete(upload.path)
        upload.path = ''
        upload.save()

        version_uploaded.send(instance=version, sender=Version)

        if version.is_webextension:
            if (
                    waffle.switch_is_active('enable-yara') or
                    waffle.switch_is_active('enable-customs') or
                    waffle.switch_is_active('enable-wat')
            ):
                ScannerResult.objects.filter(upload_id=upload.id).update(
                    version=version)

        if waffle.switch_is_active('enable-uploads-commit-to-git-storage'):
            # Schedule this version for git extraction.
            transaction.on_commit(
                lambda: create_git_extraction_entry(version=version)
            )

        # Generate a preview and icon for listed static themes
        if (addon.type == amo.ADDON_STATICTHEME and
                channel == amo.RELEASE_CHANNEL_LISTED):
            theme_data = parsed_data.get('theme', {})
            generate_static_theme_preview(theme_data, version.pk)

        # Authors need to be notified about auto-approval delay again since
        # they are submitting a new version.
        addon.reset_notified_about_auto_approval_delay()

        # Track the time it took from first upload through validation
        # (and whatever else) until a version was created.
        upload_start = utc_millesecs_from_epoch(upload.created)
        now = datetime.datetime.now()
        now_ts = utc_millesecs_from_epoch(now)
        upload_time = now_ts - upload_start

        log.info('Time for version {version} creation from upload: {delta}; '
                 'created={created}; now={now}'
                 .format(delta=upload_time, version=version,
                         created=upload.created, now=now))
        statsd.timing('devhub.version_created_from_upload', upload_time)

        return version
コード例 #7
0
    def test_known_ip_adresses(self):
        self.user.update(last_login_ip='127.1.2.3')
        Rating.objects.create(addon=addon_factory(),
                              user=self.user,
                              ip_address='127.1.2.3')
        dummy_addon = addon_factory()
        Rating.objects.create(
            addon=dummy_addon,
            version=dummy_addon.current_version,
            user=self.user,
            ip_address='128.1.2.3',
        )
        Rating.objects.create(
            addon=dummy_addon,
            version=version_factory(addon=dummy_addon),
            user=self.user,
            ip_address='129.1.2.4',
        )
        Rating.objects.create(addon=addon_factory(),
                              user=self.user,
                              ip_address='130.1.2.4')
        Rating.objects.create(addon=addon_factory(),
                              user=self.user,
                              ip_address='130.1.2.4')
        Rating.objects.create(addon=dummy_addon,
                              user=user_factory(),
                              ip_address='255.255.0.0')
        with core.override_remote_addr('15.16.23.42'):
            ActivityLog.create(amo.LOG.ADD_VERSION,
                               dummy_addon,
                               user=self.user)
        UserRestrictionHistory.objects.create(user=self.user,
                                              last_login_ip='4.8.15.16')
        UserRestrictionHistory.objects.create(user=self.user,
                                              ip_address='172.0.0.2')
        model_admin = UserAdmin(UserProfile, admin.site)
        doc = pq(model_admin.known_ip_adresses(self.user))
        result = doc('ul li').text().split()
        assert len(result) == 7
        assert set(result) == {
            '130.1.2.4',
            '128.1.2.3',
            '129.1.2.4',
            '127.1.2.3',
            '15.16.23.42',
            '172.0.0.2',
            '4.8.15.16',
        }

        # Duplicates are ignored
        Rating.objects.create(
            addon=dummy_addon,
            version=version_factory(addon=dummy_addon),
            user=self.user,
            ip_address='127.1.2.3',
        )
        with core.override_remote_addr('172.0.0.2'):
            ActivityLog.create(amo.LOG.ADD_VERSION,
                               dummy_addon,
                               user=self.user)
        UserRestrictionHistory.objects.create(user=self.user,
                                              last_login_ip='15.16.23.42')
        UserRestrictionHistory.objects.create(user=self.user,
                                              ip_address='4.8.15.16')
        doc = pq(model_admin.known_ip_adresses(self.user))
        result = doc('ul li').text().split()
        assert len(result) == 7
        assert set(result) == {
            '130.1.2.4',
            '128.1.2.3',
            '129.1.2.4',
            '127.1.2.3',
            '15.16.23.42',
            '172.0.0.2',
            '4.8.15.16',
        }
コード例 #8
0
ファイル: utils.py プロジェクト: copyit/addons-server
    def create_version(self, addon=None):
        from olympia.addons.models import Addon
        from olympia.files.models import FileUpload
        from olympia.files.utils import parse_addon
        from olympia.versions.models import Version
        from olympia.versions.utils import get_next_version_number

        version_number = '1.0'

        # If passing an existing add-on, we need to bump the version number
        # to avoid clashes, and also perform a few checks.
        if addon is not None:
            # Obviously we want an add-on with the right type.
            if addon.type != amo.ADDON_SITE_PERMISSION:
                raise ImproperlyConfigured(
                    'SitePermissionVersionCreator was instantiated with non '
                    'site-permission add-on'
                )
            # If the user isn't an author, something is wrong.
            if not addon.authors.filter(pk=self.user.pk).exists():
                raise ImproperlyConfigured(
                    'SitePermissionVersionCreator was instantiated with a '
                    'bogus addon/user'
                )
            # Changing the origins isn't supported at the moment.
            latest_version = addon.find_latest_version(
                exclude=(), channel=amo.RELEASE_CHANNEL_UNLISTED
            )
            previous_origins = sorted(
                latest_version.installorigin_set.all().values_list('origin', flat=True)
            )
            if previous_origins != self.install_origins:
                raise ImproperlyConfigured(
                    'SitePermissionVersionCreator was instantiated with an '
                    'addon that has different origins'
                )

            version_number = get_next_version_number(addon)

        # Create the manifest, with more user-friendly name & description built
        # from install_origins/site_permissions, and then the zipfile with that
        # manifest inside.
        manifest_data = self._create_manifest(version_number)
        file_obj = self._create_zipfile(manifest_data)

        # Parse the zip we just created. The user needs to be the Mozilla User
        # because regular submissions of this type of add-on is forbidden to
        # normal users.
        parsed_data = parse_addon(
            file_obj,
            addon=addon,
            user=get_task_user(),
        )

        with core.override_remote_addr(self.remote_addr):
            if addon is None:
                # Create the Addon instance (without a Version/File at this point).
                addon = Addon.initialize_addon_from_upload(
                    data=parsed_data,
                    upload=file_obj,
                    channel=amo.RELEASE_CHANNEL_UNLISTED,
                    user=self.user,
                )

            # Create the FileUpload that will become the File+Version.
            upload = FileUpload.from_post(
                file_obj,
                filename=file_obj.name,
                size=file_obj.size,
                addon=addon,
                version=version_number,
                channel=amo.RELEASE_CHANNEL_UNLISTED,
                user=self.user,
                source=amo.UPLOAD_SOURCE_GENERATED,
            )

        # And finally create the Version instance from the FileUpload.
        return Version.from_upload(
            upload,
            addon,
            amo.RELEASE_CHANNEL_UNLISTED,
            selected_apps=[x[0] for x in amo.APPS_CHOICES],
            parsed_data=parsed_data,
        )