improve error handling in accountlinker

This commit is contained in:
Carson McManus 2021-08-09 18:44:42 -04:00
parent db2ec59c07
commit 298d29dc07
5 changed files with 57 additions and 43 deletions

21
Cargo.lock generated
View file

@ -1625,6 +1625,7 @@ dependencies = [
"serde",
"serde_json",
"standback",
"thiserror",
"uuid",
]
@ -1781,6 +1782,26 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
[[package]]
name = "thiserror"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "thread_local"
version = "0.3.4"

View file

@ -9,8 +9,8 @@ use std::{
sync::{Arc, Mutex},
};
use steamguard::{
steamapi, AccountLinker, Confirmation, ConfirmationType, LoginError, SteamGuardAccount,
UserLogin, FinalizeLinkError
steamapi, AccountLinker, Confirmation, ConfirmationType, FinalizeLinkError, LoginError,
SteamGuardAccount, UserLogin,
};
use termion::{
event::{Event, Key},
@ -172,7 +172,7 @@ fn main() {
let sms_code = prompt();
let mut tries = 0;
loop {
match linker.finalize(&mut account, sms_code) {
match linker.finalize(&mut account, sms_code.clone()) {
Ok(_) => break,
Err(FinalizeLinkError::WantMore) => {
debug!("steam wants more 2fa codes (tries: {})", tries);
@ -182,7 +182,7 @@ fn main() {
break;
}
continue;
},
}
Err(err) => {
error!("Failed to finalize: {}", err);
break;

View file

@ -23,3 +23,4 @@ uuid = { version = "0.8", features = ["v4"] }
log = "0.4.14"
scraper = "0.12.0"
maplit = "1.0.2"
thiserror = "1.0.26"

View file

@ -1,9 +1,9 @@
use crate::{
steamapi::{AddAuthenticatorResponse, Session, SteamApiClient},
steamapi::{AddAuthenticatorResponse, Session, SteamApiClient, FinalizeAddAuthenticatorResponse},
SteamGuardAccount,
};
use log::*;
use std::error::Error;
use thiserror::Error;
use std::fmt::Display;
#[derive(Debug)]
@ -30,28 +30,27 @@ impl AccountLinker {
};
}
pub fn link(&mut self) -> anyhow::Result<SteamGuardAccount> {
ensure!(!self.finalized);
pub fn link(&mut self) -> anyhow::Result<SteamGuardAccount, AccountLinkError> {
let has_phone = self.client.has_phone()?;
if has_phone && !self.phone_number.is_empty() {
bail!(AccountLinkError::MustRemovePhoneNumber);
return Err(AccountLinkError::MustRemovePhoneNumber);
}
if !has_phone && self.phone_number.is_empty() {
bail!(AccountLinkError::MustProvidePhoneNumber);
return Err(AccountLinkError::MustProvidePhoneNumber);
}
if !has_phone {
if self.sent_confirmation_email {
if !self.client.check_email_confirmation()? {
bail!("Failed email confirmation check");
return Err(anyhow!("Failed email confirmation check"))?;
}
} else if !self.client.add_phone_number(self.phone_number.clone())? {
bail!("Failed to add phone number");
return Err(anyhow!("Failed to add phone number"))?;
} else {
self.sent_confirmation_email = true;
bail!(AccountLinkError::MustConfirmEmail);
return Err(AccountLinkError::MustConfirmEmail);
}
}
@ -60,7 +59,7 @@ impl AccountLinker {
match resp.status {
29 => {
bail!(AccountLinkError::AuthenticatorPresent);
return Err(AccountLinkError::AuthenticatorPresent);
}
1 => {
let mut account = resp.to_steam_guard_account();
@ -69,7 +68,7 @@ impl AccountLinker {
return Ok(account);
}
status => {
bail!("Unknown add authenticator status code: {}", status);
return Err(anyhow!("Unknown add authenticator status code: {}", status))?;
}
}
}
@ -79,30 +78,27 @@ impl AccountLinker {
&mut self,
account: &mut SteamGuardAccount,
sms_code: String,
) -> anyhow::Result<()> {
ensure!(!account.fully_enrolled);
ensure!(!self.finalized);
) -> anyhow::Result<(), FinalizeLinkError> {
let time = crate::steamapi::get_server_time();
let code = account.generate_code(time);
let resp = self
let resp: FinalizeAddAuthenticatorResponse = self
.client
.finalize_authenticator(sms_code.clone(), code, time)?;
info!("finalize response status: {}", resp.status);
match resp.status {
89 => {
bail!(FinalizeLinkError::BadSmsCode);
return Err(FinalizeLinkError::BadSmsCode);
}
_ => {}
}
if !resp.success {
bail!("Failed to finalize authenticator. Status: {}", resp.status);
return Err(FinalizeLinkError::Failure { status: resp.status })?;
}
if resp.want_more {
bail!(FinalizeLinkError::WantMore);
return Err(FinalizeLinkError::WantMore);
}
self.finalized = true;
@ -115,38 +111,35 @@ fn generate_device_id() -> String {
return format!("android:{}", uuid::Uuid::new_v4().to_string());
}
#[derive(Debug)]
#[derive(Error, Debug)]
pub enum AccountLinkError {
/// No phone number on the account
#[error("A phone number is needed, but not already present on the account.")]
MustProvidePhoneNumber,
/// A phone number is already on the account
#[error("A phone number was provided, but one is already present on the account.")]
MustRemovePhoneNumber,
/// User need to click link from confirmation email
#[error("An email has been sent to the user's email, click the link in that email.")]
MustConfirmEmail,
/// Must provide an SMS code
#[error("Awaiting finalization")]
AwaitingFinalization,
#[error("Authenticator is already present.")]
AuthenticatorPresent,
#[error(transparent)]
Unknown(#[from] anyhow::Error),
}
impl Display for AccountLinkError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
write!(f, "{:?}", self)
}
}
impl Error for AccountLinkError {}
#[derive(Debug)]
#[derive(Error, Debug)]
pub enum FinalizeLinkError {
#[error("Provided SMS code was incorrect.")]
BadSmsCode,
/// Steam wants more 2fa codes to verify that we can generate valid codes. Call finalize again.
#[error("Steam wants more 2fa codes for verification.")]
WantMore,
#[error("Finalization was not successful. Status code {status:?}")]
Failure{ status: i32 },
#[error(transparent)]
Unknown(#[from] anyhow::Error),
}
impl Display for FinalizeLinkError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
write!(f, "{:?}", self)
}
}
impl Error for FinalizeLinkError {}

View file

@ -1,4 +1,4 @@
pub use accountlinker::{AccountLinkError, AccountLinker};
pub use accountlinker::{AccountLinkError, AccountLinker, FinalizeLinkError};
use anyhow::Result;
pub use confirmation::{Confirmation, ConfirmationType};
use hmacsha1::hmac_sha1;
@ -11,7 +11,6 @@ use reqwest::{
use scraper::{Html, Selector};
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, convert::TryInto};
pub use steamapi::AddAuthenticatorResponse;
pub use userlogin::{LoginError, UserLogin};
#[macro_use]
extern crate lazy_static;