cmail_rpgp/composed/
signature.rs

1use std::iter::Peekable;
2
3use crate::composed::Deserializable;
4use crate::errors::Result;
5use crate::packet::{Packet, Signature};
6use crate::ser::Serialize;
7use crate::types::PublicKeyTrait;
8use crate::types::Tag;
9use crate::{armor, ArmorOptions};
10
11/// Standalone signature as defined by the cleartext framework.
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct StandaloneSignature {
14    pub signature: Signature,
15}
16
17impl StandaloneSignature {
18    pub fn new(signature: Signature) -> Self {
19        StandaloneSignature { signature }
20    }
21
22    pub fn to_armored_writer(
23        &self,
24        writer: &mut impl std::io::Write,
25        opts: ArmorOptions<'_>,
26    ) -> Result<()> {
27        armor::write(
28            self,
29            armor::BlockType::Signature,
30            writer,
31            opts.headers,
32            opts.include_checksum,
33        )
34    }
35
36    pub fn to_armored_bytes(&self, opts: ArmorOptions<'_>) -> Result<Vec<u8>> {
37        let mut buf = Vec::new();
38
39        self.to_armored_writer(&mut buf, opts)?;
40
41        Ok(buf)
42    }
43
44    pub fn to_armored_string(&self, opts: ArmorOptions<'_>) -> Result<String> {
45        let res = String::from_utf8(self.to_armored_bytes(opts)?).map_err(|e| e.utf8_error())?;
46        Ok(res)
47    }
48
49    /// Verify this signature.
50    pub fn verify(&self, key: &impl PublicKeyTrait, content: &[u8]) -> Result<()> {
51        self.signature.verify(key, content)
52    }
53}
54
55impl Serialize for StandaloneSignature {
56    fn to_writer<W: std::io::Write>(&self, writer: &mut W) -> Result<()> {
57        crate::packet::write_packet(writer, &self.signature)
58    }
59}
60
61impl Deserializable for StandaloneSignature {
62    /// Parse a signature.
63    fn from_packets<'a, I: Iterator<Item = Result<Packet>> + 'a>(
64        packets: std::iter::Peekable<I>,
65    ) -> Box<dyn Iterator<Item = Result<Self>> + 'a> {
66        Box::new(SignatureParser { source: packets })
67    }
68
69    fn matches_block_type(typ: armor::BlockType) -> bool {
70        matches!(typ, armor::BlockType::Signature)
71    }
72}
73
74pub struct SignatureParser<I: Sized + Iterator<Item = Result<Packet>>> {
75    source: Peekable<I>,
76}
77
78impl<I: Sized + Iterator<Item = Result<Packet>>> Iterator for SignatureParser<I> {
79    type Item = Result<StandaloneSignature>;
80
81    fn next(&mut self) -> Option<Self::Item> {
82        next(self.source.by_ref())
83    }
84}
85
86fn next<I: Iterator<Item = Result<Packet>>>(
87    packets: &mut Peekable<I>,
88) -> Option<Result<StandaloneSignature>> {
89    match packets.by_ref().next() {
90        Some(Ok(packet)) => match packet.tag() {
91            Tag::Signature => Some(packet.try_into().map(StandaloneSignature::new)),
92            _ => Some(Err(format_err!("unexpected packet {:?}", packet.tag()))),
93        },
94        Some(Err(e)) => Some(Err(e)),
95        None => None,
96    }
97}