#!/usr/bin/env python3
"""
Sample & analyze a single record from the deskblob entropy FIFO.

Reads binary data from the FIFO pipe, analyzes its structure & entropy,
& generates a report on what the blob might contain.
"""

import os
import sys
import struct
from collections import Counter
from pathlib import Path
import binascii

FIFO_PATH = "/tmp/deskblob-entropy-321039.fifo"

def calculate_entropy(data):
    """Calculate Shannon entropy of byte sequence."""
    if not data:
        return 0.0

    counter = Counter(data)
    length = len(data)
    entropy = 0.0

    for count in counter.values():
        probability = count / length
        entropy -= probability * (probability.bit_length() - 1)

    return entropy

def analyze_structure(data):
    """Analyze potential structure patterns in the data."""
    findings = []

    # Check for null-terminated strings
    if b'\x00' in data:
        parts = data.split(b'\x00')
        printable_parts = [p for p in parts if p and all(32 <= b < 127 for b in p)]
        if printable_parts:
            findings.append(f"Possible null-terminated strings: {len(printable_parts)}")
            for i, part in enumerate(printable_parts[:3]):
                try:
                    findings.append(f"  String {i+1}: {part.decode('ascii')}")
                except:
                    pass

    # Check for common magic numbers
    if len(data) >= 4:
        magic = data[:4]
        magic_hex = binascii.hexlify(magic).decode('ascii')
        findings.append(f"First 4 bytes (magic?): 0x{magic_hex}")

        # Common file signatures
        magic_types = {
            b'\x89PNG': 'PNG image',
            b'\xff\xd8\xff': 'JPEG image',
            b'GIF8': 'GIF image',
            b'PK\x03\x04': 'ZIP archive',
            b'\x1f\x8b\x08': 'GZIP compressed',
            b'BM': 'BMP image',
            b'%PDF': 'PDF document',
        }

        for sig, desc in magic_types.items():
            if data.startswith(sig):
                findings.append(f"DETECTED: {desc}")

    # Check for timestamp-like patterns (Unix epoch)
    if len(data) >= 8:
        try:
            ts_int32 = struct.unpack('<I', data[:4])[0]
            ts_int64 = struct.unpack('<Q', data[:8])[0]

            # Reasonable timestamp range: 2020-2030
            if 1577836800 <= ts_int32 <= 1893456000:
                import datetime
                dt = datetime.datetime.fromtimestamp(ts_int32)
                findings.append(f"Possible timestamp (32-bit LE): {dt.isoformat()}")

            if 1577836800 <= ts_int64 <= 1893456000:
                dt = datetime.datetime.fromtimestamp(ts_int64)
                findings.append(f"Possible timestamp (64-bit LE): {dt.isoformat()}")
        except:
            pass

    # Check byte distribution
    byte_counts = Counter(data)
    most_common = byte_counts.most_common(3)
    findings.append(f"Most common bytes: {[(hex(b), c) for b, c in most_common]}")

    return findings

def generate_report(data):
    """Generate comprehensive analysis report."""
    print("=" * 70)
    print("BLOB FIFO SAMPLE ANALYSIS REPORT")
    print("=" * 70)
    print()

    print(f"Source: {FIFO_PATH}")
    print(f"Sample size: {len(data)} bytes")
    print()

    # Entropy analysis
    entropy = calculate_entropy(data)
    print(f"Shannon Entropy: {entropy:.4f} bits/byte")

    if entropy > 7.5:
        print("  → HIGH entropy: likely compressed or encrypted data")
    elif entropy > 6.0:
        print("  → MEDIUM-HIGH entropy: mixed binary data")
    elif entropy > 4.0:
        print("  → MEDIUM entropy: structured binary or text")
    else:
        print("  → LOW entropy: repetitive or simple structure")
    print()

    # Printability check
    printable_count = sum(1 for b in data if 32 <= b < 127 or b in (9, 10, 13))
    printable_ratio = printable_count / len(data)

    print(f"Printable characters: {printable_ratio:.1%}")
    if printable_ratio > 0.8:
        print("  → Likely text-based format")
    elif printable_ratio > 0.4:
        print("  → Mixed text & binary")
    else:
        print("  → Primarily binary data")
    print()

    # Structure analysis
    print("STRUCTURAL ANALYSIS:")
    print("-" * 70)
    findings = analyze_structure(data)
    for finding in findings:
        print(finding)
    print()

    # Hex dump preview
    print("HEX DUMP (first 256 bytes):")
    print("-" * 70)
    preview = data[:256]
    for i in range(0, len(preview), 16):
        chunk = preview[i:i+16]
        hex_part = ' '.join(f'{b:02x}' for b in chunk)
        ascii_part = ''.join(chr(b) if 32 <= b < 127 else '.' for b in chunk)
        print(f"{i:04x}  {hex_part:<48}  {ascii_part}")
    print()

    # Speculation section
    print("HYPOTHESIS:")
    print("-" * 70)

    if "deskblob" in FIFO_PATH and "entropy" in FIFO_PATH:
        print("Based on the FIFO name 'deskblob-entropy-*':")
        print("  • Likely a desktop entropy/randomness collection daemon")
        print("  • Could be collecting environmental entropy sources:")
        print("    - Mouse movements, keyboard timings")
        print("    - System events, process states")
        print("    - Hardware noise (audio, sensors)")
        print("  • May feed into /dev/random or custom PRNG")
        print("  • FIFO suggests producer-consumer pattern")

        if entropy > 7.0:
            print()
            print("  HIGH ENTROPY CONFIRMS: This appears to be a quality")
            print("  randomness source suitable for cryptographic purposes.")

    print()
    print("=" * 70)

def main():
    """Read from FIFO & generate report."""
    if not os.path.exists(FIFO_PATH):
        print(f"ERROR: FIFO not found at {FIFO_PATH}", file=sys.stderr)
        print("Available FIFOs in /tmp:", file=sys.stderr)
        os.system("find /tmp -type p 2>/dev/null")
        return 1

    print(f"Opening FIFO: {FIFO_PATH}")
    print("Waiting for data... (this will block until writer sends data)")
    print()

    try:
        # Open FIFO in non-blocking mode to avoid hanging
        # Read a reasonable chunk (could be adjusted)
        with open(FIFO_PATH, 'rb') as fifo:
            data = fifo.read(4096)  # Read up to 4KB

            if not data:
                print("WARNING: No data received from FIFO", file=sys.stderr)
                return 1

            generate_report(data)
            return 0

    except KeyboardInterrupt:
        print("\nInterrupted by user", file=sys.stderr)
        return 130
    except Exception as e:
        print(f"ERROR: {e}", file=sys.stderr)
        import traceback
        traceback.print_exc()
        return 1

if __name__ == '__main__':
    sys.exit(main())
