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",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"standback",
|
"standback",
|
||||||
|
"thiserror",
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1781,6 +1782,26 @@ version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
|
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]]
|
[[package]]
|
||||||
name = "thread_local"
|
name = "thread_local"
|
||||||
version = "0.3.4"
|
version = "0.3.4"
|
||||||
|
|
|
@ -9,8 +9,8 @@ use std::{
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
use steamguard::{
|
use steamguard::{
|
||||||
steamapi, AccountLinker, Confirmation, ConfirmationType, LoginError, SteamGuardAccount,
|
steamapi, AccountLinker, Confirmation, ConfirmationType, FinalizeLinkError, LoginError,
|
||||||
UserLogin, FinalizeLinkError
|
SteamGuardAccount, UserLogin,
|
||||||
};
|
};
|
||||||
use termion::{
|
use termion::{
|
||||||
event::{Event, Key},
|
event::{Event, Key},
|
||||||
|
@ -172,7 +172,7 @@ fn main() {
|
||||||
let sms_code = prompt();
|
let sms_code = prompt();
|
||||||
let mut tries = 0;
|
let mut tries = 0;
|
||||||
loop {
|
loop {
|
||||||
match linker.finalize(&mut account, sms_code) {
|
match linker.finalize(&mut account, sms_code.clone()) {
|
||||||
Ok(_) => break,
|
Ok(_) => break,
|
||||||
Err(FinalizeLinkError::WantMore) => {
|
Err(FinalizeLinkError::WantMore) => {
|
||||||
debug!("steam wants more 2fa codes (tries: {})", tries);
|
debug!("steam wants more 2fa codes (tries: {})", tries);
|
||||||
|
@ -182,7 +182,7 @@ fn main() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
},
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("Failed to finalize: {}", err);
|
error!("Failed to finalize: {}", err);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -23,3 +23,4 @@ uuid = { version = "0.8", features = ["v4"] }
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
scraper = "0.12.0"
|
scraper = "0.12.0"
|
||||||
maplit = "1.0.2"
|
maplit = "1.0.2"
|
||||||
|
thiserror = "1.0.26"
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
steamapi::{AddAuthenticatorResponse, Session, SteamApiClient},
|
steamapi::{AddAuthenticatorResponse, Session, SteamApiClient, FinalizeAddAuthenticatorResponse},
|
||||||
SteamGuardAccount,
|
SteamGuardAccount,
|
||||||
};
|
};
|
||||||
use log::*;
|
use log::*;
|
||||||
use std::error::Error;
|
use thiserror::Error;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -30,28 +30,27 @@ impl AccountLinker {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn link(&mut self) -> anyhow::Result<SteamGuardAccount> {
|
pub fn link(&mut self) -> anyhow::Result<SteamGuardAccount, AccountLinkError> {
|
||||||
ensure!(!self.finalized);
|
|
||||||
|
|
||||||
let has_phone = self.client.has_phone()?;
|
let has_phone = self.client.has_phone()?;
|
||||||
|
|
||||||
if has_phone && !self.phone_number.is_empty() {
|
if has_phone && !self.phone_number.is_empty() {
|
||||||
bail!(AccountLinkError::MustRemovePhoneNumber);
|
return Err(AccountLinkError::MustRemovePhoneNumber);
|
||||||
}
|
}
|
||||||
if !has_phone && self.phone_number.is_empty() {
|
if !has_phone && self.phone_number.is_empty() {
|
||||||
bail!(AccountLinkError::MustProvidePhoneNumber);
|
return Err(AccountLinkError::MustProvidePhoneNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !has_phone {
|
if !has_phone {
|
||||||
if self.sent_confirmation_email {
|
if self.sent_confirmation_email {
|
||||||
if !self.client.check_email_confirmation()? {
|
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())? {
|
} 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 {
|
} else {
|
||||||
self.sent_confirmation_email = true;
|
self.sent_confirmation_email = true;
|
||||||
bail!(AccountLinkError::MustConfirmEmail);
|
return Err(AccountLinkError::MustConfirmEmail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +59,7 @@ impl AccountLinker {
|
||||||
|
|
||||||
match resp.status {
|
match resp.status {
|
||||||
29 => {
|
29 => {
|
||||||
bail!(AccountLinkError::AuthenticatorPresent);
|
return Err(AccountLinkError::AuthenticatorPresent);
|
||||||
}
|
}
|
||||||
1 => {
|
1 => {
|
||||||
let mut account = resp.to_steam_guard_account();
|
let mut account = resp.to_steam_guard_account();
|
||||||
|
@ -69,7 +68,7 @@ impl AccountLinker {
|
||||||
return Ok(account);
|
return Ok(account);
|
||||||
}
|
}
|
||||||
status => {
|
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,
|
&mut self,
|
||||||
account: &mut SteamGuardAccount,
|
account: &mut SteamGuardAccount,
|
||||||
sms_code: String,
|
sms_code: String,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<(), FinalizeLinkError> {
|
||||||
ensure!(!account.fully_enrolled);
|
|
||||||
ensure!(!self.finalized);
|
|
||||||
|
|
||||||
let time = crate::steamapi::get_server_time();
|
let time = crate::steamapi::get_server_time();
|
||||||
let code = account.generate_code(time);
|
let code = account.generate_code(time);
|
||||||
let resp = self
|
let resp: FinalizeAddAuthenticatorResponse = self
|
||||||
.client
|
.client
|
||||||
.finalize_authenticator(sms_code.clone(), code, time)?;
|
.finalize_authenticator(sms_code.clone(), code, time)?;
|
||||||
info!("finalize response status: {}", resp.status);
|
info!("finalize response status: {}", resp.status);
|
||||||
|
|
||||||
match resp.status {
|
match resp.status {
|
||||||
89 => {
|
89 => {
|
||||||
bail!(FinalizeLinkError::BadSmsCode);
|
return Err(FinalizeLinkError::BadSmsCode);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !resp.success {
|
if !resp.success {
|
||||||
bail!("Failed to finalize authenticator. Status: {}", resp.status);
|
return Err(FinalizeLinkError::Failure { status: resp.status })?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.want_more {
|
if resp.want_more {
|
||||||
bail!(FinalizeLinkError::WantMore);
|
return Err(FinalizeLinkError::WantMore);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.finalized = true;
|
self.finalized = true;
|
||||||
|
@ -115,38 +111,35 @@ fn generate_device_id() -> String {
|
||||||
return format!("android:{}", uuid::Uuid::new_v4().to_string());
|
return format!("android:{}", uuid::Uuid::new_v4().to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum AccountLinkError {
|
pub enum AccountLinkError {
|
||||||
/// No phone number on the account
|
/// No phone number on the account
|
||||||
|
#[error("A phone number is needed, but not already present on the account.")]
|
||||||
MustProvidePhoneNumber,
|
MustProvidePhoneNumber,
|
||||||
/// A phone number is already on the account
|
/// A phone number is already on the account
|
||||||
|
#[error("A phone number was provided, but one is already present on the account.")]
|
||||||
MustRemovePhoneNumber,
|
MustRemovePhoneNumber,
|
||||||
/// User need to click link from confirmation email
|
/// 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,
|
MustConfirmEmail,
|
||||||
/// Must provide an SMS code
|
/// Must provide an SMS code
|
||||||
|
#[error("Awaiting finalization")]
|
||||||
AwaitingFinalization,
|
AwaitingFinalization,
|
||||||
|
#[error("Authenticator is already present.")]
|
||||||
AuthenticatorPresent,
|
AuthenticatorPresent,
|
||||||
|
#[error(transparent)]
|
||||||
|
Unknown(#[from] anyhow::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for AccountLinkError {
|
#[derive(Error, Debug)]
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
|
||||||
write!(f, "{:?}", self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error for AccountLinkError {}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum FinalizeLinkError {
|
pub enum FinalizeLinkError {
|
||||||
|
#[error("Provided SMS code was incorrect.")]
|
||||||
BadSmsCode,
|
BadSmsCode,
|
||||||
/// Steam wants more 2fa codes to verify that we can generate valid codes. Call finalize again.
|
/// 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,
|
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;
|
use anyhow::Result;
|
||||||
pub use confirmation::{Confirmation, ConfirmationType};
|
pub use confirmation::{Confirmation, ConfirmationType};
|
||||||
use hmacsha1::hmac_sha1;
|
use hmacsha1::hmac_sha1;
|
||||||
|
@ -11,7 +11,6 @@ use reqwest::{
|
||||||
use scraper::{Html, Selector};
|
use scraper::{Html, Selector};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{collections::HashMap, convert::TryInto};
|
use std::{collections::HashMap, convert::TryInto};
|
||||||
pub use steamapi::AddAuthenticatorResponse;
|
|
||||||
pub use userlogin::{LoginError, UserLogin};
|
pub use userlogin::{LoginError, UserLogin};
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
Loading…
Reference in a new issue