Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: packagerSafari.py

Issue 29349885: Issue 4340 - Drop dependency on external xar tool (Closed)
Patch Set: Merged cert and private key extraction Created Aug. 17, 2016, 2:10 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | xarfile.py » ('j') | xarfile.py » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: packagerSafari.py
===================================================================
--- a/packagerSafari.py
+++ b/packagerSafari.py
@@ -105,144 +105,38 @@ def fixAbsoluteUrls(files):
if os.path.splitext(filename)[1].lower() == '.html':
files[filename] = re.sub(
r'(<[^<>]*?\b(?:href|src)\s*=\s*["\']?)\/+',
r'\1' + '/'.join(['..'] * filename.count('/') + ['']),
content, re.S | re.I
)
-def get_certificates_and_key(keyfile):
- from Crypto.PublicKey import RSA
-
- with open(keyfile, 'r') as file:
- data = file.read()
-
- certificates = []
- key = None
- for match in re.finditer(r'-+BEGIN (.*?)-+(.*?)-+END \1-+', data, re.S):
- section = match.group(1)
- if section == 'CERTIFICATE':
- certificates.append(base64.b64decode(match.group(2)))
- elif section == 'PRIVATE KEY':
- key = RSA.importKey(match.group(0))
- if key is None:
- raise Exception('Cound not find private key in file')
-
- return certificates, key
-
-
def _get_sequence(data):
from Crypto.Util import asn1
sequence = asn1.DerSequence()
sequence.decode(data)
return sequence
def get_developer_identifier(certs):
for cert in certs:
# See https://tools.ietf.org/html/rfc5280#section-4
- tbscertificate = _get_sequence(cert)[0]
+ tbscertificate = _get_sequence(base64.b64decode(cert))[0]
subject = _get_sequence(tbscertificate)[5]
# We could decode the subject but since we have to apply a regular
# expression on CN entry anyway we can just skip that.
m = re.search(r'Safari Developer: \((\S*?)\)', subject)
if m:
return m.group(1)
raise Exception('No Safari developer certificate found in chain')
-def sign_digest(key, digest):
- from Crypto.Hash import SHA
- from Crypto.Signature import PKCS1_v1_5
-
- # xar already calculated the SHA1 digest so we have to fake hashing here.
- class FakeHash(SHA.SHA1Hash):
- def digest(self):
- return digest
-
- return PKCS1_v1_5.new(key).sign(FakeHash())
-
-
-def createSignedXarArchive(outFile, files, certs, key):
- import subprocess
- import tempfile
- import shutil
-
- # write files to temporary directory and create a xar archive
- dirname = tempfile.mkdtemp()
- try:
- for filename, contents in files.iteritems():
- path = os.path.join(dirname, filename)
-
- try:
- os.makedirs(os.path.dirname(path))
- except OSError:
- pass
-
- with open(path, 'wb') as file:
- file.write(contents)
-
- subprocess.check_output(
- ['xar', '-czf', os.path.abspath(outFile), '--distribution'] + os.listdir(dirname),
- cwd=dirname
- )
- finally:
- shutil.rmtree(dirname)
-
- certificate_filenames = []
- try:
- # write each certificate in DER format to a separate
- # temporary file, that they can be passed to xar
- for cert in certs:
- fd, filename = tempfile.mkstemp()
- try:
- certificate_filenames.append(filename)
- os.write(fd, cert)
- finally:
- os.close(fd)
-
- # add certificates and placeholder signature
- # to the xar archive, and get data to sign
- fd, digest_filename = tempfile.mkstemp()
- os.close(fd)
- try:
- subprocess.check_call(
- [
- 'xar', '--sign', '-f', outFile,
- '--data-to-sign', digest_filename,
- '--sig-size', str(len(sign_digest(key, '')))
- ] + [
- arg for cert in certificate_filenames for arg in ('--cert-loc', cert)
- ]
- )
-
- with open(digest_filename, 'rb') as file:
- digest = file.read()
- finally:
- os.unlink(digest_filename)
- finally:
- for filename in certificate_filenames:
- os.unlink(filename)
-
- # sign data and inject signature into xar archive
- fd, signature_filename = tempfile.mkstemp()
- try:
- try:
- os.write(fd, sign_digest(key, digest))
- finally:
- os.close(fd)
-
- subprocess.check_call(['xar', '--inject-sig', signature_filename, '-f', outFile])
- finally:
- os.unlink(signature_filename)
-
-
def createBuild(baseDir, type, outFile=None, buildNum=None, releaseBuild=False, keyFile=None, devenv=False):
metadata = readMetadata(baseDir, type)
version = getBuildVersion(baseDir, metadata, releaseBuild, buildNum)
if not outFile:
outFile = getDefaultFileName(metadata, version, 'safariextz' if keyFile else 'zip')
params = {
@@ -272,26 +166,28 @@ def createBuild(baseDir, type, outFile=N
if metadata.has_section('import_locales'):
importGeckoLocales(params, files)
if metadata.has_option('general', 'testScripts'):
files['qunit/index.html'] = createScriptPage(params, 'testIndex.html.tmpl',
('general', 'testScripts'))
if keyFile:
- certs, key = get_certificates_and_key(keyFile)
+ from buildtools import xarfile
+ certs, key = xarfile.read_certificates_and_key(keyFile)
params['developerIdentifier'] = get_developer_identifier(certs)
files['lib/info.js'] = createInfoModule(params)
files['background.html'] = createScriptPage(params, 'background.html.tmpl',
('general', 'backgroundScripts'))
files['Info.plist'] = createManifest(params, files)
fixAbsoluteUrls(files)
dirname = metadata.get('general', 'basename') + '.safariextension'
for filename in files.keys():
files[os.path.join(dirname, filename)] = files.pop(filename)
if not devenv and keyFile:
- createSignedXarArchive(outFile, files, certs, key)
+ from buildtools import xarfile
+ xarfile.create(outFile, files, keyFile)
else:
files.zip(outFile)
« no previous file with comments | « no previous file | xarfile.py » ('j') | xarfile.py » ('J')

Powered by Google App Engine
This is Rietveld