mirror of
https://github.com/saphid/frame-control.git
synced 2026-10-06 04:04:21 +02:00
Fix the follow-up review's findings
- APK reader: read members with a bounded read, since ZipFile.read inflates a member fully before trimming it to a forged declared size; the reference walk counts every entry it examines, dead ends and cycles included. - Titles: a path that exists under the root wins over stripping the archive prefix; the prefix is taken before a linked folder is staged elsewhere (another drive on Windows); the install dialog loads a fresh title list first and says so if it couldn't check. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
0530a6d045
commit
dfacf43e55
5 files changed
+85
-15
No files matched your search
+15
-6
@@ -18,6 +18,7 @@ MAX_MANIFEST = 16 * 1024**2
|
||||
MAX_ARSC = 128 * 1024**2 # real ones are a few MB; the largest apps' tens of MB
|
||||
MAX_ICON = 8 * 1024**2
|
||||
MAX_VALUES = 256 # resolved values per reference, across all its hops
|
||||
MAX_STEPS = 4096 # entries examined per reference, dead ends and cycles included
|
||||
|
||||
|
||||
class ApkError(Exception):
|
||||
@@ -135,18 +136,20 @@ class Resources:
|
||||
resid = (pid << 24) | (tid << 16) | index
|
||||
self.entries.setdefault(resid, []).append((language, density, dtype, value))
|
||||
|
||||
def values(self, resid, depth=0, seen=frozenset()):
|
||||
"""[(language, density, type, data)] with references followed, at most
|
||||
MAX_VALUES of them and never round a cycle."""
|
||||
def values(self, resid, depth=0, seen=frozenset(), steps=None):
|
||||
"""[(language, density, type, data)] with references followed: never round a
|
||||
cycle, at most MAX_VALUES results and MAX_STEPS entries examined in all."""
|
||||
steps = steps if steps is not None else [MAX_STEPS]
|
||||
out = []
|
||||
seen = seen | {resid}
|
||||
for lang, dens, dtype, value in self.entries.get(resid, []):
|
||||
if len(out) >= MAX_VALUES:
|
||||
steps[0] -= 1
|
||||
if steps[0] < 0 or len(out) >= MAX_VALUES:
|
||||
break
|
||||
if dtype == T_REF and depth < 5:
|
||||
if value not in seen:
|
||||
out += [(lang or l2, dens or d2, t2, v2)
|
||||
for l2, d2, t2, v2 in self.values(value, depth + 1, seen)]
|
||||
for l2, d2, t2, v2 in self.values(value, depth + 1, seen, steps)]
|
||||
else:
|
||||
out.append((lang, dens, dtype, value))
|
||||
return out[:MAX_VALUES]
|
||||
@@ -184,10 +187,16 @@ def _icons(attr, res):
|
||||
|
||||
|
||||
def _read(z, name, limit):
|
||||
"""A member's bytes, inflating at most limit + 1 of them whatever its header claims
|
||||
(ZipFile.read inflates everything first, then trims to the declared size)."""
|
||||
size = z.getinfo(name).file_size
|
||||
if size > limit:
|
||||
raise ApkError(f'{name} in the APK is {size / 1024**2:.0f} MB, more than a real one ({limit // 1024**2} MB)')
|
||||
return z.read(name)
|
||||
with z.open(name) as f:
|
||||
data = f.read(limit + 1)
|
||||
if len(data) > limit:
|
||||
raise ApkError(f'{name} in the APK is larger than a real one ({limit // 1024**2} MB)')
|
||||
return data
|
||||
|
||||
|
||||
def apk_info(path):
|
||||
|
||||
Reference in new issue
Block a user