vapored functions should be library
This commit is contained in:
parent
b714115f5f
commit
1b50452647
36
Cargo.lock
generated
36
Cargo.lock
generated
|
@ -1854,24 +1854,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vapore-client"
|
name = "vapore"
|
||||||
version = "0.0.0"
|
|
||||||
dependencies = [
|
|
||||||
"ctor",
|
|
||||||
"env_logger",
|
|
||||||
"log",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vapore-proto"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"protobuf",
|
|
||||||
"protobuf-codegen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vapored"
|
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-tungstenite",
|
"async-tungstenite",
|
||||||
|
@ -1894,6 +1877,23 @@ dependencies = [
|
||||||
"vapore-proto",
|
"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]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.5"
|
version = "0.9.5"
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = [
|
members = [
|
||||||
"client",
|
"client",
|
||||||
"daemon",
|
"lib",
|
||||||
"proto",
|
"proto",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
protobuf
|
protobuf
|
||||||
];
|
];
|
||||||
RUST_SRC_PATH = "${rustPackages.rustPlatform.rustLibSrc}";
|
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";
|
RUST_BACKTRACE = "1";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[package]
|
[package]
|
||||||
name = "vapored"
|
name = "vapore"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ async-tungstenite = { version = "0.27.0", features = ["tokio-rustls-native-certs
|
||||||
base64 = "0.22.1"
|
base64 = "0.22.1"
|
||||||
color-eyre.workspace = true
|
color-eyre.workspace = true
|
||||||
dialoguer = "0.11.0"
|
dialoguer = "0.11.0"
|
||||||
env_logger.workspace = true
|
|
||||||
flate2 = "1.0.33"
|
flate2 = "1.0.33"
|
||||||
futures = "0.3.30"
|
futures = "0.3.30"
|
||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
|
@ -22,3 +21,6 @@ rsa = "0.9.6"
|
||||||
serde = { version = "1.0.209", features = ["derive"] }
|
serde = { version = "1.0.209", features = ["derive"] }
|
||||||
tokio = { version = "1.39", features = ["rt", "rt-multi-thread", "macros", "time"]}
|
tokio = { version = "1.39", features = ["rt", "rt-multi-thread", "macros", "time"]}
|
||||||
vapore-proto.path = "../proto"
|
vapore-proto.path = "../proto"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
env_logger.workspace = true
|
191
lib/examples/login_qr.rs
Normal file
191
lib/examples/login_qr.rs
Normal 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(())
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
use color_eyre::eyre::{self, Context, OptionExt};
|
use color_eyre::eyre::{self, Context, OptionExt};
|
||||||
use connection::CMSession;
|
|
||||||
use message::CMProtoBufMessage;
|
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
|
use vapore::connection::CMSession;
|
||||||
|
use vapore::message::CMProtoBufMessage;
|
||||||
use vapore_proto::{
|
use vapore_proto::{
|
||||||
enums::ESessionPersistence,
|
enums::ESessionPersistence,
|
||||||
enums_clientserver::EMsg,
|
enums_clientserver::EMsg,
|
||||||
|
@ -22,9 +22,6 @@ use vapore_proto::{
|
||||||
steammessages_clientserver_login::{CMsgClientHello, CMsgClientLogon, CMsgClientLogonResponse},
|
steammessages_clientserver_login::{CMsgClientHello, CMsgClientLogon, CMsgClientLogonResponse},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod connection;
|
|
||||||
mod message;
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
pub async fn main() -> eyre::Result<()> {
|
pub async fn main() -> eyre::Result<()> {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
@ -32,10 +29,10 @@ pub async fn main() -> eyre::Result<()> {
|
||||||
|
|
||||||
log::info!("Starting vapored");
|
log::info!("Starting vapored");
|
||||||
|
|
||||||
let servers = connection::bootstrap_find_servers().await?;
|
let servers = vapore::connection::bootstrap_find_servers().await?;
|
||||||
log::debug!("Found servers: {:?}", servers);
|
log::debug!("Found servers: {:?}", servers);
|
||||||
|
|
||||||
let session = connection::CMSession::connect(&servers[0]).await?;
|
let session = CMSession::connect(&servers[0]).await?;
|
||||||
|
|
||||||
session.send_notification(
|
session.send_notification(
|
||||||
EMsg::k_EMsgClientHello,
|
EMsg::k_EMsgClientHello,
|
2
lib/src/lib.rs
Normal file
2
lib/src/lib.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod connection;
|
||||||
|
pub mod message;
|
Loading…
Reference in a new issue