Add bad logon function
This commit is contained in:
parent
e64e563e11
commit
d92b6f2bac
29
lib/examples/login_steamguard_new.rs
Normal file
29
lib/examples/login_steamguard_new.rs
Normal 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(())
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use base64::Engine as _;
|
use base64::{prelude::BASE64_STANDARD, Engine as _};
|
||||||
use snafu::prelude::*;
|
use snafu::prelude::*;
|
||||||
use vapore_proto::{
|
use vapore_proto::{
|
||||||
enums::ESessionPersistence,
|
enums::ESessionPersistence,
|
||||||
|
@ -9,14 +9,22 @@ use vapore_proto::{
|
||||||
CAuthentication_BeginAuthSessionViaCredentials_Request,
|
CAuthentication_BeginAuthSessionViaCredentials_Request,
|
||||||
CAuthentication_BeginAuthSessionViaCredentials_Response, CAuthentication_DeviceDetails,
|
CAuthentication_BeginAuthSessionViaCredentials_Response, CAuthentication_DeviceDetails,
|
||||||
CAuthentication_GetPasswordRSAPublicKey_Request,
|
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::{
|
use crate::{
|
||||||
connection::CMSession,
|
connection::CMSession,
|
||||||
error::{RSAEncryptSnafu, RSAParameterParseSnafu, RSAParseSnafu},
|
error::{
|
||||||
|
ListenRecvSnafu, MissingFieldSnafu, RSAEncryptSnafu, RSAParameterParseSnafu, RSAParseSnafu,
|
||||||
|
},
|
||||||
message::CMProtoBufMessage,
|
message::CMProtoBufMessage,
|
||||||
platform::generate_machine_id,
|
platform::generate_machine_id,
|
||||||
state::apps::AppsHandler,
|
state::apps::AppsHandler,
|
||||||
|
@ -41,8 +49,8 @@ pub struct SteamClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SteamClient {
|
impl SteamClient {
|
||||||
pub async fn connect(servers: &[&str]) -> Result<Self, ClientError> {
|
pub async fn connect(servers: &[String]) -> Result<Self, ClientError> {
|
||||||
let (session, context) = CMSession::connect(servers[0]).await?;
|
let (session, context) = CMSession::connect(&servers[0]).await?;
|
||||||
|
|
||||||
let inner = Arc::new(SteamClientInner {
|
let inner = Arc::new(SteamClientInner {
|
||||||
apps: AppsHandler::listen(&session),
|
apps: AppsHandler::listen(&session),
|
||||||
|
@ -84,6 +92,8 @@ impl SteamClient {
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
password_key_response.ok()?;
|
||||||
|
|
||||||
let password_key = rsa::RsaPublicKey::new(
|
let password_key = rsa::RsaPublicKey::new(
|
||||||
rsa::BigUint::parse_bytes(password_key_response.body.publickey_mod().as_bytes(), 16)
|
rsa::BigUint::parse_bytes(password_key_response.body.publickey_mod().as_bytes(), 16)
|
||||||
.context(RSAParameterParseSnafu {})?,
|
.context(RSAParameterParseSnafu {})?,
|
||||||
|
@ -107,13 +117,9 @@ impl SteamClient {
|
||||||
"Authentication.BeginAuthSessionViaCredentials#1".to_string(),
|
"Authentication.BeginAuthSessionViaCredentials#1".to_string(),
|
||||||
CAuthentication_BeginAuthSessionViaCredentials_Request {
|
CAuthentication_BeginAuthSessionViaCredentials_Request {
|
||||||
account_name: Some(username.clone()),
|
account_name: Some(username.clone()),
|
||||||
encrypted_password: Some(
|
encrypted_password: Some(BASE64_STANDARD.encode(&encrypted_password)),
|
||||||
base64::engine::general_purpose::STANDARD.encode(&encrypted_password),
|
|
||||||
),
|
|
||||||
encryption_timestamp: password_key_response.body.timestamp,
|
encryption_timestamp: password_key_response.body.timestamp,
|
||||||
persistence: Some(protobuf::EnumOrUnknown::new(
|
persistence: Some(ESessionPersistence::k_ESessionPersistence_Ephemeral.into()),
|
||||||
ESessionPersistence::k_ESessionPersistence_Ephemeral,
|
|
||||||
)),
|
|
||||||
device_details: protobuf::MessageField::some(CAuthentication_DeviceDetails {
|
device_details: protobuf::MessageField::some(CAuthentication_DeviceDetails {
|
||||||
device_friendly_name: Some("vapore".to_string()),
|
device_friendly_name: Some("vapore".to_string()),
|
||||||
platform_type: Some(protobuf::EnumOrUnknown::new(
|
platform_type: Some(protobuf::EnumOrUnknown::new(
|
||||||
|
@ -128,6 +134,122 @@ impl SteamClient {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await?;
|
.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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use snafu::prelude::*;
|
use snafu::prelude::*;
|
||||||
|
use vapore_proto::steammessages_auth_steamclient::EAuthSessionGuardType;
|
||||||
use vapore_struct::eresult::EResult;
|
use vapore_struct::eresult::EResult;
|
||||||
|
|
||||||
#[derive(Debug, Snafu)]
|
#[derive(Debug, Snafu)]
|
||||||
|
@ -38,6 +39,9 @@ pub enum ClientError {
|
||||||
#[snafu(display("Protobuf Serialization error"))]
|
#[snafu(display("Protobuf Serialization error"))]
|
||||||
ProtobufSer { source: protobuf::Error },
|
ProtobufSer { source: protobuf::Error },
|
||||||
|
|
||||||
|
#[snafu(display("Struct Missing Field `{field}`"))]
|
||||||
|
MissingField { field: &'static str },
|
||||||
|
|
||||||
#[snafu(display("Invalid WebSocket message type from server"))]
|
#[snafu(display("Invalid WebSocket message type from server"))]
|
||||||
BadWSMessageType,
|
BadWSMessageType,
|
||||||
|
|
||||||
|
@ -77,6 +81,17 @@ pub enum ClientError {
|
||||||
|
|
||||||
#[snafu(display("Unable to encrupt with RSA"))]
|
#[snafu(display("Unable to encrupt with RSA"))]
|
||||||
RSAEncrypt { source: rsa::Error },
|
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 {
|
impl<T> From<std::sync::PoisonError<T>> for ClientError {
|
||||||
|
|
Loading…
Reference in a new issue