Skip to content
Browse files

hack together a copy of flatpkgfixer using this

  • Loading branch information...
1 parent 814f49c commit 32cff932044294a1b7233de5486c19bdbe7f4da6 @etrepum committed Apr 12, 2012
Showing with 78 additions and 53 deletions.
  1. +14 −37 flatpkgfixer.py
  2. +64 −16 strip_pkg_signature.py
View
51 flatpkgfixer.py
@@ -4,6 +4,13 @@
flatpkgfixer.py
"""
+#
+# NOTE:
+# This is a modified version of the original. The modifications
+# replace pkgutil usage with strip_pkg_signature.py. The original
+# can be found here:
+# http://managingosx.wordpress.com/2012/03/24/fixing-packages-with-expired-signatures
+#
# Copyright 2012 Greg Neagle.
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,6 +34,8 @@
import tempfile
from xml.parsers.expat import ExpatError
+from strip_pkg_signature import strip_signature, XARFormatError
+
def getFirstPlist(textString):
"""Gets the next plist from a text string that may contain one or
more text-style plists.
@@ -125,42 +134,10 @@ def unmountdmg(mountpoint):
print >> sys.stderr, 'Failed to unmount %s' % mountpoint
-class ExpandOrFlattenError(Exception):
- '''Base error for exapnding and flattening pkgs'''
-
-class ExpandPkgError(ExpandOrFlattenError):
- '''Exception to raise if there's an error while expanding a pkg'''
-
-class FlattenPkgError(ExpandOrFlattenError):
- '''Exception to raise if there's an error while flatening a pkg'''
-
def expandAndFlatten(sourcepkg, destination=None):
- '''Uses pkgutil to expand and reflatten a flat package.
- A side-effect is that any package signing will be removed.'''
-
- if not destination:
- destination = sourcepkg
- if os.path.isdir(destination):
- destination = os.path.join(destination, os.path.basename(sourcepkg))
- expand_dir = os.path.join(TMPDIR, os.path.basename(sourcepkg))
- print "Expanding %s to %s..." % (sourcepkg, expand_dir)
- try:
- subprocess.check_call(
- ['/usr/sbin/pkgutil', '--expand', sourcepkg, expand_dir])
- except subprocess.CalledProcessError, e:
- raise ExpandPkgError("ERROR: %s expanding %s" % (e, sourcepkg))
- print "Flattening %s to %s..." % (expand_dir, destination)
- if os.path.exists(destination):
- os.unlink(destination)
- try:
- subprocess.check_call(
- ['/usr/sbin/pkgutil', '--flatten', expand_dir, destination])
- except subprocess.CalledProcessError, e:
- # lets try a different way
- raise FlattenPkgError("ERROR: %s while flattening %s" % (e, expand_dir))
-
- #clean up our expand_dir
- shutil.rmtree(expand_dir, ignore_errors=True)
+ '''Uses strip_pkg_signature to remove package signing.'''
+
+ strip_signature(sourcepkg, out_fn=destination)
def cleanupFromFailAndExit(errmsg=''):
@@ -211,7 +188,7 @@ def main():
cleanupFromFailAndExit('%s is a bundle-style package!')
try:
expandAndFlatten(source_item, dest_item)
- except ExpandOrFlattenError, e:
+ except XARFormatError, e:
cleanupFromFailAndExit(str(e))
elif source_item.endswith('.dmg'):
@@ -242,7 +219,7 @@ def main():
flattened_path = os.path.join(
flattened_dir, name)
expandAndFlatten(filepath, flattened_path)
- except ExpandOrFlattenError, e:
+ except XARFormatError, e:
unmountdmg(mountpoint)
cleanupFromFailAndExit(str(e))
# copy reflattened package back to diskimage
View
80 strip_pkg_signature.py
@@ -6,9 +6,15 @@
import struct
import hashlib
import argparse
+from binascii import b2a_hex
from xml.etree import cElementTree as etree
from tempfile import NamedTemporaryFile
-from shutil import copyfileobj
+from shutil import copyfileobj, copy2
+
+
+class XARFormatError(ValueError):
+ pass
+
class NoChecksum(object):
def __init__(self, initial=''):
@@ -17,12 +23,14 @@ def __init__(self, initial=''):
def digest(self):
return ''
+
MAGIC = 0x78617221 # xar!
VERSIONS = {0, 1}
CHECKSUM = {0: NoChecksum,
1: hashlib.sha1,
2: hashlib.md5}
+
class Struct(object):
def __init__(self, fmt, fields):
self.fmt = fmt
@@ -39,40 +47,78 @@ def pack(self, dct):
return struct.pack(self.fmt,
*(dct[field] for field in self.fields))
+
HEADER = Struct('>IHHQQI',
('magic', 'size', 'version',
'toc_length_compressed', 'toc_length_uncompressed',
'cksum_alg'))
+
+def toc_digest(hdr, ztocdata):
+ return CHECKSUM[hdr['cksum_alg']](ztocdata).digest()
+
+
def readtoc(f):
hdr = HEADER.fromfile(f)
- assert(hdr['magic'] == MAGIC)
- assert(hdr['version'] in VERSIONS)
- assert(hdr['cksum_alg'] in CHECKSUM)
- tocdata_compressed = f.read(hdr['toc_length_compressed'])
- tocdata = zlib.decompress(tocdata_compressed)
- assert(len(tocdata) == hdr['toc_length_uncompressed'])
- digest = CHECKSUM[hdr['cksum_alg']](tocdata_compressed).digest()
+ if hdr['magic'] != MAGIC:
+ raise XARFormatError('magic %r != %r' %
+ (hdr['magic'], MAGIC))
+ if hdr['version'] not in VERSIONS:
+ raise XARFormatError('version %r not supported' %
+ (hdr['version'],))
+ if hdr['cksum_alg'] not in CHECKSUM:
+ raise XARFormatError('cksum_alg %r not supported' %
+ (hdr['cksum_alg'],))
+ ztocdata = f.read(hdr['toc_length_compressed'])
+ tocdata = zlib.decompress(ztocdata)
+ if hdr['toc_length_uncompressed'] != len(tocdata):
+ raise XARFormatError('toc_length_uncompressed %r != %r' %
+ (hdr['toc_length_uncompressed'],
+ len(tocdata)))
+ digest = toc_digest(hdr, ztocdata)
if digest:
orig_digest = f.read(len(digest))
- assert(digest == orig_digest)
+ if digest != orig_digest:
+ raise XARFormatError('digest %r != %r' %
+ (b2a_hex(digest),
+ b2a_hex(orig_digest)))
return hdr, tocdata
-def strip_signature(fn, dry_run=False, keep_old=False):
+
+def strip_signature(fn, out_fn=None, dry_run=False, keep_old=False):
+ if out_fn is not None:
+ if keep_old:
+ raise TypeError('keep_old is not compatible with out_fn')
+ if os.path.isdir(out_fn):
+ out_fn = os.path.join(out_fn, os.path.basename(fn))
+ def do(msg, func, *args, **kw):
+ if not dry_run:
+ if func is not None:
+ func(*args, **kw)
+ else:
+ msg = msg + ' (dry run)'
+ print fn, msg
+ in_place = out_fn is None
with open(fn, 'rb') as f:
hdr, tocdata = readtoc(f)
new_tocdata = strip_toc_signature(tocdata)
if new_tocdata is None:
- print fn, '- SKIPPED (already unsigned)'
- elif dry_run:
- print fn, '- would replace signature (dry-run)'
+ if in_place:
+ do('SKIPPED, already unsigned',
+ None)
+ else:
+ do('COPIED, already unsigned',
+ copy2, fn, out_fn)
else:
- write_xar(fn, hdr, new_tocdata, f, keep_old)
- print fn, '- replaced toc'
+ do('REPLACED TOC',
+ write_xar,
+ fn if in_place else out_fn,
+ hdr, new_tocdata, f, keep_old)
+
def write_xar(fn, hdr, tocdata, heap, keep_old=False):
ztocdata = zlib.compress(tocdata)
- digest = CHECKSUM[hdr['cksum_alg']](ztocdata).digest()
+ digest = toc_digest(hdr, ztocdata)
newhdr = dict(hdr,
toc_length_uncompressed=len(tocdata),
toc_length_compressed=len(ztocdata))
@@ -102,6 +148,7 @@ def write_xar(fn, hdr, tocdata, heap, keep_old=False):
os.link(fn, oldfn)
os.rename(outf.name, fn)
+
def strip_toc_signature(xmlstr):
et = etree.fromstring(xmlstr)
toc = et.find('toc')
@@ -113,6 +160,7 @@ def strip_toc_signature(xmlstr):
toc.remove(sig)
return etree.tostring(et)
+
def main():
parser = argparse.ArgumentParser(sys.argv[0])
parser.add_argument('--dry-run', dest='dry_run', action='store_true',

0 comments on commit 32cff93

Please sign in to comment.
Something went wrong with that request. Please try again.