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.
302 lines
7.2 KiB
302 lines
7.2 KiB
//! Arg parsing
|
|
#![allow(unused_macros)]
|
|
use super::*;
|
|
use tokio::{
|
|
sync::{
|
|
mpsc,
|
|
},
|
|
};
|
|
use std::{
|
|
iter,
|
|
};
|
|
use eyre::eyre;
|
|
use config::op::Password;
|
|
use error::ParseErrorKind;
|
|
|
|
#[derive(Debug)]
|
|
enum IsSigning
|
|
{
|
|
No,
|
|
Yes,
|
|
Only,
|
|
}
|
|
|
|
impl Default for IsSigning
|
|
{
|
|
#[inline]
|
|
fn default() -> Self
|
|
{
|
|
Self::No
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
enum KeyKind
|
|
{
|
|
Autodetect,
|
|
RsaPublic,
|
|
RsaPrivate(IsSigning), // is signing key?
|
|
Aes,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
enum TranslationMode
|
|
{
|
|
Autodetect,
|
|
Encrypt,
|
|
Decrypt,
|
|
}
|
|
|
|
impl Default for TranslationMode
|
|
{
|
|
#[inline]
|
|
fn default() -> Self
|
|
{
|
|
Self::Autodetect
|
|
}
|
|
}
|
|
|
|
|
|
#[derive(Debug)]
|
|
enum Atom
|
|
{
|
|
Key(KeyKind, String, Password),
|
|
|
|
NonSpecific,
|
|
FileAuto(String),
|
|
FileSpecific(String, String, TranslationMode),
|
|
//TODO:
|
|
}
|
|
|
|
|
|
#[instrument]
|
|
pub async fn parse<I: IntoIterator<Item=String> + std::fmt::Debug>(args: I) -> Result<!/* TODO: What type do we make for this? */, eyre::Report>
|
|
{
|
|
let (mut tx, mut rx) = mpsc::channel(1);
|
|
|
|
macro_rules! unwrap_handler {
|
|
($handler:expr) => ($handler.await
|
|
.wrap_err_with(|| eyre!("Atom parser panicked")
|
|
.with_warning(|| "This usually indicates a bug in the program, not invalid input.")));
|
|
}
|
|
|
|
let mut args = args.into_iter();
|
|
let handler = if let Some(arg) = args.next()
|
|
{
|
|
match arg.to_lowercase().trim() {
|
|
"--generate" => todo!(),
|
|
"--help" => todo!(),
|
|
"--stat" => todo!(),
|
|
_ => {
|
|
let handler = tokio::spawn(async move {
|
|
//TODO: What container type do we make for this?
|
|
while let Some(atom) = rx.recv().await {
|
|
debug!("[Normal] recv atom: {:?}", atom);
|
|
// Construct `Normal` with atoms
|
|
}
|
|
todo!()
|
|
});
|
|
match parse_normal(std::iter::once(arg)
|
|
.chain(args.map(Into::into)), &mut tx).await
|
|
{
|
|
// The `handler` has dropped `rx` and returned an error, let unwrap_handler down there handle this.
|
|
Err(error::Error::AtomInternal) => Ok(()),
|
|
other => other,
|
|
}
|
|
.with_note(|| "In parsing of normal operation spec")?;
|
|
|
|
|
|
handler
|
|
},
|
|
}
|
|
} else {
|
|
return Err(eyre!("No arguments specified"));
|
|
};
|
|
|
|
match unwrap_handler!(handler)? {
|
|
Err(error) => {
|
|
return Err(error)
|
|
.wrap_err_with(|| eyre!("Failed to construct operation from arguments"))
|
|
.with_note(|| "In constructing of operation from spec");
|
|
},
|
|
Ok(result) => {
|
|
|
|
},
|
|
}
|
|
|
|
todo!()
|
|
}
|
|
|
|
async fn parse_normal<I: IntoIterator<Item=String>>(args: I, atoms: &mut mpsc::Sender<Atom>) -> Result<(), error::Error>
|
|
{
|
|
let mut args = args.into_iter();
|
|
let mut reading=true;
|
|
|
|
|
|
while let Some(arg) = args.next()
|
|
{
|
|
|
|
macro_rules! take_one {
|
|
($msg:literal $($tt:tt)*) => {
|
|
match args.next() {
|
|
Some(v) => v,
|
|
None => return Err((arg, ParseErrorKind::ExpectedArg(format!($msg $($tt)*))).into()),
|
|
}
|
|
}
|
|
}
|
|
if reading && arg.starts_with("-") {
|
|
let mut opt = arg.chars().skip(1);
|
|
match opt.next() {
|
|
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()),
|
|
},
|
|
Some('t') => {
|
|
let input = take_one!("t: Expected input file");
|
|
let output = take_one!("t: Expected output file");
|
|
let mut trans = TranslationMode::default();
|
|
|
|
let mut had = smallmap::Map::new();
|
|
while let Some(opt) = opt.next() {
|
|
if (had.contains_key(&opt), had.insert(opt, ())).0 {
|
|
// arg has been repeated, not allowed
|
|
return Err((arg, error::ParseErrorKind::NotUnique(opt)).into());
|
|
}
|
|
macro_rules! check_combine {
|
|
($($chars:expr),+) => {
|
|
$(if had.contains_key(&$chars) {
|
|
return Err(error::Error::from((arg, error::ParseErrorKind::CannotCombine(opt, $chars))));
|
|
})*
|
|
};
|
|
}
|
|
|
|
match opt {
|
|
'e' => trans= TranslationMode::Encrypt,
|
|
'd' => trans= TranslationMode::Decrypt,
|
|
_ => return Err((arg, error::ParseErrorKind::UnknownOptionFor('t', opt)).into()),
|
|
}
|
|
}
|
|
atoms.send(Atom::FileSpecific(input, output, trans)).await?;
|
|
},
|
|
Some('k') => {
|
|
let key_file = take_one!("k: Expected a key file");
|
|
enum KeySpec {
|
|
Autodetect,
|
|
RsaPrivate,
|
|
RsaPublic,
|
|
Aes,
|
|
}
|
|
let mut kind = KeySpec::Autodetect;
|
|
let mut password = Password::default();
|
|
let mut signing = IsSigning::default();
|
|
|
|
let mut had = smallmap::Map::new();
|
|
while let Some(opt) = opt.next() {
|
|
if (had.contains_key(&opt), had.insert(opt, ())).0 {
|
|
// arg has been repeated, not allowed
|
|
return Err((arg, error::ParseErrorKind::NotUnique(opt)).into());
|
|
}
|
|
macro_rules! check_combine {
|
|
($($chars:expr),+) => {
|
|
$(if had.contains_key(&$chars) {
|
|
return Err(error::Error::from((arg, error::ParseErrorKind::CannotCombine(opt, $chars))));
|
|
})*
|
|
};
|
|
}
|
|
|
|
match opt {
|
|
'R' => {
|
|
check_combine!['r','a'];
|
|
kind = KeySpec::RsaPrivate;
|
|
},
|
|
'r' => {
|
|
check_combine!['R','a'];
|
|
kind = KeySpec::RsaPublic;
|
|
},
|
|
'a' => {
|
|
check_combine!['r','R'];
|
|
kind = KeySpec::Aes;
|
|
},
|
|
'P' => {
|
|
check_combine!['p'];
|
|
password= Password::Yes;
|
|
},
|
|
'p' => {
|
|
check_combine!['P'];
|
|
password = Password::Specific(take_one!("P: Expected a password"));
|
|
},
|
|
'S' => {
|
|
check_combine!['s', 'a'];
|
|
signing = IsSigning::Only;
|
|
},
|
|
's' => {
|
|
check_combine!['S', 'a'];
|
|
signing = IsSigning::Yes;
|
|
},
|
|
_ => return Err((arg, error::ParseErrorKind::UnknownOptionFor('k', opt)).into()),
|
|
}
|
|
}
|
|
|
|
let kind = match kind {
|
|
KeySpec::Autodetect => KeyKind::Autodetect,
|
|
KeySpec::RsaPublic => KeyKind::RsaPublic,
|
|
KeySpec::RsaPrivate => KeyKind::RsaPrivate(signing),
|
|
KeySpec::Aes => KeyKind::Aes,
|
|
};
|
|
atoms.send(Atom::Key(kind, key_file, password)).await?;
|
|
},
|
|
Some(unknown) => return Err((arg, error::ParseErrorKind::UnknownOption(unknown)).into()),
|
|
None => reading=false,
|
|
}
|
|
} else {
|
|
reading=false;
|
|
atoms.send(Atom::FileAuto(arg)).await?;
|
|
}
|
|
}
|
|
todo!()
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
#[instrument]
|
|
pub fn parse<T: Into<String>, I: IntoIterator<Item = T> + std::fmt::Debug>(args: I) -> Result<Spec, eyre::Report>
|
|
{
|
|
let mut args = args.into_iter();
|
|
if let Some(arg) = args.next()
|
|
{
|
|
let arg =arg.into();
|
|
match arg.to_lowercase().trim() {
|
|
"--generate" => Ok(Spec::Concrete(config::Operation::GenerateKey(parse_keygen(args.map(Into::into))
|
|
.with_note(|| "Mode was `--generate`")?))),
|
|
"--help" => Ok(Spec::Concrete(config::Operation::Help)),
|
|
"--stat" => Ok(Spec::Concrete(config::Operation::KeyInfo(parse_stat(args.map(Into::into))
|
|
.with_note(|| "Mode was `--stat")?))),
|
|
_ => Ok(parse_normal(std::iter::once(arg)
|
|
.chain(args.map(Into::into)))
|
|
.with_note(|| "Mode was crypt")?.into()),
|
|
}
|
|
} else {
|
|
Err(eyre!("No arguments specified"))
|
|
}
|
|
}
|
|
|
|
fn parse_normal<I: IntoIterator<Item = String>>(args: I) -> Result<OperationSpec, eyre::Report>
|
|
{
|
|
todo!()
|
|
}
|
|
|
|
|
|
fn parse_keygen<I: IntoIterator<Item = String>>(args: I) -> Result<config::op::GenerateKey, eyre::Report>
|
|
{
|
|
todo!()
|
|
}
|
|
|
|
|
|
fn parse_stat<I: IntoIterator<Item = String>>(args: I) -> Result<Vec<(String, config::op::Password)>, eyre::Report>
|
|
{
|
|
todo!()
|
|
}
|
|
*/
|