Add bad logon function

This commit is contained in:
Artemis Tosini 2024-09-10 04:15:11 +00:00
parent e64e563e11
commit d92b6f2bac
Signed by: artemist
GPG key ID: ADFFE553DCBB831E
3 changed files with 178 additions and 12 deletions

View file

@ -0,0 +1,29 @@
use color_eyre::eyre::{self};
use vapore::client::SteamClient;
#[tokio::main]
pub async fn main() -> eyre::Result<()> {
env_logger::init();
color_eyre::install()?;
let servers = vapore::selection::bootstrap_find_servers().await?;
log::debug!("Found servers: {:?}", servers);
let client = SteamClient::connect(&servers).await?;
let username = dialoguer::Input::<String>::new()
.with_prompt("Username")
.interact_text()?;
let password = dialoguer::Password::new()
.with_prompt("Password")
.interact()?;
let guard_code = dialoguer::Input::<String>::new()
.with_prompt("Steam Guard Code")
.interact_text()?;
client
.auth_password(username, password, Some(guard_code))
.await?;
Ok(())
}

View file

@ -1,6 +1,6 @@
use std::sync::Arc;
use base64::Engine as _;
use base64::{prelude::BASE64_STANDARD, Engine as _};
use snafu::prelude::*;
use vapore_proto::{
enums::ESessionPersistence,
@ -9,14 +9,22 @@ use vapore_proto::{
CAuthentication_BeginAuthSessionViaCredentials_Request,
CAuthentication_BeginAuthSessionViaCredentials_Response, CAuthentication_DeviceDetails,
CAuthentication_GetPasswordRSAPublicKey_Request,
CAuthentication_GetPasswordRSAPublicKey_Response, EAuthTokenPlatformType,
CAuthentication_GetPasswordRSAPublicKey_Response,
CAuthentication_PollAuthSessionStatus_Request,
CAuthentication_PollAuthSessionStatus_Response,
CAuthentication_UpdateAuthSessionWithSteamGuardCode_Request,
CAuthentication_UpdateAuthSessionWithSteamGuardCode_Response, EAuthSessionGuardType,
EAuthTokenPlatformType,
},
steammessages_clientserver_login::CMsgClientHello,
steammessages_base::{cmsg_ipaddress, CMsgIPAddress},
steammessages_clientserver_login::{CMsgClientHello, CMsgClientLogon, CMsgClientLogonResponse},
};
use crate::{
connection::CMSession,
error::{RSAEncryptSnafu, RSAParameterParseSnafu, RSAParseSnafu},
error::{
ListenRecvSnafu, MissingFieldSnafu, RSAEncryptSnafu, RSAParameterParseSnafu, RSAParseSnafu,
},
message::CMProtoBufMessage,
platform::generate_machine_id,
state::apps::AppsHandler,
@ -41,8 +49,8 @@ pub struct SteamClient {
}
impl SteamClient {
pub async fn connect(servers: &[&str]) -> Result<Self, ClientError> {
let (session, context) = CMSession::connect(servers[0]).await?;
pub async fn connect(servers: &[String]) -> Result<Self, ClientError> {
let (session, context) = CMSession::connect(&servers[0]).await?;
let inner = Arc::new(SteamClientInner {
apps: AppsHandler::listen(&session),
@ -84,6 +92,8 @@ impl SteamClient {
)
.await?;
password_key_response.ok()?;
let password_key = rsa::RsaPublicKey::new(
rsa::BigUint::parse_bytes(password_key_response.body.publickey_mod().as_bytes(), 16)
.context(RSAParameterParseSnafu {})?,
@ -107,13 +117,9 @@ impl SteamClient {
"Authentication.BeginAuthSessionViaCredentials#1".to_string(),
CAuthentication_BeginAuthSessionViaCredentials_Request {
account_name: Some(username.clone()),
encrypted_password: Some(
base64::engine::general_purpose::STANDARD.encode(&encrypted_password),
),
encrypted_password: Some(BASE64_STANDARD.encode(&encrypted_password)),
encryption_timestamp: password_key_response.body.timestamp,
persistence: Some(protobuf::EnumOrUnknown::new(
ESessionPersistence::k_ESessionPersistence_Ephemeral,
)),
persistence: Some(ESessionPersistence::k_ESessionPersistence_Ephemeral.into()),
device_details: protobuf::MessageField::some(CAuthentication_DeviceDetails {
device_friendly_name: Some("vapore".to_string()),
platform_type: Some(protobuf::EnumOrUnknown::new(
@ -128,6 +134,122 @@ impl SteamClient {
},
)
.await?;
log::debug!("Got auth response {:#x?}", auth_session_response);
auth_session_response.ok()?;
let confirmation_type = auth_session_response
.body
.allowed_confirmations
.first()
.unwrap_or_default()
.confirmation_type();
if confirmation_type == EAuthSessionGuardType::k_EAuthSessionGuardType_Unknown {
return Err(ClientError::NoAllowedConfirmations);
} else if confirmation_type == EAuthSessionGuardType::k_EAuthSessionGuardType_None {
// No required confirmation, we can go directly to login
} else if confirmation_type == EAuthSessionGuardType::k_EAuthSessionGuardType_EmailCode
|| confirmation_type == EAuthSessionGuardType::k_EAuthSessionGuardType_DeviceCode
{
let update_response: CMProtoBufMessage<
CAuthentication_UpdateAuthSessionWithSteamGuardCode_Response,
> = self
.inner
.session
.call_service_method(
"Authentication.UpdateAuthSessionWithSteamGuardCode#1".to_string(),
CAuthentication_UpdateAuthSessionWithSteamGuardCode_Request {
client_id: auth_session_response.body.client_id,
steamid: auth_session_response.body.steamid,
code,
code_type: Some(confirmation_type.into()),
..Default::default()
},
)
.await?;
update_response.ok()?;
} else {
return Err(ClientError::UnsupportedConfirmation {
typ: confirmation_type,
});
}
let poll_response: CMProtoBufMessage<CAuthentication_PollAuthSessionStatus_Response> = self
.inner
.session
.call_service_method(
"Authentication.PollAuthSessionStatus#1".to_string(),
CAuthentication_PollAuthSessionStatus_Request {
client_id: auth_session_response.body.client_id,
request_id: auth_session_response.body.request_id.clone(),
..Default::default()
},
)
.await?;
poll_response.ok()?;
log::debug!("Got poll response: {:#?}", poll_response);
let mut logon_receiver = self
.inner
.session
.subscribe_message_type(EMsg::k_EMsgClientLogOnResponse);
let account_name = poll_response.body.account_name.context(MissingFieldSnafu {
field: "account_name",
})?;
let refresh_token = poll_response
.body
.refresh_token
.context(MissingFieldSnafu {
field: "refresh_token",
})?;
log::debug!(
"Got account name {}, access token {}",
account_name,
refresh_token
);
// normal user, desktop instance, public universe
self.inner.session.set_steam_id(0x0110_0001_0000_0000);
self.inner.session.send_notification(
EMsg::k_EMsgClientLogon,
CMsgClientLogon {
account_name: Some(account_name),
access_token: Some(refresh_token),
machine_name: Some("vapore".to_string()),
machine_id: Some(machine_id),
client_language: Some("english".to_string()),
protocol_version: Some(0x1002c),
client_os_type: Some(20),
client_package_version: Some(1771),
supports_rate_limit_response: Some(true),
should_remember_password: Some(true),
obfuscated_private_ip: protobuf::MessageField::some(CMsgIPAddress {
ip: Some(cmsg_ipaddress::Ip::V4(0xc0a8_0102 ^ 0xbaad_f00d)),
..Default::default()
}),
deprecated_obfustucated_private_ip: Some(0xc0a8_0102 ^ 0xbaad_f00d),
..Default::default()
},
)?;
let raw_logon = logon_receiver.recv().await.context(ListenRecvSnafu {})?;
let logon: CMProtoBufMessage<CMsgClientLogonResponse> =
CMProtoBufMessage::deserialize(raw_logon)?;
self.inner.session.set_steam_id(logon.header.steamid());
self.inner
.session
.set_client_session_id(logon.header.client_sessionid());
if let Some(heartbeat_seconds) = logon.body.heartbeat_seconds {
if heartbeat_seconds >= 5 {
self.inner.session.begin_heartbeat(heartbeat_seconds as u32);
}
}
Ok(())
}

View file

@ -1,4 +1,5 @@
use snafu::prelude::*;
use vapore_proto::steammessages_auth_steamclient::EAuthSessionGuardType;
use vapore_struct::eresult::EResult;
#[derive(Debug, Snafu)]
@ -38,6 +39,9 @@ pub enum ClientError {
#[snafu(display("Protobuf Serialization error"))]
ProtobufSer { source: protobuf::Error },
#[snafu(display("Struct Missing Field `{field}`"))]
MissingField { field: &'static str },
#[snafu(display("Invalid WebSocket message type from server"))]
BadWSMessageType,
@ -77,6 +81,17 @@ pub enum ClientError {
#[snafu(display("Unable to encrupt with RSA"))]
RSAEncrypt { source: rsa::Error },
#[snafu(display("Unsupported Confirmation type {typ:?}"))]
UnsupportedConfirmation { typ: EAuthSessionGuardType },
#[snafu(display("No allowed confirmations"))]
NoAllowedConfirmations,
#[snafu(display("Unable to fetch messages from listen thread"))]
ListenRecv {
source: tokio::sync::broadcast::error::RecvError,
},
}
impl<T> From<std::sync::PoisonError<T>> for ClientError {