You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

216 lines
4.6 KiB

//! Way of serialising multiple keys in file
use super::*;
use std::{
io,
path::{
PathBuf,
Path,
},
marker::Unpin,
fmt,
error,
};
use tokio::{
prelude::*,
io::{
AsyncRead,
AsyncWrite,
},
fs::{
OpenOptions,
},
};
/// An error type for serialisation or deserialisation
#[derive(Debug)]
pub enum SerdeError
{
Serialise(toml::ser::Error),
Deserialise(toml::de::Error),
IO(io::Error),
}
impl From<toml::ser::Error> for SerdeError
{
fn from(from: toml::ser::Error) -> Self
{
Self::Serialise(from)
}
}
impl From<toml::de::Error> for SerdeError
{
fn from(from: toml::de::Error) -> Self
{
Self::Deserialise(from)
}
}
impl From<io::Error> for SerdeError
{
fn from(from: io::Error) -> Self
{
Self::IO(from)
}
}
impl error::Error for SerdeError
{
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match &self {
Self::Serialise(s) => Some(s),
Self::Deserialise(d) => Some(d),
Self::IO(io) => Some(io),
}
}
}
impl fmt::Display for SerdeError
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
match self {
Self::Serialise(_) => write!(f, "writing failed"),
Self::Deserialise(_) => write!(f, "reading failed"),
Self::IO(_) => write!(f, "io error"),
}
}
}
/// Serialisable struct containing key file information
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Spec
{
rsa: Vec<String>,
rsa_sign: Vec<String>,
sign_all: Option<bool>,
aes: Vec<String>,
}
pub struct Signers<'a>(&'a Spec, usize);
impl<'a> Iterator for Signers<'a>
{
type Item = &'a String;
fn next(&mut self) -> Option<Self::Item> {
(if self.1 < self.0.rsa_sign.len() {
Some(&self.0.rsa_sign[self.1])
} else if self.0.is_sign_all() {
let rest = self.1 -self.0.rsa_sign.len();
if rest < self.0.rsa.len() {
Some(&self.0.rsa[rest])
} else {
None
}
} else {
None
}, self.1+=1).0
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.0.rsa_sign.len() + if self.0.is_sign_all() {
self.0.rsa.len()
} else {
0
};
(len, Some(len))
}
}
impl<'a> std::iter::ExactSizeIterator for Signers<'a>{}
impl Spec
{
#[inline] fn is_sign_all(&self) -> bool
{
self.sign_all.unwrap_or(false)
}
pub fn new() -> Self
{
Self {
rsa: Vec::new(),
rsa_sign: Vec::new(),
sign_all: Some(false),
aes: Vec::new(),
}
}
/// An iterator over all signers
pub fn signers(&self) -> Signers<'_>
{
Signers(self, 0)
}
/// An iterator over all RSA encryptors
pub fn rsa(&self) -> std::slice::Iter<'_, String>
{
self.rsa.iter()
}
/// An iterator over all AES encryptors
pub fn aes(&self) -> std::slice::Iter<'_, String>
{
self.aes.iter()
}
/// Consume this instance into a `Normal` operation.
///
/// # Panics
/// If `op` is not `Normal` mode.
pub fn into_operation(self, op: &mut Operation)
{
match op {
Operation::Normal {
rsa,
aes,
sign,
auto_sign,
..
} => {
let sign_all = self.is_sign_all();
if *auto_sign == sign_all {
// Both are true or both are false, no extra conversion needed
sign.extend(self.rsa_sign.into_iter().map(PathBuf::from));
} else if sign_all {
// Need to add `rsa` and `rsa_sign` to `sign`.
sign.extend(self.rsa_sign.iter()
.chain(self.rsa.iter())
.cloned()
.map(PathBuf::from));
}
rsa.extend(self.rsa.into_iter().map(PathBuf::from));
aes.extend(self.aes.into_iter().map(PathBuf::from));
},
_ => panic!("Tried to consume into an operation of invalid type"),
}
}
/// Read an instance from a stream
pub async fn read_from_stream<S: AsyncRead + ?Sized + Unpin>(from: &mut S) -> eyre::Result<Self>
{
let mut output = Vec::with_capacity(4096);
async fn internal<S: AsyncRead + ?Sized + Unpin>(output: &mut Vec<u8>, from: &mut S) -> Result<Spec, SerdeError> {
let mut buffer = [0u8; 4096];
let mut read;
while {read = from.read(&mut buffer[..]).await?; read>0} {
output.extend_from_slice(&buffer[..read]);
}
Ok(toml::from_slice(&output[..])?)
}
internal(&mut output, from).await
.with_section(move || String::from_utf8_lossy(&output[..]).to_string().header("Read contents was"))
}
/// Read an instance from a file
pub async fn read_from_file<P: AsRef<Path>>(from: P) -> eyre::Result<Self>
{
let mut file = OpenOptions::new()
.read(true)
.open(from.as_ref()).await?;
Ok(Self::read_from_stream(&mut file).await
.with_section(move || format!("{:?}", from.as_ref()).header("Filename was"))?)
}
}