proofmode 0.9.0

Capture, share, and preserve verifiable photos and videos
Documentation
#[cfg(feature = "sequoia-openpgp")]
use crate::crypto::pgp::PgpUtils;
use crate::generate::core::PlatformCallbacks;
use crate::generate_error::Result;
use crate::generate_types::*;
use std::fs;
use std::path::PathBuf;

pub struct NativeCallbacks {
    storage_path: PathBuf,
    #[cfg(feature = "sequoia-openpgp")]
    pgp_utils: Option<PgpUtils>,
    #[cfg(feature = "sequoia-openpgp")]
    pgp_passphrase: String,
}

impl NativeCallbacks {
    pub fn new(storage_path: PathBuf) -> Self {
        Self {
            storage_path,
            #[cfg(feature = "sequoia-openpgp")]
            pgp_utils: None,
            #[cfg(feature = "sequoia-openpgp")]
            pgp_passphrase: String::new(),
        }
    }

    #[cfg(feature = "sequoia-openpgp")]
    pub fn initialize_pgp(&mut self, email: &str, passphrase: &str) -> Result<()> {
        let mut pgp = PgpUtils::new();
        pgp.generate_keys(email, passphrase)?;
        self.pgp_passphrase = passphrase.to_string();
        self.pgp_utils = Some(pgp);
        Ok(())
    }

    fn get_hash_dir(&self, hash: &str) -> PathBuf {
        self.storage_path.join("proofmode").join(hash)
    }

    fn get_file_path(&self, hash: &str, filename: &str) -> PathBuf {
        self.get_hash_dir(hash).join(filename)
    }
}

impl PlatformCallbacks for NativeCallbacks {
    fn get_device_info(&self) -> Option<DeviceData> {
        Some(DeviceData {
            manufacturer: "Unknown".to_string(),
            model: std::env::consts::OS.to_string(),
            os_version: std::env::consts::ARCH.to_string(),
            device_id: None,
        })
    }

    fn get_location_info(&self) -> Option<LocationData> {
        None
    }

    fn get_network_info(&self) -> Option<NetworkData> {
        None
    }

    fn save_data(&self, hash: &str, filename: &str, data: &[u8]) -> Result<()> {
        let file_path = self.get_file_path(hash, filename);
        if let Some(parent) = file_path.parent() {
            fs::create_dir_all(parent)?;
        }
        fs::write(&file_path, data)?;
        Ok(())
    }

    fn save_text(&self, hash: &str, filename: &str, text: &str) -> Result<()> {
        self.save_data(hash, filename, text.as_bytes())
    }

    fn sign_data(&self, data: &[u8]) -> Result<Option<Vec<u8>>> {
        #[cfg(feature = "sequoia-openpgp")]
        {
            if let Some(ref pgp) = self.pgp_utils {
                match pgp.sign_data(data, &self.pgp_passphrase) {
                    Ok(signature) => Ok(Some(signature)),
                    Err(_) => Ok(None),
                }
            } else {
                Ok(None)
            }
        }

        #[cfg(not(feature = "sequoia-openpgp"))]
        {
            let _ = data;
            Ok(None)
        }
    }

    fn notarize_hash(&self, _hash: &str) -> Result<Option<NotarizationData>> {
        Ok(None)
    }

    fn report_progress(&self, message: &str) {
        eprintln!("{}", message);
    }
}

fn metadata_to_map(metadata: Option<Metadata>) -> std::collections::HashMap<String, String> {
    metadata
        .map(|m| {
            let mut map = std::collections::HashMap::new();
            if let Some(desc) = m.description {
                map.insert("description".to_string(), desc);
            }
            if let Some(loc) = m.location {
                map.insert("location".to_string(), loc);
            }
            if let Some(event) = m.event_type {
                map.insert("event_type".to_string(), event);
            }
            if let Some(tags) = m.tags {
                map.insert("tags".to_string(), tags);
            }
            map
        })
        .unwrap_or_default()
}

pub fn generate_proof_from_file_sync(
    file_path: &std::path::Path,
    storage_path: &std::path::Path,
    _email: &str,
    _passphrase: &str,
    metadata: Option<Metadata>,
) -> Result<String> {
    #[allow(unused_mut)]
    let mut callbacks = NativeCallbacks::new(storage_path.to_path_buf());

    #[cfg(feature = "sequoia-openpgp")]
    callbacks.initialize_pgp(_email, _passphrase)?;

    let config = ProofModeConfig {
        auto_notarize: false,
        track_location: false,
        track_device_id: true,
        track_network: false,
        add_credentials: true,
        embed_c2pa: true,
    };

    let generator = crate::generate::core::ProofGenerator::new(config);
    let media_data = std::fs::read(file_path)?;
    let metadata_map = metadata_to_map(metadata);

    generator.generate_proof(&media_data, metadata_map, &callbacks)
}

pub fn generate_proof_from_data_sync(
    media_data: &[u8],
    storage_path: &std::path::Path,
    _email: &str,
    _passphrase: &str,
    metadata: Option<Metadata>,
) -> Result<String> {
    #[allow(unused_mut)]
    let mut callbacks = NativeCallbacks::new(storage_path.to_path_buf());

    #[cfg(feature = "sequoia-openpgp")]
    callbacks.initialize_pgp(_email, _passphrase)?;

    let config = ProofModeConfig {
        auto_notarize: false,
        track_location: false,
        track_device_id: true,
        track_network: false,
        add_credentials: true,
        embed_c2pa: true,
    };

    let generator = crate::generate::core::ProofGenerator::new(config);
    let metadata_map = metadata_to_map(metadata);

    generator.generate_proof(media_data, metadata_map, &callbacks)
}