Merge branch 'feature/UpdateRarfile' into dev

This commit is contained in:
JackDandy 2024-06-07 16:45:37 +01:00
commit b623ffae4d
2 changed files with 47 additions and 13 deletions

View file

@ -12,6 +12,7 @@
* Update imdbpie 5.6.4 (f695e87) to 5.6.5 (f8ed7a0) * Update imdbpie 5.6.4 (f695e87) to 5.6.5 (f8ed7a0)
* Update profilehooks module 1.12.1 (c3fc078) to 1.13.0.dev0 (99f8a31) * Update profilehooks module 1.12.1 (c3fc078) to 1.13.0.dev0 (99f8a31)
* Update pytz 2023.3/2023c (488d3eb) to 2024.1/2024a (3680953) * Update pytz 2023.3/2023c (488d3eb) to 2024.1/2024a (3680953)
* Update Rarfile 4.1a1 (8a72967) to 4.2 (db1df33)
* Update Requests library 2.31.0 (8812812) to 2.32.3 (0e322af) * Update Requests library 2.31.0 (8812812) to 2.32.3 (0e322af)
* Update Tornado Web Server 6.4 (b3f2a4b) to 6.4.1 (2a0e1d1) * Update Tornado Web Server 6.4 (b3f2a4b) to 6.4.1 (2a0e1d1)
* Update urllib3 2.0.7 (56f01e0) to 2.2.1 (54d6edf) * Update urllib3 2.0.7 (56f01e0) to 2.2.1 (54d6edf)

View file

@ -1,6 +1,6 @@
# rarfile.py # rarfile.py
# #
# Copyright (c) 2005-2020 Marko Kreen <markokr@gmail.com> # Copyright (c) 2005-2024 Marko Kreen <markokr@gmail.com>
# #
# Permission to use, copy, modify, and/or distribute this software for any # Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above # purpose with or without fee is hereby granted, provided that the above
@ -92,7 +92,7 @@ class AES_CBC_Decrypt:
self.decrypt = ciph.decryptor().update self.decrypt = ciph.decryptor().update
__version__ = "4.1" __version__ = "4.2"
# export only interesting items # export only interesting items
__all__ = ["get_rar_version", "is_rarfile", "is_rarfile_sfx", "RarInfo", "RarFile", "RarExtFile"] __all__ = ["get_rar_version", "is_rarfile", "is_rarfile_sfx", "RarInfo", "RarFile", "RarExtFile"]
@ -210,6 +210,9 @@ RAR_M3 = 0x33 #: Compression level `-m3`.
RAR_M4 = 0x34 #: Compression level `-m4`. RAR_M4 = 0x34 #: Compression level `-m4`.
RAR_M5 = 0x35 #: Compression level `-m5` - Maximum compression. RAR_M5 = 0x35 #: Compression level `-m5` - Maximum compression.
RAR_MAX_PASSWORD = 127 #: Max number of utf-16 chars in passwords.
RAR_MAX_KDF_SHIFT = 24 #: Max power-of-2 for KDF count
# #
# RAR5 constants # RAR5 constants
# #
@ -739,6 +742,13 @@ class RarFile:
""" """
return self._file_parser.needs_password() return self._file_parser.needs_password()
def is_solid(self):
"""Returns True if archive uses solid compression.
.. versionadded:: 4.2
"""
return self._file_parser.is_solid()
def namelist(self): def namelist(self):
"""Return list of filenames in archive. """Return list of filenames in archive.
""" """
@ -1030,6 +1040,14 @@ class CommonParser:
self._sfx_offset = sfx_offset self._sfx_offset = sfx_offset
self._part_only = part_only self._part_only = part_only
def is_solid(self):
"""Returns True if archive uses solid compression.
"""
if self._main:
if self._main.flags & RAR_MAIN_SOLID:
return True
return False
def has_header_encryption(self): def has_header_encryption(self):
"""Returns True if headers are encrypted """Returns True if headers are encrypted
""" """
@ -1167,7 +1185,9 @@ class CommonParser:
if not self._password: if not self._password:
break break
elif h.type == RAR_BLOCK_ENDARC: elif h.type == RAR_BLOCK_ENDARC:
more_vols = (h.flags & RAR_ENDARC_NEXT_VOLUME) > 0 # use flag, but also allow RAR 2.x logic below to trigger
if h.flags & RAR_ENDARC_NEXT_VOLUME:
more_vols = True
endarc = True endarc = True
if raise_need_first_vol and (h.flags & RAR_ENDARC_VOLNR) > 0: if raise_need_first_vol and (h.flags & RAR_ENDARC_VOLNR) > 0:
raise NeedFirstVolume( raise NeedFirstVolume(
@ -1810,10 +1830,10 @@ class RAR5Parser(CommonParser):
def _gen_key(self, kdf_count, salt): def _gen_key(self, kdf_count, salt):
if self._last_aes256_key[:2] == (kdf_count, salt): if self._last_aes256_key[:2] == (kdf_count, salt):
return self._last_aes256_key[2] return self._last_aes256_key[2]
if kdf_count > 24: if kdf_count > RAR_MAX_KDF_SHIFT:
raise BadRarFile("Too large kdf_count") raise BadRarFile("Too large kdf_count")
pwd = self._get_utf8_password() pwd = self._get_utf8_password()
key = pbkdf2_hmac("sha256", pwd, salt, 1 << kdf_count) key = rar5_s2k(pwd, salt, 1 << kdf_count)
self._last_aes256_key = (kdf_count, salt, key) self._last_aes256_key = (kdf_count, salt, key)
return key return key
@ -1978,6 +1998,8 @@ class RAR5Parser(CommonParser):
def _check_password(self, check_value, kdf_count_shift, salt): def _check_password(self, check_value, kdf_count_shift, salt):
if len(check_value) != RAR5_PW_CHECK_SIZE + RAR5_PW_SUM_SIZE: if len(check_value) != RAR5_PW_CHECK_SIZE + RAR5_PW_SUM_SIZE:
return return
if kdf_count_shift > RAR_MAX_KDF_SHIFT:
raise BadRarFile("Too large kdf_count")
hdr_check = check_value[:RAR5_PW_CHECK_SIZE] hdr_check = check_value[:RAR5_PW_CHECK_SIZE]
hdr_sum = check_value[RAR5_PW_CHECK_SIZE:] hdr_sum = check_value[RAR5_PW_CHECK_SIZE:]
@ -1987,7 +2009,7 @@ class RAR5Parser(CommonParser):
kdf_count = (1 << kdf_count_shift) + 32 kdf_count = (1 << kdf_count_shift) + 32
pwd = self._get_utf8_password() pwd = self._get_utf8_password()
pwd_hash = pbkdf2_hmac("sha256", pwd, salt, kdf_count) pwd_hash = rar5_s2k(pwd, salt, kdf_count)
pwd_check = bytearray(RAR5_PW_CHECK_SIZE) pwd_check = bytearray(RAR5_PW_CHECK_SIZE)
len_mask = RAR5_PW_CHECK_SIZE - 1 len_mask = RAR5_PW_CHECK_SIZE - 1
@ -2341,8 +2363,8 @@ class RarExtFile(io.RawIOBase):
"""Seek in data. """Seek in data.
On uncompressed files, the seeking works by actual On uncompressed files, the seeking works by actual
seeks so it's fast. On compresses files its slow seeks so it's fast. On compressed files its slow
- forward seeking happends by reading ahead, - forward seeking happens by reading ahead,
backwards by re-opening and decompressing from the start. backwards by re-opening and decompressing from the start.
""" """
@ -3044,12 +3066,23 @@ def is_filelike(obj):
return True return True
def rar5_s2k(pwd, salt, kdf_count):
"""String-to-key hash for RAR5.
"""
if not isinstance(pwd, str):
pwd = pwd.decode("utf8")
wstr = pwd.encode("utf-16le")[:RAR_MAX_PASSWORD*2]
ustr = wstr.decode("utf-16le").encode("utf8")
return pbkdf2_hmac("sha256", ustr, salt, kdf_count)
def rar3_s2k(pwd, salt): def rar3_s2k(pwd, salt):
"""String-to-key hash for RAR3. """String-to-key hash for RAR3.
""" """
if not isinstance(pwd, str): if not isinstance(pwd, str):
pwd = pwd.decode("utf8") pwd = pwd.decode("utf8")
seed = bytearray(pwd.encode("utf-16le") + salt) wstr = pwd.encode("utf-16le")[:RAR_MAX_PASSWORD*2]
seed = bytearray(wstr + salt)
h = Rar3Sha1(rarbug=True) h = Rar3Sha1(rarbug=True)
iv = b"" iv = b""
for i in range(16): for i in range(16):
@ -3114,7 +3147,7 @@ def rar3_decompress(vers, meth, data, declen=0, flags=0, crc=0, pwd=None, salt=N
def sanitize_filename(fname, pathsep, is_win32): def sanitize_filename(fname, pathsep, is_win32):
"""Simulate unrar sanitization. """Make filename safe for write access.
""" """
if is_win32: if is_win32:
if len(fname) > 1 and fname[1] == ":": if len(fname) > 1 and fname[1] == ":":
@ -3186,12 +3219,12 @@ def parse_dos_time(stamp):
class nsdatetime(datetime): class nsdatetime(datetime):
"""Datetime that carries nanoseconds. """Datetime that carries nanoseconds.
Arithmetic not supported, will lose nanoseconds. Arithmetic operations will lose nanoseconds.
.. versionadded:: 4.0 .. versionadded:: 4.0
""" """
__slots__ = ("nanosecond",) __slots__ = ("nanosecond",)
nanosecond: int #: Number of nanoseconds, 0 <= nanosecond < 999999999 nanosecond: int #: Number of nanoseconds, 0 <= nanosecond <= 999999999
def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0, def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
microsecond=0, tzinfo=None, *, fold=0, nanosecond=0): microsecond=0, tzinfo=None, *, fold=0, nanosecond=0):
@ -3393,7 +3426,7 @@ class ToolSetup:
UNRAR_CONFIG = { UNRAR_CONFIG = {
"open_cmd": ("UNRAR_TOOL", "p", "-inul"), "open_cmd": ("UNRAR_TOOL", "p", "-inul"),
"check_cmd": ("UNRAR_TOOL", "-inul"), "check_cmd": ("UNRAR_TOOL", "-inul", "-?"),
"password": "-p", "password": "-p",
"no_password": ("-p-",), "no_password": ("-p-",),
# map return code to exception class, codes from rar.txt # map return code to exception class, codes from rar.txt