diff --git a/src/login.rs b/src/login.rs index ead6082..6cefcfe 100644 --- a/src/login.rs +++ b/src/login.rs @@ -130,6 +130,11 @@ fn do_login_impl( confirmation_methods ); + let is_device_confirmation_available = confirmation_methods.iter().any(|method| { + method.confirmation_type + == EAuthSessionGuardType::k_EAuthSessionGuardType_DeviceConfirmation + }); + for method in confirmation_methods { match method.confirmation_type { EAuthSessionGuardType::k_EAuthSessionGuardType_DeviceConfirmation => { @@ -151,9 +156,14 @@ fn do_login_impl( let prompt = if method.confirmation_type == EAuthSessionGuardType::k_EAuthSessionGuardType_DeviceCode { - "Enter the 2fa code from your device: " + if is_device_confirmation_available { + "Please confirm this login on your other device and press enter, OR\n" + } else { + "" + } + .to_string() + "Enter the 2fa code from your device: " } else { - "Enter the 2fa code sent to your email: " + "Enter the 2fa code sent to your email: ".to_string() }; let mut attempts = 0; loop { @@ -162,13 +172,23 @@ fn do_login_impl( let time = steamapi::get_server_time(transport.clone())?.server_time(); account.generate_code(time) } else { - tui::prompt_non_empty(prompt).trim().to_owned() + tui::prompt_allow_empty(&prompt).trim().to_owned() }; + if code.is_empty() { + if !is_device_confirmation_available { + error!("Code is empty. Please enter a valid code."); + continue; + } + break; + } + match login.submit_steam_guard_code(method.confirmation_type, code) { Ok(_) => break, Err(err) => { - error!("Failed to submit code: {}", err); + if !matches!(err, UpdateAuthSessionError::DuplicateRequest) { + error!("Failed to submit code: {}", err); + } match err { UpdateAuthSessionError::TooManyAttempts @@ -177,6 +197,10 @@ fn do_login_impl( error!("Error is unrecoverable. Aborting."); return Err(err.into()); } + UpdateAuthSessionError::DuplicateRequest => { + info!("Login was already approved."); + break; + } _ => {} } attempts += 1; diff --git a/src/tui.rs b/src/tui.rs index b7a6b40..9427b1b 100644 --- a/src/tui.rs +++ b/src/tui.rs @@ -34,6 +34,11 @@ pub(crate) fn prompt() -> String { line } +pub(crate) fn prompt_allow_empty(prompt_text: impl AsRef) -> String { + eprint!("{}", prompt_text.as_ref()); + prompt() +} + pub(crate) fn prompt_non_empty(prompt_text: impl AsRef) -> String { loop { eprint!("{}", prompt_text.as_ref()); diff --git a/steamguard/src/userlogin.rs b/steamguard/src/userlogin.rs index 9b358ff..5da3def 100644 --- a/steamguard/src/userlogin.rs +++ b/steamguard/src/userlogin.rs @@ -393,6 +393,8 @@ pub enum UpdateAuthSessionError { TooManyAttempts, SessionExpired, IncorrectSteamGuardCode, + /// This login session already was approved somewhere else. Polling should give you the tokens. + DuplicateRequest, UnknownEResult(EResult), TransportError(TransportError), NetworkFailure(reqwest::Error), @@ -413,6 +415,7 @@ impl From for UpdateAuthSessionError { EResult::RateLimitExceeded => UpdateAuthSessionError::TooManyAttempts, EResult::Expired => UpdateAuthSessionError::SessionExpired, EResult::TwoFactorCodeMismatch => UpdateAuthSessionError::IncorrectSteamGuardCode, + EResult::DuplicateRequest => UpdateAuthSessionError::DuplicateRequest, _ => UpdateAuthSessionError::UnknownEResult(err), } }