proofmode 0.9.0

Capture, share, and preserve verifiable photos and videos
Documentation
#[cfg(feature = "polars")]
mod analytics;
#[allow(clippy::module_inception)]
mod check;
mod consistency;
pub mod discrepancy;
mod error;
mod integrity;
mod preprocess;
mod synchrony;
mod translate;
pub mod utils;

use crate::check::check::check_common;
pub use crate::check::check::ProofCheck;
#[cfg(not(feature = "wasm"))]
use crate::check::error::ProofModeError;
#[cfg(feature = "wasm")]
use crate::check::utils::translate_from_js_files;
#[cfg(not(feature = "wasm"))]
use crate::check::utils::ReporterCallback;
use crate::check::utils::{fetch_url, ProgressReporter};
#[cfg(feature = "wasm")]
use js_sys::Function;
#[cfg(feature = "wasm")]
use serde::Serialize;
#[cfg(feature = "wasm")]
use serde_wasm_bindgen::Serializer;
#[cfg(not(feature = "wasm"))]
use std::fs::File;
#[cfg(not(feature = "wasm"))]
use std::io::Cursor;
#[cfg(not(feature = "wasm"))]
use std::io::Read;
#[cfg(feature = "wasm")]
use wasm_bindgen::prelude::*;
#[cfg(feature = "wasm")]
use wasm_bindgen::JsValue;

#[cfg(feature = "wasm")]
#[wasm_bindgen(js_name = "checkFiles")]
pub async fn check_files(files: JsValue, send_message: &Function) -> Result<JsValue, JsValue> {
    let web_files = translate_from_js_files(files);
    let progress = ProgressReporter::new(send_message.clone());
    let proof_check = check_common(web_files, &progress);
    let serializer = Serializer::new()
        .serialize_maps_as_objects(true)
        .serialize_bytes_as_arrays(false);

    match proof_check.serialize(&serializer) {
        Ok(json) => Ok(json),
        Err(e) => Err(JsValue::from_str(&format!(
            "Failed to serialize proof check: {}",
            e
        ))),
    }
}

#[cfg(not(feature = "wasm"))]
pub fn check_files(
    files: &[String],
    send_message: ReporterCallback,
) -> Result<ProofCheck, ProofModeError> {
    let input_files = files
        .iter()
        .map(|path| match File::open(path) {
            Ok(mut file) => {
                let mut contents = Vec::new();
                match file.read_to_end(&mut contents) {
                    Ok(_) => {
                        let cursor = Cursor::new(contents);
                        preprocess::LocalFile {
                            name: path.clone(),
                            error: None,
                            data: cursor,
                        }
                    }
                    Err(e) => preprocess::LocalFile {
                        name: path.clone(),
                        error: Some(format!("Could not read file: {}", e)),
                        data: Cursor::new(Vec::new()),
                    },
                }
            }
            Err(e) => preprocess::LocalFile {
                name: path.clone(),
                error: Some(format!("Could not open file: {}", e)),
                data: Cursor::new(Vec::new()),
            },
        })
        .collect();

    let progress = ProgressReporter::new(send_message);
    let proof_check = check_common(input_files, &progress);

    Ok(proof_check)
}

#[cfg(feature = "wasm")]
#[wasm_bindgen(js_name = "checkURLs")]
pub async fn check_urls(urls: JsValue, send_message: &Function) -> Result<JsValue, JsValue> {
    let urls_array: js_sys::Array = urls.into();
    let mut fetch_files = Vec::new();

    for i in 0..urls_array.length() {
        match urls_array.get(i).as_string() {
            Some(url) => match fetch_url(&url).await {
                Ok(res) => fetch_files.push(res),
                Err(e) => {
                    let error_msg = format!("Failed to fetch URL {}: {:?}", url, e);
                    return Err(JsValue::from_str(&error_msg));
                }
            },
            None => {
                return Err(JsValue::from_str("Invalid URL in array"));
            }
        }
    }

    let progress = ProgressReporter::new(send_message.clone());
    let proof_check = check_common(fetch_files, &progress);
    let serializer = Serializer::new()
        .serialize_maps_as_objects(true)
        .serialize_bytes_as_arrays(false);

    match proof_check.serialize(&serializer) {
        Ok(json) => Ok(json),
        Err(e) => Err(JsValue::from_str(&format!(
            "Failed to serialize proof check: {}",
            e
        ))),
    }
}

#[cfg(not(feature = "wasm"))]
pub fn check_urls(
    urls: &[String],
    send_message: ReporterCallback,
) -> Result<ProofCheck, ProofModeError> {
    let mut fetch_files = Vec::new();

    for i in 0..urls.len() {
        let url = urls.get(i).ok_or_else(|| ProofModeError::Failure {
            message: "Invalid URL index".to_string(),
        })?;
        let res = fetch_url(url)?;
        fetch_files.push(res);
    }

    let progress = ProgressReporter::new(send_message);
    let proof_check = check_common(fetch_files, &progress);

    Ok(proof_check)
}

#[cfg(feature = "wasm")]
#[wasm_bindgen(js_name = "checkCIDs")]
pub async fn check_cids(cids: JsValue, send_message: &Function) -> Result<JsValue, JsValue> {
    let cids_array: js_sys::Array = cids.into();
    let urls_array = js_sys::Array::new();
    for i in 0..cids_array.length() {
        match cids_array.get(i).as_string() {
            Some(cid) => {
                let url = format!("https://cloudflare-ipfs.com/ipfs/{}", cid);
                urls_array.push(&JsValue::from_str(url.as_str()));
            }
            None => {
                return Err(JsValue::from_str("Invalid CID in array"));
            }
        }
    }
    check_urls(urls_array.into(), send_message).await
}

#[cfg(not(feature = "wasm"))]
pub fn check_cids(
    cids: &Vec<String>,
    send_message: ReporterCallback,
) -> Result<ProofCheck, ProofModeError> {
    let mut urls = Vec::new();
    for cid in cids {
        let url = format!("https://cloudflare-ipfs.com/ipfs/{}", cid);
        urls.push(url);
    }
    check_urls(&urls, send_message)
}