From fca43d6220a951036759c5e328f90033ad24f856 Mon Sep 17 00:00:00 2001 From: Artemis Tosini Date: Wed, 4 Sep 2024 23:17:26 +0000 Subject: [PATCH] vapored: Log in with code --- Cargo.lock | 188 +++++++++++++++++++++++++++++++++++++++++++++ daemon/Cargo.toml | 3 + daemon/src/main.rs | 110 ++++++++++++++++++++++---- 3 files changed, 284 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d9e3ac2..f469af1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -131,6 +131,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bitflags" version = "2.6.0" @@ -224,6 +230,25 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "unicode-width", + "windows-sys 0.52.0", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "core-foundation" version = "0.9.4" @@ -284,6 +309,30 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "dialoguer" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de" +dependencies = [ + "console", + "shell-words", + "tempfile", + "thiserror", + "zeroize", +] + [[package]] name = "digest" version = "0.10.7" @@ -291,6 +340,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", ] @@ -300,6 +350,12 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "env_filter" version = "0.1.2" @@ -717,6 +773,9 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] [[package]] name = "libc" @@ -724,6 +783,12 @@ version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -778,6 +843,43 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -785,6 +887,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -814,6 +917,15 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -897,6 +1009,27 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1143,6 +1276,26 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rsa" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "spki", + "subtle", + "zeroize", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -1335,12 +1488,28 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + [[package]] name = "slab" version = "0.4.9" @@ -1372,6 +1541,16 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "subtle" version = "2.6.1" @@ -1633,6 +1812,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-width" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" + [[package]] name = "untrusted" version = "0.9.0" @@ -1690,7 +1875,9 @@ name = "vapored" version = "0.1.0" dependencies = [ "async-tungstenite", + "base64", "color-eyre", + "dialoguer", "env_logger", "flate2", "futures", @@ -1701,6 +1888,7 @@ dependencies = [ "qrcode", "rand", "reqwest", + "rsa", "serde", "tokio", "vapore-proto", diff --git a/daemon/Cargo.toml b/daemon/Cargo.toml index d3b547c..8277e4c 100644 --- a/daemon/Cargo.toml +++ b/daemon/Cargo.toml @@ -5,7 +5,9 @@ version.workspace = true [dependencies] 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" @@ -16,6 +18,7 @@ protobuf.workspace = true qrcode = "0.14.1" rand = "0.8.5" reqwest = { version = "0.12", features = ["rustls-tls-native-roots"], default-features = false} +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" diff --git a/daemon/src/main.rs b/daemon/src/main.rs index ce98cf1..aa5a7c7 100644 --- a/daemon/src/main.rs +++ b/daemon/src/main.rs @@ -1,14 +1,21 @@ -use color_eyre::eyre; +use base64::Engine; +use color_eyre::eyre::{self, Context, OptionExt}; use connection::CMSession; use message::CMProtoBufMessage; use rand::RngCore; use vapore_proto::{ + enums::ESessionPersistence, enums_clientserver::EMsg, steammessages_auth_steamclient::{ - CAuthentication_BeginAuthSessionViaQR_Request, - CAuthentication_BeginAuthSessionViaQR_Response, CAuthentication_DeviceDetails, + CAuthentication_BeginAuthSessionViaCredentials_Request, + CAuthentication_BeginAuthSessionViaCredentials_Response, CAuthentication_DeviceDetails, + CAuthentication_GetPasswordRSAPublicKey_Request, + CAuthentication_GetPasswordRSAPublicKey_Response, CAuthentication_PollAuthSessionStatus_Request, - CAuthentication_PollAuthSessionStatus_Response, EAuthTokenPlatformType, + CAuthentication_PollAuthSessionStatus_Response, + CAuthentication_UpdateAuthSessionWithSteamGuardCode_Request, + CAuthentication_UpdateAuthSessionWithSteamGuardCode_Response, EAuthSessionGuardType, + EAuthTokenPlatformType, }, steammessages_base::{cmsg_ipaddress, CMsgIPAddress}, steammessages_clientserver::CMsgClientLicenseList, @@ -64,10 +71,52 @@ pub async fn main() -> eyre::Result<()> { // 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 { + let username = dialoguer::Input::::new() + .with_prompt("Username") + .interact_text()?; + let password = dialoguer::Password::new() + .with_prompt("Password") + .interact()?; + + let password_key_response: CMProtoBufMessage = + session + .call_service_method( + "Authentication.GetPasswordRSAPublicKey#1".to_string(), + CAuthentication_GetPasswordRSAPublicKey_Request { + account_name: Some(username.clone()), + ..Default::default() + }, + ) + .await?; + + let password_key = rsa::RsaPublicKey::new( + rsa::BigUint::parse_bytes(password_key_response.body.publickey_mod().as_bytes(), 16) + .ok_or_eyre("Invalid RSA public modulus")?, + rsa::BigUint::parse_bytes(password_key_response.body.publickey_exp().as_bytes(), 16) + .ok_or_eyre("Invalid RSA public exponent")?, + ) + .wrap_err("Invalid RSA public key")?; + + let encrypted_password = password_key + .encrypt( + &mut rand::thread_rng(), + rsa::Pkcs1v15Encrypt, + &password.as_bytes(), + ) + .wrap_err("Unable to encrypt password")?; + + let auth_session_response = session + .call_service_method::<_, CAuthentication_BeginAuthSessionViaCredentials_Response>( + "Authentication.BeginAuthSessionViaCredentials#1".to_string(), + CAuthentication_BeginAuthSessionViaCredentials_Request { + account_name: Some(username.clone()), + encrypted_password: Some( + base64::engine::general_purpose::STANDARD.encode(&encrypted_password), + ), + encryption_timestamp: password_key_response.body.timestamp, + persistence: Some(protobuf::EnumOrUnknown::new( + ESessionPersistence::k_ESessionPersistence_Ephemeral, + )), device_details: protobuf::MessageField::some(CAuthentication_DeviceDetails { device_friendly_name: Some("vapore".to_string()), platform_type: Some(protobuf::EnumOrUnknown::new( @@ -83,16 +132,16 @@ pub async fn main() -> eyre::Result<()> { ) .await?; - log::debug!("Got response {:#x?}", response); + log::debug!("Got response {:#x?}", auth_session_response); - let code = qrcode::QrCode::new(response.body.challenge_url()).unwrap(); - log::info!( - "Got new QR code:\n{}", - code.render::().build() - ); + if auth_session_response.header.eresult != Some(1) { + eyre::bail!("Got bad resonse from BeginAuthSessionViaCredentials"); + }; + + // TODO: check allowed_confirmations let mut interval = tokio::time::interval(tokio::time::Duration::from_secs_f32( - response.body.interval(), + auth_session_response.body.interval(), )); let session_cloned = session.clone(); @@ -100,8 +149,8 @@ pub async fn main() -> eyre::Result<()> { loop { interval.tick().await; let request = CAuthentication_PollAuthSessionStatus_Request { - client_id: response.body.client_id, - request_id: response.body.request_id.clone(), + client_id: auth_session_response.body.client_id, + request_id: auth_session_response.body.request_id.clone(), ..Default::default() }; let response: CMProtoBufMessage = @@ -130,6 +179,33 @@ pub async fn main() -> eyre::Result<()> { } }); + loop { + let guard_code = dialoguer::Input::::new() + .with_prompt("Steam Guard Code") + .interact_text()?; + + let update_response: CMProtoBufMessage< + CAuthentication_UpdateAuthSessionWithSteamGuardCode_Response, + > = 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: Some(guard_code), + code_type: Some(protobuf::EnumOrUnknown::new( + EAuthSessionGuardType::k_EAuthSessionGuardType_DeviceCode, + )), + ..Default::default() + }, + ) + .await?; + + if update_response.header.eresult == Some(1) { + break; + } + } + let (refresh_token, account_name) = poll_handle.await?; log::debug!(