#!/usr/bin/env python3
"""Supply chain malware artifact analysis agent.

Analyzes software supply chain compromise indicators including package
integrity, build pipeline artifacts, dependency confusion, and trojanized updates.
"""

import os
import sys
import json
import hashlib
import re
import subprocess
from datetime import datetime

try:
    import requests
    HAS_REQUESTS = True
except ImportError:
    HAS_REQUESTS = False


def compute_hash(filepath):
    hashes = {}
    for algo in ("md5", "sha1", "sha256"):
        h = hashlib.new(algo)
        with open(filepath, "rb") as f:
            for chunk in iter(lambda: f.read(65536), b""):
                h.update(chunk)
        hashes[algo] = h.hexdigest()
    return hashes


def check_npm_package(package_name):
    if not HAS_REQUESTS:
        return {"error": "requests not installed"}
    url = f"https://registry.npmjs.org/{package_name}"
    try:
        resp = requests.get(url, timeout=15)
        resp.raise_for_status()
        data = resp.json()
        latest = data.get("dist-tags", {}).get("latest", "")
        versions = list(data.get("versions", {}).keys())
        maintainers = data.get("maintainers", [])
        return {
            "name": package_name, "latest": latest,
            "version_count": len(versions),
            "maintainers": [m.get("name") for m in maintainers],
        }
    except requests.RequestException as e:
        return {"error": str(e)}


def check_pypi_package(package_name):
    if not HAS_REQUESTS:
        return {"error": "requests not installed"}
    url = f"https://pypi.org/pypi/{package_name}/json"
    try:
        resp = requests.get(url, timeout=15)
        resp.raise_for_status()
        data = resp.json()
        info = data.get("info", {})
        return {
            "name": info.get("name"), "version": info.get("version"),
            "author": info.get("author"),
            "release_count": len(data.get("releases", {})),
        }
    except requests.RequestException as e:
        return {"error": str(e)}


def detect_typosquat_packages(target_name):
    permutations = set()
    for i in range(len(target_name)):
        permutations.add(target_name[:i] + target_name[i+1:])
    for i in range(len(target_name) - 1):
        swapped = list(target_name)
        swapped[i], swapped[i+1] = swapped[i+1], swapped[i]
        permutations.add("".join(swapped))
    permutations.add(target_name.replace("-", "_"))
    permutations.add(target_name.replace("_", "-"))
    permutations.discard(target_name)
    return sorted(permutations)


def analyze_package_scripts(package_json_path):
    with open(package_json_path, "r") as f:
        pkg = json.load(f)
    findings = []
    scripts = pkg.get("scripts", {})
    for hook in ["preinstall", "postinstall", "preuninstall"]:
        if hook in scripts:
            cmd = scripts[hook]
            findings.append({
                "type": "install_hook", "hook": hook, "command": cmd[:200],
                "severity": "HIGH" if any(s in cmd.lower() for s in
                    ["curl", "wget", "eval", "exec", "base64"]) else "MEDIUM",
            })
    deps = {**pkg.get("dependencies", {}), **pkg.get("devDependencies", {})}
    for dep, ver in deps.items():
        if ver.startswith("http") or ver.startswith("git"):
            findings.append({
                "type": "url_dependency", "package": dep,
                "source": ver[:200], "severity": "HIGH",
            })
    return {"name": pkg.get("name"), "findings": findings}


def analyze_python_setup(setup_py_path):
    with open(setup_py_path, "r") as f:
        content = f.read()
    findings = []
    patterns = [
        (r"os\.system\(", "os.system() execution"),
        (r"subprocess\.", "subprocess execution"),
        (r"exec\(", "exec() code execution"),
        (r"eval\(", "eval() code execution"),
        (r"base64\.b64decode", "Base64 decoding"),
        (r"socket\.", "Network socket usage"),
    ]
    for pattern, description in patterns:
        if re.search(pattern, content):
            findings.append({
                "type": "suspicious_setup_code",
                "pattern": description, "severity": "HIGH",
            })
    return {"file": setup_py_path, "findings": findings}


if __name__ == "__main__":
    print("=" * 60)
    print("Supply Chain Malware Artifact Analysis Agent")
    print("Package integrity, typosquat detection, install hook analysis")
    print("=" * 60)

    target = sys.argv[1] if len(sys.argv) > 1 else None
    if not target:
        print("\n[DEMO] Usage:")
        print("  python agent.py <package.json>         # Analyze npm package")
        print("  python agent.py npm:<package_name>     # Check npm registry")
        print("  python agent.py pypi:<package_name>    # Check PyPI registry")
        sys.exit(0)

    if target.startswith("npm:"):
        pkg_name = target[4:]
        print(f"\n[*] Checking npm: {pkg_name}")
        info = check_npm_package(pkg_name)
        typos = detect_typosquat_packages(pkg_name)
        print(json.dumps(info, indent=2))
        print(f"\n  Potential typosquats: {typos[:10]}")
    elif target.startswith("pypi:"):
        pkg_name = target[5:]
        print(f"\n[*] Checking PyPI: {pkg_name}")
        info = check_pypi_package(pkg_name)
        print(json.dumps(info, indent=2))
    elif os.path.exists(target):
        basename = os.path.basename(target)
        if basename == "package.json":
            result = analyze_package_scripts(target)
        elif basename == "setup.py":
            result = analyze_python_setup(target)
        else:
            result = {"file": target, "hashes": compute_hash(target)}
        print(json.dumps(result, indent=2))
