use subclass hack for better ZIP cloning

See https://bugs.python.org/issue43547 for more info on the details.

thanks to @obfusk for the technique
This commit is contained in:
Felix C. Stegerman 2021-04-12 19:30:45 +02:00
parent 3d6345a595
commit 67a0f3ae5b
No known key found for this signature in database
GPG Key ID: B218FF2C27FC6CC6
2 changed files with 31 additions and 2 deletions

View File

@ -3,6 +3,7 @@
# common.py - part of the FDroid server tools
# Copyright (C) 2010-13, Ciaran Gultnieks, ciaran@ciarang.com
# Copyright (C) 2013-2014 Daniel Martí <mvdan@mvdan.cc>
# Copyright (C) 2021 Felix C. Stegerman <flx@obfusk.net>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -3007,6 +3008,27 @@ def metadata_find_developer_signing_files(appid, vercode):
return None
class ClonedZipInfo(zipfile.ZipInfo):
"""Hack to allow fully cloning ZipInfo instances
The zipfile library has some bugs that prevent it from fully
cloning ZipInfo entries. https://bugs.python.org/issue43547
"""
def __init__(self, zinfo):
self.original = zinfo
for k in self.__slots__:
try:
setattr(self, k, getattr(zinfo, k))
except AttributeError:
pass
def __getattribute__(self, name):
if name in ("date_time", "external_attr", "flag_bits"):
return getattr(self.original, name)
return object.__getattribute__(self, name)
def apk_strip_v1_signatures(signed_apk, strip_manifest=False):
"""Removes signatures from APK.
@ -3024,10 +3046,10 @@ def apk_strip_v1_signatures(signed_apk, strip_manifest=False):
if strip_manifest:
if info.filename != 'META-INF/MANIFEST.MF':
buf = in_apk.read(info.filename)
out_apk.writestr(info, buf)
out_apk.writestr(ClonedZipInfo(info), buf)
else:
buf = in_apk.read(info.filename)
out_apk.writestr(info, buf)
out_apk.writestr(ClonedZipInfo(info), buf)
def _zipalign(unsigned_apk, aligned_apk):

View File

@ -1754,6 +1754,13 @@ class CommonTest(unittest.TestCase):
fdroidserver.common.read_pkg_args(appid_versionCode_pairs, allow_vercodes)
)
def test_apk_strip_v1_signatures(self):
testdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir)
before = os.path.join(self.basedir, 'no_targetsdk_minsdk1_unsigned.apk')
after = os.path.join(testdir, 'after.apk')
shutil.copy(before, after)
fdroidserver.common.apk_strip_v1_signatures(after, strip_manifest=False)
if __name__ == "__main__":
os.chdir(os.path.dirname(__file__))