move args definitions to new file
This commit is contained in:
parent
b55df7ea26
commit
14d49d33b1
2 changed files with 171 additions and 170 deletions
134
src/cli.rs
Normal file
134
src/cli.rs
Normal 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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
207
src/main.rs
207
src/main.rs
|
@ -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!(
|
||||||
|
|
Loading…
Reference in a new issue