pyzipper icon indicating copy to clipboard operation
pyzipper copied to clipboard

Fail to support ZipInfo `extra` fields

Open ze42 opened this issue 4 years ago • 1 comments

I was trying to add timestamp to the extra header field while using pyzipper, and ran into a bug.

pyzipper does not use the ZipInfo's extra attribute, though zipfile from python3.7 did.

Little code example to show the difference, adding 2 files to a zip (one with, one without an extra field), and checking what can be found in the extra field in the zip.

#! /usr/bin/env python3.7

import io
import time
import struct
import zipfile
import pyzipper


def test(zipCls, infoCls, encrypt=False):
    print("Testing {0.__module__}.{0.__name__} ({0.__module__}.{0.__name__})".format(zipCls, infoCls))
    buff = io.BytesIO()
    now_ts = time.time()
    extra_ts = struct.pack(
        '<HHbi',
        0x5455,  #     extended timestamp
        0x05,  #       5 bytes
        0x01,  #       mod-timestamp
        int(now_ts),
    )
    now = time.gmtime(now_ts)
    opts = {}
    if encrypt:
        opts = {'encryption': pyzipper.WZ_AES}
    with zipCls(buff, 'w', **opts) as _zip:
        if encrypt:
            _zip.setpassword(b'S3cr3t!')
        info = infoCls('First', date_time=now)
        info.external_attr = 0o600 << 16
        _zip.writestr(info, 'Foo!')

        info = infoCls('Last', date_time=now)
        info.external_attr = 0o600 << 16
        info.extra = extra_ts
        _zip.writestr(info, 'Bar!')

    with zipCls(buff) as _zip:
        for info in _zip.infolist():
            print(f"{info.filename!r}: {info.extra!r}")
    print()


if __name__ == '__main__':
    test(zipfile.ZipFile, zipfile.ZipInfo)
    test(pyzipper.ZipFile, pyzipper.ZipInfo)
    test(pyzipper.AESZipFile, pyzipper.zipfile_aes.AESZipInfo, True)

Result shows that zipfile properly store the field, and retrieves it, while pyzipper ignores it, setting it with specific AES extra info, but both not caring about what the use might have provided in ZipInfo.

$ ./foo.py 
Testing zipfile.ZipFile (zipfile.ZipFile)
'First': b''
'Last': b'UT\x05\x00\x01\xae(Ka'

Testing pyzipper.zipfile.ZipFile (pyzipper.zipfile.ZipFile)
'First': b''
'Last': b''

Testing pyzipper.zipfile_aes.AESZipFile (pyzipper.zipfile_aes.AESZipFile)
'First': b'\x01\x99\x07\x00\x01\x00AE\x03\x00\x00'
'Last': b'\x01\x99\x07\x00\x01\x00AE\x03\x00\x00'

ze42 avatar Sep 22 '21 13:09 ze42

Thanks for the bug report. I changed the way the extra fields were generated while making them extensible via subclassing. I'll have a look at how hard it would be to reintroduce that behaviour. In the meantime, it may be possible to subclass ZipFile or AESZipFile from pyzipper and add support for that extra field.

danifus avatar Sep 29 '21 04:09 danifus