move args definitions to new file

This commit is contained in:
Carson McManus 2022-06-19 10:48:18 -04:00
parent b55df7ea26
commit 14d49d33b1
2 changed files with 171 additions and 170 deletions

134
src/cli.rs Normal file
View file

@ -0,0 +1,134 @@
use std::str::FromStr;
use clap::Parser;
#[derive(Debug, Clone, Parser)]
#[clap(author, version, about = "Generate Steam 2FA codes and confirm Steam trades from the command line.", long_about = None)]
pub(crate) struct Args {
#[clap(short, long, help = "Steam username, case-sensitive.", long_help = "Select the account you want by steam username. Case-sensitive. By default, the first account in the manifest is selected.")]
pub username: Option<String>,
#[clap(short, long, help = "Select all accounts in the manifest.")]
pub all: bool,
/// The path to the maFiles directory.
#[clap(short, long, default_value = "~/.config/steamguard-cli/maFiles", help = "Specify which folder your maFiles are in. This should be a path to a folder that contains manifest.json.")]
pub mafiles_path: String,
#[clap(short, long, help = "Specify your encryption passkey.")]
pub passkey: Option<String>,
#[clap(short, long, default_value_t=Verbosity::Info, help = "Set the log level.")]
pub verbosity: Verbosity,
#[clap(subcommand)]
pub sub: Option<Subcommands>,
}
#[derive(Debug, Clone, Parser)]
pub(crate) enum Subcommands {
Debug {
#[clap(long)]
demo_conf_menu: bool
},
// Completions {
// TODO: Add completions
// },
#[clap(about = "Interactive interface for trade confirmations")]
Trade {
#[clap(short, long, help = "Accept all open trade confirmations. Does not open interactive interface.")]
accept_all: bool,
#[clap(short, long, help = "If submitting a confirmation response fails, exit immediately.")]
fail_fast: bool,
},
#[clap(about = "Set up a new account with steamguard-cli")]
Setup {
#[clap(short, long, from_global, help = "Steam username, case-sensitive.")]
username: Option<String>,
},
#[clap(about = "Import an account with steamguard already set up")]
Import {
#[clap(long, help = "Paths to one or more maFiles, eg. \"./gaben.maFile\"")]
files: Vec<String>,
},
#[clap(about = "Remove the authenticator from an account.")]
Remove {
#[clap(short, long, from_global, help = "Steam username, case-sensitive.")]
username: String,
},
#[clap(about = "Encrypt all maFiles")]
Encrypt,
#[clap(about = "Decrypt all maFiles")]
Decrypt,
}
#[derive(Debug, Clone, Copy)]
pub(crate) enum Verbosity {
Error = 0,
Warn = 1,
Info = 2,
Debug = 3,
Trace = 4,
}
impl std::fmt::Display for Verbosity {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("{}", match self {
Verbosity::Error => "error",
Verbosity::Warn => "warn",
Verbosity::Info => "info",
Verbosity::Debug => "debug",
Verbosity::Trace => "trace",
}))
}
}
impl FromStr for Verbosity {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"error" => Ok(Verbosity::Error),
"warn" => Ok(Verbosity::Warn),
"info" => Ok(Verbosity::Info),
"debug" => Ok(Verbosity::Debug),
"trace" => Ok(Verbosity::Trace),
_ => Err(anyhow!("Invalid verbosity level: {}", s)),
}
}
}
pub(crate) struct ArgsSetup {
pub username: Option<String>,
}
impl From<Subcommands> for ArgsSetup {
fn from(sub: Subcommands) -> Self {
match sub {
Subcommands::Setup { username } => Self { username },
_ => panic!("ArgsSetup::from() called with non-Setup subcommand"),
}
}
}
pub(crate) struct ArgsImport {
pub files: Vec<String>,
}
impl From<Subcommands> for ArgsImport {
fn from(sub: Subcommands) -> Self {
match sub {
Subcommands::Import { files } => Self { files },
_ => panic!("ArgsImport::from() called with non-Import subcommand"),
}
}
}
pub(crate) struct ArgsTrade {
pub accept_all: bool,
pub fail_fast: bool,
}
impl From<Subcommands> for ArgsTrade {
fn from(sub: Subcommands) -> Self {
match sub {
Subcommands::Trade { accept_all, fail_fast } => Self { accept_all, fail_fast },
_ => panic!("ArgsTrade::from() called with non-Trade subcommand"),
}
}
}

View file

@ -1,7 +1,6 @@
extern crate rpassword; extern crate rpassword;
use clap::{crate_version, App, Arg, ArgMatches, Parser, Subcommand}; use clap::{crate_version, App, Arg, ArgMatches, Parser, Subcommand};
use log::*; use log::*;
use std::str::FromStr;
use std::{ use std::{
io::{stdout, Write}, io::{stdout, Write},
path::Path, path::Path,
@ -24,143 +23,12 @@ extern crate dirs;
extern crate proptest; extern crate proptest;
extern crate ring; extern crate ring;
mod accountmanager; mod accountmanager;
mod cli;
mod demos; mod demos;
mod encryption; mod encryption;
mod errors; mod errors;
mod tui; mod tui;
#[derive(Debug, Clone, Parser)]
#[clap(author, version, about = "Generate Steam 2FA codes and confirm Steam trades from the command line.", long_about = None)]
struct Args {
#[clap(short, long, help = "Steam username, case-sensitive.", long_help = "Select the account you want by steam username. Case-sensitive. By default, the first account in the manifest is selected.")]
username: Option<String>,
#[clap(short, long, help = "Select all accounts in the manifest.")]
all: bool,
/// The path to the maFiles directory.
#[clap(short, long, default_value = "~/.config/steamguard-cli/maFiles", help = "Specify which folder your maFiles are in. This should be a path to a folder that contains manifest.json.")]
mafiles_path: String,
#[clap(short, long, help = "Specify your encryption passkey.")]
passkey: Option<String>,
#[clap(short, long, default_value_t=Verbosity::Info, help = "Set the log level.")]
verbosity: Verbosity,
#[clap(subcommand)]
sub: Option<Subcommands>,
}
#[derive(Debug, Clone, Parser)]
enum Subcommands {
Debug {
#[clap(long)]
demo_conf_menu: bool
},
// Completions {
// TODO: Add completions
// },
#[clap(about = "Interactive interface for trade confirmations")]
Trade {
#[clap(short, long, help = "Accept all open trade confirmations. Does not open interactive interface.")]
accept_all: bool,
#[clap(short, long, help = "If submitting a confirmation response fails, exit immediately.")]
fail_fast: bool,
},
#[clap(about = "Set up a new account with steamguard-cli")]
Setup {
#[clap(short, long, from_global, help = "Steam username, case-sensitive.")]
username: Option<String>,
},
#[clap(about = "Import an account with steamguard already set up")]
Import {
#[clap(long, help = "Paths to one or more maFiles, eg. \"./gaben.maFile\"")]
files: Vec<String>,
},
#[clap(about = "Remove the authenticator from an account.")]
Remove {
#[clap(short, long, from_global, help = "Steam username, case-sensitive.")]
username: String,
},
#[clap(about = "Encrypt all maFiles")]
Encrypt,
#[clap(about = "Decrypt all maFiles")]
Decrypt,
}
#[derive(Debug, Clone, Copy)]
enum Verbosity {
Error = 0,
Warn = 1,
Info = 2,
Debug = 3,
Trace = 4,
}
impl std::fmt::Display for Verbosity {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("{}", match self {
Verbosity::Error => "error",
Verbosity::Warn => "warn",
Verbosity::Info => "info",
Verbosity::Debug => "debug",
Verbosity::Trace => "trace",
}))
}
}
impl FromStr for Verbosity {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"error" => Ok(Verbosity::Error),
"warn" => Ok(Verbosity::Warn),
"info" => Ok(Verbosity::Info),
"debug" => Ok(Verbosity::Debug),
"trace" => Ok(Verbosity::Trace),
_ => Err(anyhow!("Invalid verbosity level: {}", s)),
}
}
}
struct ArgsSetup {
username: Option<String>,
}
impl From<Subcommands> for ArgsSetup {
fn from(sub: Subcommands) -> Self {
match sub {
Subcommands::Setup { username } => Self { username },
_ => panic!("ArgsSetup::from() called with non-Setup subcommand"),
}
}
}
struct ArgsImport {
files: Vec<String>,
}
impl From<Subcommands> for ArgsImport {
fn from(sub: Subcommands) -> Self {
match sub {
Subcommands::Import { files } => Self { files },
_ => panic!("ArgsImport::from() called with non-Import subcommand"),
}
}
}
struct ArgsTrade {
accept_all: bool,
fail_fast: bool,
}
impl From<Subcommands> for ArgsTrade {
fn from(sub: Subcommands) -> Self {
match sub {
Subcommands::Trade { accept_all, fail_fast } => Self { accept_all, fail_fast },
_ => panic!("ArgsTrade::from() called with non-Trade subcommand"),
}
}
}
fn cli() -> App<'static> { fn cli() -> App<'static> {
App::new("steamguard-cli") App::new("steamguard-cli")
.version(crate_version!()) .version(crate_version!())
@ -276,7 +144,7 @@ fn main() {
} }
fn run() -> anyhow::Result<()> { fn run() -> anyhow::Result<()> {
let new_args = Args::parse(); let new_args = cli::Args::parse();
println!("{:?}", new_args); println!("{:?}", new_args);
let matches = cli().get_matches(); let matches = cli().get_matches();
@ -288,25 +156,23 @@ fn run() -> anyhow::Result<()> {
.init() .init()
.unwrap(); .unwrap();
if let Some(subcmd) = new_args.sub { match new_args.sub {
match subcmd { Some(cli::Subcommands::Debug{demo_conf_menu}) => {
Subcommand::Debug{demo_conf_menu} => { if demo_conf_menu {
if demo_conf_menu { demos::demo_confirmation_menu();
demos::demo_confirmation_menu(); }
} return Ok(());
return Ok(()); },
}, // Subcommand::Completions{shell} => {
// Subcommand::Completions{shell} => { // // cli().gen_completions_to(
// // cli().gen_completions_to( // // "steamguard",
// // "steamguard", // // Shell::from_str(completion_matches.value_of("shell").unwrap()).unwrap(),
// // Shell::from_str(completion_matches.value_of("shell").unwrap()).unwrap(), // // &mut std::io::stdout(),
// // &mut std::io::stdout(), // // );
// // ); // return Ok(());
// return Ok(()); // },
// }, _ => {},
_ => {}, };
};
}
let mafiles_dir = if matches.occurrences_of("mafiles-path") > 0 { let mafiles_dir = if matches.occurrences_of("mafiles-path") > 0 {
matches.value_of("mafiles-path").unwrap().into() matches.value_of("mafiles-path").unwrap().into()
@ -367,16 +233,14 @@ fn run() -> anyhow::Result<()> {
} }
} }
if let Some(subcmd) = new_args.sub { match new_args.sub {
match subcmd { Some(cli::Subcommands::Setup{ username }) => {
Subcommands::Setup{ username } => { do_subcmd_setup(new_args.sub.unwrap().into(), &mut manifest)?;
do_subcmd_setup(new_args.sub.unwrap().into(), &mut manifest)?; },
}, Some(cli::Subcommands::Import { files }) => {todo!()},
Subcommands::Import { files } => {todo!()}, Some(cli::Subcommands::Encrypt {}) => {todo!()},
Subcommands::Encrypt {} => {todo!()}, Some(cli::Subcommands::Decrypt {}) => {todo!()},
Subcommands::Decrypt {} => {todo!()}, _ => {},
_ => {},
}
} }
if matches.is_present("setup") { if matches.is_present("setup") {
@ -458,7 +322,7 @@ fn run() -> anyhow::Result<()> {
if let Some(subcmd) = new_args.sub { if let Some(subcmd) = new_args.sub {
match subcmd { match subcmd {
Subcommands::Trade{ accept_all, fail_fast } => { cli::Subcommands::Trade{ accept_all, fail_fast } => {
for a in selected_accounts.iter_mut() { for a in selected_accounts.iter_mut() {
let mut account = a.lock().unwrap(); let mut account = a.lock().unwrap();
@ -535,7 +399,7 @@ fn run() -> anyhow::Result<()> {
manifest.save()?; manifest.save()?;
}, },
Subcommands::Remove { username } => { cli::Subcommands::Remove { username } => {
println!( println!(
"This will remove the mobile authenticator from {} accounts: {}", "This will remove the mobile authenticator from {} accounts: {}",
selected_accounts.len(), selected_accounts.len(),
@ -735,13 +599,16 @@ fn get_mafiles_dir() -> String {
return paths[0].to_str().unwrap().into(); return paths[0].to_str().unwrap().into();
} }
fn do_subcmd_setup(args: ArgsSetup, manifest: &mut accountmanager::Manifest) -> anyhow::Result<()> { fn do_subcmd_setup(args: cli::ArgsSetup, manifest: &mut accountmanager::Manifest) -> anyhow::Result<()> {
println!("Log in to the account that you want to link to steamguard-cli"); println!("Log in to the account that you want to link to steamguard-cli");
print!("Username: "); print!("Username: ");
let username = args.username.unwrap_or(tui::prompt()); let username = if args.username.is_some() {
if args.username.is_some() { let u = args.username.unwrap();
println!("{}", username); println!("{}", u);
} u
} else {
tui::prompt()
};
let account_name = username.clone(); let account_name = username.clone();
if manifest.account_exists(&username) { if manifest.account_exists(&username) {
bail!( bail!(