protect Session
memory, values are zeroized when dropped
This commit is contained in:
parent
deabfc299d
commit
eeded86641
8 changed files with 40 additions and 27 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1857,6 +1857,7 @@ dependencies = [
|
|||
"standback",
|
||||
"thiserror",
|
||||
"uuid",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::fs::File;
|
|||
use std::io::{BufReader, Read, Write};
|
||||
use std::path::Path;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use steamguard::SteamGuardAccount;
|
||||
use steamguard::{SteamGuardAccount, ExposeSecret};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
|
@ -169,7 +169,7 @@ impl Manifest {
|
|||
|
||||
pub fn add_account(&mut self, account: SteamGuardAccount) {
|
||||
debug!("adding account to manifest: {}", account.account_name);
|
||||
let steamid = account.session.as_ref().map_or(0, |s| s.steam_id);
|
||||
let steamid = account.session.as_ref().map_or(0, |s| s.expose_secret().steam_id);
|
||||
self.entries.push(ManifestEntry {
|
||||
filename: format!("{}.maFile", &account.account_name),
|
||||
steam_id: steamid,
|
||||
|
@ -675,7 +675,7 @@ use tempdir::TempDir;
|
|||
let account = manifest.get_account(&account_name)?;
|
||||
assert_eq!(account_name, account.lock().unwrap().account_name);
|
||||
assert_eq!(
|
||||
account.lock().unwrap().session.as_ref().unwrap().web_cookie,
|
||||
account.lock().unwrap().session.as_ref().unwrap().expose_secret().web_cookie,
|
||||
None
|
||||
);
|
||||
Ok(())
|
||||
|
@ -693,7 +693,7 @@ use tempdir::TempDir;
|
|||
assert_eq!(account_name, account.lock().unwrap().account_name);
|
||||
assert_eq!(account.lock().unwrap().revocation_code.expose_secret(), "R12345");
|
||||
assert_eq!(
|
||||
account.lock().unwrap().session.as_ref().unwrap().steam_id,
|
||||
account.lock().unwrap().session.as_ref().unwrap().expose_secret().steam_id,
|
||||
1234
|
||||
);
|
||||
|
||||
|
@ -702,7 +702,7 @@ use tempdir::TempDir;
|
|||
assert_eq!(account_name, account.lock().unwrap().account_name);
|
||||
assert_eq!(account.lock().unwrap().revocation_code.expose_secret(), "R56789");
|
||||
assert_eq!(
|
||||
account.lock().unwrap().session.as_ref().unwrap().steam_id,
|
||||
account.lock().unwrap().session.as_ref().unwrap().expose_secret().steam_id,
|
||||
5678
|
||||
);
|
||||
Ok(())
|
||||
|
|
|
@ -227,7 +227,7 @@ fn do_login(account: &mut SteamGuardAccount) -> anyhow::Result<()> {
|
|||
} else {
|
||||
debug!("password is empty");
|
||||
}
|
||||
account.session = Some(do_login_impl(
|
||||
account.set_session(do_login_impl(
|
||||
account.account_name.clone(),
|
||||
password,
|
||||
Some(account),
|
||||
|
|
|
@ -29,3 +29,4 @@ scraper = "0.12.0"
|
|||
maplit = "1.0.2"
|
||||
thiserror = "1.0.26"
|
||||
secrecy = { version = "0.8", features = ["serde"] }
|
||||
zeroize = "^1.4.3"
|
||||
|
|
|
@ -27,7 +27,7 @@ impl AccountLinker {
|
|||
finalized: false,
|
||||
sent_confirmation_email: false,
|
||||
session: session.clone(),
|
||||
client: SteamApiClient::new(Some(session)),
|
||||
client: SteamApiClient::new(Some(secrecy::Secret::new(session))),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ pub struct SteamGuardAccount {
|
|||
#[serde(with = "secret_string")]
|
||||
pub secret_1: SecretString,
|
||||
#[serde(default, rename = "Session")]
|
||||
pub session: Option<steamapi::Session>,
|
||||
pub session: Option<secrecy::Secret<steamapi::Session>>,
|
||||
}
|
||||
|
||||
fn build_time_bytes(time: i64) -> [u8; 8] {
|
||||
|
@ -95,12 +95,16 @@ impl SteamGuardAccount {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn set_session(&mut self, session: steamapi::Session) {
|
||||
self.session = Some(session.into());
|
||||
}
|
||||
|
||||
pub fn generate_code(&self, time: i64) -> String {
|
||||
return self.shared_secret.generate_code(time);
|
||||
}
|
||||
|
||||
fn get_confirmation_query_params(&self, tag: &str) -> HashMap<&str, String> {
|
||||
let session = self.session.clone().unwrap();
|
||||
let session = self.session.as_ref().unwrap().expose_secret();
|
||||
let time = steamapi::get_server_time();
|
||||
let mut params = HashMap::new();
|
||||
params.insert("p", self.device_id.clone());
|
||||
|
@ -118,13 +122,12 @@ impl SteamGuardAccount {
|
|||
fn build_cookie_jar(&self) -> reqwest::cookie::Jar {
|
||||
let url = "https://steamcommunity.com".parse::<Url>().unwrap();
|
||||
let cookies = reqwest::cookie::Jar::default();
|
||||
let session = self.session.clone().unwrap();
|
||||
let session_id = session.session_id;
|
||||
let session = self.session.as_ref().unwrap().expose_secret();
|
||||
cookies.add_cookie_str("mobileClientVersion=0 (2.1.3)", &url);
|
||||
cookies.add_cookie_str("mobileClient=android", &url);
|
||||
cookies.add_cookie_str("Steam_Language=english", &url);
|
||||
cookies.add_cookie_str("dob=", &url);
|
||||
cookies.add_cookie_str(format!("sessionid={}", session_id).as_str(), &url);
|
||||
cookies.add_cookie_str(format!("sessionid={}", session.session_id).as_str(), &url);
|
||||
cookies.add_cookie_str(format!("steamid={}", session.steam_id).as_str(), &url);
|
||||
cookies.add_cookie_str(format!("steamLogin={}", session.steam_login).as_str(), &url);
|
||||
cookies.add_cookie_str(
|
||||
|
|
|
@ -8,6 +8,8 @@ use reqwest::{
|
|||
header::{HeaderMap, HeaderName, HeaderValue, SET_COOKIE},
|
||||
Url,
|
||||
};
|
||||
use secrecy::{SerializableSecret, CloneableSecret, DebugSecret, ExposeSecret};
|
||||
use zeroize::Zeroize;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use serde_json::Value;
|
||||
use std::iter::FromIterator;
|
||||
|
@ -90,7 +92,8 @@ pub struct OAuthData {
|
|||
webcookie: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Zeroize)]
|
||||
#[zeroize(drop)]
|
||||
pub struct Session {
|
||||
#[serde(rename = "SessionID")]
|
||||
pub session_id: String,
|
||||
|
@ -106,6 +109,10 @@ pub struct Session {
|
|||
pub steam_id: u64,
|
||||
}
|
||||
|
||||
impl SerializableSecret for Session {}
|
||||
impl CloneableSecret for Session {}
|
||||
impl DebugSecret for Session {}
|
||||
|
||||
pub fn get_server_time() -> i64 {
|
||||
let client = reqwest::blocking::Client::new();
|
||||
let resp = client
|
||||
|
@ -124,11 +131,11 @@ pub fn get_server_time() -> i64 {
|
|||
pub struct SteamApiClient {
|
||||
cookies: reqwest::cookie::Jar,
|
||||
client: reqwest::blocking::Client,
|
||||
pub session: Option<Session>,
|
||||
pub session: Option<secrecy::Secret<Session>>,
|
||||
}
|
||||
|
||||
impl SteamApiClient {
|
||||
pub fn new(session: Option<Session>) -> SteamApiClient {
|
||||
pub fn new(session: Option<secrecy::Secret<Session>>) -> SteamApiClient {
|
||||
SteamApiClient {
|
||||
cookies: reqwest::cookie::Jar::default(),
|
||||
client: reqwest::blocking::ClientBuilder::new()
|
||||
|
@ -195,7 +202,7 @@ impl SteamApiClient {
|
|||
.add_cookie_str("Steam_Language=english", &STEAM_COOKIE_URL);
|
||||
if let Some(session) = &self.session {
|
||||
self.cookies.add_cookie_str(
|
||||
format!("sessionid={}", session.session_id).as_str(),
|
||||
format!("sessionid={}", session.expose_secret().session_id).as_str(),
|
||||
&STEAM_COOKIE_URL,
|
||||
);
|
||||
}
|
||||
|
@ -270,7 +277,7 @@ impl SteamApiClient {
|
|||
let login_resp: LoginResponse = serde_json::from_str(text.as_str())?;
|
||||
|
||||
if let Some(oauth) = &login_resp.oauth {
|
||||
self.session = Some(self.build_session(&oauth));
|
||||
self.session = Some(secrecy::Secret::new(self.build_session(&oauth)));
|
||||
}
|
||||
|
||||
return Ok(login_resp);
|
||||
|
@ -295,7 +302,7 @@ impl SteamApiClient {
|
|||
wgtoken_secure: params.token_secure,
|
||||
webcookie: params.webcookie,
|
||||
};
|
||||
self.session = Some(self.build_session(&oauth));
|
||||
self.session = Some(secrecy::Secret::new(self.build_session(&oauth)));
|
||||
return Ok(oauth);
|
||||
}
|
||||
(None, None) => {
|
||||
|
@ -319,7 +326,7 @@ impl SteamApiClient {
|
|||
let mut params = hashmap! {
|
||||
"op" => op,
|
||||
"arg" => arg,
|
||||
"sessionid" => self.session.as_ref().unwrap().session_id.as_str(),
|
||||
"sessionid" => self.session.as_ref().unwrap().expose_secret().session_id.as_str(),
|
||||
};
|
||||
if op == "check_sms_code" {
|
||||
params.insert("checkfortos", "0");
|
||||
|
@ -365,7 +372,7 @@ impl SteamApiClient {
|
|||
let params = hashmap! {
|
||||
"op" => op,
|
||||
"input" => input,
|
||||
"sessionid" => self.session.as_ref().unwrap().session_id.as_str(),
|
||||
"sessionid" => self.session.as_ref().unwrap().expose_secret().session_id.as_str(),
|
||||
};
|
||||
|
||||
let resp = self
|
||||
|
@ -421,8 +428,8 @@ impl SteamApiClient {
|
|||
) -> anyhow::Result<AddAuthenticatorResponse> {
|
||||
ensure!(matches!(self.session, Some(_)));
|
||||
let params = hashmap! {
|
||||
"access_token" => self.session.as_ref().unwrap().token.clone(),
|
||||
"steamid" => self.session.as_ref().unwrap().steam_id.to_string(),
|
||||
"access_token" => self.session.as_ref().unwrap().expose_secret().token.clone(),
|
||||
"steamid" => self.session.as_ref().unwrap().expose_secret().steam_id.to_string(),
|
||||
"authenticator_type" => "1".into(),
|
||||
"device_identifier" => device_id,
|
||||
"sms_phone_id" => "1".into(),
|
||||
|
@ -454,8 +461,8 @@ impl SteamApiClient {
|
|||
) -> anyhow::Result<FinalizeAddAuthenticatorResponse> {
|
||||
ensure!(matches!(self.session, Some(_)));
|
||||
let params = hashmap! {
|
||||
"steamid" => self.session.as_ref().unwrap().steam_id.to_string(),
|
||||
"access_token" => self.session.as_ref().unwrap().token.clone(),
|
||||
"steamid" => self.session.as_ref().unwrap().expose_secret().steam_id.to_string(),
|
||||
"access_token" => self.session.as_ref().unwrap().expose_secret().token.clone(),
|
||||
"activation_code" => sms_code,
|
||||
"authenticator_code" => code_2fa,
|
||||
"authenticator_time" => time_2fa.to_string(),
|
||||
|
@ -485,10 +492,10 @@ impl SteamApiClient {
|
|||
revocation_code: String,
|
||||
) -> anyhow::Result<RemoveAuthenticatorResponse> {
|
||||
let params = hashmap! {
|
||||
"steamid" => self.session.as_ref().unwrap().steam_id.to_string(),
|
||||
"steamid" => self.session.as_ref().unwrap().expose_secret().steam_id.to_string(),
|
||||
"steamguard_scheme" => "2".into(),
|
||||
"revocation_code" => revocation_code,
|
||||
"access_token" => self.session.as_ref().unwrap().token.to_string(),
|
||||
"access_token" => self.session.as_ref().unwrap().expose_secret().token.to_string(),
|
||||
};
|
||||
|
||||
let resp = self
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::steamapi::{LoginResponse, RsaResponse, Session, SteamApiClient};
|
||||
use log::*;
|
||||
use rsa::{PublicKey, RsaPublicKey};
|
||||
use secrecy::ExposeSecret;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -154,7 +155,7 @@ impl UserLogin {
|
|||
self.client.transfer_login(login_resp)?;
|
||||
}
|
||||
|
||||
return Ok(self.client.session.clone().unwrap());
|
||||
return Ok(self.client.session.as_ref().unwrap().expose_secret().to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue