2021-08-08 21:25:27 +02:00
|
|
|
use crate::{
|
2021-08-09 00:32:50 +02:00
|
|
|
steamapi::{AddAuthenticatorResponse, Session, SteamApiClient},
|
2021-08-08 21:25:27 +02:00
|
|
|
SteamGuardAccount,
|
|
|
|
};
|
2021-08-05 03:26:14 +02:00
|
|
|
use std::error::Error;
|
|
|
|
use std::fmt::Display;
|
2021-07-27 22:24:56 +02:00
|
|
|
|
2021-08-09 00:32:50 +02:00
|
|
|
#[derive(Debug)]
|
2021-07-27 22:24:56 +02:00
|
|
|
pub struct AccountLinker {
|
2021-08-08 18:54:46 +02:00
|
|
|
device_id: String,
|
|
|
|
phone_number: String,
|
2021-08-09 00:32:50 +02:00
|
|
|
pub account: Option<SteamGuardAccount>,
|
2021-08-05 03:26:14 +02:00
|
|
|
pub finalized: bool,
|
2021-08-09 00:32:50 +02:00
|
|
|
sent_confirmation_email: bool,
|
|
|
|
session: Session,
|
|
|
|
client: SteamApiClient,
|
2021-07-27 22:24:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl AccountLinker {
|
2021-08-09 00:32:50 +02:00
|
|
|
pub fn new(session: Session) -> AccountLinker {
|
2021-08-08 18:54:46 +02:00
|
|
|
return AccountLinker {
|
|
|
|
device_id: generate_device_id(),
|
2021-08-09 00:32:50 +02:00
|
|
|
phone_number: "".into(),
|
|
|
|
account: None,
|
2021-08-05 03:26:14 +02:00
|
|
|
finalized: false,
|
2021-08-09 00:32:50 +02:00
|
|
|
sent_confirmation_email: false,
|
|
|
|
session: session,
|
|
|
|
client: SteamApiClient::new(),
|
2021-08-08 18:54:46 +02:00
|
|
|
};
|
|
|
|
}
|
2021-07-27 22:24:56 +02:00
|
|
|
|
2021-08-09 00:32:50 +02:00
|
|
|
pub fn link(&mut self) -> anyhow::Result<SteamGuardAccount, AccountLinkError> {
|
|
|
|
let has_phone = self.client.has_phone()?;
|
|
|
|
|
|
|
|
if has_phone && !self.phone_number.is_empty() {
|
|
|
|
return Err(AccountLinkError::MustRemovePhoneNumber);
|
|
|
|
}
|
|
|
|
if !has_phone && self.phone_number.is_empty() {
|
|
|
|
return Err(AccountLinkError::MustProvidePhoneNumber);
|
|
|
|
}
|
|
|
|
|
|
|
|
if !has_phone {
|
|
|
|
if self.sent_confirmation_email {
|
|
|
|
if !self.client.check_email_confirmation()? {
|
|
|
|
return Err(AccountLinkError::Unknown(anyhow!(
|
|
|
|
"Failed email confirmation check"
|
|
|
|
)));
|
|
|
|
}
|
|
|
|
} else if !self.client.add_phone_number(self.phone_number.clone())? {
|
|
|
|
return Err(AccountLinkError::Unknown(anyhow!(
|
|
|
|
"Failed to add phone number"
|
|
|
|
)));
|
|
|
|
} else {
|
|
|
|
self.sent_confirmation_email = true;
|
|
|
|
return Err(AccountLinkError::MustConfirmEmail);
|
|
|
|
}
|
|
|
|
}
|
2021-08-05 03:26:14 +02:00
|
|
|
|
2021-08-09 00:32:50 +02:00
|
|
|
let resp: AddAuthenticatorResponse =
|
|
|
|
self.client.add_authenticator(self.device_id.clone())?;
|
2021-08-05 03:26:14 +02:00
|
|
|
|
2021-08-09 01:09:15 +02:00
|
|
|
match resp.status {
|
2021-08-09 00:32:50 +02:00
|
|
|
29 => {
|
|
|
|
return Err(AccountLinkError::AuthenticatorPresent);
|
|
|
|
}
|
|
|
|
1 => {
|
|
|
|
let mut account = resp.to_steam_guard_account();
|
|
|
|
account.device_id = self.device_id.clone();
|
|
|
|
account.session = self.client.session.clone();
|
|
|
|
return Ok(account);
|
|
|
|
}
|
|
|
|
status => {
|
|
|
|
return Err(AccountLinkError::Unknown(anyhow!(
|
|
|
|
"Unknown add authenticator status code: {}",
|
|
|
|
status
|
|
|
|
)));
|
|
|
|
}
|
|
|
|
}
|
2021-08-08 18:54:46 +02:00
|
|
|
}
|
2021-07-27 22:24:56 +02:00
|
|
|
|
2021-08-09 00:32:50 +02:00
|
|
|
pub fn finalize(&self, account: &SteamGuardAccount, sms_code: String) {}
|
2021-07-27 22:24:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn generate_device_id() -> String {
|
2021-08-08 18:54:46 +02:00
|
|
|
return format!("android:{}", uuid::Uuid::new_v4().to_string());
|
2021-07-27 22:24:56 +02:00
|
|
|
}
|
|
|
|
|
2021-08-05 03:26:14 +02:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum AccountLinkError {
|
|
|
|
/// No phone number on the account
|
|
|
|
MustProvidePhoneNumber,
|
|
|
|
/// A phone number is already on the account
|
|
|
|
MustRemovePhoneNumber,
|
|
|
|
/// User need to click link from confirmation email
|
|
|
|
MustConfirmEmail,
|
|
|
|
/// Must provide an SMS code
|
|
|
|
AwaitingFinalization,
|
|
|
|
AuthenticatorPresent,
|
|
|
|
NetworkFailure(reqwest::Error),
|
2021-08-09 00:32:50 +02:00
|
|
|
Unknown(anyhow::Error),
|
2021-08-05 03:26:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for AccountLinkError {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
|
|
|
write!(f, "{:?}", self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Error for AccountLinkError {}
|
|
|
|
|
|
|
|
impl From<reqwest::Error> for AccountLinkError {
|
|
|
|
fn from(err: reqwest::Error) -> AccountLinkError {
|
|
|
|
AccountLinkError::NetworkFailure(err)
|
|
|
|
}
|
|
|
|
}
|
2021-08-09 00:32:50 +02:00
|
|
|
|
|
|
|
impl From<anyhow::Error> for AccountLinkError {
|
|
|
|
fn from(err: anyhow::Error) -> AccountLinkError {
|
|
|
|
AccountLinkError::Unknown(err)
|
|
|
|
}
|
|
|
|
}
|