use std::borrow::Cow;
use crate::{
commit::CommitHash,
crypto::AeadPack,
encoding::encoding_error,
events::{
AuditData, AuditEvent, AuditLogFile, EventKind, EventRecord,
LogFlags, WriteEvent,
},
formats::{EventLogFileRecord, FileRecord, VaultRecord},
vault::{secret::SecretId, VaultCommit},
Timestamp,
};
use futures::io::{AsyncRead, AsyncSeek, AsyncWrite};
use std::io::{Error, ErrorKind, Result, SeekFrom};
use async_trait::async_trait;
use binary_stream::futures::{
BinaryReader, BinaryWriter, Decodable, Encodable,
};
use uuid::Uuid;
#[async_trait]
impl Encodable for EventKind {
async fn encode<W: AsyncWrite + AsyncSeek + Unpin + Send>(
&self,
writer: &mut BinaryWriter<W>,
) -> Result<()> {
let value: u16 = self.into();
writer.write_u16(value).await?;
Ok(())
}
}
#[async_trait]
impl Decodable for EventKind {
async fn decode<R: AsyncRead + AsyncSeek + Unpin + Send>(
&mut self,
reader: &mut BinaryReader<R>,
) -> Result<()> {
let op = reader.read_u16().await?;
*self = op.try_into().map_err(|_| {
Error::new(ErrorKind::Other, format!("unknown event kind {}", op))
})?;
Ok(())
}
}
#[async_trait]
impl Encodable for EventRecord {
async fn encode<W: AsyncWrite + AsyncSeek + Unpin + Send>(
&self,
writer: &mut BinaryWriter<W>,
) -> Result<()> {
let size_pos = writer.stream_position().await?;
writer.write_u32(0).await?;
self.0.encode(&mut *writer).await?;
writer.write_bytes(self.1.as_ref()).await?;
writer.write_bytes(self.2.as_ref()).await?;
writer.write_u32(self.3.len() as u32).await?;
writer.write_bytes(&self.3).await?;
let row_pos = writer.stream_position().await?;
let row_len = row_pos - (size_pos + 4);
writer.seek(SeekFrom::Start(size_pos)).await?;
writer.write_u32(row_len as u32).await?;
writer.seek(SeekFrom::Start(row_pos)).await?;
writer.write_u32(row_len as u32).await?;
Ok(())
}
}
#[async_trait]
impl Decodable for EventRecord {
async fn decode<R: AsyncRead + AsyncSeek + Unpin + Send>(
&mut self,
reader: &mut BinaryReader<R>,
) -> Result<()> {
let _ = reader.read_u32().await?;
let mut time: Timestamp = Default::default();
time.decode(&mut *reader).await?;
let previous: [u8; 32] = reader
.read_bytes(32)
.await?
.as_slice()
.try_into()
.map_err(encoding_error)?;
let commit: [u8; 32] = reader
.read_bytes(32)
.await?
.as_slice()
.try_into()
.map_err(encoding_error)?;
let length = reader.read_u32().await?;
let buffer = reader.read_bytes(length as usize).await?;
self.0 = time;
self.1 = CommitHash(previous);
self.2 = CommitHash(commit);
self.3 = buffer;
let _ = reader.read_u32().await?;
Ok(())
}
}
#[async_trait]
impl Encodable for AuditEvent {
async fn encode<W: AsyncWrite + AsyncSeek + Unpin + Send>(
&self,
writer: &mut BinaryWriter<W>,
) -> Result<()> {
let flags = self.log_flags();
writer.write_u16(flags.bits()).await?;
self.time.encode(&mut *writer).await?;
self.event_kind.encode(&mut *writer).await?;
writer.write_bytes(self.address.as_ref()).await?;
if flags.contains(LogFlags::DATA) {
let data = self.data.as_ref().unwrap();
data.encode(&mut *writer).await?;
}
Ok(())
}
}
#[async_trait]
impl Decodable for AuditEvent {
async fn decode<R: AsyncRead + AsyncSeek + Unpin + Send>(
&mut self,
reader: &mut BinaryReader<R>,
) -> Result<()> {
let bits = reader.read_u16().await?;
let mut timestamp: Timestamp = Default::default();
timestamp.decode(&mut *reader).await?;
self.time = timestamp;
self.event_kind.decode(&mut *reader).await?;
let address = reader.read_bytes(20).await?;
let address: [u8; 20] =
address.as_slice().try_into().map_err(encoding_error)?;
self.address = address.into();
if let Some(flags) = LogFlags::from_bits(bits) {
if flags.contains(LogFlags::DATA) {
if flags.contains(LogFlags::DATA_VAULT) {
let vault_id: [u8; 16] = reader
.read_bytes(16)
.await?
.as_slice()
.try_into()
.map_err(encoding_error)?;
if !flags.contains(LogFlags::DATA_SECRET) {
self.data = Some(AuditData::Vault(Uuid::from_bytes(
vault_id,
)));
} else {
let secret_id: [u8; 16] = reader
.read_bytes(16)
.await?
.as_slice()
.try_into()
.map_err(encoding_error)?;
self.data = Some(AuditData::Secret(
Uuid::from_bytes(vault_id),
Uuid::from_bytes(secret_id),
));
}
} else if flags.contains(LogFlags::MOVE_SECRET) {
let from_vault_id: [u8; 16] = reader
.read_bytes(16)
.await?
.as_slice()
.try_into()
.map_err(encoding_error)?;
let from_secret_id: [u8; 16] = reader
.read_bytes(16)
.await?
.as_slice()
.try_into()
.map_err(encoding_error)?;
let to_vault_id: [u8; 16] = reader
.read_bytes(16)
.await?
.as_slice()
.try_into()
.map_err(encoding_error)?;
let to_secret_id: [u8; 16] = reader
.read_bytes(16)
.await?
.as_slice()
.try_into()
.map_err(encoding_error)?;
self.data = Some(AuditData::MoveSecret {
from_vault_id: Uuid::from_bytes(from_vault_id),
from_secret_id: Uuid::from_bytes(from_secret_id),
to_vault_id: Uuid::from_bytes(to_vault_id),
to_secret_id: Uuid::from_bytes(to_secret_id),
});
}
}
} else {
return Err(Error::new(
ErrorKind::Other,
"log data flags has bad bits",
));
}
Ok(())
}
}
#[async_trait]
impl Encodable for AuditData {
async fn encode<W: AsyncWrite + AsyncSeek + Unpin + Send>(
&self,
writer: &mut BinaryWriter<W>,
) -> Result<()> {
match self {
AuditData::Vault(vault_id) => {
writer.write_bytes(vault_id.as_bytes()).await?;
}
AuditData::Secret(vault_id, secret_id) => {
writer.write_bytes(vault_id.as_bytes()).await?;
writer.write_bytes(secret_id.as_bytes()).await?;
}
AuditData::MoveSecret {
from_vault_id,
from_secret_id,
to_vault_id,
to_secret_id,
} => {
writer.write_bytes(from_vault_id.as_bytes()).await?;
writer.write_bytes(from_secret_id.as_bytes()).await?;
writer.write_bytes(to_vault_id.as_bytes()).await?;
writer.write_bytes(to_secret_id.as_bytes()).await?;
}
}
Ok(())
}
}
#[async_trait]
impl<'a> Encodable for WriteEvent<'a> {
async fn encode<W: AsyncWrite + AsyncSeek + Unpin + Send>(
&self,
writer: &mut BinaryWriter<W>,
) -> Result<()> {
let op = self.event_kind();
op.encode(&mut *writer).await?;
match self {
WriteEvent::Noop => {
panic!("attempt to encode a noop")
}
WriteEvent::CreateVault(vault)
| WriteEvent::UpdateVault(vault) => {
writer.write_u32(vault.as_ref().len() as u32).await?;
writer.write_bytes(vault.as_ref()).await?;
}
WriteEvent::DeleteVault => {}
WriteEvent::SetVaultName(name) => {
writer.write_string(name).await?;
}
WriteEvent::SetVaultMeta(meta) => {
writer.write_bool(meta.is_some()).await?;
if let Some(meta) = meta.as_ref() {
meta.encode(&mut *writer).await?;
}
}
WriteEvent::CreateSecret(uuid, value) => {
writer.write_bytes(uuid.as_bytes()).await?;
value.as_ref().encode(&mut *writer).await?;
}
WriteEvent::UpdateSecret(uuid, value) => {
writer.write_bytes(uuid.as_bytes()).await?;
value.as_ref().encode(&mut *writer).await?;
}
WriteEvent::DeleteSecret(uuid) => {
writer.write_bytes(uuid.as_bytes()).await?;
}
}
Ok(())
}
}
#[async_trait]
impl<'a> Decodable for WriteEvent<'a> {
async fn decode<R: AsyncRead + AsyncSeek + Unpin + Send>(
&mut self,
reader: &mut BinaryReader<R>,
) -> Result<()> {
let mut op: EventKind = Default::default();
op.decode(&mut *reader).await?;
match op {
EventKind::Noop => panic!("attempt to decode a noop"),
EventKind::CreateVault => {
let length = reader.read_u32().await?;
let buffer = reader.read_bytes(length as usize).await?;
*self = WriteEvent::CreateVault(Cow::Owned(buffer))
}
EventKind::UpdateVault => {
let length = reader.read_u32().await?;
let buffer = reader.read_bytes(length as usize).await?;
*self = WriteEvent::UpdateVault(Cow::Owned(buffer))
}
EventKind::DeleteVault => {
*self = WriteEvent::DeleteVault;
}
EventKind::SetVaultName => {
let name = reader.read_string().await?;
*self = WriteEvent::SetVaultName(Cow::Owned(name));
}
EventKind::SetVaultMeta => {
let has_meta = reader.read_bool().await?;
let aead_pack = if has_meta {
let mut aead_pack: AeadPack = Default::default();
aead_pack.decode(&mut *reader).await?;
Some(aead_pack)
} else {
None
};
*self = WriteEvent::SetVaultMeta(Cow::Owned(aead_pack));
}
EventKind::CreateSecret => {
let id = SecretId::from_bytes(
reader
.read_bytes(16)
.await?
.as_slice()
.try_into()
.map_err(encoding_error)?,
);
let mut commit: VaultCommit = Default::default();
commit.decode(&mut *reader).await?;
*self = WriteEvent::CreateSecret(id, Cow::Owned(commit));
}
EventKind::UpdateSecret => {
let id = SecretId::from_bytes(
reader
.read_bytes(16)
.await?
.as_slice()
.try_into()
.map_err(encoding_error)?,
);
let mut commit: VaultCommit = Default::default();
commit.decode(&mut *reader).await?;
*self = WriteEvent::UpdateSecret(id, Cow::Owned(commit));
}
EventKind::DeleteSecret => {
let id = SecretId::from_bytes(
reader
.read_bytes(16)
.await?
.as_slice()
.try_into()
.map_err(encoding_error)?,
);
*self = WriteEvent::DeleteSecret(id);
}
_ => {
return Err(Error::new(
ErrorKind::Other,
format!("unknown event kind {}", op),
));
}
}
Ok(())
}
}
#[async_trait]
impl Decodable for EventLogFileRecord {
async fn decode<R: AsyncRead + AsyncSeek + Unpin + Send>(
&mut self,
reader: &mut BinaryReader<R>,
) -> Result<()> {
self.time.decode(&mut *reader).await?;
self.last_commit = reader
.read_bytes(32)
.await?
.as_slice()
.try_into()
.map_err(encoding_error)?;
self.commit = reader
.read_bytes(32)
.await?
.as_slice()
.try_into()
.map_err(encoding_error)?;
Ok(())
}
}
#[async_trait]
impl Decodable for FileRecord {
async fn decode<R: AsyncRead + AsyncSeek + Unpin + Send>(
&mut self,
_reader: &mut BinaryReader<R>,
) -> Result<()> {
Ok(())
}
}
#[async_trait]
impl Decodable for VaultRecord {
async fn decode<R: AsyncRead + AsyncSeek + Unpin + Send>(
&mut self,
reader: &mut BinaryReader<R>,
) -> Result<()> {
let id: [u8; 16] = reader
.read_bytes(16)
.await?
.as_slice()
.try_into()
.map_err(encoding_error)?;
let commit: [u8; 32] = reader
.read_bytes(32)
.await?
.as_slice()
.try_into()
.map_err(encoding_error)?;
self.id = id;
self.commit = commit;
Ok(())
}
}
impl AuditLogFile {
pub(crate) async fn encode_row<
W: AsyncWrite + AsyncSeek + Unpin + Send,
>(
writer: &mut BinaryWriter<W>,
event: AuditEvent,
) -> Result<()> {
let size_pos = writer.stream_position().await?;
writer.write_u32(0).await?;
event.encode(&mut *writer).await?;
let row_pos = writer.stream_position().await?;
let row_len = row_pos - (size_pos + 4);
writer.seek(SeekFrom::Start(size_pos)).await?;
writer.write_u32(row_len as u32).await?;
writer.seek(SeekFrom::Start(row_pos)).await?;
writer.write_u32(row_len as u32).await?;
Ok(())
}
pub(crate) async fn decode_row<
R: AsyncRead + AsyncSeek + Unpin + Send,
>(
reader: &mut BinaryReader<R>,
) -> Result<AuditEvent> {
let _ = reader.read_u32().await?;
let mut event: AuditEvent = Default::default();
event.decode(&mut *reader).await?;
let _ = reader.read_u32().await?;
Ok(event)
}
}