1import tarfile
2import sys
3
4
5def process_columns(line: list[str]) -> tuple[str, list[str]]:
6 match line:
7 case [name, h_prefix, nrbytes, flags]:
8 return (h_prefix, flags.lower().split(","))
9 case other:
10 raise Exception("Unsupported hashes.conf line format", other)
11
12
13def find_tar_file(tar: tarfile.TarFile, requested_name: str):
14 """Attempts to find a single file with given name in tarball."""
15 all_names = tar.getnames()
16
17 if requested_name in all_names:
18 return requested_name
19
20 requested_suffix = f"/{requested_name}"
21 candidate_names = [name for name in all_names if name.endswith(requested_suffix)]
22 match candidate_names:
23 case [real_name]:
24 return real_name
25 case other:
26 raise KeyError(
27 f"Could not locate a single {requested_name} in the contents of the tarball."
28 )
29
30
31hashes_path = "lib/hashes.conf"
32
33
34def main() -> None:
35 match sys.argv:
36 case [_name, src, enable_hashes, "--", *enabled_crypt_scheme_ids]:
37 pass
38 case other:
39 raise Exception(
40 "Incorrect number of arguments. Usage: check_passthru_matches.py <src> <enable_hashes> -- <enabled_crypt_scheme_ids...>"
41 )
42
43 with tarfile.open(src, "r") as tar:
44 real_hashes_path = find_tar_file(tar, hashes_path)
45 config = tar.extractfile(real_hashes_path).read().decode("utf-8")
46
47 formats = [
48 process_columns(columns)
49 for line in config.splitlines()
50 if not line.startswith("#") and len(columns := line.split()) > 0
51 ]
52 expected_supported_formats = set(
53 prefix
54 for (prefix, flags) in formats
55 if enable_hashes in flags or enable_hashes == "all"
56 )
57 passthru_supported_schemes = set(
58 f"${scheme}$" for scheme in enabled_crypt_scheme_ids
59 )
60
61 assert (
62 len(expected_supported_formats - passthru_supported_schemes) == 0
63 ), f"libxcrypt package enables the following crypt schemes that are not listed in passthru.enabledCryptSchemeIds: {expected_supported_formats - passthru_supported_schemes}"
64 assert (
65 len(passthru_supported_schemes - expected_supported_formats) == 0
66 ), f"libxcrypt package lists the following crypt schemes in passthru.enabledCryptSchemeIds that are not supported: {passthru_supported_schemes - expected_supported_formats}"
67
68
69if __name__ == "__main__":
70 main()