#![allow(dead_code, clippy::missing_errors_doc)]
#![warn(missing_docs, missing_doc_code_examples)]
#![deny(
missing_debug_implementations,
missing_copy_implementations,
trivial_casts,
trivial_numeric_casts,
unsafe_code,
unused_import_braces,
unused_qualifications
)]
use std::fmt;
use std::fmt::Debug;
use std::fmt::Formatter;
use std::path::PathBuf;
use std::sync::Arc;
pub use client::Authenticated;
pub use client::SteamAuthenticator;
pub use client::Unauthenticated;
use const_format::concatcp;
use parking_lot::RwLock;
pub use reqwest::header::HeaderMap;
pub use reqwest::Method;
pub use reqwest::Url;
use serde::Deserialize;
use serde::Serialize;
use steamid_parser::SteamID;
pub use utils::format_captcha_url;
use uuid::Uuid;
pub use web_handler::confirmation::ConfirmationAction;
pub use web_handler::confirmation::Confirmations;
pub use web_handler::confirmation::EConfirmationType;
pub use web_handler::steam_guard_linker::AddAuthenticatorStep;
use crate::errors::AuthError;
use crate::errors::InternalError;
use crate::errors::MobileAuthFileError;
use crate::utils::read_from_disk;
mod adapter;
pub(crate) mod client;
pub mod errors;
mod page_scraper;
pub(crate) mod retry;
mod types;
pub mod user;
pub(crate) mod utils;
mod web_handler;
const STEAM_DELAY_MS: u64 = 350;
const MA_FILE_EXT: &str = ".maFile";
pub(crate) const STEAM_COMMUNITY_HOST: &str = "steamcommunity.com";
pub(crate) const STEAM_HELP_HOST: &str = ".help.steampowered.com";
pub(crate) const STEAM_STORE_HOST: &str = ".store.steampowered.com";
pub(crate) const STEAM_COMMUNITY_BASE: &str = "https://steamcommunity.com";
pub(crate) const STEAM_STORE_BASE: &str = "https://store.steampowered.com";
pub(crate) const STEAM_API_BASE: &str = "https://api.steampowered.com";
pub(crate) const STEAM_LOGIN_BASE: &str = "https://login.steampowered.com";
const MOBILE_REFERER: &str = concatcp!(
STEAM_COMMUNITY_BASE,
"/mobilelogin?oauth_client_id=DE45CD61&oauth_scope=read_profile%20write_profile%20read_client%20write_client"
);
#[allow(missing_docs)]
pub type AuthResult<T> = Result<T, AuthError>;
#[derive(Debug, Clone)]
struct SteamCache {
steamid: SteamID,
api_key: Option<String>,
oauth_token: String,
access_token: String,
}
pub(crate) type CacheGuard = Arc<RwLock<SteamCache>>;
impl SteamCache {
fn query_tokens(&self) -> Vec<(&'static str, String)> {
[("access_token", self.access_token.clone())].to_vec()
}
fn with_login_data(steamid: &str, access_token: String, refresh_token: String) -> Result<Self, InternalError> {
let parsed_steamid = SteamID::parse(steamid).ok_or_else(|| {
let err_str = format!("Failed to parse {steamid} as SteamID.");
InternalError::GeneralFailure(err_str)
})?;
Ok(Self {
steamid: parsed_steamid,
api_key: None,
oauth_token: refresh_token,
access_token,
})
}
fn set_api_key(&mut self, api_key: Option<String>) {
self.api_key = api_key;
}
fn api_key(&self) -> Option<&str> {
self.api_key.as_deref()
}
fn steam_id(&self) -> u64 {
self.steamid.to_steam64()
}
fn oauth_token(&self) -> &str {
&self.oauth_token
}
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct MobileAuthFile {
identity_secret: String,
shared_secret: String,
device_id: Option<String>,
revocation_code: Option<String>,
pub account_name: Option<String>,
}
impl Debug for MobileAuthFile {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("MobileAuthFile")
.field("AccountName", &self.account_name)
.finish()
}
}
impl MobileAuthFile {
fn set_device_id(&mut self, device_id: String) {
self.device_id = Some(device_id);
}
pub fn new<T>(identity_secret: String, shared_secret: String, device_id: T) -> Self
where
T: Into<Option<String>>,
{
Self {
identity_secret,
shared_secret,
device_id: device_id.into(),
revocation_code: None,
account_name: None,
}
}
pub fn from_json(string: &str) -> Result<Self, MobileAuthFileError> {
serde_json::from_str::<Self>(string)
.map_err(|e| MobileAuthFileError::InternalError(InternalError::DeserializationError(e)))
}
pub fn from_disk<T>(path: T) -> Result<Self, MobileAuthFileError>
where
T: Into<PathBuf>,
{
let buffer = read_from_disk(path);
Self::from_json(&buffer)
}
}
#[derive(Serialize, Deserialize, Debug)]
struct DeviceId(String);
impl DeviceId {
const PREFIX: &'static str = "android:";
pub fn generate() -> Self {
Self(Self::PREFIX.to_owned() + &Uuid::new_v4().to_string())
}
pub fn validate() {}
}