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
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"))?)
|
|
}
|
|
}
|