use std::ops::Range;
use bstr::{BStr, BString, ByteSlice};
#[cfg(feature = "signature")]
pub mod sign;
#[cfg(feature = "signature")]
pub mod verify;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct SignatureRef<'a> {
pub format: Format,
pub data: &'a BStr,
}
#[derive(PartialEq, Eq, Debug, Hash, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SignedData<'a> {
data: &'a [u8],
excluded: Range<usize>,
}
impl<'a> SignedData<'a> {
pub(crate) fn new(data: &'a [u8], excluded: Range<usize>) -> Self {
SignedData { data, excluded }
}
pub(crate) fn segments(&self) -> [&[u8]; 2] {
[&self.data[..self.excluded.start], &self.data[self.excluded.end..]]
}
pub fn to_bstring(&self) -> BString {
let [before, after] = self.segments();
let mut out = BString::from(before);
out.extend_from_slice(after);
out
}
}
impl From<SignedData<'_>> for BString {
fn from(value: SignedData<'_>) -> Self {
value.to_bstring()
}
}
pub(crate) fn find(data: &[u8]) -> Option<(usize, Format)> {
let mut found = None;
let mut offset = 0;
while offset < data.len() {
if let Some(format) = Format::from_signature(&data[offset..]) {
found = Some((offset, format));
}
offset = data[offset..]
.find_byte(b'\n')
.map_or(data.len(), |newline| offset + newline + 1);
}
found
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Format {
OpenPgp,
X509,
Ssh,
}
impl Format {
pub fn from_signature(signature: &[u8]) -> Option<Self> {
if signature.starts_with(b"-----BEGIN PGP SIGNATURE-----")
|| signature.starts_with(b"-----BEGIN PGP MESSAGE-----")
{
Some(Format::OpenPgp)
} else if signature.starts_with(b"-----BEGIN SIGNED MESSAGE-----") {
Some(Format::X509)
} else if signature.starts_with(b"-----BEGIN SSH SIGNATURE-----") {
Some(Format::Ssh)
} else {
None
}
}
}