From 357d04f34bf94a6e579e992a1a56053ded83b1db Mon Sep 17 00:00:00 2001 From: Carson McManus Date: Wed, 11 Aug 2021 19:39:29 -0400 Subject: [PATCH] add account removal, closes #10 --- src/accountmanager.rs | 10 ++++++++ src/main.rs | 53 +++++++++++++++++++++++++++++++++++++++++++ steamguard/src/lib.rs | 14 ++++++++++++ 3 files changed, 77 insertions(+) diff --git a/src/accountmanager.rs b/src/accountmanager.rs index 3e3e6bf..537b86d 100644 --- a/src/accountmanager.rs +++ b/src/accountmanager.rs @@ -66,6 +66,16 @@ impl Manifest { self.accounts.push(Arc::new(Mutex::new(account))); } + pub fn remove_account(&mut self, account_name: String) { + let index = self + .accounts + .iter() + .position(|a| a.lock().unwrap().account_name == account_name) + .unwrap(); + self.accounts.remove(index); + self.entries.remove(index); + } + pub fn save(&self) -> anyhow::Result<()> { ensure!( self.entries.len() == self.accounts.len(), diff --git a/src/main.rs b/src/main.rs index c7c028b..da21c34 100644 --- a/src/main.rs +++ b/src/main.rs @@ -85,6 +85,10 @@ fn main() { App::new("setup") .about("Set up a new account with steamguard-cli") ) + .subcommand( + App::new("remove") + .about("Remove the authenticator from an account.") + ) .subcommand( App::new("debug") .arg( @@ -298,6 +302,55 @@ fn main() { } manifest.save(); + } else if let Some(_) = matches.subcommand_matches("remove") { + println!( + "This will remove the mobile authenticator from {} accounts: {}", + selected_accounts.len(), + selected_accounts + .iter() + .map(|a| a.lock().unwrap().account_name.clone()) + .collect::>() + .join(", ") + ); + + print!("Do you want to continue? [yN] "); + match prompt().as_str() { + "y" => {} + _ => { + println!("Aborting!"); + return; + } + } + + let mut successful = vec![]; + for a in selected_accounts { + let account = a.lock().unwrap(); + match account.remove_authenticator(None) { + Ok(success) => { + if success { + println!("Removed authenticator from {}", account.account_name); + successful.push(account.account_name.clone()); + } else { + println!( + "Failed to remove authenticator from {}", + account.account_name + ); + } + } + Err(err) => { + println!( + "Unexpected error when removing authenticator from {}: {}", + account.account_name, err + ); + } + } + } + + for account_name in successful { + manifest.remove_account(account_name); + } + + manifest.save().expect("Failed to save manifest."); } else { let server_time = steamapi::get_server_time(); for account in selected_accounts { diff --git a/steamguard/src/lib.rs b/steamguard/src/lib.rs index b240f3e..a9b5403 100644 --- a/steamguard/src/lib.rs +++ b/steamguard/src/lib.rs @@ -11,6 +11,7 @@ use reqwest::{ use scraper::{Html, Selector}; use serde::{Deserialize, Serialize}; use std::{collections::HashMap, convert::TryInto}; +use steamapi::SteamApiClient; pub use userlogin::{LoginError, UserLogin}; #[macro_use] extern crate lazy_static; @@ -245,6 +246,19 @@ impl SteamGuardAccount { ensure!(resp.success); Ok(resp.html) } + + /// Removes the mobile authenticator from the steam account. If this operation succeeds, this object can no longer be considered valid. + /// Returns whether or not the operation was successful. + pub fn remove_authenticator(&self, revocation_code: Option) -> anyhow::Result { + ensure!( + matches!(revocation_code, Some(_)) || !self.revocation_code.is_empty(), + "Revocation code not provided." + ); + let client: SteamApiClient = SteamApiClient::new(self.session.clone()); + let resp = + client.remove_authenticator(revocation_code.unwrap_or(self.revocation_code.clone()))?; + Ok(resp.success) + } } fn parse_confirmations(text: String) -> anyhow::Result> {