use ssh_encoding::{self, CheckedSum, Decode, Encode, Reader, Writer};
use crate::proto::{
extension::{KeyConstraintExtension, MessageExtension},
Error, Result, Unparsed,
};
#[derive(Clone, PartialEq, Debug)]
pub struct Extension {
pub name: String,
pub details: Unparsed,
}
impl Extension {
pub fn new_message<T>(extension: T) -> Result<Self>
where
T: MessageExtension + Encode,
{
let mut buffer: Vec<u8> = vec![];
extension.encode(&mut buffer)?;
Ok(Self {
name: T::NAME.into(),
details: buffer.into(),
})
}
pub fn parse_message<T>(&self) -> std::result::Result<Option<T>, <T as Decode>::Error>
where
T: MessageExtension + Decode,
{
if T::NAME == self.name {
Ok(Some(self.details.parse::<T>()?))
} else {
Ok(None)
}
}
pub fn new_key_constraint<T>(extension: T) -> Result<Self>
where
T: KeyConstraintExtension + Encode,
{
let mut buffer: Vec<u8> = vec![];
extension.encode(&mut buffer)?;
Ok(Self {
name: T::NAME.into(),
details: buffer.into(),
})
}
pub fn parse_key_constraint<T>(&self) -> std::result::Result<Option<T>, <T as Decode>::Error>
where
T: KeyConstraintExtension + Decode,
{
if T::NAME == self.name {
Ok(Some(self.details.parse::<T>()?))
} else {
Ok(None)
}
}
}
impl Decode for Extension {
type Error = Error;
fn decode(reader: &mut impl Reader) -> Result<Self> {
let name = String::decode(reader)?;
let mut details = vec![0; reader.remaining_len()];
reader.read(&mut details)?;
Ok(Self {
name,
details: details.into(),
})
}
}
impl Encode for Extension {
fn encoded_len(&self) -> ssh_encoding::Result<usize> {
[self.name.encoded_len()?, self.details.encoded_len()?].checked_sum()
}
fn encode(&self, writer: &mut impl Writer) -> ssh_encoding::Result<()> {
self.name.encode(writer)?;
self.details.encode(writer)?;
Ok(())
}
}