1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use super::Error;
use crate::borrowed::{
util::{parse_header_field, parse_hex_sha1, parse_signature, NL},
Signature,
};
use crate::{BStr, ByteSlice};
use nom::{
branch::alt,
bytes::complete::{tag, take_until, take_while1},
character::is_alphabetic,
combinator::opt,
combinator::{all_consuming, recognize},
sequence::preceded,
sequence::{delimited, tuple},
IResult,
};
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]
#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
pub struct Tag<'data> {
#[cfg_attr(feature = "serde1", serde(borrow))]
pub target: &'data BStr,
pub name: &'data BStr,
pub target_kind: crate::Kind,
pub message: &'data BStr,
pub signature: Signature<'data>,
pub pgp_signature: Option<&'data BStr>,
}
fn parse(i: &[u8]) -> IResult<&[u8], Tag, Error> {
let (i, target) =
parse_header_field(i, b"object", parse_hex_sha1).map_err(Error::context("object <40 lowercase hex char>"))?;
let (i, kind) =
parse_header_field(i, b"type", take_while1(is_alphabetic)).map_err(Error::context("type <object kind>"))?;
let kind = crate::Kind::from_bytes(kind).map_err(|e| nom::Err::Error(Error::ParseKindError(e)))?;
let (i, tag_version) =
parse_header_field(i, b"tag", take_while1(|b| b != NL[0])).map_err(Error::context("tag <version>"))?;
let (i, signature) =
parse_header_field(i, b"tagger", parse_signature).map_err(Error::context("tagger <signature>"))?;
let (i, (message, pgp_signature)) = all_consuming(parse_message)(i)?;
Ok((
i,
Tag {
target,
name: tag_version.as_bstr(),
target_kind: kind,
message,
signature,
pgp_signature,
},
))
}
fn parse_message(i: &[u8]) -> IResult<&[u8], (&BStr, Option<&BStr>), Error> {
const PGP_SIGNATURE_BEGIN: &[u8] = b"\n-----BEGIN PGP SIGNATURE-----";
const PGP_SIGNATURE_END: &[u8] = b"-----END PGP SIGNATURE-----";
if i.is_empty() {
return Ok((i, (i.as_bstr(), None)));
}
let (i, _) = tag(NL)(i)?;
fn all_to_end(i: &[u8]) -> IResult<&[u8], (&[u8], &[u8]), Error> {
if i.is_empty() {
return Err(nom::Err::Error(Error::NomDetail(i.into(), "tag message is missing")));
}
Ok((&[], (&i, &[])))
}
let (i, (message, signature)) = alt((
tuple((
take_until(PGP_SIGNATURE_BEGIN),
preceded(
tag(NL),
recognize(delimited(
tag(&PGP_SIGNATURE_BEGIN[1..]),
take_until(PGP_SIGNATURE_END),
tag(PGP_SIGNATURE_END),
)),
),
)),
all_to_end,
))(i)?;
let (i, _) = opt(tag(NL))(i)?;
Ok((
i,
(
message.as_bstr(),
if signature.is_empty() {
None
} else {
Some(signature.as_bstr())
},
),
))
}
impl<'data> Tag<'data> {
pub fn target(&self) -> crate::Id {
crate::Id::from_hex(self.target).expect("prior validation")
}
pub fn from_bytes(d: &'data [u8]) -> Result<Tag<'data>, Error> {
parse(d).map(|(_, t)| t).map_err(Error::from)
}
}