kpx 0.0.1

Pure Rust KeePassXC browser integration client with a simple synchronous API
Documentation
use base64::{DecodeError, Engine};
use rand_core::{OsRng, RngCore};

use crate::models::SuccessValue;

/// Length in bytes of the KeePassXC nonce value.
pub const NONCE_LEN: usize = 24;
/// Length in bytes of the client identifier (matches KeePassXC expectations).
pub const CLIENT_ID_LEN: usize = 24;
/// Length in bytes of the NaCl key material.
pub const KEY_LEN: usize = 32;

#[inline]
/// Encode the provided bytes as standard base64.
pub fn encode_base64(bytes: &[u8]) -> String {
    base64::engine::general_purpose::STANDARD.encode(bytes)
}

#[inline]
/// Decode a standard base64 string into a byte vector.
pub fn decode_base64(input: &str) -> Result<Vec<u8>, base64::DecodeError> {
    base64::engine::general_purpose::STANDARD.decode(input)
}

/// Decode a base64 string into a fixed-size byte array.
pub fn decode_base64_array<const N: usize>(input: &str) -> Result<[u8; N], DecodeError> {
    let decoded = decode_base64(input)?;
    let boxed: Box<[u8]> = decoded.into_boxed_slice();
    let len = boxed.len();
    if len != N {
        return Err(DecodeError::InvalidLength(len));
    }
    let mut array = [0u8; N];
    array.copy_from_slice(&boxed);
    Ok(array)
}

/// Generate a buffer filled with cryptographically-secure random bytes.
pub fn random_bytes<const N: usize>() -> [u8; N] {
    let mut bytes = [0u8; N];
    OsRng.fill_bytes(&mut bytes);
    bytes
}

/// Convert KeePassXC's loose `"success"` field into an `Option<bool>`.
pub fn success_to_bool(value: Option<&SuccessValue>) -> Option<bool> {
    value.map(SuccessValue::is_true)
}