cmail_rpgp/composed/
shared.rs1use std::io::{BufRead, Read};
2
3use buffer_redux::BufReader;
4use log::{debug, warn};
5
6use crate::armor::{self, BlockType};
7use crate::errors::{Error, Result};
8use crate::packet::{Packet, PacketParser};
9
10pub trait Deserializable: Sized {
11 fn from_bytes(bytes: impl Read) -> Result<Self> {
13 let mut el = Self::from_bytes_many(bytes);
14 el.next().ok_or(Error::NoMatchingPacket)?
15 }
16
17 fn from_string(input: &str) -> Result<(Self, armor::Headers)> {
19 let (mut el, headers) = Self::from_string_many(input)?;
20 Ok((el.next().ok_or(Error::NoMatchingPacket)??, headers))
21 }
22
23 #[allow(clippy::type_complexity)]
25 fn from_string_many<'a>(
26 input: &'a str,
27 ) -> Result<(Box<dyn Iterator<Item = Result<Self>> + 'a>, armor::Headers)> {
28 Self::from_armor_many_buf(input.as_bytes())
29 }
30
31 fn from_armor_single<R: Read>(input: R) -> Result<(Self, armor::Headers)> {
33 let (mut el, headers) = Self::from_armor_many(input)?;
34 Ok((el.next().ok_or(Error::NoMatchingPacket)??, headers))
35 }
36
37 fn from_armor_single_buf<R: BufRead>(input: R) -> Result<(Self, armor::Headers)> {
39 let (mut el, headers) = Self::from_armor_many_buf(input)?;
40 Ok((el.next().ok_or(Error::NoMatchingPacket)??, headers))
41 }
42
43 #[allow(clippy::type_complexity)]
45 fn from_armor_many<'a, R: Read + 'a>(
46 input: R,
47 ) -> Result<(Box<dyn Iterator<Item = Result<Self>> + 'a>, armor::Headers)> {
48 Self::from_armor_many_buf(BufReader::new(input))
49 }
50
51 #[allow(clippy::type_complexity)]
52 fn from_armor_many_buf<'a, R: BufRead + 'a>(
53 input: R,
54 ) -> Result<(Box<dyn Iterator<Item = Result<Self>> + 'a>, armor::Headers)> {
55 let mut dearmor = armor::Dearmor::new(input);
56 dearmor.read_header()?;
57 let typ = dearmor
59 .typ
60 .ok_or_else(|| format_err!("dearmor failed to retrieve armor type"))?;
61
62 match typ {
64 BlockType::PublicKey
66 | BlockType::PrivateKey
67 | BlockType::Message
68 | BlockType::MultiPartMessage(_, _)
69 | BlockType::Signature
70 | BlockType::CleartextMessage
71 | BlockType::File => {
72 let headers = dearmor.headers.clone(); if !Self::matches_block_type(typ) {
75 bail!("unexpected block type: {}", typ);
76 }
77 Ok((Self::from_bytes_many(dearmor), headers))
78 }
79 BlockType::PublicKeyPKCS1(_)
80 | BlockType::PublicKeyPKCS8
81 | BlockType::PublicKeyOpenssh
82 | BlockType::PrivateKeyPKCS1(_)
83 | BlockType::PrivateKeyPKCS8
84 | BlockType::PrivateKeyOpenssh => {
85 unimplemented_err!("key format {:?}", typ);
86 }
87 }
88 }
89
90 fn from_bytes_many<'a>(bytes: impl Read + 'a) -> Box<dyn Iterator<Item = Result<Self>> + 'a> {
92 let packets = PacketParser::new(bytes).filter_map(filter_parsed_packet_results);
93
94 Self::from_packets(packets.peekable())
95 }
96
97 fn from_packets<'a, I: Iterator<Item = Result<Packet>> + 'a>(
99 packets: std::iter::Peekable<I>,
100 ) -> Box<dyn Iterator<Item = Result<Self>> + 'a>;
101
102 fn matches_block_type(typ: BlockType) -> bool;
104
105 #[allow(clippy::type_complexity)]
110 fn from_reader_single<'a, R: Read + 'a>(input: R) -> Result<(Self, Option<armor::Headers>)> {
111 Self::from_reader_single_buf(BufReader::new(input))
112 }
113
114 #[allow(clippy::type_complexity)]
115 fn from_reader_single_buf<'a, R: BufRead + 'a>(
116 mut input: R,
117 ) -> Result<(Self, Option<armor::Headers>)> {
118 if !is_binary(&mut input)? {
119 let (keys, headers) = Self::from_armor_single(input)?;
120 Ok((keys, Some(headers)))
121 } else {
122 Ok((Self::from_bytes(input)?, None))
123 }
124 }
125
126 #[allow(clippy::type_complexity)]
131 fn from_reader_many<'a, R: Read + 'a>(
132 input: R,
133 ) -> Result<(
134 Box<dyn Iterator<Item = Result<Self>> + 'a>,
135 Option<armor::Headers>,
136 )> {
137 Self::from_reader_many_buf(BufReader::new(input))
138 }
139
140 #[allow(clippy::type_complexity)]
145 fn from_reader_many_buf<'a, R: BufRead + 'a>(
146 mut input: R,
147 ) -> Result<(
148 Box<dyn Iterator<Item = Result<Self>> + 'a>,
149 Option<armor::Headers>,
150 )> {
151 if !is_binary(&mut input)? {
152 let (keys, headers) = Self::from_armor_many_buf(input)?;
153 Ok((keys, Some(headers)))
154 } else {
155 Ok((Self::from_bytes_many(input), None))
156 }
157 }
158}
159
160pub(crate) fn filter_parsed_packet_results(p: Result<Packet>) -> Option<Result<Packet>> {
169 match &p {
173 Ok(Packet::Marker(_m)) => {
174 debug!("skipping marker packet");
175 None
176 }
177 Ok(_) => Some(p),
178 Err(e) => {
179 if let Error::Unsupported(e) = e {
180 warn!("skipping unsupported packet: {p:?}");
183 debug!("error: {e:?}");
184 return None;
185 }
186 if let Error::InvalidPacketContent(b) = &e {
187 let err: &Error = b; if let Error::Unsupported(e) = err {
189 warn!("skipping unsupported packet: {p:?}");
192 debug!("error: {e:?}");
193 return None;
194 }
195 if let Error::EllipticCurve(e) = err {
196 warn!("skipping bad elliptic curve data: {p:?}");
199 debug!("error: {e:?}");
200 return None;
201 }
202 }
203 if let Error::PacketIncomplete = e {
204 warn!("skipping incomplete packet: {p:?}");
206 return None;
207 }
208
209 Some(Err(Error::Message(format!(
211 "unexpected packet data: {e:?}"
212 ))))
213 }
214 }
215}
216
217pub(crate) fn is_binary<R: BufRead>(input: &mut R) -> Result<bool> {
220 let buf = input.fill_buf()?;
222 if buf.is_empty() {
223 bail!("empty input");
224 }
225
226 let binary = buf[0] & 0x80 != 0;
229
230 Ok(binary)
231}