well, steam gives me an auth token now

This commit is contained in:
Artemis Tosini 2024-08-27 22:59:24 +00:00
parent 6e2eb1aea0
commit 2331c7ecf1
Signed by: artemist
GPG key ID: EE5227935FE3FF18
5 changed files with 184 additions and 11 deletions

79
Cargo.lock generated
View file

@ -17,6 +17,12 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "adler2"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "1.1.3" version = "1.1.3"
@ -114,7 +120,7 @@ dependencies = [
"cc", "cc",
"cfg-if", "cfg-if",
"libc", "libc",
"miniz_oxide", "miniz_oxide 0.7.4",
"object", "object",
"rustc-demangle", "rustc-demangle",
] ]
@ -146,12 +152,24 @@ version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
[[package]]
name = "bytemuck"
version = "1.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773d90827bc3feecfb67fab12e24de0749aad83c74b9504ecde46237b5cd24e2"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
version = "1.5.0" version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "byteorder-lite"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.7.1" version = "1.7.1"
@ -231,6 +249,15 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "crc32fast"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "crypto-common" name = "crypto-common"
version = "0.1.6" version = "0.1.6"
@ -328,6 +355,16 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
[[package]]
name = "flate2"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253"
dependencies = [
"crc32fast",
"miniz_oxide 0.8.0",
]
[[package]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"
@ -599,6 +636,17 @@ dependencies = [
"unicode-normalization", "unicode-normalization",
] ]
[[package]]
name = "image"
version = "0.25.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99314c8a2152b8ddb211f924cdae532d8c5e4c8bb54728e12fff1b0cd5963a10"
dependencies = [
"bytemuck",
"byteorder-lite",
"num-traits",
]
[[package]] [[package]]
name = "indenter" name = "indenter"
version = "0.3.3" version = "0.3.3"
@ -709,6 +757,15 @@ dependencies = [
"adler", "adler",
] ]
[[package]]
name = "miniz_oxide"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
dependencies = [
"adler2",
]
[[package]] [[package]]
name = "mio" name = "mio"
version = "1.0.2" version = "1.0.2"
@ -721,6 +778,15 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "object" name = "object"
version = "0.32.2" version = "0.32.2"
@ -897,6 +963,15 @@ dependencies = [
"thiserror", "thiserror",
] ]
[[package]]
name = "qrcode"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d68782463e408eb1e668cf6152704bd856c78c5b6417adaee3203d8f4c1fc9ec"
dependencies = [
"image",
]
[[package]] [[package]]
name = "quinn" name = "quinn"
version = "0.11.2" version = "0.11.2"
@ -1617,11 +1692,13 @@ dependencies = [
"async-tungstenite", "async-tungstenite",
"color-eyre", "color-eyre",
"env_logger", "env_logger",
"flate2",
"futures", "futures",
"hex", "hex",
"keyvalues-serde", "keyvalues-serde",
"log", "log",
"protobuf", "protobuf",
"qrcode",
"rand", "rand",
"reqwest", "reqwest",
"serde", "serde",

View file

@ -7,13 +7,15 @@ version.workspace = true
async-tungstenite = { version = "0.27.0", features = ["tokio-rustls-native-certs"] } async-tungstenite = { version = "0.27.0", features = ["tokio-rustls-native-certs"] }
color-eyre.workspace = true color-eyre.workspace = true
env_logger.workspace = true env_logger.workspace = true
flate2 = "1.0.33"
futures = "0.3.30" futures = "0.3.30"
hex = "0.4.3" hex = "0.4.3"
keyvalues-serde.workspace = true keyvalues-serde.workspace = true
log.workspace = true log.workspace = true
protobuf.workspace = true protobuf.workspace = true
qrcode = "0.14.1"
rand = "0.8.5" rand = "0.8.5"
reqwest = { version = "0.12", features = ["rustls-tls-native-roots"], default-features = false} reqwest = { version = "0.12", features = ["rustls-tls-native-roots"], default-features = false}
serde = { version = "1.0.209", features = ["derive"] } serde = { version = "1.0.209", features = ["derive"] }
tokio = { version = "1.39", features = ["rt", "rt-multi-thread", "macros"]} tokio = { version = "1.39", features = ["rt", "rt-multi-thread", "macros", "time"]}
vapore-proto.path = "../proto" vapore-proto.path = "../proto"

View file

@ -1,3 +1,4 @@
use core::time;
use std::{ use std::{
collections::{BTreeMap, HashMap, VecDeque}, collections::{BTreeMap, HashMap, VecDeque},
future::Future, future::Future,
@ -16,7 +17,10 @@ use color_eyre::eyre::{self, bail, OptionExt};
use futures::{SinkExt as _, StreamExt}; use futures::{SinkExt as _, StreamExt};
use serde::Deserialize; use serde::Deserialize;
use tokio::sync::broadcast; use tokio::sync::broadcast;
use vapore_proto::{enums_clientserver::EMsg, steammessages_base::CMsgProtoBufHeader}; use vapore_proto::{
enums_clientserver::EMsg, steammessages_base::CMsgProtoBufHeader,
steammessages_clientserver_login::CMsgClientHeartBeat,
};
use crate::message::{CMProtoBufMessage, CMRawProtoBufMessage}; use crate::message::{CMProtoBufMessage, CMRawProtoBufMessage};
@ -235,9 +239,27 @@ impl CMSession {
tokio::spawn(context); tokio::spawn(context);
Ok(Self { let session = Self {
inner: inner_wrapped, inner: inner_wrapped,
}) };
let session_cloned = session.clone();
tokio::spawn(async move { session_cloned.send_heartbeat_task().await });
Ok(session)
}
async fn send_heartbeat_task(mut self) -> eyre::Result<()> {
let mut interval = tokio::time::interval(time::Duration::from_secs(5));
loop {
interval.tick().await;
self.send_notification(EMsg::k_EMsgClientHeartBeat, CMsgClientHeartBeat::default())?
}
}
pub fn set_client_session_id(&mut self, new_client_session_id: i32) {
let mut inner = self.inner.lock().expect("Lock was poisoned");
inner.client_session_id = new_client_session_id;
} }
pub fn call_service_method<T: protobuf::Message, U: protobuf::Message>( pub fn call_service_method<T: protobuf::Message, U: protobuf::Message>(

View file

@ -1,13 +1,15 @@
use color_eyre::eyre; use color_eyre::eyre;
use message::CMProtoBufMessage;
use rand::RngCore; use rand::RngCore;
use vapore_proto::{ use vapore_proto::{
enums_clientserver::EMsg, enums_clientserver::EMsg,
steammessages_auth_steamclient::{ steammessages_auth_steamclient::{
CAuthentication_BeginAuthSessionViaQR_Request, CAuthentication_BeginAuthSessionViaQR_Request,
CAuthentication_BeginAuthSessionViaQR_Response, CAuthentication_DeviceDetails, CAuthentication_BeginAuthSessionViaQR_Response, CAuthentication_DeviceDetails,
EAuthTokenPlatformType, CAuthentication_PollAuthSessionStatus_Request,
CAuthentication_PollAuthSessionStatus_Response, EAuthTokenPlatformType,
}, },
steammessages_clientserver_login::CMsgClientHello, steammessages_clientserver_login::{CMsgClientHello, CMsgClientLogonResponse},
}; };
mod connection; mod connection;
@ -82,5 +84,56 @@ pub async fn main() -> eyre::Result<()> {
log::debug!("Got response {:#x?}", response); 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 cloned_session = session.clone();
let poll_task = tokio::spawn(async move {
let mut session = cloned_session;
let mut interval = tokio::time::interval(tokio::time::Duration::from_secs_f32(
response.body.interval(),
));
loop {
interval.tick().await;
let request = CAuthentication_PollAuthSessionStatus_Request {
client_id: response.body.client_id.clone(),
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
.unwrap();
log::debug!("Got auth poll status {:#?}", response.body);
if let Some(new_url) = response.body.new_challenge_url {
let code = qrcode::QrCode::new(new_url).unwrap();
log::info!(
"Got new QR code:\n{}",
code.render::<qrcode::render::unicode::Dense1x2>().build()
)
};
}
});
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)?;
poll_task.abort();
log::debug!("Got logon response: {:#x?}", response);
Ok(()) Ok(())
} }

View file

@ -1,4 +1,7 @@
use std::io::Read;
use color_eyre::eyre; use color_eyre::eyre;
use flate2::read::GzDecoder;
use protobuf::{Enum as _, Message as _}; use protobuf::{Enum as _, Message as _};
use vapore_proto::{ use vapore_proto::{
enums_clientserver::EMsg, enums_clientserver::EMsg,
@ -82,12 +85,28 @@ impl CMRawProtoBufMessage {
// possibly gzipped bytes inside a protobuf. // possibly gzipped bytes inside a protobuf.
// why, valve // why, valve
let root = CMProtoBufMessage::<CMsgMulti>::deserialize(root_raw)?; let root = CMProtoBufMessage::<CMsgMulti>::deserialize(root_raw)?;
if root.body.size_unzipped.is_some() { let mut gzip_decompressed = Vec::new();
todo!("gzip support in CMsgMulti")
} let mut body = if let Some(size_unzipped) = root.body.size_unzipped {
gzip_decompressed.reserve(size_unzipped as usize);
let mut gz = GzDecoder::new(root.body.message_body());
gz.read_to_end(&mut gzip_decompressed)?;
if gzip_decompressed.len() != size_unzipped as usize {
eyre::bail!(
"Expected decompressed len {}, got {}",
size_unzipped,
gzip_decompressed.len()
);
}
&gzip_decompressed
} else {
root.body.message_body()
};
let mut items = Vec::new(); let mut items = Vec::new();
let mut body = root.body.message_body();
while body.len() >= 4 { while body.len() >= 4 {
let full_length = u32::from_le_bytes(body[0..4].try_into().unwrap()); let full_length = u32::from_le_bytes(body[0..4].try_into().unwrap());
let message_end = 4 + full_length as usize; let message_end = 4 + full_length as usize;