From 7b00455385fa6c99ec4dce2fcacb272f08f786b0 Mon Sep 17 00:00:00 2001 From: Avril Date: Mon, 21 Sep 2020 17:27:17 +0100 Subject: [PATCH] normal atom stream ok --- src/args/error.rs | 59 +++++++++++++++++++++++- src/args/parse.rs | 114 +++++++++++++++++++++++++++++++++++++--------- src/config.rs | 25 +++++----- src/main.rs | 2 + src/resolve.rs | 37 +++++++++++++++ 5 files changed, 201 insertions(+), 36 deletions(-) create mode 100644 src/resolve.rs diff --git a/src/args/error.rs b/src/args/error.rs index 8474b1d..6805fc1 100644 --- a/src/args/error.rs +++ b/src/args/error.rs @@ -15,8 +15,20 @@ pub enum ParseErrorKind CannotCombine(char, char), BadTail(char, String), NotUnique(char), + ModeSet, } +impl error::Error for ParseErrorKind{} + +impl fmt::Display for ParseErrorKind +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + Ok(()) + } +} + + impl From<(String, ParseErrorKind)> for Error { #[inline] fn from((froms, fromk): (String, ParseErrorKind)) -> Self @@ -25,6 +37,33 @@ impl From<(String, ParseErrorKind)> for Error } } +#[derive(Debug)] +#[non_exhaustive] +pub enum ConstructError +{ + AlreadyExists(String), + Resolve(resolve::Error), +} +impl error::Error for ConstructError +{ + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + Some(match self { + Self::Resolve(res) => res, + _=> return None, + }) + } +} +impl fmt::Display for ConstructError +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + match self { + _ => write!(f, "unknown error"), + } + } +} + + #[derive(Debug)] #[non_exhaustive] @@ -34,12 +73,21 @@ pub enum Error { Unknown, AtomInternal, } -impl error::Error for Error{} +impl error::Error for Error +{ + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + Some(match &self { + Error::Parse(_, parse) => parse, + _=> return None, + }) + } +} impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { + Error::AtomInternal => unreachable!("This should've been handled."), _ => write!(f, "unknown error"), } } @@ -53,3 +101,12 @@ impl From> for Error Self::AtomInternal } } + + +impl From for ConstructError +{ + #[inline] fn from(from: resolve::Error) -> Self + { + Self::Resolve(from) + } +} diff --git a/src/args/parse.rs b/src/args/parse.rs index ab748f8..dc25d0c 100644 --- a/src/args/parse.rs +++ b/src/args/parse.rs @@ -10,10 +10,10 @@ use std::{ iter, }; use eyre::eyre; -use config::op::Password; +use config::op::{self, Password}; use error::ParseErrorKind; -#[derive(Debug)] +#[derive(Debug, Hash, PartialEq, Eq)] enum IsSigning { No, @@ -30,18 +30,17 @@ impl Default for IsSigning } } -#[derive(Debug)] +#[derive(Debug, Hash, PartialEq, Eq)] enum KeyKind { - Autodetect, - RsaPublic, + Autodetect(IsSigning), + RsaPublic(IsSigning), RsaPrivate(IsSigning), // is signing key? Aes, } -#[derive(Debug)] -enum TranslationMode -{ +#[derive(Debug, Hash, PartialEq, Eq)] +enum TranslationMode { Autodetect, Encrypt, Decrypt, @@ -57,20 +56,35 @@ impl Default for TranslationMode } -#[derive(Debug)] +#[derive(Debug, Hash, PartialEq, Eq)] enum Atom { Key(KeyKind, String, Password), - NonSpecific, FileAuto(String), FileSpecific(String, String, TranslationMode), - //TODO: + SetMode(config::op::Mode), } +impl Atom +{ + pub fn hash_into(&self, map: &mut smallmap::Map) -> bool + { + use std::hash::{Hash,Hasher,}; + let hasher = std::collections::hash_map::DefaultHasher::new(); + self.hash(&mut hasher); + let vl = hasher.finish(); + if map.contains_key(&vl) { + true + } else { + map.insert(hasher.finish(),()); + false + } + } +} #[instrument] -pub async fn parse + std::fmt::Debug>(args: I) -> Result +pub async fn parse + std::fmt::Debug>(args: I) -> Result { let (mut tx, mut rx) = mpsc::channel(1); @@ -89,13 +103,50 @@ pub async fn parse + std::fmt::Debug>(args: I) -> R "--stat" => todo!(), _ => { let handler = tokio::spawn(async move { - //TODO: What container type do we make for this? + let mut output = op::Normal::default(); + let mut had = smallmap::Map::new(); while let Some(atom) = rx.recv().await { debug!("[Normal] recv atom: {:?}", atom); // Construct `Normal` with atoms + + if Atom::hash_into(&atom, &mut had) { + return Err(error::ConstructError::AlreadyExists(format!("TODO: {:?}", atom))); + } + + match atom { + Atom::NonSpecific => output.in_place = true, + Atom::SetMode(mode) => output.mode = Some(mode), + Atom::FileAuto(file) => output.files.push((file, None, None)), + Atom::FileSpecific(finput, foutput, mode) => { + let mode = match mode { + TranslationMode::Autodetect => resolve::find_file_mode(&finput).await?, + TranslationMode::Encrypt => op::Mode::Encrypt, + TranslationMode::Decrypt => op::Mode::Decrypt, + }; + output.files.push((finput, Some(foutput), Some(mode))); + }, + Atom::Key(kind, string, password) => { + let (kind, sign) = match kind { + KeyKind::Autodetect(s) => (resolve::find_key_mode(&string).await?, s), + KeyKind::RsaPrivate(s) => (config::KeyKind::RsaPrivate, s), + KeyKind::RsaPublic(s) => (config::KeyKind::RsaPublic, s), + KeyKind::Aes => (config::KeyKind::Aes, Default::default()), + }; + if sign != IsSigning::No && kind == config::KeyKind::Aes { + warn!("Key was detected to not be RSA, option to sign is set and ignored."); + } else { + output.sign.push((string.clone(), password.clone())); + } + match kind { + config::KeyKind::Aes => output.aes.push((string, password)), + config::KeyKind::RsaPublic => output.rsa.push((string, password)), + config::KeyKind::RsaPrivate => output.rsa.push((string, password)) + } + }, + } } - todo!() - }); + Ok(config::Operation::Normal(output)) + }.instrument(tracing::info_span!("handler"))); match parse_normal(std::iter::once(arg) .chain(args.map(Into::into)), &mut tx).await { @@ -119,12 +170,11 @@ pub async fn parse + std::fmt::Debug>(args: I) -> R .wrap_err_with(|| eyre!("Failed to construct operation from arguments")) .with_note(|| "In constructing of operation from spec"); }, - Ok(result) => { - + Ok(operation) => { + //TODO: Validate operation here? + Ok(operation) }, } - - todo!() } async fn parse_normal>(args: I, atoms: &mut mpsc::Sender) -> Result<(), error::Error> @@ -132,7 +182,7 @@ async fn parse_normal>(args: I, atoms: &mut mpsc::S let mut args = args.into_iter(); let mut reading=true; - + let mut mode_set=false; while let Some(arg) = args.next() { @@ -146,7 +196,27 @@ async fn parse_normal>(args: I, atoms: &mut mpsc::S } if reading && arg.starts_with("-") { let mut opt = arg.chars().skip(1); + + macro_rules! check_mode_set + { + () => { + if mode_set { + return Err((arg, error::ParseErrorKind::ModeSet).into()); + } else { + mode_set=true; + } + } + } match opt.next() { + Some('a') => check_mode_set!(), + Some('e') => { + check_mode_set!(); + atoms.send(Atom::SetMode(config::op::Mode::Encrypt)).await?; + }, + Some('d') => { + check_mode_set!(); + atoms.send(Atom::SetMode(config::op::Mode::Decrypt)).await?; + }, Some('i') => match opt.next() { None => atoms.send(Atom::NonSpecific).await?, Some(r) => return Err((ParseErrorKind::BadTail('i', iter::once(r).chain(opt).collect()), arg).swap().into()), @@ -238,8 +308,8 @@ async fn parse_normal>(args: I, atoms: &mut mpsc::S } let kind = match kind { - KeySpec::Autodetect => KeyKind::Autodetect, - KeySpec::RsaPublic => KeyKind::RsaPublic, + KeySpec::Autodetect => KeyKind::Autodetect(signing), + KeySpec::RsaPublic => KeyKind::RsaPublic(signing), KeySpec::RsaPrivate => KeyKind::RsaPrivate(signing), KeySpec::Aes => KeyKind::Aes, }; diff --git a/src/config.rs b/src/config.rs index 2fefc80..2e01a9c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -6,28 +6,19 @@ pub mod op { /// The crypt mode #[derive(Debug, PartialEq, Eq, Clone, Hash)] pub enum Mode { - /// Detect based on file-type - Autodetect, Encrypt, Decrypt, } - impl Default for Mode - { - #[inline] - fn default() -> Self - { - Mode::Autodetect - } - } #[derive(Debug, Clone,PartialEq, Eq, Default)] pub struct Normal { pub rsa: Vec<(String, Password)>, pub sign: Vec<(String, Password)>, pub aes: Vec<(String, Password)>, - pub mode: Mode, - - pub files: Vec<(String, Option)>, + pub in_place: bool, + + pub mode: Option,// `None` is autodetect mode per file + pub files: Vec<(String, Option, Option /* `None` is use global*/)>, } #[derive(Debug, Clone,PartialEq, Eq)] @@ -92,3 +83,11 @@ pub enum Operation KeyInfo(Vec<(String, op::Password)>), Help, } + +#[derive(Debug, Clone,PartialEq, Eq)] +pub enum KeyKind +{ + RsaPublic, + RsaPrivate, + Aes, +} diff --git a/src/main.rs b/src/main.rs index 7cd6ef8..57beee1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,6 +15,7 @@ use color_eyre::{ }; use lazy_static::lazy_static; use serde::{Serialize, Deserialize}; +use tracing_futures::Instrument; pub const CURRENT_VERSION: version::Version = version::Version::new(0,0,0,version::Tag::Prerelease); @@ -22,6 +23,7 @@ mod ext; use ext::*; mod version; mod config; +mod resolve; mod args; /*/// Dispatch params operations that can be handled at top level (i.e. `Help`) diff --git a/src/resolve.rs b/src/resolve.rs new file mode 100644 index 0000000..c90e3e2 --- /dev/null +++ b/src/resolve.rs @@ -0,0 +1,37 @@ +//! Used for resolving autodetects +use super::*; +use std::{ + path::{ + Path, + }, + error, + fmt, +}; + +pub async fn find_file_mode>(path: P) -> Result +{ + //TODO: we need to calculate mode here + todo!() +} + +pub async fn find_key_mode>(path: P) -> Result +{ + //TODO: we need to calculate mode here + todo!() +} + +#[derive(Debug)] +#[non_exhaustive] +pub enum Error +{ + +} + +impl error::Error for Error{} +impl fmt::Display for Error +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + Ok(()) + } +}