mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-23 12:19:13 -05:00
fix: verify each 3DS file once per content
check_crypto_validation keeps its answer keyed by the file and keys file as compute_hashes keys them (path, inode, size, mtime, ctime). verify --all ran the verifiers 35 times for 5 files (0.88 s), now 5 times (0.13 s). verify --all --json output is byte-identical.
This commit is contained in:
1 parent
11c836cdee
commit
d904116a79
2 files changed
+65
-3
No files matched your search
@@ -490,6 +490,23 @@ _CRYPTO_VERIFIERS: dict[str, Callable] = {
|
||||
}
|
||||
|
||||
|
||||
def _stat_key(path: str | Path) -> tuple | None:
|
||||
"""(path, inode, size, mtime_ns, ctime_ns): the file as compute_hashes
|
||||
keys it, None when it cannot be read."""
|
||||
try:
|
||||
stat = Path(path).stat()
|
||||
except OSError:
|
||||
return None
|
||||
return (str(Path(path).resolve()), stat.st_ino, stat.st_size,
|
||||
stat.st_mtime_ns, stat.st_ctime_ns)
|
||||
|
||||
|
||||
# (verifier, file key, keys file key) -> reason or None. verify --all ran the
|
||||
# curve and RSA checks of the same five files once per platform, 35 runs for
|
||||
# 5 answers: the answer depends on the file's bytes and the keys file alone.
|
||||
_crypto_cache: dict[tuple, str | None] = {}
|
||||
|
||||
|
||||
def check_crypto_validation(
|
||||
local_path: str,
|
||||
filename: str,
|
||||
@@ -508,8 +525,13 @@ def check_crypto_validation(
|
||||
if not keys_file:
|
||||
return "crypto check skipped: no keys file found"
|
||||
|
||||
file_key, keys_key = _stat_key(local_path), _stat_key(keys_file)
|
||||
key = (filename, file_key, keys_key) if file_key and keys_key else None
|
||||
if key in _crypto_cache:
|
||||
return _crypto_cache[key]
|
||||
keys = parse_keys_file(keys_file)
|
||||
valid, reason = verifier(local_path, keys)
|
||||
if valid:
|
||||
return None
|
||||
return reason
|
||||
result = None if valid else reason
|
||||
if key is not None:
|
||||
_crypto_cache[key] = result
|
||||
return result
|
||||
@@ -19,6 +19,7 @@ import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
import unittest.mock
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
@@ -329,5 +330,44 @@ class KeysFile(unittest.TestCase):
|
||||
self.assertIsNone(crypto_verify.find_keys_file(self.tmp))
|
||||
|
||||
|
||||
class OneFileIsVerifiedOncePerContent(unittest.TestCase):
|
||||
"""verify --all ran the 3DS checks of the same five files once per
|
||||
platform: 35 runs of pure-Python curve and RSA work for 5 answers."""
|
||||
|
||||
def setUp(self):
|
||||
self._tmp = tempfile.TemporaryDirectory()
|
||||
self.bios = Path(self._tmp.name)
|
||||
target = self.bios / "Nintendo" / "3DS"
|
||||
target.mkdir(parents=True)
|
||||
(target / "aes_keys.txt").write_text(":AES\n")
|
||||
self.file = target / "otp.bin"
|
||||
self.file.write_bytes(b"\x00" * 0x100)
|
||||
self.calls: list[bytes] = []
|
||||
|
||||
def verifier(path, keys):
|
||||
data = Path(path).read_bytes()
|
||||
self.calls.append(data)
|
||||
return data[0] == 1, "first byte is not 1"
|
||||
|
||||
patcher = unittest.mock.patch.dict(crypto_verify._CRYPTO_VERIFIERS, {"otp.bin": verifier})
|
||||
patcher.start()
|
||||
self.addCleanup(patcher.stop)
|
||||
self.addCleanup(crypto_verify._crypto_cache.clear)
|
||||
self.addCleanup(self._tmp.cleanup)
|
||||
|
||||
def check(self) -> str | None:
|
||||
return crypto_verify.check_crypto_validation(str(self.file), "otp.bin", str(self.bios))
|
||||
|
||||
def test_the_same_file_is_verified_once(self):
|
||||
self.assertEqual([self.check() for _ in range(7)], ["first byte is not 1"] * 7)
|
||||
self.assertEqual(len(self.calls), 1)
|
||||
|
||||
def test_a_rewritten_file_is_verified_again(self):
|
||||
self.assertEqual(self.check(), "first byte is not 1")
|
||||
self.file.write_bytes(b"\x01" + b"\x00" * 0x1FF)
|
||||
self.assertIsNone(self.check())
|
||||
self.assertEqual(len(self.calls), 2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user