vapored functions should be library

This commit is contained in:
Artemis Tosini 2024-09-05 00:10:51 +00:00
parent b714115f5f
commit 1b50452647
Signed by: artemist
GPG key ID: ADFFE553DCBB831E
9 changed files with 221 additions and 29 deletions

36
Cargo.lock generated
View file

@ -1854,24 +1854,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
name = "vapore-client"
version = "0.0.0"
dependencies = [
"ctor",
"env_logger",
"log",
]
[[package]]
name = "vapore-proto"
version = "0.1.0"
dependencies = [
"protobuf",
"protobuf-codegen",
]
[[package]]
name = "vapored"
name = "vapore"
version = "0.1.0"
dependencies = [
"async-tungstenite",
@ -1894,6 +1877,23 @@ dependencies = [
"vapore-proto",
]
[[package]]
name = "vapore-client"
version = "0.0.0"
dependencies = [
"ctor",
"env_logger",
"log",
]
[[package]]
name = "vapore-proto"
version = "0.1.0"
dependencies = [
"protobuf",
"protobuf-codegen",
]
[[package]]
name = "version_check"
version = "0.9.5"

View file

@ -2,7 +2,7 @@
resolver = "2"
members = [
"client",
"daemon",
"lib",
"proto",
]

View file

@ -28,7 +28,7 @@
protobuf
];
RUST_SRC_PATH = "${rustPackages.rustPlatform.rustLibSrc}";
RUST_LOG = "debug,vapored=trace,vapore-client=trace";
RUST_LOG = "debug,vapore=trace,vapore-client=trace";
RUST_BACKTRACE = "1";
};

View file

@ -1,5 +1,5 @@
[package]
name = "vapored"
name = "vapore"
edition = "2021"
version.workspace = true
@ -8,7 +8,6 @@ async-tungstenite = { version = "0.27.0", features = ["tokio-rustls-native-certs
base64 = "0.22.1"
color-eyre.workspace = true
dialoguer = "0.11.0"
env_logger.workspace = true
flate2 = "1.0.33"
futures = "0.3.30"
hex = "0.4.3"
@ -22,3 +21,6 @@ rsa = "0.9.6"
serde = { version = "1.0.209", features = ["derive"] }
tokio = { version = "1.39", features = ["rt", "rt-multi-thread", "macros", "time"]}
vapore-proto.path = "../proto"
[dev-dependencies]
env_logger.workspace = true

191
lib/examples/login_qr.rs Normal file
View file

@ -0,0 +1,191 @@
use color_eyre::eyre;
use rand::RngCore;
use vapore::message::CMProtoBufMessage;
use vapore_proto::{
enums_clientserver::EMsg,
steammessages_auth_steamclient::{
CAuthentication_BeginAuthSessionViaQR_Request,
CAuthentication_BeginAuthSessionViaQR_Response, CAuthentication_DeviceDetails,
CAuthentication_PollAuthSessionStatus_Request,
CAuthentication_PollAuthSessionStatus_Response, EAuthTokenPlatformType,
},
steammessages_base::{cmsg_ipaddress, CMsgIPAddress},
steammessages_clientserver::CMsgClientLicenseList,
steammessages_clientserver_login::{CMsgClientHello, CMsgClientLogon, CMsgClientLogonResponse},
};
#[tokio::main]
pub async fn main() -> eyre::Result<()> {
env_logger::init();
color_eyre::install()?;
log::info!("Starting vapored");
let servers = vapore::connection::bootstrap_find_servers().await?;
log::debug!("Found servers: {:?}", servers);
let session = vapore::connection::CMSession::connect(&servers[0]).await?;
session.send_notification(
EMsg::k_EMsgClientHello,
CMsgClientHello {
protocol_version: Some(0x1002c),
..Default::default()
},
)?;
log::debug!("Sent hello");
// machine_id is supposed to be a binary key/value with the SHA1 of the machine's
// BB3: Machine GUID
// FF2: MAC address
// 3B3: Disk ID
// We should probably make these consistent so Valve doesn't get suspicious,
// but for now let's make them random
// TODO: Find a more generic way to make this
let mut machine_id = Vec::with_capacity(155);
machine_id.extend_from_slice(b"\x00MessageObject\x00");
for key in [b"BB3", b"FF2", b"3B3"] {
let mut data = [0u8; 20];
rand::thread_rng().fill_bytes(&mut data);
let hex_bytes = hex::encode(data).into_bytes();
// Type is string
machine_id.push(b'\x01');
machine_id.extend_from_slice(key);
machine_id.push(b'\x00');
machine_id.extend_from_slice(&hex_bytes);
machine_id.push(b'\x00');
}
// suitable end bytes
machine_id.extend_from_slice(b"\x08\x08");
let response = session
.call_service_method::<_, CAuthentication_BeginAuthSessionViaQR_Response>(
"Authentication.BeginAuthSessionViaQR#1".to_string(),
CAuthentication_BeginAuthSessionViaQR_Request {
device_details: protobuf::MessageField::some(CAuthentication_DeviceDetails {
device_friendly_name: Some("vapore".to_string()),
platform_type: Some(protobuf::EnumOrUnknown::new(
EAuthTokenPlatformType::k_EAuthTokenPlatformType_SteamClient,
)),
// Windows 11
os_type: Some(20),
machine_id: Some(machine_id.clone()),
..Default::default()
}),
..Default::default()
},
)
.await?;
log::debug!("Got response {:#x?}", response);
let code = qrcode::QrCode::new(response.body.challenge_url()).unwrap();
log::info!(
"Got new QR code:\n{}",
code.render::<qrcode::render::unicode::Dense1x2>().build()
);
let mut interval = tokio::time::interval(tokio::time::Duration::from_secs_f32(
response.body.interval(),
));
let (refresh_token, account_name) = loop {
interval.tick().await;
let request = CAuthentication_PollAuthSessionStatus_Request {
client_id: response.body.client_id,
request_id: response.body.request_id.clone(),
..Default::default()
};
let response: CMProtoBufMessage<CAuthentication_PollAuthSessionStatus_Response> = session
.call_service_method(
"Authentication.PollAuthSessionStatus#1".to_string(),
request,
)
.await?;
log::debug!("Got auth poll status {:#?}", response.body);
if let Some(access_token) = response.body.refresh_token {
let account_name = response.body.account_name.unwrap_or_default();
break (access_token, account_name);
}
if let Some(new_url) = response.body.new_challenge_url {
let code = qrcode::QrCode::new(new_url)?;
log::info!(
"Got new QR code:\n{}",
code.render::<qrcode::render::unicode::Dense1x2>().build()
)
};
};
log::debug!(
"Got account name {}, access token {}",
account_name,
refresh_token
);
// normal user, desktop instance, public universe
session.set_steam_id(0x0110_0001_0000_0000);
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 session_cloned = session.clone();
tokio::spawn(async move {
let license_list_raw = session_cloned
.subscribe_message_type(EMsg::k_EMsgClientLicenseList)
.recv()
.await
.unwrap();
let license_list: CMProtoBufMessage<CMsgClientLicenseList> =
CMProtoBufMessage::deserialize(license_list_raw).unwrap();
for license in &license_list.body.licenses {
log::info!("Own package ID: {}", license.package_id());
}
});
let mut finish_receiver = session.subscribe_message_type(EMsg::k_EMsgClientLogOnResponse);
let raw_response = finish_receiver.recv().await?;
let response: CMProtoBufMessage<CMsgClientLogonResponse> =
CMProtoBufMessage::deserialize(raw_response)?;
log::debug!("Got logon response: {:#x?}", response);
if response.body.eresult != Some(0x01) {
eyre::bail!("Login failed");
};
session.set_steam_id(response.header.steamid());
session.set_client_session_id(response.header.client_sessionid());
if let Some(heartbeat_seconds) = response.body.heartbeat_seconds {
if heartbeat_seconds >= 5 {
session.begin_heartbeat(heartbeat_seconds as u32);
}
}
Ok(())
}

View file

@ -1,8 +1,8 @@
use base64::Engine;
use color_eyre::eyre::{self, Context, OptionExt};
use connection::CMSession;
use message::CMProtoBufMessage;
use rand::RngCore;
use vapore::connection::CMSession;
use vapore::message::CMProtoBufMessage;
use vapore_proto::{
enums::ESessionPersistence,
enums_clientserver::EMsg,
@ -22,9 +22,6 @@ use vapore_proto::{
steammessages_clientserver_login::{CMsgClientHello, CMsgClientLogon, CMsgClientLogonResponse},
};
mod connection;
mod message;
#[tokio::main]
pub async fn main() -> eyre::Result<()> {
env_logger::init();
@ -32,10 +29,10 @@ pub async fn main() -> eyre::Result<()> {
log::info!("Starting vapored");
let servers = connection::bootstrap_find_servers().await?;
let servers = vapore::connection::bootstrap_find_servers().await?;
log::debug!("Found servers: {:?}", servers);
let session = connection::CMSession::connect(&servers[0]).await?;
let session = CMSession::connect(&servers[0]).await?;
session.send_notification(
EMsg::k_EMsgClientHello,

2
lib/src/lib.rs Normal file
View file

@ -0,0 +1,2 @@
pub mod connection;
pub mod message;