improve error handling in accountlinker
This commit is contained in:
parent
db2ec59c07
commit
298d29dc07
5 changed files with 57 additions and 43 deletions
21
Cargo.lock
generated
21
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue