mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-17 00:43:29 -05:00
fix: compare md5 one way in verify and packs
This commit is contained in:
1 parent
20638fde93
commit
cd4a9143f7
3 files changed
+45
-22
No files matched your search
+15
-3
@@ -8,6 +8,7 @@ truth data for reporting.
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import zipfile
|
||||
from collections.abc import Mapping
|
||||
|
||||
from common import (
|
||||
@@ -17,7 +18,7 @@ from common import (
|
||||
sanitize_pack_path,
|
||||
size_fits,
|
||||
)
|
||||
from hashing import parse_md5_list
|
||||
from hashing import md5_composite, parse_md5_list
|
||||
from nativemode import digest_algorithm, hash_mismatch_excludes_file
|
||||
from ziptools import check_inside_zip
|
||||
|
||||
@@ -663,7 +664,8 @@ def frontend_digest_matches(file_entry: dict, local_path: str, algorithm: str) -
|
||||
resolve_local_file calls a file `hash_mismatch` when any declared hash
|
||||
disagrees, but a frontend compares one digest. RomM's list carries md5,
|
||||
sha1 and crc32: a mistyped crc32 next to the right md5 must not withhold
|
||||
a file RomM accepts. Same comparison as verify_entry_md5/_sha1.
|
||||
a file RomM accepts. verify_entry_md5 reads it too: Batocera compares a
|
||||
truncated md5 by prefix and Recalbox hashes a ZIP by its members.
|
||||
"""
|
||||
if algorithm == "md5":
|
||||
declared = parse_md5_list(file_entry.get("md5"))
|
||||
@@ -673,7 +675,17 @@ def frontend_digest_matches(file_entry: dict, local_path: str, algorithm: str) -
|
||||
declared = [str(v).strip().lower() for v in values if v]
|
||||
if not declared or not local_path:
|
||||
return False
|
||||
return compute_hashes(local_path)[algorithm].lower() in declared
|
||||
actual = compute_hashes(local_path)[algorithm].lower()
|
||||
if algorithm != "md5":
|
||||
return actual in declared
|
||||
if any(actual == d or (len(d) < 32 and actual.startswith(d)) for d in declared):
|
||||
return True
|
||||
if ".zip" not in os.path.basename(local_path):
|
||||
return False
|
||||
try:
|
||||
return md5_composite(local_path).lower() in declared
|
||||
except (zipfile.BadZipFile, OSError):
|
||||
return False
|
||||
|
||||
|
||||
def inner_rom_check(file_entry: dict, local_path: str) -> str:
|
||||
|
||||
+4
-19
@@ -28,7 +28,6 @@ import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import zipfile
|
||||
from collections.abc import Mapping
|
||||
|
||||
import slots
|
||||
@@ -47,7 +46,6 @@ from common import (
|
||||
check_inside_zip,
|
||||
compute_hashes,
|
||||
expand_directory_entries,
|
||||
name_match_size_ok,
|
||||
platform_declarations,
|
||||
filter_systems_by_target,
|
||||
group_identical_platforms,
|
||||
@@ -56,7 +54,6 @@ from common import (
|
||||
load_data_dir_registry,
|
||||
load_emulator_profiles,
|
||||
load_platform_config,
|
||||
md5_composite,
|
||||
md5sum,
|
||||
require_yaml,
|
||||
resolve_local_file,
|
||||
@@ -76,6 +73,7 @@ from nativemode import (
|
||||
)
|
||||
from validation import (
|
||||
declaration_settles,
|
||||
frontend_digest_matches,
|
||||
existence_discrepancy,
|
||||
destination_owners,
|
||||
validated_choice,
|
||||
@@ -235,23 +233,10 @@ def verify_entry_md5(
|
||||
if resolve_status == "md5_exact":
|
||||
return {**base, "status": Status.OK, "path": local_path}
|
||||
|
||||
# The builder's comparison, so the two count the same files as held.
|
||||
if frontend_digest_matches(file_entry, local_path, "md5"):
|
||||
return {**base, "status": Status.OK, "path": local_path}
|
||||
actual_md5 = md5sum(local_path)
|
||||
actual_lower = actual_md5.lower()
|
||||
for expected in md5_list:
|
||||
if actual_lower == expected.lower():
|
||||
return {**base, "status": Status.OK, "path": local_path}
|
||||
if len(expected) < 32 and actual_lower.startswith(expected.lower()):
|
||||
return {**base, "status": Status.OK, "path": local_path}
|
||||
|
||||
if ".zip" in os.path.basename(local_path):
|
||||
try:
|
||||
composite = md5_composite(local_path)
|
||||
for expected in md5_list:
|
||||
if composite.lower() == expected.lower():
|
||||
return {**base, "status": Status.OK, "path": local_path}
|
||||
except (zipfile.BadZipFile, OSError):
|
||||
pass
|
||||
|
||||
return {
|
||||
**base,
|
||||
"status": Status.UNTESTED,
|
||||
|
||||
@@ -758,6 +758,32 @@ class OneBaselineVerdict(unittest.TestCase):
|
||||
_intentional_hash_exclusion([entry], db, verification_mode="existence")
|
||||
)
|
||||
|
||||
def test_the_builder_accepts_what_verify_accepts(self):
|
||||
"""verify took a 29-character md5 by prefix and a ZIP by its
|
||||
composite; the builder compared exact md5s and refused both when
|
||||
another declared hash disagreed."""
|
||||
import hashlib
|
||||
|
||||
from scripts.common import md5_composite
|
||||
from scripts.validation import baseline_verdict
|
||||
|
||||
with tempfile.TemporaryDirectory(dir=TMP_ROOT) as directory:
|
||||
loose = Path(directory) / "abc.bin"
|
||||
loose.write_bytes(b"abc")
|
||||
truncated = {"name": "abc.bin", "md5": hashlib.md5(b"abc").hexdigest()[:29],
|
||||
"crc32": "deadbeef"}
|
||||
self.assertEqual(
|
||||
baseline_verdict(truncated, str(loose), "hash_mismatch", "md5"),
|
||||
("frontend_digest_exact", None),
|
||||
)
|
||||
archive = self._archive(Path(directory), "rom.bin")
|
||||
composite = {"name": "dragon32.zip", "md5": md5_composite(archive),
|
||||
"crc32": "deadbeef"}
|
||||
self.assertEqual(
|
||||
baseline_verdict(composite, archive, "hash_mismatch", "md5"),
|
||||
("frontend_digest_exact", None),
|
||||
)
|
||||
|
||||
def test_a_release_asset_keeps_its_answer(self):
|
||||
from scripts.slots import apply_override
|
||||
|
||||
|
||||
Reference in new issue
Block a user