jazz-rs 0.1.0

A framework for CRDT based, end-to-end enrypted distributed apps
Documentation
use conundrum::{symm_encr::EncrKey, unauth_symm_encr::UnauthEncryptionStream};
use std::{
    cell::{RefCell, RefMut},
    io::Write,
    rc::Rc,
};
use jazz_telepathy::{logs::LogWriteAccess, TelepathyNode};

use super::LogEncryption;

pub(crate) struct LogWriter {
    content_telepathy: Rc<RefCell<TelepathyNode>>,
    write_access: LogWriteAccess,
    encryption_stream: UnauthEncryptionStream<LogEncryption>,
}

impl LogWriter {
    pub(crate) fn new(
        content_telepathy: Rc<RefCell<TelepathyNode>>,
        write_access: LogWriteAccess,
        encryption_key: EncrKey<LogEncryption>,
    ) -> Self {
        Self {
            content_telepathy,
            write_access,
            // Null nonce is safe IFF the key is unique to this log
            encryption_stream: UnauthEncryptionStream::new(encryption_key, [0; 12].into()),
        }
    }
}

impl Write for LogWriter {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        let mut logs = RefMut::map(self.content_telepathy.borrow_mut(), |telepathy| {
            &mut telepathy.local_state.logs
        });

        let current_len = logs
            .current_data(&self.write_access.id())
            .map(|d| d.len())
            .unwrap_or(0) as u64;

        let mut nonce: [u8; 12] = [0; 12];
        (&mut nonce[0..8]).copy_from_slice(&current_len.to_le_bytes());

        let mut encrypted = buf.to_vec();
        self.encryption_stream.xor_chunk(&mut encrypted);

        logs.append(&self.write_access, &encrypted)
            .map(|_ok| encrypted.len())
            .map_err(|log_err| match log_err {
                jazz_telepathy::logs::LogError::InvalidHash => {
                    std::io::Error::new(std::io::ErrorKind::InvalidData, log_err)
                }
                jazz_telepathy::logs::LogError::InvalidSignature(_) => {
                    std::io::Error::new(std::io::ErrorKind::PermissionDenied, log_err)
                }
            })
    }

    fn flush(&mut self) -> std::io::Result<()> {
        Ok(())
    }
}