use crate::{BlockType, JisLevel, MAGIC, VERSION};
use serde::{Deserialize, Serialize};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum BlockError {
#[error("Invalid magic bytes: expected TBZ (0x54425A)")]
InvalidMagic,
#[error("Unsupported version: {0}")]
UnsupportedVersion(u8),
#[error("Block validation failed: {0}")]
ValidationFailed(String),
#[error("Decompression failed: {0}")]
DecompressionFailed(String),
#[error("Signature verification failed")]
SignatureInvalid,
#[error("JIS authorization insufficient: required level {required}, got {provided}")]
Unauthorized { required: JisLevel, provided: JisLevel },
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BlockHeader {
pub magic: [u8; 3],
pub version: u8,
pub block_index: u32,
pub block_type: BlockType,
pub jis_level: JisLevel,
pub uncompressed_size: u64,
pub compressed_size: u64,
}
impl BlockHeader {
pub fn new(
block_index: u32,
block_type: BlockType,
jis_level: JisLevel,
uncompressed_size: u64,
compressed_size: u64,
) -> Self {
Self {
magic: MAGIC,
version: VERSION,
block_index,
block_type,
jis_level,
uncompressed_size,
compressed_size,
}
}
pub fn validate(&self) -> Result<(), BlockError> {
if self.magic != MAGIC {
return Err(BlockError::InvalidMagic);
}
if self.version != VERSION {
return Err(BlockError::UnsupportedVersion(self.version));
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct Block {
pub header: BlockHeader,
pub envelope: crate::envelope::TibetEnvelope,
pub payload: Vec<u8>,
pub signature: Vec<u8>,
pub header_raw: Vec<u8>,
pub envelope_raw: Vec<u8>,
}
impl Block {
pub fn validate(&self) -> Result<(), BlockError> {
self.header.validate()?;
Ok(())
}
pub fn verify_signature(
&self,
verifying_key: &ed25519_dalek::VerifyingKey,
) -> Result<(), BlockError> {
let mut sign_data = Vec::new();
sign_data.extend_from_slice(&self.header_raw);
sign_data.extend_from_slice(&self.envelope_raw);
sign_data.extend_from_slice(&self.payload);
crate::signature::verify(&sign_data, &self.signature, verifying_key)
.map_err(|_| BlockError::SignatureInvalid)
}
pub fn decompress(&self) -> Result<Vec<u8>, BlockError> {
zstd::decode_all(self.payload.as_slice())
.map_err(|e| BlockError::DecompressionFailed(e.to_string()))
}
pub fn check_authorization(&self, caller_level: JisLevel) -> Result<(), BlockError> {
if caller_level < self.header.jis_level {
return Err(BlockError::Unauthorized {
required: self.header.jis_level,
provided: caller_level,
});
}
Ok(())
}
}