#!/usr/bin/env python3
"""Agent for analyzing USB device connection history from Windows registry hives."""

import os
import json
import argparse
import csv

from regipy.registry import RegistryHive


def parse_usbstor(system_hive_path):
    """Parse USBSTOR registry key to enumerate USB storage devices."""
    reg = RegistryHive(system_hive_path)
    select_key = reg.get_key("Select")
    current = select_key.get_value("Current")
    controlset = f"ControlSet{current:03d}"
    usbstor_path = f"{controlset}\\Enum\\USBSTOR"
    devices = []
    try:
        usbstor_key = reg.get_key(usbstor_path)
    except Exception:
        return devices
    for device_class in usbstor_key.iter_subkeys():
        parts = device_class.name.split("&")
        vendor = parts[1].replace("Ven_", "") if len(parts) > 1 else "Unknown"
        product = parts[2].replace("Prod_", "") if len(parts) > 2 else "Unknown"
        revision = parts[3].replace("Rev_", "") if len(parts) > 3 else "Unknown"
        for instance in device_class.iter_subkeys():
            serial = instance.name
            device_info = {
                "vendor": vendor,
                "product": product,
                "revision": revision,
                "serial": serial,
                "last_connected": str(instance.header.last_modified),
            }
            for val in instance.iter_values():
                if val.name == "FriendlyName":
                    device_info["friendly_name"] = val.value
            devices.append(device_info)
    return devices


def parse_mounted_devices(system_hive_path):
    """Parse MountedDevices to map drive letters to USB devices."""
    reg = RegistryHive(system_hive_path)
    mounted_key = reg.get_key("MountedDevices")
    mappings = []
    for val in mounted_key.iter_values():
        if val.name.startswith("\\DosDevices\\"):
            drive_letter = val.name.replace("\\DosDevices\\", "")
            data = val.value
            if isinstance(data, bytes) and len(data) > 24:
                try:
                    device_path = data.decode("utf-16-le").strip("\x00")
                    if "USBSTOR" in device_path or "USB#" in device_path:
                        mappings.append({
                            "drive_letter": drive_letter,
                            "device_path": device_path,
                        })
                except (UnicodeDecodeError, ValueError):
                    pass
    return mappings


def parse_mountpoints2(ntuser_path):
    """Parse MountPoints2 from NTUSER.DAT to find user-accessed volumes."""
    reg = RegistryHive(ntuser_path)
    mp2_path = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MountPoints2"
    mount_points = []
    try:
        mp2_key = reg.get_key(mp2_path)
    except Exception:
        return mount_points
    for subkey in mp2_key.iter_subkeys():
        if "{" in subkey.name:
            mount_points.append({
                "volume_guid": subkey.name,
                "last_accessed": str(subkey.header.last_modified),
            })
    return mount_points


def parse_setupapi_log(log_path):
    """Parse setupapi.dev.log for USB first-install timestamps."""
    import re
    installs = []
    with open(log_path, "r", errors="ignore") as f:
        content = f.read()
    pattern = r">>>\s+\[Device Install.*?\n.*?Section start (\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}).*?\n(.*?)<<<"
    for match in re.finditer(pattern, content, re.DOTALL):
        timestamp, section = match.group(1), match.group(2)
        dev_match = re.search(r"(USBSTOR\\[^\s]+|USB\\VID_\w+&PID_\w+[^\s]*)", section)
        if dev_match:
            installs.append({
                "first_install": timestamp,
                "device_id": dev_match.group(1),
            })
    return installs


def build_timeline(devices, mappings, mount_points):
    """Build a unified USB activity timeline."""
    timeline = []
    for dev in devices:
        timeline.append({
            "timestamp": dev["last_connected"],
            "source": "USBSTOR",
            "device": f"{dev['vendor']} {dev['product']}",
            "serial": dev["serial"],
            "event": "Last Connected",
            "detail": dev.get("friendly_name", ""),
        })
    for mp in mount_points:
        timeline.append({
            "timestamp": mp["last_accessed"],
            "source": "MountPoints2",
            "device": mp["volume_guid"],
            "serial": "",
            "event": "Volume Accessed",
            "detail": "",
        })
    timeline.sort(key=lambda x: x["timestamp"])
    return timeline


def export_timeline_csv(timeline, output_path):
    """Export timeline to CSV."""
    if not timeline:
        return
    with open(output_path, "w", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=timeline[0].keys())
        writer.writeheader()
        writer.writerows(timeline)


def main():
    parser = argparse.ArgumentParser(description="USB Device Connection History Agent")
    parser.add_argument("--system-hive", required=True, help="Path to SYSTEM registry hive")
    parser.add_argument("--ntuser", help="Path to NTUSER.DAT hive")
    parser.add_argument("--setupapi-log", help="Path to setupapi.dev.log")
    parser.add_argument("--output-dir", default="./usb_analysis")
    parser.add_argument("--case-id", default="CASE-001")
    args = parser.parse_args()

    os.makedirs(args.output_dir, exist_ok=True)

    devices = parse_usbstor(args.system_hive)
    print(f"[+] USBSTOR devices: {len(devices)}")
    for d in devices:
        print(f"    {d['vendor']} {d['product']} | Serial: {d['serial']}")

    mappings = parse_mounted_devices(args.system_hive)
    print(f"[+] USB drive mappings: {len(mappings)}")

    mount_points = []
    if args.ntuser:
        mount_points = parse_mountpoints2(args.ntuser)
        print(f"[+] MountPoints2 entries: {len(mount_points)}")

    if args.setupapi_log:
        installs = parse_setupapi_log(args.setupapi_log)
        print(f"[+] SetupAPI installations: {len(installs)}")

    timeline = build_timeline(devices, mappings, mount_points)
    csv_path = os.path.join(args.output_dir, "usb_timeline.csv")
    export_timeline_csv(timeline, csv_path)
    print(f"[+] Timeline exported to {csv_path} ({len(timeline)} events)")

    report = {
        "case_id": args.case_id,
        "total_devices": len(devices),
        "devices": devices,
        "drive_mappings": mappings,
        "timeline_events": len(timeline),
    }
    print(json.dumps(report, indent=2, default=str))


if __name__ == "__main__":
    main()
