From fe663cf43f479e1103603658f94edf97f800b275 Mon Sep 17 00:00:00 2001 From: Carson McManus Date: Sun, 2 Jul 2023 08:57:13 -0400 Subject: [PATCH] add HTTP proxy support (#264) - allow extracting the http client from web api transport - refactor most commands so that they can accept an external transport - update confirmer to use transport's http client - update remove command - update TwoFactorClient so it doesn't need to be mutable - update get_server_time so it requires a transport - update remove_authenticator - update login proceedure to use given transport - update usages of do_login - update setup - update trade - update code command - update qr-login command - make borrowcheck happy - make WebApiTransport Clone and remove Default impl - remove dead code - fix lints closes #177 --- src/commands.rs | 32 +++++++++++++++----- src/commands/code.rs | 8 +++-- src/commands/decrypt.rs | 7 +++-- src/commands/encrypt.rs | 7 +++-- src/commands/import.rs | 7 +++-- src/commands/qr.rs | 6 +++- src/commands/qr_login.rs | 14 +++++---- src/commands/remove.rs | 13 +++++--- src/commands/setup.rs | 21 +++++++------ src/commands/trade.rs | 14 +++++---- src/main.rs | 41 ++++++++++++++++++-------- steamguard/src/confirmation.rs | 44 +++++++++++++++------------- steamguard/src/lib.rs | 10 +++---- steamguard/src/steamapi.rs | 9 +++--- steamguard/src/steamapi/twofactor.rs | 10 +++---- steamguard/src/transport/mod.rs | 4 +++ steamguard/src/transport/webapi.rs | 22 ++++---------- 17 files changed, 164 insertions(+), 105 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index c9c910d..bf0d9b7 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -4,7 +4,7 @@ use clap::{clap_derive::ArgEnum, Parser}; use clap_complete::Shell; use secrecy::SecretString; use std::str::FromStr; -use steamguard::SteamGuardAccount; +use steamguard::{transport::Transport, SteamGuardAccount}; use crate::AccountManager; @@ -40,23 +40,33 @@ pub(crate) trait ConstCommand { } /// A command that operates the manifest as a whole -pub(crate) trait ManifestCommand { - fn execute(&self, manager: &mut AccountManager) -> anyhow::Result<()>; +pub(crate) trait ManifestCommand +where + T: Transport, +{ + fn execute(&self, transport: T, manager: &mut AccountManager) -> anyhow::Result<()>; } /// A command that operates on individual accounts. -pub(crate) trait AccountCommand { +pub(crate) trait AccountCommand +where + T: Transport, +{ fn execute( &self, + transport: T, manager: &mut AccountManager, accounts: Vec>>, ) -> anyhow::Result<()>; } -pub(crate) enum CommandType { +pub(crate) enum CommandType +where + T: Transport, +{ Const(Box), - Manifest(Box), - Account(Box), + Manifest(Box>), + Account(Box>), } #[derive(Debug, Clone, Parser)] @@ -114,6 +124,14 @@ pub(crate) struct GlobalArgs { long_help = "Disable checking for updates. By default, steamguard-cli will check for updates every now and then. This can be disabled with this flag." )] pub no_update_check: bool, + + #[clap( + long, + env = "HTTP_PROXY", + help = "Use a proxy for HTTP requests.", + long_help = "Use a proxy for HTTP requests. This is useful if you are behind a firewall and need to use a proxy to access the internet." + )] + pub http_proxy: Option, } #[derive(Debug, Clone, Parser)] diff --git a/src/commands/code.rs b/src/commands/code.rs index 1a9e84c..9429c72 100644 --- a/src/commands/code.rs +++ b/src/commands/code.rs @@ -20,16 +20,20 @@ pub struct CodeCommand { pub offline: bool, } -impl AccountCommand for CodeCommand { +impl AccountCommand for CodeCommand +where + T: Transport, +{ fn execute( &self, + transport: T, _manager: &mut AccountManager, accounts: Vec>>, ) -> anyhow::Result<()> { let server_time = if self.offline { SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs() } else { - steamapi::get_server_time()?.server_time() + steamapi::get_server_time(transport)?.server_time() }; debug!("Time used to generate codes: {}", server_time); diff --git a/src/commands/decrypt.rs b/src/commands/decrypt.rs index cdbf93c..b952634 100644 --- a/src/commands/decrypt.rs +++ b/src/commands/decrypt.rs @@ -8,8 +8,11 @@ use super::*; #[clap(about = "Decrypt all maFiles")] pub struct DecryptCommand; -impl ManifestCommand for DecryptCommand { - fn execute(&self, manager: &mut AccountManager) -> anyhow::Result<()> { +impl ManifestCommand for DecryptCommand +where + T: Transport, +{ + fn execute(&self, _transport: T, manager: &mut AccountManager) -> anyhow::Result<()> { load_accounts_with_prompts(manager)?; for mut entry in manager.iter_mut() { entry.encryption = None; diff --git a/src/commands/encrypt.rs b/src/commands/encrypt.rs index e4ed4e3..8b7ef99 100644 --- a/src/commands/encrypt.rs +++ b/src/commands/encrypt.rs @@ -8,8 +8,11 @@ use super::*; #[clap(about = "Encrypt all maFiles")] pub struct EncryptCommand; -impl ManifestCommand for EncryptCommand { - fn execute(&self, manager: &mut AccountManager) -> anyhow::Result<()> { +impl ManifestCommand for EncryptCommand +where + T: Transport, +{ + fn execute(&self, _transport: T, manager: &mut AccountManager) -> anyhow::Result<()> { if !manager.has_passkey() { let mut passkey; loop { diff --git a/src/commands/import.rs b/src/commands/import.rs index f4a1b54..b910892 100644 --- a/src/commands/import.rs +++ b/src/commands/import.rs @@ -18,8 +18,11 @@ pub struct ImportCommand { pub files: Vec, } -impl ManifestCommand for ImportCommand { - fn execute(&self, manager: &mut AccountManager) -> anyhow::Result<()> { +impl ManifestCommand for ImportCommand +where + T: Transport, +{ + fn execute(&self, _transport: T, manager: &mut AccountManager) -> anyhow::Result<()> { for file_path in self.files.iter() { if self.sda { let path = Path::new(&file_path); diff --git a/src/commands/qr.rs b/src/commands/qr.rs index 6acda6e..d647518 100644 --- a/src/commands/qr.rs +++ b/src/commands/qr.rs @@ -18,9 +18,13 @@ pub struct QrCommand { pub ascii: bool, } -impl AccountCommand for QrCommand { +impl AccountCommand for QrCommand +where + T: Transport, +{ fn execute( &self, + _transport: T, _manager: &mut AccountManager, accounts: Vec>>, ) -> anyhow::Result<()> { diff --git a/src/commands/qr_login.rs b/src/commands/qr_login.rs index b6fddb6..e3c2a53 100644 --- a/src/commands/qr_login.rs +++ b/src/commands/qr_login.rs @@ -1,7 +1,7 @@ use std::sync::{Arc, Mutex}; use log::*; -use steamguard::{transport::WebApiTransport, QrApprover, QrApproverError}; +use steamguard::{QrApprover, QrApproverError}; use crate::AccountManager; @@ -17,9 +17,13 @@ pub struct QrLoginCommand { pub url: String, } -impl AccountCommand for QrLoginCommand { +impl AccountCommand for QrLoginCommand +where + T: Transport + Clone, +{ fn execute( &self, + transport: T, _manager: &mut AccountManager, accounts: Vec>>, ) -> anyhow::Result<()> { @@ -33,7 +37,7 @@ impl AccountCommand for QrLoginCommand { info!("Approving login to {}", account.account_name); if account.tokens.is_none() { - crate::do_login(&mut account)?; + crate::do_login(transport.clone(), &mut account)?; } loop { @@ -42,7 +46,7 @@ impl AccountCommand for QrLoginCommand { return Err(anyhow!("No tokens found for {}", account.account_name)); }; - let mut approver = QrApprover::new(WebApiTransport::default(), tokens); + let mut approver = QrApprover::new(transport.clone(), tokens); match approver.approve(&account, &self.url) { Ok(_) => { info!("Login approved."); @@ -50,7 +54,7 @@ impl AccountCommand for QrLoginCommand { } Err(QrApproverError::Unauthorized) => { warn!("tokens are invalid. Attempting to log in again."); - crate::do_login(&mut account)?; + crate::do_login(transport.clone(), &mut account)?; } Err(e) => { error!("Failed to approve login: {}", e); diff --git a/src/commands/remove.rs b/src/commands/remove.rs index 81cf107..bae01a4 100644 --- a/src/commands/remove.rs +++ b/src/commands/remove.rs @@ -1,7 +1,7 @@ use std::sync::{Arc, Mutex}; use log::*; -use steamguard::{transport::TransportError, RemoveAuthenticatorError}; +use steamguard::{steamapi::TwoFactorClient, transport::TransportError, RemoveAuthenticatorError}; use crate::{errors::UserError, tui, AccountManager}; @@ -11,9 +11,13 @@ use super::*; #[clap(about = "Remove the authenticator from an account.")] pub struct RemoveCommand; -impl AccountCommand for RemoveCommand { +impl AccountCommand for RemoveCommand +where + T: Transport + Clone, +{ fn execute( &self, + transport: T, manager: &mut AccountManager, accounts: Vec>>, ) -> anyhow::Result<()> { @@ -38,10 +42,11 @@ impl AccountCommand for RemoveCommand { let mut successful = vec![]; for a in accounts { let mut account = a.lock().unwrap(); + let client = TwoFactorClient::new(transport.clone()); let mut revocation: Option = None; loop { - match account.remove_authenticator(revocation.as_ref()) { + match account.remove_authenticator(&client, revocation.as_ref()) { Ok(_) => { info!("Removed authenticator from {}", account.account_name); successful.push(account.account_name.clone()); @@ -49,7 +54,7 @@ impl AccountCommand for RemoveCommand { } Err(RemoveAuthenticatorError::TransportError(TransportError::Unauthorized)) => { error!("Account {} is not logged in", account.account_name); - crate::do_login(&mut account)?; + crate::do_login(transport.clone(), &mut account)?; continue; } Err(RemoveAuthenticatorError::IncorrectRevocationCode { diff --git a/src/commands/setup.rs b/src/commands/setup.rs index f1a2b01..5659eed 100644 --- a/src/commands/setup.rs +++ b/src/commands/setup.rs @@ -3,7 +3,7 @@ use phonenumber::PhoneNumber; use secrecy::ExposeSecret; use steamguard::{ accountlinker::AccountLinkSuccess, phonelinker::PhoneLinker, steamapi::PhoneClient, - token::Tokens, transport::WebApiTransport, AccountLinkError, AccountLinker, FinalizeLinkError, + token::Tokens, AccountLinkError, AccountLinker, FinalizeLinkError, }; use crate::{tui, AccountManager}; @@ -14,8 +14,11 @@ use super::*; #[clap(about = "Set up a new account with steamguard-cli")] pub struct SetupCommand; -impl ManifestCommand for SetupCommand { - fn execute(&self, manager: &mut AccountManager) -> anyhow::Result<()> { +impl ManifestCommand for SetupCommand +where + T: Transport + Clone, +{ + fn execute(&self, transport: T, manager: &mut AccountManager) -> anyhow::Result<()> { eprintln!("Log in to the account that you want to link to steamguard-cli"); eprint!("Username: "); let username = tui::prompt().to_lowercase(); @@ -27,11 +30,11 @@ impl ManifestCommand for SetupCommand { ); } info!("Logging in to {}", username); - let tokens = - crate::do_login_raw(username).expect("Failed to log in. Account has not been linked."); + let tokens = crate::do_login_raw(transport.clone(), username) + .expect("Failed to log in. Account has not been linked."); info!("Adding authenticator..."); - let mut linker = AccountLinker::new(WebApiTransport::default(), tokens); + let mut linker = AccountLinker::new(transport.clone(), tokens); let link: AccountLinkSuccess; loop { match linker.link() { @@ -41,7 +44,7 @@ impl ManifestCommand for SetupCommand { } Err(AccountLinkError::MustProvidePhoneNumber) => { eprintln!("Looks like you don't have a phone number on this account."); - do_add_phone_number(linker.tokens())?; + do_add_phone_number(transport.clone(), linker.tokens())?; } Err(AccountLinkError::MustConfirmEmail) => { println!("Check your email and click the link."); @@ -129,8 +132,8 @@ impl ManifestCommand for SetupCommand { } } -pub fn do_add_phone_number(tokens: &Tokens) -> anyhow::Result<()> { - let client = PhoneClient::new(WebApiTransport::default()); +pub fn do_add_phone_number(transport: T, tokens: &Tokens) -> anyhow::Result<()> { + let client = PhoneClient::new(transport); let linker = PhoneLinker::new(client, tokens.clone()); diff --git a/src/commands/trade.rs b/src/commands/trade.rs index fb31294..4e6129a 100644 --- a/src/commands/trade.rs +++ b/src/commands/trade.rs @@ -25,9 +25,13 @@ pub struct TradeCommand { pub fail_fast: bool, } -impl AccountCommand for TradeCommand { +impl AccountCommand for TradeCommand +where + T: Transport + Clone, +{ fn execute( &self, + transport: T, manager: &mut AccountManager, accounts: Vec>>, ) -> anyhow::Result<()> { @@ -36,13 +40,13 @@ impl AccountCommand for TradeCommand { if !account.is_logged_in() { info!("Account does not have tokens, logging in"); - crate::do_login(&mut account)?; + crate::do_login(transport.clone(), &mut account)?; } info!("{}: Checking for trade confirmations", account.account_name); let confirmations: Vec; loop { - let confirmer = Confirmer::new(&account); + let confirmer = Confirmer::new(transport.clone(), &account); match confirmer.get_trade_confirmations() { Ok(confs) => { @@ -51,7 +55,7 @@ impl AccountCommand for TradeCommand { } Err(ConfirmerError::InvalidTokens) => { info!("obtaining new tokens"); - crate::do_login(&mut account)?; + crate::do_login(transport.clone(), &mut account)?; } Err(err) => { error!("Failed to get trade confirmations: {}", err); @@ -65,7 +69,7 @@ impl AccountCommand for TradeCommand { continue; } - let confirmer = Confirmer::new(&account); + let confirmer = Confirmer::new(transport.clone(), &account); let mut any_failed = false; if self.accept_all { info!("accepting all confirmations"); diff --git a/src/main.rs b/src/main.rs index 70706d8..3e56498 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,7 @@ use std::{ use steamguard::{ protobufs::steammessages_auth_steamclient::{EAuthSessionGuardType, EAuthTokenPlatformType}, refresher::TokenRefresher, - transport::WebApiTransport, + transport::{Transport, WebApiTransport}, }; use steamguard::{steamapi, DeviceDetails, LoginError, SteamGuardAccount, UserLogin}; use steamguard::{steamapi::AuthenticationClient, token::Tokens}; @@ -83,7 +83,7 @@ fn main() { fn run(args: commands::Args) -> anyhow::Result<()> { let globalargs = args.global; - let cmd: CommandType = match args.sub.unwrap_or(Subcommands::Code(args.code)) { + let cmd: CommandType = match args.sub.unwrap_or(Subcommands::Code(args.code)) { Subcommands::Debug(args) => CommandType::Const(Box::new(args)), Subcommands::Completion(args) => CommandType::Const(Box::new(args)), Subcommands::Setup(args) => CommandType::Manifest(Box::new(args)), @@ -198,8 +198,16 @@ fn run(args: commands::Args) -> anyhow::Result<()> { } } + let mut http_client = reqwest::blocking::Client::builder(); + if let Some(proxy) = &globalargs.http_proxy { + let proxy = reqwest::Proxy::all(proxy)?; + http_client = http_client.proxy(proxy); + } + let http_client = http_client.build()?; + let transport = WebApiTransport::new(http_client); + if let CommandType::Manifest(cmd) = cmd { - cmd.execute(&mut manager)?; + cmd.execute(transport, &mut manager)?; return Ok(()); } @@ -237,7 +245,7 @@ fn run(args: commands::Args) -> anyhow::Result<()> { ); if let CommandType::Account(cmd) = cmd { - return cmd.execute(&mut manager, selected_accounts); + return cmd.execute(transport, &mut manager, selected_accounts); } Ok(()) @@ -271,10 +279,13 @@ fn get_selected_accounts( Ok(selected_accounts) } -fn do_login(account: &mut SteamGuardAccount) -> anyhow::Result<()> { +fn do_login( + transport: T, + account: &mut SteamGuardAccount, +) -> anyhow::Result<()> { if let Some(tokens) = account.tokens.as_mut() { info!("Refreshing access token..."); - let client = AuthenticationClient::new(WebApiTransport::default()); + let client = AuthenticationClient::new(transport.clone()); let mut refresher = TokenRefresher::new(client); match refresher.refresh(account.steam_id, tokens) { Ok(token) => { @@ -304,14 +315,19 @@ fn do_login(account: &mut SteamGuardAccount) -> anyhow::Result<()> { } else { debug!("password is empty"); } - let tokens = do_login_impl(account.account_name.clone(), password, Some(account))?; + let tokens = do_login_impl( + transport, + account.account_name.clone(), + password, + Some(account), + )?; let steam_id = tokens.access_token().decode()?.steam_id(); account.set_tokens(tokens); account.steam_id = steam_id; Ok(()) } -fn do_login_raw(username: String) -> anyhow::Result { +fn do_login_raw(transport: T, username: String) -> anyhow::Result { let _ = std::io::stdout().flush(); let password = rpassword::prompt_password_stdout("Password: ").unwrap(); if !password.is_empty() { @@ -319,15 +335,16 @@ fn do_login_raw(username: String) -> anyhow::Result { } else { debug!("password is empty"); } - do_login_impl(username, password, None) + do_login_impl(transport, username, password, None) } -fn do_login_impl( +fn do_login_impl( + transport: T, username: String, password: String, account: Option<&SteamGuardAccount>, ) -> anyhow::Result { - let mut login = UserLogin::new(WebApiTransport::default(), build_device_details()); + let mut login = UserLogin::new(transport.clone(), build_device_details()); let mut password = password; let confirmation_methods; @@ -375,7 +392,7 @@ fn do_login_impl( EAuthSessionGuardType::k_EAuthSessionGuardType_DeviceCode => { let code = if let Some(account) = account { debug!("Generating 2fa code..."); - let time = steamapi::get_server_time()?.server_time(); + let time = steamapi::get_server_time(transport)?.server_time(); account.generate_code(time) } else { eprint!("Enter the 2fa code from your device: "); diff --git a/steamguard/src/confirmation.rs b/steamguard/src/confirmation.rs index cde9747..c09c29c 100644 --- a/steamguard/src/confirmation.rs +++ b/steamguard/src/confirmation.rs @@ -10,20 +10,30 @@ use reqwest::{ use secrecy::ExposeSecret; use serde::Deserialize; -use crate::{steamapi, SteamGuardAccount}; +use crate::{ + steamapi::{self}, + transport::Transport, + SteamGuardAccount, +}; lazy_static! { static ref STEAM_COOKIE_URL: Url = "https://steamcommunity.com".parse::().unwrap(); } /// Provides an interface that wraps the Steam mobile confirmation API. -pub struct Confirmer<'a> { +/// +/// Only compatible with WebApiTransport. +pub struct Confirmer<'a, T> { account: &'a SteamGuardAccount, + transport: T, } -impl<'a> Confirmer<'a> { - pub fn new(account: &'a SteamGuardAccount) -> Self { - Self { account } +impl<'a, T> Confirmer<'a, T> +where + T: Transport + Clone, +{ + pub fn new(transport: T, account: &'a SteamGuardAccount) -> Self { + Self { account, transport } } fn get_confirmation_query_params<'q>( @@ -72,11 +82,9 @@ impl<'a> Confirmer<'a> { pub fn get_trade_confirmations(&self) -> Result, ConfirmerError> { let cookies = self.build_cookie_jar(); - let client = reqwest::blocking::ClientBuilder::new() - .cookie_store(true) - .build()?; + let client = self.transport.innner_http_client()?; - let time = steamapi::get_server_time()?.server_time(); + let time = steamapi::get_server_time(self.transport.clone())?.server_time(); let resp = client .get( "https://steamcommunity.com/mobileconf/getlist" @@ -117,11 +125,9 @@ impl<'a> Confirmer<'a> { let operation = action.to_operation(); let cookies = self.build_cookie_jar(); - let client = reqwest::blocking::ClientBuilder::new() - .cookie_store(true) - .build()?; + let client = self.transport.innner_http_client()?; - let time = steamapi::get_server_time()?.server_time(); + let time = steamapi::get_server_time(self.transport.clone())?.server_time(); let mut query_params = self.get_confirmation_query_params("conf", time); query_params.push(("op", operation.into())); query_params.push(("cid", Cow::Borrowed(&conf.id))); @@ -185,11 +191,9 @@ impl<'a> Confirmer<'a> { let operation = action.to_operation(); let cookies = self.build_cookie_jar(); - let client = reqwest::blocking::ClientBuilder::new() - .cookie_store(true) - .build()?; + let client = self.transport.innner_http_client()?; - let time = steamapi::get_server_time()?.server_time(); + let time = steamapi::get_server_time(self.transport.clone())?.server_time(); let mut query_params = self.get_confirmation_query_params("conf", time); query_params.push(("op", operation.into())); for conf in confs.iter() { @@ -262,11 +266,9 @@ impl<'a> Confirmer<'a> { } let cookies = self.build_cookie_jar(); - let client = reqwest::blocking::ClientBuilder::new() - .cookie_store(true) - .build()?; + let client = self.transport.innner_http_client()?; - let time = steamapi::get_server_time()?.server_time(); + let time = steamapi::get_server_time(self.transport.clone())?.server_time(); let query_params = self.get_confirmation_query_params("details", time); let resp = client diff --git a/steamguard/src/lib.rs b/steamguard/src/lib.rs index 6c3fbce..1467e28 100644 --- a/steamguard/src/lib.rs +++ b/steamguard/src/lib.rs @@ -1,8 +1,6 @@ use crate::protobufs::service_twofactor::CTwoFactor_RemoveAuthenticator_Request; use crate::steamapi::EResult; -use crate::{ - steamapi::twofactor::TwoFactorClient, token::TwoFactorSecret, transport::WebApiTransport, -}; +use crate::{steamapi::twofactor::TwoFactorClient, token::TwoFactorSecret}; pub use accountlinker::{AccountLinkError, AccountLinker, FinalizeLinkError}; pub use confirmation::*; pub use qrapprover::{QrApprover, QrApproverError}; @@ -10,7 +8,7 @@ pub use secrecy::{ExposeSecret, SecretString}; use serde::{Deserialize, Serialize}; use std::io::Read; use token::Tokens; -use transport::TransportError; +use transport::{Transport, TransportError}; pub use userlogin::{DeviceDetails, LoginError, UserLogin}; #[macro_use] @@ -99,8 +97,9 @@ impl SteamGuardAccount { /// Removes the mobile authenticator from the steam account. If this operation succeeds, this object can no longer be considered valid. /// Returns whether or not the operation was successful. - pub fn remove_authenticator( + pub fn remove_authenticator( &self, + client: &TwoFactorClient, revocation_code: Option<&String>, ) -> Result<(), RemoveAuthenticatorError> { if !matches!(revocation_code, Some(_)) && self.revocation_code.expose_secret().is_empty() { @@ -109,7 +108,6 @@ impl SteamGuardAccount { let Some(tokens) = &self.tokens else { return Err(RemoveAuthenticatorError::TransportError(TransportError::Unauthorized)); }; - let mut client = TwoFactorClient::new(WebApiTransport::default()); let mut req = CTwoFactor_RemoveAuthenticator_Request::new(); req.set_revocation_code( revocation_code diff --git a/steamguard/src/steamapi.rs b/steamguard/src/steamapi.rs index 154b6c9..4d8198a 100644 --- a/steamguard/src/steamapi.rs +++ b/steamguard/src/steamapi.rs @@ -2,9 +2,8 @@ pub mod authentication; pub mod phone; pub mod twofactor; -use crate::{ - protobufs::service_twofactor::CTwoFactor_Time_Response, token::Jwt, transport::WebApiTransport, -}; +use crate::transport::Transport; +use crate::{protobufs::service_twofactor::CTwoFactor_Time_Response, token::Jwt}; use reqwest::Url; use serde::Deserialize; @@ -20,8 +19,8 @@ lazy_static! { /// Queries Steam for the current time. A convenience function around TwoFactorClient. /// /// Endpoint: `/ITwoFactorService/QueryTime/v0001` -pub fn get_server_time() -> anyhow::Result { - let mut client = TwoFactorClient::new(WebApiTransport::default()); +pub fn get_server_time(client: T) -> anyhow::Result { + let client = TwoFactorClient::new(client); let resp = client.query_time()?; if resp.result != EResult::OK { return Err(anyhow::anyhow!("QueryTime failed: {:?}", resp)); diff --git a/steamguard/src/steamapi/twofactor.rs b/steamguard/src/steamapi/twofactor.rs index 86f5774..ed38197 100644 --- a/steamguard/src/steamapi/twofactor.rs +++ b/steamguard/src/steamapi/twofactor.rs @@ -26,7 +26,7 @@ where } pub fn add_authenticator( - &mut self, + &self, req: CTwoFactor_AddAuthenticator_Request, access_token: &Jwt, ) -> anyhow::Result> { @@ -41,7 +41,7 @@ where } pub fn finalize_authenticator( - &mut self, + &self, req: CTwoFactor_FinalizeAddAuthenticator_Request, access_token: &Jwt, ) -> anyhow::Result> { @@ -56,7 +56,7 @@ where } pub fn remove_authenticator( - &mut self, + &self, req: CTwoFactor_RemoveAuthenticator_Request, access_token: &Jwt, ) -> Result, TransportError> { @@ -71,7 +71,7 @@ where } pub fn query_status( - &mut self, + &self, req: CTwoFactor_Status_Request, access_token: &Jwt, ) -> anyhow::Result> { @@ -83,7 +83,7 @@ where Ok(resp) } - pub fn query_time(&mut self) -> anyhow::Result> { + pub fn query_time(&self) -> anyhow::Result> { let req = ApiRequest::new(SERVICE_NAME, "QueryTime", 1, CTwoFactor_Time_Request::new()); let resp = self .transport diff --git a/steamguard/src/transport/mod.rs b/steamguard/src/transport/mod.rs index 2a71145..b453d2a 100644 --- a/steamguard/src/transport/mod.rs +++ b/steamguard/src/transport/mod.rs @@ -12,6 +12,10 @@ pub trait Transport { ) -> Result, TransportError>; fn close(&mut self); + + fn innner_http_client(&self) -> anyhow::Result { + bail!("Transport does not support extracting HTTP client") + } } #[derive(Debug, thiserror::Error)] diff --git a/steamguard/src/transport/webapi.rs b/steamguard/src/transport/webapi.rs index ccd14aa..22dab99 100644 --- a/steamguard/src/transport/webapi.rs +++ b/steamguard/src/transport/webapi.rs @@ -10,31 +10,15 @@ lazy_static! { static ref STEAM_API_BASE: String = "https://api.steampowered.com".into(); } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct WebApiTransport { client: reqwest::blocking::Client, } -impl Default for WebApiTransport { - fn default() -> Self { - Self::new(reqwest::blocking::Client::new()) - } -} - impl WebApiTransport { pub fn new(client: reqwest::blocking::Client) -> Self { Self { client } } - - // pub fn new_with_proxy(proxy: &str) -> Self { - // Self { - // client: reqwest::blocking::Client::builder() - // // .danger_accept_invalid_certs(true) - // .proxy(reqwest::Proxy::all(proxy).unwrap()) - // .build() - // .unwrap(), - // } - // } } impl Transport for WebApiTransport { @@ -129,6 +113,10 @@ impl Transport for WebApiTransport { } fn close(&mut self) {} + + fn innner_http_client(&self) -> anyhow::Result { + Ok(self.client.clone()) + } } fn encode_msg(msg: &T, config: base64::Config) -> anyhow::Result {