Skip to content

Commit

Permalink
Merge pull request #945 from magopian/1225036-resign-wrongly-signed-f…
Browse files Browse the repository at this point in the history
…iles

Resign wrongly signed files (bug 1225036)
  • Loading branch information
magopian committed Nov 27, 2015
2 parents 31952d1 + 9092ffa commit 830a367
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 4 deletions.
35 changes: 35 additions & 0 deletions apps/addons/management/commands/resign_files.py
@@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
from optparse import make_option

from django.conf import settings
from django.core.management.base import BaseCommand, CommandError
from django.test.utils import override_settings

from lib.crypto.tasks import resign_files


class Command(BaseCommand):
args = '<file_id file_id ...>'
help = 'Resign a list of already signed files.'
option_list = BaseCommand.option_list + (
make_option('--signing-server', action='store', type='string',
dest='signing_server',
help='The signing server to use for full reviews'),
make_option('--preliminary-signing-server', action='store',
type='string',
dest='preliminary_signing_server',
help='The signing server to use for preliminary reviews'),
)

def handle(self, *args, **options):
if len(args) == 0:
raise CommandError('Please provide at least one file id to resign')
full_server = options.get('signing_server') or settings.SIGNING_SERVER
prelim_server = (options.get('preliminary_signing_server') or
settings.PRELIMINARY_SIGNING_SERVER)

file_ids = [int(file_id) for file_id in args]
with override_settings(
SIGNING_SERVER=full_server,
PRELIMINARY_SIGNING_SERVER=prelim_server):
resign_files(file_ids)
111 changes: 107 additions & 4 deletions lib/crypto/tasks.py
Expand Up @@ -8,6 +8,7 @@
import amo
from addons.models import AddonUser
from amo.celery import task
from files.models import File
from files.utils import update_version_number
from lib.crypto.packaged import sign_file
from versions.compare import version_int
Expand Down Expand Up @@ -60,6 +61,30 @@
"""


MAIL_RESIGN_SUBJECT = (
u'Mozilla Add-ons: {addon} has been automatically resigned on AMO')
MAIL_RESIGN_MESSAGE = u"""
Your add-on, {addon}, has been automatically resigned for distribution in
upcoming versions of Firefox. The signing process involved repackaging the
add-on files and adding the string '.1-signed' to their versions numbers. The
new versions have kept their review status and are now available for your
users.
We recommend that you give them a try to make sure they don't have any
unexpected problems: {addon_url}
This has been done following an issue on our servers: the files that got
reviewed between 2015-11-10 and 2015-11-18 were signed incorrectly, which can
lead to installation problems. We strongly recommend that you use the newly
signed versions and distribute them to your users.
If you have any questions or comments on this, please reply to this email or
join #addons on irc.mozilla.org.
You're receiving this email because you have an add-on hosted on
https://addons.mozilla.org
"""


@task
def sign_addons(addon_ids, force=False, **kw):
"""Used to sign all the versions of an addon.
Expand Down Expand Up @@ -91,7 +116,7 @@ def file_supports_firefox(version):
(~is_default_compatible &
file_supports_firefox(settings.MIN_NOT_D2C_VERSION)))

addons_emailed = []
addons_emailed = set()
# We only care about extensions.
for version in Version.objects.filter(addon_id__in=addon_ids,
addon__type=amo.ADDON_EXTENSION):
Expand Down Expand Up @@ -158,7 +183,7 @@ def file_supports_firefox(version):
subject, message, recipient_list=emails,
fail_silently=True,
headers={'Reply-To': 'amo-editors@mozilla.org'})
addons_emailed.append(addon.pk)
addons_emailed.add(addon.pk)


@task
Expand Down Expand Up @@ -191,7 +216,7 @@ def file_supports_firefox(version):
(~is_default_compatible &
file_supports_firefox(settings.MIN_NOT_D2C_VERSION)))

addons_emailed = []
addons_emailed = set()
# We only care about extensions and themes which are multi-package XPIs.
# We don't sign multi-package XPIs since bug 1172696, but we had signed
# some before that, and we now have to deal with it, eg for bug 1205823.
Expand Down Expand Up @@ -256,4 +281,82 @@ def file_supports_firefox(version):
subject, message, recipient_list=emails,
fail_silently=True,
headers={'Reply-To': 'amo-editors@mozilla.org'})
addons_emailed.append(addon.pk)
addons_emailed.add(addon.pk)


@task
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 install.rdf or package.json)
# 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': 'amo-editors@mozilla.org'})
addons_emailed.add(addon.pk)

0 comments on commit 830a367

Please sign in to comment.