use std::io::BufRead;
use log::warn;
use crate::pgp::{
errors::{format_err, Error, Result, UnsupportedSnafu},
packet::{
CompressedData, GnupgAeadData, LiteralData, Marker, ModDetectionCode, OnePassSignature,
Packet, PacketHeader, Padding, PublicKey, PublicKeyEncryptedSessionKey, PublicSubkey,
SecretKey, SecretSubkey, Signature, SymEncryptedData, SymEncryptedProtectedData,
SymKeyEncryptedSessionKey, Trust, UserAttribute, UserId,
},
parsing_reader::BufReadParsing,
types::Tag,
};
impl Packet {
pub fn from_reader<R: BufRead>(packet_header: PacketHeader, mut body: R) -> Result<Self> {
let res: Result<Self> = match packet_header.tag() {
Tag::Signature => Signature::try_from_reader(packet_header, &mut body).map(Into::into),
Tag::OnePassSignature => {
OnePassSignature::try_from_reader(packet_header, &mut body).map(Into::into)
}
Tag::SecretKey => SecretKey::try_from_reader(packet_header, &mut body).map(Into::into),
Tag::SecretSubkey => {
SecretSubkey::try_from_reader(packet_header, &mut body).map(Into::into)
}
Tag::PublicKey => PublicKey::try_from_reader(packet_header, &mut body).map(Into::into),
Tag::PublicSubkey => {
PublicSubkey::try_from_reader(packet_header, &mut body).map(Into::into)
}
Tag::PublicKeyEncryptedSessionKey => {
PublicKeyEncryptedSessionKey::try_from_reader(packet_header, &mut body)
.map(Into::into)
}
Tag::SymKeyEncryptedSessionKey => {
SymKeyEncryptedSessionKey::try_from_reader(packet_header, &mut body).map(Into::into)
}
Tag::LiteralData => {
LiteralData::try_from_reader(packet_header, &mut body).map(Into::into)
}
Tag::CompressedData => {
CompressedData::try_from_reader(packet_header, &mut body).map(Into::into)
}
Tag::SymEncryptedData => {
SymEncryptedData::try_from_reader(packet_header, &mut body).map(Into::into)
}
Tag::SymEncryptedProtectedData => {
SymEncryptedProtectedData::try_from_reader(packet_header, &mut body).map(Into::into)
}
Tag::Marker => Marker::try_from_reader(packet_header, &mut body).map(Into::into),
Tag::Trust => Trust::try_from_reader(packet_header, &mut body).map(Into::into),
Tag::UserId => UserId::try_from_reader(packet_header, &mut body).map(Into::into),
Tag::UserAttribute => {
UserAttribute::try_from_reader(packet_header, &mut body).map(Into::into)
}
Tag::ModDetectionCode => {
ModDetectionCode::try_from_reader(packet_header, &mut body).map(Into::into)
}
Tag::Padding => Padding::try_from_reader(packet_header, &mut body).map(Into::into),
Tag::GnupgAeadData => {
GnupgAeadData::try_from_reader(packet_header, &mut body).map(Into::into)
}
Tag::UnassignedCritical(id) => {
Err(Error::InvalidPacketContent {
source: Box::new(format_err!("Unassigned Critical Packet type {:?}", id)),
})
}
Tag::UnassignedNonCritical(id) => {
Err(UnsupportedSnafu {
message: format!("Unassigned Non-Critical Packet type {id:?}"),
}
.build())
}
Tag::Experimental(id) => Err(UnsupportedSnafu {
message: format!("Experimental Packet type: {id:?}"),
}
.build()),
Tag::Invalid(id) => Err(Error::InvalidPacketContent {
source: Box::new(format_err!("Unexpected Packet type {:?}", id)),
}),
};
if let Err(ref err) = res {
log::info!("error {err:#?}");
}
let drained_bytes = body.drain()?;
match res {
Ok(res) => {
if drained_bytes > 0 {
warn!("failed to consume data: {drained_bytes} bytes too many");
return Err(Error::PacketTooLarge {
size: drained_bytes,
});
}
Ok(res)
}
Err(Error::PacketParsing { source }) if source.is_incomplete() => {
Err(Error::PacketIncomplete { source })
}
Err(Error::IO { source, backtrace })
if source.kind() == std::io::ErrorKind::UnexpectedEof =>
{
Err(Error::PacketIncomplete {
source: Box::new(crate::pgp::parsing::Error::UnexpectedEof { source, backtrace }),
})
}
Err(err) => {
warn!("invalid packet: {:#?} {:?}", err, packet_header.tag());
Err(Error::InvalidPacketContent {
source: Box::new(err),
})
}
}
}
}