use buffered_reader::BufferedReader;
use crate::Result;
use crate::parse::PacketParserResult;
use crate::parse::PacketParser;
use crate::parse::PacketParserEOF;
use crate::parse::PacketParserState;
use crate::parse::PacketParserSettings;
use crate::parse::ParserResult;
use crate::parse::Parse;
use crate::parse::Cookie;
use crate::armor;
use crate::packet;
#[derive(PartialEq)]
#[non_exhaustive]
pub enum Dearmor {
Enabled(armor::ReaderMode),
Disabled,
Auto(armor::ReaderMode),
}
assert_send_and_sync!(Dearmor);
impl Default for Dearmor {
fn default() -> Self {
Dearmor::Auto(Default::default())
}
}
pub(super) const ARMOR_READER_LEVEL: isize = -2;
pub struct PacketParserBuilder<'a> {
bio: Box<dyn BufferedReader<Cookie> + 'a>,
dearmor: Dearmor,
settings: PacketParserSettings,
csf_transformation: bool,
}
assert_send_and_sync!(PacketParserBuilder<'_>);
impl<'a> Parse<'a, PacketParserBuilder<'a>> for PacketParserBuilder<'a> {
fn from_buffered_reader<R>(reader: R) -> Result<PacketParserBuilder<'a>>
where
R: BufferedReader<Cookie> + 'a,
{
PacketParserBuilder::from_cookie_reader(reader.into_boxed())
}
}
impl<'a> crate::seal::Sealed for PacketParserBuilder<'a> {}
impl<'a> PacketParserBuilder<'a> {
pub(crate) fn from_cookie_reader(mut bio: Box<dyn BufferedReader<Cookie> + 'a>)
-> Result<Self> {
bio.cookie_mut().level = None;
Ok(PacketParserBuilder {
bio,
dearmor: Default::default(),
settings: PacketParserSettings::default(),
csf_transformation: false,
})
}
pub fn max_recursion_depth(mut self, value: u8) -> Self {
self.settings.max_recursion_depth = value;
self
}
pub fn max_packet_size(mut self, value: u32) -> Self {
self.settings.max_packet_size = value;
self
}
pub fn buffer_unread_content(mut self) -> Self {
self.settings.buffer_unread_content = true;
self
}
pub fn drop_unread_content(mut self) -> Self {
self.settings.buffer_unread_content = false;
self
}
pub fn map(mut self, enable: bool) -> Self {
self.settings.map = enable;
self
}
pub fn dearmor(mut self, mode: Dearmor) -> Self {
self.dearmor = mode;
self
}
pub fn automatic_hashing(mut self, enable: bool) -> Self {
self.settings.automatic_hashing = enable;
self
}
pub(crate) fn csf_transformation(mut self, enable: bool) -> Self {
self.csf_transformation = enable;
self
}
#[allow(clippy::redundant_pattern_matching)]
pub fn build(mut self)
-> Result<PacketParserResult<'a>>
where Self: 'a
{
let state = PacketParserState::new(self.settings);
let dearmor_mode = match self.dearmor {
Dearmor::Enabled(mode) => Some(mode),
Dearmor::Disabled => None,
Dearmor::Auto(mode) => {
if self.bio.eof() {
None
} else {
let mut reader = buffered_reader::Dup::with_cookie(
self.bio, Cookie::default());
let header = packet::Header::parse(&mut reader);
self.bio = Box::new(reader).into_inner().unwrap();
if let Ok(header) = header {
if let Err(_) = header.valid(false) {
Some(mode)
} else {
None
}
} else {
Some(mode)
}
}
}
};
if let Some(mode) = dearmor_mode {
self.bio =
armor::Reader::from_cookie_reader_csft(self.bio, Some(mode),
Cookie::new(ARMOR_READER_LEVEL), self.csf_transformation)
.into_boxed();
}
match PacketParser::parse(Box::new(self.bio), state, vec![ 0 ])? {
ParserResult::Success(mut pp) => {
pp.state.message_validator.push(
pp.packet.tag(), pp.packet.version(), &[0]);
pp.state.keyring_validator.push(pp.packet.tag());
pp.state.cert_validator.push(pp.packet.tag());
Ok(PacketParserResult::Some(pp))
},
ParserResult::EOF((reader, state, _path)) => {
Ok(PacketParserResult::EOF(PacketParserEOF::new(state, reader)))
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn armor() {
let msg = crate::tests::message("sig.pgp");
let ppr = PacketParserBuilder::from_bytes(msg).unwrap()
.dearmor(Dearmor::Disabled)
.build();
assert_match!(Ok(PacketParserResult::Some(ref _pp)) = ppr);
let ppr = PacketParserBuilder::from_bytes(msg).unwrap()
.dearmor(Dearmor::Auto(Default::default()))
.build();
assert_match!(Ok(PacketParserResult::Some(ref _pp)) = ppr);
let ppr = PacketParserBuilder::from_bytes(msg).unwrap()
.dearmor(Dearmor::Enabled(Default::default()))
.build();
assert_match!(Err(_) = ppr);
let msg = crate::tests::message("a-cypherpunks-manifesto.txt.ed25519.sig");
let ppr = PacketParserBuilder::from_bytes(msg).unwrap()
.dearmor(Dearmor::Disabled)
.build();
assert_match!(Err(_) = ppr);
let ppr = PacketParserBuilder::from_bytes(msg).unwrap()
.dearmor(Dearmor::Auto(Default::default()))
.build();
assert_match!(Ok(PacketParserResult::Some(ref _pp)) = ppr);
let ppr = PacketParserBuilder::from_bytes(msg).unwrap()
.dearmor(Dearmor::Enabled(Default::default()))
.build();
assert_match!(Ok(PacketParserResult::Some(ref _pp)) = ppr);
}
}