libvctrl 0.3.0

A robust, content-addressed version control engine for arbitrary data, designed for embedding into applications.
Documentation
use crate::crypto::Signer;
use crate::error::VctrlError;
use ed25519_dalek::{Signer as EdSigner, SigningKey, VerifyingKey};
use rand::RngCore;
use std::path::Path;

pub struct LibrageSigner {
    signing_key: SigningKey,
}

impl std::fmt::Debug for LibrageSigner {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("LibrageSigner")
            .field("signing_key", &"[REDACTED]")
            .finish()
    }
}

impl LibrageSigner {
    #[cfg(unix)]
    pub fn from_seed_file(path: impl AsRef<Path>) -> Result<Self, VctrlError> {
        use std::os::unix::fs::PermissionsExt;
        let path = path.as_ref();
        let metadata = std::fs::metadata(path).map_err(VctrlError::Io)?;
        if metadata.permissions().mode() & 0o077 != 0 {
            return Err(VctrlError::Other(
                "seed file permissions too permissive; must be 0600".into(),
            ));
        }
        let bytes = std::fs::read(path).map_err(VctrlError::Io)?;
        let seed: [u8; 32] = bytes
            .try_into()
            .map_err(|_| VctrlError::Other("seed file must be exactly 32 bytes".into()))?;
        let signing_key = SigningKey::from_bytes(&seed);
        Ok(Self { signing_key })
    }

    #[cfg(not(unix))]
    pub fn from_seed_file(path: impl AsRef<Path>) -> Result<Self, VctrlError> {
        let bytes = std::fs::read(path.as_ref()).map_err(VctrlError::Io)?;
        let seed: [u8; 32] = bytes
            .try_into()
            .map_err(|_| VctrlError::Other("seed file must be exactly 32 bytes".into()))?;
        let signing_key = SigningKey::from_bytes(&seed);
        Ok(Self { signing_key })
    }

    pub fn generate() -> Self {
        let mut csprng = rand::rngs::OsRng;
        let mut seed = [0u8; 32];
        csprng.fill_bytes(&mut seed);
        let signing_key = SigningKey::from_bytes(&seed);
        Self { signing_key }
    }

    pub fn verifying_key(&self) -> VerifyingKey {
        self.signing_key.verifying_key()
    }
}

impl Signer for LibrageSigner {
    fn sign(&self, commit_hash: &[u8]) -> Result<Vec<u8>, VctrlError> {
        let signature = self.signing_key.sign(commit_hash);
        Ok(signature.to_bytes().to_vec())
    }
}