add subcommand arg types
This commit is contained in:
parent
e6847975ff
commit
b55df7ea26
1 changed files with 288 additions and 246 deletions
310
src/main.rs
310
src/main.rs
|
@ -121,6 +121,46 @@ impl FromStr for Verbosity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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!())
|
||||||
|
@ -329,120 +369,18 @@ fn run() -> anyhow::Result<()> {
|
||||||
|
|
||||||
if let Some(subcmd) = new_args.sub {
|
if let Some(subcmd) = new_args.sub {
|
||||||
match subcmd {
|
match subcmd {
|
||||||
Subcommands::Setup{ username } => {},
|
Subcommands::Setup{ username } => {
|
||||||
s => {
|
do_subcmd_setup(new_args.sub.unwrap().into(), &mut manifest)?;
|
||||||
error!("Unknown subcommand: {:?}", s);
|
|
||||||
},
|
},
|
||||||
|
Subcommands::Import { files } => {todo!()},
|
||||||
|
Subcommands::Encrypt {} => {todo!()},
|
||||||
|
Subcommands::Decrypt {} => {todo!()},
|
||||||
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if matches.is_present("setup") {
|
if matches.is_present("setup") {
|
||||||
println!("Log in to the account that you want to link to steamguard-cli");
|
|
||||||
print!("Username: ");
|
|
||||||
let username = tui::prompt();
|
|
||||||
let account_name = username.clone();
|
|
||||||
if manifest.account_exists(&username) {
|
|
||||||
bail!(
|
|
||||||
"Account {} already exists in manifest, remove it first",
|
|
||||||
username
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let session =
|
|
||||||
do_login_raw(username).expect("Failed to log in. Account has not been linked.");
|
|
||||||
|
|
||||||
let mut linker = AccountLinker::new(session);
|
|
||||||
let account: SteamGuardAccount;
|
|
||||||
loop {
|
|
||||||
match linker.link() {
|
|
||||||
Ok(a) => {
|
|
||||||
account = a;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Err(AccountLinkError::MustRemovePhoneNumber) => {
|
|
||||||
println!("There is already a phone number on this account, please remove it and try again.");
|
|
||||||
bail!("There is already a phone number on this account, please remove it and try again.");
|
|
||||||
}
|
|
||||||
Err(AccountLinkError::MustProvidePhoneNumber) => {
|
|
||||||
println!("Enter your phone number in the following format: +1 123-456-7890");
|
|
||||||
print!("Phone number: ");
|
|
||||||
linker.phone_number = tui::prompt().replace(&['(', ')', '-'][..], "");
|
|
||||||
}
|
|
||||||
Err(AccountLinkError::AuthenticatorPresent) => {
|
|
||||||
println!("An authenticator is already present on this account.");
|
|
||||||
bail!("An authenticator is already present on this account.");
|
|
||||||
}
|
|
||||||
Err(AccountLinkError::MustConfirmEmail) => {
|
|
||||||
println!("Check your email and click the link.");
|
|
||||||
tui::pause();
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
error!(
|
|
||||||
"Failed to link authenticator. Account has not been linked. {}",
|
|
||||||
err
|
|
||||||
);
|
|
||||||
return Err(err.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
manifest.add_account(account);
|
|
||||||
match manifest.save() {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(err) => {
|
|
||||||
error!("Aborting the account linking process because we failed to save the manifest. This is really bad. Here is the error: {}", err);
|
|
||||||
println!(
|
|
||||||
"Just in case, here is the account info. Save it somewhere just in case!\n{:?}",
|
|
||||||
manifest.get_account(&account_name).unwrap().lock().unwrap()
|
|
||||||
);
|
|
||||||
return Err(err.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let account_arc = manifest.get_account(&account_name).unwrap();
|
|
||||||
let mut account = account_arc.lock().unwrap();
|
|
||||||
|
|
||||||
println!("Authenticator has not yet been linked. Before continuing with finalization, please take the time to write down your revocation code: {}", account.revocation_code);
|
|
||||||
tui::pause();
|
|
||||||
|
|
||||||
debug!("attempting link finalization");
|
|
||||||
print!("Enter SMS code: ");
|
|
||||||
let sms_code = tui::prompt();
|
|
||||||
let mut tries = 0;
|
|
||||||
loop {
|
|
||||||
match linker.finalize(&mut account, sms_code.clone()) {
|
|
||||||
Ok(_) => break,
|
|
||||||
Err(FinalizeLinkError::WantMore) => {
|
|
||||||
debug!("steam wants more 2fa codes (tries: {})", tries);
|
|
||||||
tries += 1;
|
|
||||||
if tries >= 30 {
|
|
||||||
error!("Failed to finalize: unable to generate valid 2fa codes");
|
|
||||||
bail!("Failed to finalize: unable to generate valid 2fa codes");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
error!("Failed to finalize: {}", err);
|
|
||||||
return Err(err.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("Authenticator finalized.");
|
|
||||||
match manifest.save() {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(err) => {
|
|
||||||
println!(
|
|
||||||
"Failed to save manifest, but we were able to save it before. {}",
|
|
||||||
err
|
|
||||||
);
|
|
||||||
return Err(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
println!(
|
|
||||||
"Authenticator has been finalized. Please actually write down your revocation code: {}",
|
|
||||||
account.revocation_code
|
|
||||||
);
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
} else if let Some(import_matches) = matches.subcommand_matches("import") {
|
} else if let Some(import_matches) = matches.subcommand_matches("import") {
|
||||||
for file_path in import_matches.values_of("files").unwrap() {
|
for file_path in import_matches.values_of("files").unwrap() {
|
||||||
match manifest.import_account(file_path.into()) {
|
match manifest.import_account(file_path.into()) {
|
||||||
|
@ -521,28 +459,6 @@ 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 } => {
|
Subcommands::Trade{ accept_all, fail_fast } => {
|
||||||
todo!()
|
|
||||||
},
|
|
||||||
s => {
|
|
||||||
error!("Unknown subcommand: {:?}", s);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let server_time = steamapi::get_server_time();
|
|
||||||
debug!("Time used to generate codes: {}", server_time);
|
|
||||||
for account in selected_accounts {
|
|
||||||
info!(
|
|
||||||
"Generating code for {}",
|
|
||||||
account.lock().unwrap().account_name
|
|
||||||
);
|
|
||||||
trace!("{:?}", account);
|
|
||||||
let code = account.lock().unwrap().generate_code(server_time);
|
|
||||||
println!("{}", code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(trade_matches) = matches.subcommand_matches("trade") {
|
|
||||||
info!("trade");
|
|
||||||
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();
|
||||||
|
|
||||||
|
@ -562,8 +478,7 @@ fn run() -> anyhow::Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut any_failed = false;
|
let mut any_failed = false;
|
||||||
let fail_fast = trade_matches.is_present("fail-fast");
|
if accept_all {
|
||||||
if trade_matches.is_present("accept-all") {
|
|
||||||
info!("accepting all confirmations");
|
info!("accepting all confirmations");
|
||||||
for conf in &confirmations {
|
for conf in &confirmations {
|
||||||
let result = account.accept_confirmation(conf);
|
let result = account.accept_confirmation(conf);
|
||||||
|
@ -619,7 +534,8 @@ fn run() -> anyhow::Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
manifest.save()?;
|
manifest.save()?;
|
||||||
} else if let Some(_) = matches.subcommand_matches("remove") {
|
},
|
||||||
|
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(),
|
||||||
|
@ -676,7 +592,25 @@ fn run() -> anyhow::Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
manifest.save()?;
|
manifest.save()?;
|
||||||
|
},
|
||||||
|
s => {
|
||||||
|
error!("Unknown subcommand: {:?}", s);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
let server_time = steamapi::get_server_time();
|
||||||
|
debug!("Time used to generate codes: {}", server_time);
|
||||||
|
for account in selected_accounts {
|
||||||
|
info!(
|
||||||
|
"Generating code for {}",
|
||||||
|
account.lock().unwrap().account_name
|
||||||
|
);
|
||||||
|
trace!("{:?}", account);
|
||||||
|
let code = account.lock().unwrap().generate_code(server_time);
|
||||||
|
println!("{}", code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -801,6 +735,114 @@ fn get_mafiles_dir() -> String {
|
||||||
return paths[0].to_str().unwrap().into();
|
return paths[0].to_str().unwrap().into();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_subcmd_setup(args: Subcommands) -> anyhow::Result<()> {
|
fn do_subcmd_setup(args: ArgsSetup, manifest: &mut accountmanager::Manifest) -> anyhow::Result<()> {
|
||||||
|
println!("Log in to the account that you want to link to steamguard-cli");
|
||||||
|
print!("Username: ");
|
||||||
|
let username = args.username.unwrap_or(tui::prompt());
|
||||||
|
if args.username.is_some() {
|
||||||
|
println!("{}", username);
|
||||||
|
}
|
||||||
|
let account_name = username.clone();
|
||||||
|
if manifest.account_exists(&username) {
|
||||||
|
bail!(
|
||||||
|
"Account {} already exists in manifest, remove it first",
|
||||||
|
username
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let session =
|
||||||
|
do_login_raw(username).expect("Failed to log in. Account has not been linked.");
|
||||||
|
|
||||||
|
let mut linker = AccountLinker::new(session);
|
||||||
|
let account: SteamGuardAccount;
|
||||||
|
loop {
|
||||||
|
match linker.link() {
|
||||||
|
Ok(a) => {
|
||||||
|
account = a;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Err(AccountLinkError::MustRemovePhoneNumber) => {
|
||||||
|
println!("There is already a phone number on this account, please remove it and try again.");
|
||||||
|
bail!("There is already a phone number on this account, please remove it and try again.");
|
||||||
|
}
|
||||||
|
Err(AccountLinkError::MustProvidePhoneNumber) => {
|
||||||
|
println!("Enter your phone number in the following format: +1 123-456-7890");
|
||||||
|
print!("Phone number: ");
|
||||||
|
linker.phone_number = tui::prompt().replace(&['(', ')', '-'][..], "");
|
||||||
|
}
|
||||||
|
Err(AccountLinkError::AuthenticatorPresent) => {
|
||||||
|
println!("An authenticator is already present on this account.");
|
||||||
|
bail!("An authenticator is already present on this account.");
|
||||||
|
}
|
||||||
|
Err(AccountLinkError::MustConfirmEmail) => {
|
||||||
|
println!("Check your email and click the link.");
|
||||||
|
tui::pause();
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
error!(
|
||||||
|
"Failed to link authenticator. Account has not been linked. {}",
|
||||||
|
err
|
||||||
|
);
|
||||||
|
return Err(err.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
manifest.add_account(account);
|
||||||
|
match manifest.save() {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(err) => {
|
||||||
|
error!("Aborting the account linking process because we failed to save the manifest. This is really bad. Here is the error: {}", err);
|
||||||
|
println!(
|
||||||
|
"Just in case, here is the account info. Save it somewhere just in case!\n{:?}",
|
||||||
|
manifest.get_account(&account_name).unwrap().lock().unwrap()
|
||||||
|
);
|
||||||
|
return Err(err.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let account_arc = manifest.get_account(&account_name).unwrap();
|
||||||
|
let mut account = account_arc.lock().unwrap();
|
||||||
|
|
||||||
|
println!("Authenticator has not yet been linked. Before continuing with finalization, please take the time to write down your revocation code: {}", account.revocation_code);
|
||||||
|
tui::pause();
|
||||||
|
|
||||||
|
debug!("attempting link finalization");
|
||||||
|
print!("Enter SMS code: ");
|
||||||
|
let sms_code = tui::prompt();
|
||||||
|
let mut tries = 0;
|
||||||
|
loop {
|
||||||
|
match linker.finalize(&mut account, sms_code.clone()) {
|
||||||
|
Ok(_) => break,
|
||||||
|
Err(FinalizeLinkError::WantMore) => {
|
||||||
|
debug!("steam wants more 2fa codes (tries: {})", tries);
|
||||||
|
tries += 1;
|
||||||
|
if tries >= 30 {
|
||||||
|
error!("Failed to finalize: unable to generate valid 2fa codes");
|
||||||
|
bail!("Failed to finalize: unable to generate valid 2fa codes");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
error!("Failed to finalize: {}", err);
|
||||||
|
return Err(err.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Authenticator finalized.");
|
||||||
|
match manifest.save() {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(err) => {
|
||||||
|
println!(
|
||||||
|
"Failed to save manifest, but we were able to save it before. {}",
|
||||||
|
err
|
||||||
|
);
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Authenticator has been finalized. Please actually write down your revocation code: {}",
|
||||||
|
account.revocation_code
|
||||||
|
);
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue