proofmode 0.9.0

Capture, share, and preserve verifiable photos and videos
Documentation
#!/usr/bin/env python3
"""
ProofMode Docker Integration Example for Python

This script demonstrates how to integrate ProofMode Docker container
into a Python application for generating and verifying media proofs.
"""

import subprocess
import json
import os
import sys
from pathlib import Path
from typing import Dict, Optional, List
import logging

# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

class ProofModeDocker:
    """Wrapper class for ProofMode Docker operations"""
    
    def __init__(self, docker_image: str = "registry.gitlab.com/guardianproject/proofmode/proofmode-rust:latest"):
        self.docker_image = docker_image
        self.check_docker()
    
    def check_docker(self):
        """Check if Docker is available"""
        try:
            subprocess.run(["docker", "--version"], check=True, capture_output=True)
        except (subprocess.CalledProcessError, FileNotFoundError):
            raise RuntimeError("Docker is not installed or not accessible")
    
    def generate_proof(self, input_file: Path, output_dir: Path, 
                      config_file: Optional[Path] = None) -> Dict:
        """
        Generate a proof for a media file
        
        Args:
            input_file: Path to the media file
            output_dir: Directory to save proof files
            config_file: Optional custom configuration file
            
        Returns:
            Dictionary containing proof information
        """
        if not input_file.exists():
            raise FileNotFoundError(f"Input file not found: {input_file}")
        
        output_dir.mkdir(parents=True, exist_ok=True)
        
        # Build Docker command
        cmd = [
            "docker", "run", "--rm",
            "-v", f"{input_file.parent.absolute()}:/input:ro",
            "-v", f"{output_dir.absolute()}:/output"
        ]
        
        if config_file and config_file.exists():
            cmd.extend(["-v", f"{config_file.absolute()}:/config.toml:ro"])
        
        cmd.extend([
            self.docker_image,
            "generate", f"/input/{input_file.name}", "--output", "/output"
        ])
        
        if config_file:
            cmd.extend(["--config", "/config.toml"])
        
        logger.info(f"Generating proof for {input_file.name}")
        
        # Run the command
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        if result.returncode != 0:
            raise RuntimeError(f"Failed to generate proof: {result.stderr}")
        
        # Find the generated proof file
        proof_files = list(output_dir.glob("*.proof.json"))
        if not proof_files:
            raise RuntimeError("No proof file generated")
        
        # Read and return the proof data
        with open(proof_files[0], 'r') as f:
            proof_data = json.load(f)
        
        logger.info(f"Proof generated successfully: {proof_files[0].name}")
        return proof_data
    
    def verify_proof(self, proof_file: Path, media_file: Optional[Path] = None) -> bool:
        """
        Verify a proof file
        
        Args:
            proof_file: Path to the proof JSON file
            media_file: Optional path to the original media file
            
        Returns:
            True if verification passed
        """
        if not proof_file.exists():
            raise FileNotFoundError(f"Proof file not found: {proof_file}")
        
        # Build Docker command
        cmd = [
            "docker", "run", "--rm",
            "-v", f"{proof_file.parent.absolute()}:/proofs:ro"
        ]
        
        if media_file and media_file.exists():
            cmd.extend(["-v", f"{media_file.parent.absolute()}:/media:ro"])
        
        cmd.extend([
            self.docker_image,
            "check", f"/proofs/{proof_file.name}"
        ])
        
        logger.info(f"Verifying proof: {proof_file.name}")
        
        # Run the command
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        if result.returncode == 0:
            logger.info("Proof verification passed")
            return True
        else:
            logger.error(f"Proof verification failed: {result.stderr}")
            return False
    
    def batch_generate(self, input_dir: Path, output_dir: Path, 
                      pattern: str = "*.jpg") -> List[Dict]:
        """
        Generate proofs for multiple files
        
        Args:
            input_dir: Directory containing media files
            output_dir: Directory to save proof files
            pattern: File pattern to match (default: *.jpg)
            
        Returns:
            List of proof data dictionaries
        """
        media_files = list(input_dir.glob(pattern))
        if not media_files:
            logger.warning(f"No files matching pattern '{pattern}' found in {input_dir}")
            return []
        
        logger.info(f"Processing {len(media_files)} files")
        
        proofs = []
        for media_file in media_files:
            try:
                proof = self.generate_proof(media_file, output_dir)
                proofs.append(proof)
            except Exception as e:
                logger.error(f"Failed to process {media_file.name}: {e}")
        
        return proofs


def main():
    """Example usage of ProofModeDocker"""
    
    # Initialize ProofMode Docker wrapper
    proofmode = ProofModeDocker()
    
    # Example 1: Generate a single proof
    print("\n=== Example 1: Generate Single Proof ===")
    
    # Create test directories
    script_dir = Path(__file__).parent
    input_dir = script_dir / "input"
    output_dir = script_dir / "output"
    
    input_dir.mkdir(exist_ok=True)
    output_dir.mkdir(exist_ok=True)
    
    # Create a test image if it doesn't exist
    test_image = input_dir / "test.jpg"
    if not test_image.exists():
        # Create a minimal JPEG
        import base64
        jpeg_data = base64.b64decode(
            "/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB"
            "AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEB"
            "AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARCAABAAED"
            "AREAAHEBAAIRAGMBRAA/8QAFQABAQAAAAAAAAAAAAAAAAAAAAX/xAAUEAEAAAAAAAAAAAAAAAAAAAAA"
            "/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAX/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEA"
            "APQATJAA4KAA/9k="
        )
        test_image.write_bytes(jpeg_data)
        print(f"Created test image: {test_image}")
    
    try:
        proof = proofmode.generate_proof(test_image, output_dir)
        print(f"Generated proof with hash: {proof['file_hash_sha256']}")
    except Exception as e:
        print(f"Error: {e}")
        return 1
    
    # Example 2: Verify the proof
    print("\n=== Example 2: Verify Proof ===")
    
    proof_file = output_dir / f"{proof['file_hash_sha256']}.proof.json"
    if proof_file.exists():
        if proofmode.verify_proof(proof_file, test_image):
            print("Proof verification passed!")
        else:
            print("Proof verification failed!")
    
    # Example 3: Batch processing
    print("\n=== Example 3: Batch Processing ===")
    
    # Create more test images
    for i in range(1, 4):
        test_file = input_dir / f"test_{i}.jpg"
        if not test_file.exists():
            test_file.write_bytes(test_image.read_bytes())
    
    proofs = proofmode.batch_generate(input_dir, output_dir)
    print(f"Generated {len(proofs)} proofs")
    
    # Example 4: Generate with custom parameters
    print("\n=== Example 4: Custom Parameters ===")
    
    # ProofMode CLI accepts email and passphrase parameters
    cmd = [
        "docker", "run", "--rm",
        "-v", f"{input_dir.absolute()}:/input:ro",
        "-v", f"{output_dir.absolute()}:/output",
        proofmode.docker_image,
        "generate", "/input/test.jpg", "--output", "/output",
        "--email", "test@example.com",
        "--passphrase", "secure-passphrase"
    ]
    
    try:
        result = subprocess.run(cmd, capture_output=True, text=True)
        if result.returncode == 0:
            print("Generated proof with custom parameters")
        else:
            print(f"Error: {result.stderr}")
    except Exception as e:
        print(f"Error: {e}")
    
    print("\n=== All examples completed ===")
    return 0


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