Skip to content

Commit

Permalink
feat(login): be able to handle DuplicateRequest errors more gracefully
Browse files Browse the repository at this point in the history
closes #390
  • Loading branch information
dyc3 committed Dec 19, 2024
1 parent e661314 commit de18ba0
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 4 deletions.
32 changes: 28 additions & 4 deletions src/login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@ fn do_login_impl<T: Transport + Clone>(
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 => {
Expand All @@ -151,9 +156,14 @@ fn do_login_impl<T: Transport + Clone>(
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 {
Expand All @@ -162,13 +172,23 @@ fn do_login_impl<T: Transport + Clone>(
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
Expand All @@ -177,6 +197,10 @@ fn do_login_impl<T: Transport + Clone>(
error!("Error is unrecoverable. Aborting.");
return Err(err.into());
}
UpdateAuthSessionError::DuplicateRequest => {
info!("Login was already approved.");
break;
}
_ => {}
}
attempts += 1;
Expand Down
5 changes: 5 additions & 0 deletions src/tui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ pub(crate) fn prompt() -> String {
line
}

pub(crate) fn prompt_allow_empty(prompt_text: impl AsRef<str>) -> String {
eprint!("{}", prompt_text.as_ref());
prompt()
}

pub(crate) fn prompt_non_empty(prompt_text: impl AsRef<str>) -> String {
loop {
eprint!("{}", prompt_text.as_ref());
Expand Down
3 changes: 3 additions & 0 deletions steamguard/src/userlogin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -413,6 +415,7 @@ impl From<EResult> for UpdateAuthSessionError {
EResult::RateLimitExceeded => UpdateAuthSessionError::TooManyAttempts,
EResult::Expired => UpdateAuthSessionError::SessionExpired,
EResult::TwoFactorCodeMismatch => UpdateAuthSessionError::IncorrectSteamGuardCode,
EResult::DuplicateRequest => UpdateAuthSessionError::DuplicateRequest,
_ => UpdateAuthSessionError::UnknownEResult(err),
}
}
Expand Down

0 comments on commit de18ba0

Please sign in to comment.