Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fail to support ZipInfo extra fields #21

Open
ze42 opened this issue Sep 22, 2021 · 1 comment
Open

Fail to support ZipInfo extra fields #21

ze42 opened this issue Sep 22, 2021 · 1 comment

Comments

@ze42
Copy link

ze42 commented Sep 22, 2021

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'

@danifus
Copy link
Owner

danifus commented Sep 29, 2021

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants