def test_bump_version_in_package_json(file_obj):
    with amo.tests.copy_file(
            'src/olympia/files/fixtures/files/new-format-0.0.1.xpi',
            file_obj.file_path):
        utils.update_version_number(file_obj, '0.0.1.1-signed')
        parsed = utils.parse_xpi(file_obj.file_path)
        assert parsed['version'] == '0.0.1.1-signed'
Beispiel #2
0
def test_bump_version_in_manifest_json(file_obj):
    with amo.tests.copy_file(
            'src/olympia/files/fixtures/files/webextension.xpi',
            file_obj.file_path):
        utils.update_version_number(file_obj, '0.0.1.1-signed')
        parsed = utils.parse_xpi(file_obj.file_path)
        assert parsed['version'] == '0.0.1.1-signed'
def test_bump_version_in_manifest_json(file_obj):
    create_switch('webextensions')
    with amo.tests.copy_file(
            'src/olympia/files/fixtures/files/webextension.xpi',
            file_obj.file_path):
        utils.update_version_number(file_obj, '0.0.1.1-signed')
        parsed = utils.parse_xpi(file_obj.file_path)
        assert parsed['version'] == '0.0.1.1-signed'
Beispiel #4
0
def test_bump_version_in_package_json(file_obj):
    with amo.tests.copy_file(
            'src/olympia/files/fixtures/files/new-format-0.0.1.xpi',
            file_obj.file_path):
        utils.update_version_number(file_obj, '0.0.1.1-signed')

        with zipfile.ZipFile(file_obj.file_path, 'r') as source:
            parsed = json.loads(source.read('package.json'))
            assert parsed['version'] == '0.0.1.1-signed'
Beispiel #5
0
def test_bump_version_in_package_json(file_obj):
    with amo.tests.copy_file(
            'src/olympia/files/fixtures/files/new-format-0.0.1.xpi',
            file_obj.file_path):
        utils.update_version_number(file_obj, '0.0.1.1-signed')

        with zipfile.ZipFile(file_obj.file_path, 'r') as source:
            parsed = json.loads(source.read('package.json'))
            assert parsed['version'] == '0.0.1.1-signed'
Beispiel #6
0
def test_bump_version_in_manifest_json(file_obj):
    AppVersion.objects.create(application=amo.FIREFOX.id,
                              version=amo.DEFAULT_WEBEXT_MIN_VERSION)
    AppVersion.objects.create(application=amo.FIREFOX.id,
                              version=amo.DEFAULT_WEBEXT_MAX_VERSION)
    AppVersion.objects.create(application=amo.ANDROID.id,
                              version=amo.DEFAULT_WEBEXT_MIN_VERSION_ANDROID)
    AppVersion.objects.create(application=amo.ANDROID.id,
                              version=amo.DEFAULT_WEBEXT_MAX_VERSION)
    with amo.tests.copy_file(
            'src/olympia/files/fixtures/files/webextension.xpi',
            file_obj.file_path):
        utils.update_version_number(file_obj, '0.0.1.1-signed')
        parsed = utils.parse_xpi(file_obj.file_path)
        assert parsed['version'] == '0.0.1.1-signed'
Beispiel #7
0
def test_bump_version_in_manifest_json(file_obj):
    AppVersion.objects.create(application=amo.FIREFOX.id,
                              version=amo.DEFAULT_WEBEXT_MIN_VERSION)
    AppVersion.objects.create(application=amo.FIREFOX.id,
                              version=amo.DEFAULT_WEBEXT_MAX_VERSION)
    AppVersion.objects.create(application=amo.ANDROID.id,
                              version=amo.DEFAULT_WEBEXT_MIN_VERSION_ANDROID)
    AppVersion.objects.create(application=amo.ANDROID.id,
                              version=amo.DEFAULT_WEBEXT_MAX_VERSION)
    with amo.tests.copy_file(
            'src/olympia/files/fixtures/files/webextension.xpi',
            file_obj.file_path):
        utils.update_version_number(file_obj, '0.0.1.1-signed')
        parsed = utils.parse_xpi(file_obj.file_path)
        assert parsed['version'] == '0.0.1.1-signed'
def test_bump_version_in_install_rdf(file_obj):
    with amo.tests.copy_file("src/olympia/files/fixtures/files/jetpack.xpi", file_obj.file_path):
        utils.update_version_number(file_obj, "1.3.1-signed")
        parsed = utils.parse_xpi(file_obj.file_path)
        assert parsed["version"] == "1.3.1-signed"
Beispiel #9
0
def test_bump_version_in_alt_install_rdf(file_obj):
    with amo.tests.copy_file('src/olympia/files/fixtures/files/alt-rdf.xpi',
                             file_obj.file_path):
        utils.update_version_number(file_obj, '2.1.106.1-signed')
        parsed = utils.parse_xpi(file_obj.file_path)
        assert parsed['version'] == '2.1.106.1-signed'
Beispiel #10
0
def test_bump_version_in_alt_install_rdf(file_obj):
    with amo.tests.copy_file('src/olympia/files/fixtures/files/alt-rdf.xpi',
                             file_obj.file_path):
        utils.update_version_number(file_obj, '2.1.106.1-signed')
        parsed = utils.parse_xpi(file_obj.file_path)
        assert parsed['version'] == '2.1.106.1-signed'
Beispiel #11
0
def test_bump_version_in_manifest_json(file_obj):
    with amo.tests.copy_file("src/olympia/files/fixtures/files/webextension.xpi", file_obj.file_path):
        utils.update_version_number(file_obj, "0.0.1.1-signed")
        parsed = utils.parse_xpi(file_obj.file_path)
        assert parsed["version"] == "0.0.1.1-signed"
Beispiel #12
0
def resign_files(file_ids, **kw):
    """Used to force re-signing the files.

    This is used in the 'resign_files' management command. We need to
    re-sign the files that were signed with the wrong certificate (see bug
    1225036).

    It also bumps the version number of the file and the Version, so the
    Firefox extension update mecanism picks this new signed version and
    installs it.
    """
    log.info(u'[{0}] Signing files.'.format(len(file_ids)))

    addons_emailed = set()
    for file_ in File.objects.filter(id__in=file_ids):
        # We only resign files that have been reviewed and signed.
        if file_.status not in amo.REVIEWED_STATUSES:
            log.info(u'Not re-signing file {0}, not reviewed'.format(file_.pk))
            continue
        if not file_.is_signed:
            log.info(u'Not re-signing file {0}, not signed'.format(file_.pk))
            continue

        log.info(u'Re-signing file {0}'.format(file_.pk))

        bumped_version_number = u'{0}.1-signed'.format(file_.version.version)
        bump_version = False  # Did we resign the file?
        if not os.path.isfile(file_.file_path):
            log.info(u'File {0} does not exist, skip'.format(file_.pk))
            continue
        # Save the original file, before bumping the version.
        backup_path = u'{0}.backup_signature'.format(file_.file_path)
        shutil.copy(file_.file_path, backup_path)
        try:
            # Need to bump the version (modify manifest file)
            # before the file is signed.
            update_version_number(file_, bumped_version_number)
            if file_.status == amo.STATUS_PUBLIC:
                server = settings.SIGNING_SERVER
            else:
                server = settings.PRELIMINARY_SIGNING_SERVER
            signed = bool(sign_file(file_, server))
            if signed:  # Bump the version number if at least one signed.
                bump_version = True
            else:  # We didn't sign, so revert the version bump.
                shutil.move(backup_path, file_.file_path)
        except:
            log.error(u'Failed signing file {0}'.format(file_.pk),
                      exc_info=True)
            # Revert the version bump, restore the backup.
            shutil.move(backup_path, file_.file_path)

        # Now update the Version model, if we resigned the file.
        if bump_version:
            version = file_.version
            version.update(version=bumped_version_number,
                           version_int=version_int(bumped_version_number))
            addon = version.addon
            if addon.pk not in addons_emailed:
                # Send a mail to the owners/devs warning them we've
                # automatically signed their addon.
                qs = (AddonUser.objects.filter(
                    role=amo.AUTHOR_ROLE_OWNER,
                    addon=addon).exclude(user__email=None))
                emails = qs.values_list('user__email', flat=True)
                subject = MAIL_RESIGN_SUBJECT.format(addon=addon.name)
                message = MAIL_RESIGN_MESSAGE.format(
                    addon=addon.name,
                    addon_url=amo.helpers.absolutify(
                        addon.get_dev_url(action='versions')))
                amo.utils.send_mail(
                    subject,
                    message,
                    recipient_list=emails,
                    fail_silently=True,
                    headers={'Reply-To': '*****@*****.**'})
                addons_emailed.add(addon.pk)
Beispiel #13
0
def sign_addons(addon_ids, force=False, **kw):
    """Used to sign all the versions of an addon.

    This is used in the 'process_addons --task resign_addons_for_cose'
    management command.

    It also bumps the version number of the file and the Version, so the
    Firefox extension update mechanism picks this new signed version and
    installs it.
    """
    log.info(u'[{0}] Signing addons.'.format(len(addon_ids)))

    mail_subject, mail_message = MAIL_COSE_SUBJECT, MAIL_COSE_MESSAGE

    # query everything except for search-plugins as they're generally
    # not signed
    current_versions = (Addon.objects.filter(id__in=addon_ids).values_list(
        '_current_version', flat=True))
    qset = Version.objects.filter(id__in=current_versions)

    addons_emailed = set()

    for version in qset:
        # We only sign files that have been reviewed
        to_sign = version.files.filter(status__in=amo.REVIEWED_STATUSES)

        to_sign = to_sign.all()

        if not to_sign:
            log.info(u'Not signing addon {0}, version {1} (no files)'.format(
                version.addon, version))
        log.info(u'Signing addon {0}, version {1}'.format(
            version.addon, version))
        bumped_version_number = get_new_version_number(version.version)
        signed_at_least_a_file = False  # Did we sign at least one file?

        # We haven't cleared the database yet to ensure that there's only
        # one file per WebExtension, so we're going through all files just
        # to be sure.
        for file_obj in to_sign:
            if not os.path.isfile(file_obj.file_path):
                log.info(u'File {0} does not exist, skip'.format(file_obj.pk))
                continue

            # Save the original file, before bumping the version.
            backup_path = u'{0}.backup_signature'.format(file_obj.file_path)
            shutil.copy(file_obj.file_path, backup_path)

            try:
                # Need to bump the version (modify manifest file)
                # before the file is signed.
                update_version_number(file_obj, bumped_version_number)
                signed = bool(sign_file(file_obj))
                if signed:  # Bump the version number if at least one signed.
                    signed_at_least_a_file = True
                else:  # We didn't sign, so revert the version bump.
                    shutil.move(backup_path, file_obj.file_path)
            except Exception:
                log.error(u'Failed signing file {0}'.format(file_obj.pk),
                          exc_info=True)
                # Revert the version bump, restore the backup.
                shutil.move(backup_path, file_obj.file_path)

        # Now update the Version model, if we signed at least one file.
        if signed_at_least_a_file:
            version.update(version=bumped_version_number)
            addon = version.addon
            if addon.pk not in addons_emailed:
                # Send a mail to the owners/devs warning them we've
                # automatically signed their addon.
                qs = (AddonUser.objects.filter(
                    role=amo.AUTHOR_ROLE_OWNER,
                    addon=addon).exclude(user__email__isnull=True))
                emails = qs.values_list('user__email', flat=True)
                subject = mail_subject
                message = mail_message.format(addon=addon.name)
                amo.utils.send_mail(
                    subject,
                    message,
                    recipient_list=emails,
                    headers={'Reply-To': '*****@*****.**'})
                addons_emailed.add(addon.pk)
Beispiel #14
0
def fix_let_scope_bustage_in_addons(addon_ids):
    """Used to fix the "let scope bustage" (bug 1224686) in the last version of
    the provided add-ons.

    This is used in the 'fix_let_scope_bustage' management commands.

    It also bumps the version number of the file and the Version, so the
    Firefox extension update mechanism picks this new fixed version and
    installs it.
    """
    log.info(u'[{0}] Fixing addons.'.format(len(addon_ids)))

    addons_emailed = []
    for addon in Addon.objects.filter(id__in=addon_ids):
        # We only care about the latest added version for each add-on.
        version = addon.versions.first()
        log.info(u'Fixing addon {0}, version {1}'.format(addon, version))

        bumped_version_number = u'{0}.1-let-fixed'.format(version.version)
        for file_obj in version.files.all():
            if not os.path.isfile(file_obj.file_path):
                log.info(u'File {0} does not exist, skip'.format(file_obj.pk))
                continue
            # Save the original file, before bumping the version.
            backup_path = u'{0}.backup_let_fix'.format(file_obj.file_path)
            shutil.copy(file_obj.file_path, backup_path)
            try:
                # Apply the fix itself.
                fix_let_scope_bustage_in_xpi(file_obj.file_path)
            except:
                log.error(u'Failed fixing file {0}'.format(file_obj.pk),
                          exc_info=True)
                # Revert the fix by restoring the backup.
                shutil.move(backup_path, file_obj.file_path)
                continue  # We move to the next file.
            # Need to bump the version (modify the manifest file)
            # before the file is signed.
            update_version_number(file_obj, bumped_version_number)
            if file_obj.is_signed:  # Only sign if it was already signed.
                if file_obj.status == amo.STATUS_PUBLIC:
                    server = settings.SIGNING_SERVER
                else:
                    server = settings.PRELIMINARY_SIGNING_SERVER
                sign_file(file_obj, server)
            # Now update the Version model.
            version.update(version=bumped_version_number,
                           version_int=version_int(bumped_version_number))
            addon = version.addon
            if addon.pk not in addons_emailed:
                # Send a mail to the owners/devs warning them we've
                # automatically fixed their addon.
                qs = (AddonUser.objects
                      .filter(role=amo.AUTHOR_ROLE_OWNER, addon=addon)
                      .exclude(user__email__isnull=True))
                emails = qs.values_list('user__email', flat=True)
                subject = MAIL_SUBJECT.format(addon=addon.name)
                message = MAIL_MESSAGE.format(
                    addon=addon.name,
                    addon_url=amo.helpers.absolutify(
                        addon.get_dev_url(action='versions')))
                amo.utils.send_mail(
                    subject, message, recipient_list=emails,
                    fail_silently=True,
                    headers={'Reply-To': '*****@*****.**'})
                addons_emailed.append(addon.pk)
Beispiel #15
0
def sign_addons(addon_ids, force=False, **kw):
    """Used to sign all the versions of an addon.

    This is used in the 'sign_addons' and 'process_addons --task sign_addons'
    management commands.

    It also bumps the version number of the file and the Version, so the
    Firefox extension update mechanism picks this new signed version and
    installs it.
    """
    log.info(u'[{0}] Signing addons.'.format(len(addon_ids)))

    reasons = {
        'default': [MAIL_SUBJECT, MAIL_MESSAGE],
        'expiry': [MAIL_EXPIRY_SUBJECT, MAIL_EXPIRY_MESSAGE]
    }
    mail_subject, mail_message = reasons[kw.get('reason', 'default')]

    def file_supports_firefox(version):
        """Return a Q object: files supporting at least a firefox version."""
        return Q(version__apps__max__application__in=SIGN_FOR_APPS,
                 version__apps__max__version_int__gte=version_int(version))

    is_default_compatible = Q(binary_components=False,
                              strict_compatibility=False)
    # We only want to sign files that are at least compatible with Firefox
    # MIN_D2C_VERSION, or Firefox MIN_NOT_D2C_VERSION if they are not default
    # to compatible.
    # The signing feature should be supported from Firefox 40 and above, but
    # we're still signing some files that are a bit older just in case.
    ff_version_filter = (
        (is_default_compatible &
            file_supports_firefox(settings.MIN_D2C_VERSION)) |
        (~is_default_compatible &
            file_supports_firefox(settings.MIN_NOT_D2C_VERSION)))

    addons_emailed = set()
    # We only care about extensions.
    for version in Version.objects.filter(addon_id__in=addon_ids,
                                          addon__type=amo.ADDON_EXTENSION):
        # We only sign files that have been reviewed and are compatible with
        # versions of Firefox that are recent enough.
        to_sign = version.files.filter(ff_version_filter,
                                       status__in=amo.REVIEWED_STATUSES)

        if force:
            to_sign = to_sign.all()
        else:
            to_sign = to_sign.filter(is_signed=False)
        if not to_sign:
            log.info(u'Not signing addon {0}, version {1} (no files or already'
                     u' signed)'.format(version.addon, version))
        log.info(u'Signing addon {0}, version {1}'.format(version.addon,
                                                          version))
        bumped_version_number = get_new_version_number(version.version)
        signed_at_least_a_file = False  # Did we sign at least one file?
        for file_obj in to_sign:
            if not os.path.isfile(file_obj.file_path):
                log.info(u'File {0} does not exist, skip'.format(file_obj.pk))
                continue
            # Save the original file, before bumping the version.
            backup_path = u'{0}.backup_signature'.format(file_obj.file_path)
            shutil.copy(file_obj.file_path, backup_path)
            try:
                # Need to bump the version (modify manifest file)
                # before the file is signed.
                update_version_number(file_obj, bumped_version_number)
                if file_obj.status == amo.STATUS_PUBLIC:
                    server = settings.SIGNING_SERVER
                else:
                    server = settings.PRELIMINARY_SIGNING_SERVER
                signed = bool(sign_file(file_obj, server))
                if signed:  # Bump the version number if at least one signed.
                    signed_at_least_a_file = True
                else:  # We didn't sign, so revert the version bump.
                    shutil.move(backup_path, file_obj.file_path)
            except:
                log.error(u'Failed signing file {0}'.format(file_obj.pk),
                          exc_info=True)
                # Revert the version bump, restore the backup.
                shutil.move(backup_path, file_obj.file_path)
        # Now update the Version model, if we signed at least one file.
        if signed_at_least_a_file:
            version.update(version=bumped_version_number,
                           version_int=version_int(bumped_version_number))
            addon = version.addon
            if addon.pk not in addons_emailed:
                # Send a mail to the owners/devs warning them we've
                # automatically signed their addon.
                qs = (AddonUser.objects
                      .filter(role=amo.AUTHOR_ROLE_OWNER, addon=addon)
                      .exclude(user__email__isnull=True))
                emails = qs.values_list('user__email', flat=True)
                subject = mail_subject.format(addon=addon.name)
                message = mail_message.format(
                    addon=addon.name,
                    addon_url=amo.helpers.absolutify(
                        addon.get_dev_url(action='versions')))
                amo.utils.send_mail(
                    subject, message, recipient_list=emails,
                    fail_silently=True,
                    headers={'Reply-To': '*****@*****.**'})
                addons_emailed.add(addon.pk)
Beispiel #16
0
def fix_let_scope_bustage_in_addons(addon_ids):
    """Used to fix the "let scope bustage" (bug 1224686) in the last version of
    the provided add-ons.

    This is used in the 'fix_let_scope_bustage' management commands.

    It also bumps the version number of the file and the Version, so the
    Firefox extension update mecanism picks this new fixed version and installs
    it.
    """
    log.info(u'[{0}] Fixing addons.'.format(len(addon_ids)))

    addons_emailed = []
    for addon in Addon.objects.filter(id__in=addon_ids):
        # We only care about the latest added version for each add-on.
        version = addon.versions.first()
        log.info(u'Fixing addon {0}, version {1}'.format(addon, version))

        bumped_version_number = u'{0}.1-let-fixed'.format(version.version)
        for file_obj in version.files.all():
            if not os.path.isfile(file_obj.file_path):
                log.info(u'File {0} does not exist, skip'.format(file_obj.pk))
                continue
            # Save the original file, before bumping the version.
            backup_path = u'{0}.backup_let_fix'.format(file_obj.file_path)
            shutil.copy(file_obj.file_path, backup_path)
            try:
                # Apply the fix itself.
                fix_let_scope_bustage_in_xpi(file_obj.file_path)
            except:
                log.error(u'Failed fixing file {0}'.format(file_obj.pk),
                          exc_info=True)
                # Revert the fix by restoring the backup.
                shutil.move(backup_path, file_obj.file_path)
                continue  # We move to the next file.
            # Need to bump the version (modify the manifest file)
            # before the file is signed.
            update_version_number(file_obj, bumped_version_number)
            if file_obj.is_signed:  # Only sign if it was already signed.
                if file_obj.status == amo.STATUS_PUBLIC:
                    server = settings.SIGNING_SERVER
                else:
                    server = settings.PRELIMINARY_SIGNING_SERVER
                sign_file(file_obj, server)
            # Now update the Version model.
            version.update(version=bumped_version_number,
                           version_int=version_int(bumped_version_number))
            addon = version.addon
            if addon.pk not in addons_emailed:
                # Send a mail to the owners/devs warning them we've
                # automatically fixed their addon.
                qs = (AddonUser.objects
                      .filter(role=amo.AUTHOR_ROLE_OWNER, addon=addon)
                      .exclude(user__email__isnull=True))
                emails = qs.values_list('user__email', flat=True)
                subject = MAIL_SUBJECT.format(addon=addon.name)
                message = MAIL_MESSAGE.format(
                    addon=addon.name,
                    addon_url=amo.helpers.absolutify(
                        addon.get_dev_url(action='versions')))
                amo.utils.send_mail(
                    subject, message, recipient_list=emails,
                    fail_silently=True,
                    headers={'Reply-To': '*****@*****.**'})
                addons_emailed.append(addon.pk)
Beispiel #17
0
def sign_addons(addon_ids, force=False, **kw):
    """Used to sign all the versions of an addon.

    This is used in the 'sign_addons' and 'process_addons --task sign_addons'
    management commands.

    It also bumps the version number of the file and the Version, so the
    Firefox extension update mechanism picks this new signed version and
    installs it.
    """
    log.info(u'[{0}] Signing addons.'.format(len(addon_ids)))

    reasons = {
        'default': [MAIL_SUBJECT, MAIL_MESSAGE],
        'expiry': [MAIL_EXPIRY_SUBJECT, MAIL_EXPIRY_MESSAGE]
    }
    mail_subject, mail_message = reasons[kw.get('reason', 'default')]

    addons_emailed = set()
    # We only care about extensions.
    for version in Version.objects.filter(addon_id__in=addon_ids,
                                          addon__type=amo.ADDON_EXTENSION):
        # We only sign files that have been reviewed and are compatible with
        # versions of Firefox that are recent enough.
        to_sign = version.files.filter(
            version__apps__max__application__in=SIGN_FOR_APPS,
            status__in=amo.REVIEWED_STATUSES)

        if force:
            to_sign = to_sign.all()
        else:
            to_sign = to_sign.filter(is_signed=False)
        if not to_sign:
            log.info(u'Not signing addon {0}, version {1} (no files or already'
                     u' signed)'.format(version.addon, version))
        log.info(u'Signing addon {0}, version {1}'.format(version.addon,
                                                          version))
        bumped_version_number = get_new_version_number(version.version)
        signed_at_least_a_file = False  # Did we sign at least one file?
        for file_obj in to_sign:
            if not os.path.isfile(file_obj.file_path):
                log.info(u'File {0} does not exist, skip'.format(file_obj.pk))
                continue
            # Save the original file, before bumping the version.
            backup_path = u'{0}.backup_signature'.format(file_obj.file_path)
            shutil.copy(file_obj.file_path, backup_path)
            try:
                # Need to bump the version (modify manifest file)
                # before the file is signed.
                update_version_number(file_obj, bumped_version_number)
                signed = bool(sign_file(file_obj))
                if signed:  # Bump the version number if at least one signed.
                    signed_at_least_a_file = True
                else:  # We didn't sign, so revert the version bump.
                    shutil.move(backup_path, file_obj.file_path)
            except Exception:
                log.error(u'Failed signing file {0}'.format(file_obj.pk),
                          exc_info=True)
                # Revert the version bump, restore the backup.
                shutil.move(backup_path, file_obj.file_path)
        # Now update the Version model, if we signed at least one file.
        if signed_at_least_a_file:
            version.update(version=bumped_version_number,
                           version_int=version_int(bumped_version_number))
            addon = version.addon
            if addon.pk not in addons_emailed:
                # Send a mail to the owners/devs warning them we've
                # automatically signed their addon.
                qs = (AddonUser.objects
                      .filter(role=amo.AUTHOR_ROLE_OWNER, addon=addon)
                      .exclude(user__email__isnull=True))
                emails = qs.values_list('user__email', flat=True)
                subject = mail_subject.format(addon=addon.name)
                message = mail_message.format(
                    addon=addon.name,
                    addon_url=amo.templatetags.jinja_helpers.absolutify(
                        addon.get_dev_url(action='versions')))
                amo.utils.send_mail(
                    subject, message, recipient_list=emails,
                    headers={'Reply-To': '*****@*****.**'})
                addons_emailed.add(addon.pk)
Beispiel #18
0
def sign_addons(addon_ids, force=False, send_emails=True, **kw):
    """Used to sign all the versions of an addon.

    This is used in the 'process_addons --task resign_addons_for_cose'
    management command.

    This is also used to resign some promoted addons after they've been added
    to a group (or paid).

    It also bumps the version number of the file and the Version, so the
    Firefox extension update mechanism picks this new signed version and
    installs it.
    """
    log.info(f'[{len(addon_ids)}] Signing addons.')

    mail_subject, mail_message = MAIL_COSE_SUBJECT, MAIL_COSE_MESSAGE

    # query everything except for search-plugins as they're generally
    # not signed
    current_versions = Addon.objects.filter(id__in=addon_ids).values_list(
        '_current_version', flat=True
    )
    qset = Version.objects.filter(id__in=current_versions)

    addons_emailed = set()
    task_user = get_task_user()

    for version in qset:
        file_obj = version.file
        # We only sign files that have been reviewed
        if file_obj.status not in amo.REVIEWED_STATUSES:
            log.info(
                'Not signing addon {}, version {} (no files)'.format(
                    version.addon, version
                )
            )
            continue

        log.info(f'Signing addon {version.addon}, version {version}')
        bumped_version_number = get_new_version_number(version.version)
        did_sign = False  # Did we sign at the file?

        if not os.path.isfile(file_obj.file_path):
            log.info(f'File {file_obj.pk} does not exist, skip')
            continue

        # Save the original file, before bumping the version.
        backup_path = f'{file_obj.file_path}.backup_signature'
        shutil.copy(file_obj.file_path, backup_path)

        try:
            # Need to bump the version (modify manifest file)
            # before the file is signed.
            update_version_number(file_obj, bumped_version_number)
            did_sign = bool(sign_file(file_obj))
            if not did_sign:  # We didn't sign, so revert the version bump.
                shutil.move(backup_path, file_obj.file_path)
        except Exception:
            log.error(f'Failed signing file {file_obj.pk}', exc_info=True)
            # Revert the version bump, restore the backup.
            shutil.move(backup_path, file_obj.file_path)

        # Now update the Version model, if we signed at least one file.
        if did_sign:
            previous_version_str = str(version.version)
            version.update(version=bumped_version_number)
            addon = version.addon
            ActivityLog.create(
                amo.LOG.VERSION_RESIGNED,
                addon,
                version,
                previous_version_str,
                user=task_user,
            )
            if send_emails and addon.pk not in addons_emailed:
                # Send a mail to the owners/devs warning them we've
                # automatically signed their addon.
                qs = AddonUser.objects.filter(
                    role=amo.AUTHOR_ROLE_OWNER, addon=addon
                ).exclude(user__email__isnull=True)
                emails = qs.values_list('user__email', flat=True)
                subject = mail_subject
                message = mail_message.format(addon=addon.name)
                amo.utils.send_mail(
                    subject,
                    message,
                    recipient_list=emails,
                    headers={'Reply-To': '*****@*****.**'},
                )
                addons_emailed.add(addon.pk)
Beispiel #19
0
def sign_addons(addon_ids, force=False, **kw):
    """Used to sign all the versions of an addon.

    This is used in the 'sign_addons' and 'process_addons --task sign_addons'
    management commands.

    It also bumps the version number of the file and the Version, so the
    Firefox extension update mechanism picks this new signed version and
    installs it.
    """
    log.info(u'[{0}] Signing addons.'.format(len(addon_ids)))

    reasons = {
        'default': [MAIL_SUBJECT, MAIL_MESSAGE],
        'expiry': [MAIL_EXPIRY_SUBJECT, MAIL_EXPIRY_MESSAGE]
    }
    mail_subject, mail_message = reasons[kw.get('reason', 'default')]

    def file_supports_firefox(version):
        """Return a Q object: files supporting at least a firefox version."""
        return Q(version__apps__max__application__in=SIGN_FOR_APPS,
                 version__apps__max__version_int__gte=version_int(version))

    is_default_compatible = Q(binary_components=False,
                              strict_compatibility=False)
    # We only want to sign files that are at least compatible with Firefox
    # MIN_D2C_VERSION, or Firefox MIN_NOT_D2C_VERSION if they are not default
    # to compatible.
    # The signing feature should be supported from Firefox 40 and above, but
    # we're still signing some files that are a bit older just in case.
    ff_version_filter = (
        (is_default_compatible &
            file_supports_firefox(settings.MIN_D2C_VERSION)) |
        (~is_default_compatible &
            file_supports_firefox(settings.MIN_NOT_D2C_VERSION)))

    addons_emailed = set()
    # We only care about extensions.
    for version in Version.objects.filter(addon_id__in=addon_ids,
                                          addon__type=amo.ADDON_EXTENSION):
        # We only sign files that have been reviewed and are compatible with
        # versions of Firefox that are recent enough.
        to_sign = version.files.filter(ff_version_filter,
                                       status__in=amo.REVIEWED_STATUSES)

        if force:
            to_sign = to_sign.all()
        else:
            to_sign = to_sign.filter(is_signed=False)
        if not to_sign:
            log.info(u'Not signing addon {0}, version {1} (no files or already'
                     u' signed)'.format(version.addon, version))
        log.info(u'Signing addon {0}, version {1}'.format(version.addon,
                                                          version))
        bumped_version_number = get_new_version_number(version.version)
        signed_at_least_a_file = False  # Did we sign at least one file?
        for file_obj in to_sign:
            if not os.path.isfile(file_obj.file_path):
                log.info(u'File {0} does not exist, skip'.format(file_obj.pk))
                continue
            # Save the original file, before bumping the version.
            backup_path = u'{0}.backup_signature'.format(file_obj.file_path)
            shutil.copy(file_obj.file_path, backup_path)
            try:
                # Need to bump the version (modify manifest file)
                # before the file is signed.
                update_version_number(file_obj, bumped_version_number)
                server = settings.SIGNING_SERVER
                signed = bool(sign_file(file_obj, server))
                if signed:  # Bump the version number if at least one signed.
                    signed_at_least_a_file = True
                else:  # We didn't sign, so revert the version bump.
                    shutil.move(backup_path, file_obj.file_path)
            except:
                log.error(u'Failed signing file {0}'.format(file_obj.pk),
                          exc_info=True)
                # Revert the version bump, restore the backup.
                shutil.move(backup_path, file_obj.file_path)
        # Now update the Version model, if we signed at least one file.
        if signed_at_least_a_file:
            version.update(version=bumped_version_number,
                           version_int=version_int(bumped_version_number))
            addon = version.addon
            if addon.pk not in addons_emailed:
                # Send a mail to the owners/devs warning them we've
                # automatically signed their addon.
                qs = (AddonUser.objects
                      .filter(role=amo.AUTHOR_ROLE_OWNER, addon=addon)
                      .exclude(user__email__isnull=True))
                emails = qs.values_list('user__email', flat=True)
                subject = mail_subject.format(addon=addon.name)
                message = mail_message.format(
                    addon=addon.name,
                    addon_url=amo.helpers.absolutify(
                        addon.get_dev_url(action='versions')))
                amo.utils.send_mail(
                    subject, message, recipient_list=emails,
                    fail_silently=True,
                    headers={'Reply-To': '*****@*****.**'})
                addons_emailed.add(addon.pk)
Beispiel #20
0
def resign_files(file_ids, **kw):
    """Used to force re-signing the files.

    This is used in the 'resign_files' management command. We need to
    re-sign the files that were signed with the wrong certificate (see bug
    1225036).

    It also bumps the version number of the file and the Version, so the
    Firefox extension update mecanism picks this new signed version and
    installs it.
    """
    log.info(u'[{0}] Signing files.'.format(len(file_ids)))

    addons_emailed = set()
    for file_ in File.objects.filter(id__in=file_ids):
        # We only resign files that have been reviewed and signed.
        if file_.status not in amo.REVIEWED_STATUSES:
            log.info(u'Not re-signing file {0}, not reviewed'.format(file_.pk))
            continue
        if not file_.is_signed:
            log.info(u'Not re-signing file {0}, not signed'.format(file_.pk))
            continue

        log.info(u'Re-signing file {0}'.format(file_.pk))

        bumped_version_number = u'{0}.1-signed'.format(file_.version.version)
        bump_version = False  # Did we resign the file?
        if not os.path.isfile(file_.file_path):
            log.info(u'File {0} does not exist, skip'.format(file_.pk))
            continue
        # Save the original file, before bumping the version.
        backup_path = u'{0}.backup_signature'.format(file_.file_path)
        shutil.copy(file_.file_path, backup_path)
        try:
            # Need to bump the version (modify manifest file)
            # before the file is signed.
            update_version_number(file_, bumped_version_number)
            if file_.status == amo.STATUS_PUBLIC:
                server = settings.SIGNING_SERVER
            else:
                server = settings.PRELIMINARY_SIGNING_SERVER
            signed = bool(sign_file(file_, server))
            if signed:  # Bump the version number if at least one signed.
                bump_version = True
            else:  # We didn't sign, so revert the version bump.
                shutil.move(backup_path, file_.file_path)
        except:
            log.error(u'Failed signing file {0}'.format(file_.pk),
                      exc_info=True)
            # Revert the version bump, restore the backup.
            shutil.move(backup_path, file_.file_path)

        # Now update the Version model, if we resigned the file.
        if bump_version:
            version = file_.version
            version.update(version=bumped_version_number,
                           version_int=version_int(bumped_version_number))
            addon = version.addon
            if addon.pk not in addons_emailed:
                # Send a mail to the owners/devs warning them we've
                # automatically signed their addon.
                qs = (AddonUser.objects
                      .filter(role=amo.AUTHOR_ROLE_OWNER, addon=addon)
                      .exclude(user__email=None))
                emails = qs.values_list('user__email', flat=True)
                subject = MAIL_RESIGN_SUBJECT.format(addon=addon.name)
                message = MAIL_RESIGN_MESSAGE.format(
                    addon=addon.name,
                    addon_url=amo.helpers.absolutify(
                        addon.get_dev_url(action='versions')))
                amo.utils.send_mail(
                    subject, message, recipient_list=emails,
                    fail_silently=True,
                    headers={'Reply-To': '*****@*****.**'})
                addons_emailed.add(addon.pk)