diff --git a/Cargo.lock b/Cargo.lock index 1d6d38b..2233f2c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -159,10 +159,12 @@ name = "auth" version = "0.1.0" dependencies = [ "env_logger", + "hex", "libfj", "log", "rocket", "rocket-client-addr", + "steamworks", "uuid", ] @@ -199,6 +201,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72" +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.8.0" @@ -359,7 +367,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b035a542cf7abf01f2e3c4d5a7acbaebfefe120ae4efc7bde3df98186e4b8af7" dependencies = [ - "bitflags", + "bitflags 2.8.0", "proc-macro2", "proc-macro2-diagnostics", "quote", @@ -642,6 +650,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "highhash" version = "0.1.1" @@ -1388,7 +1402,7 @@ dependencies = [ "rustc-hash", "rustls", "socket2", - "thiserror", + "thiserror 2.0.11", "tokio", "tracing", ] @@ -1407,7 +1421,7 @@ dependencies = [ "rustls", "rustls-pki-types", "slab", - "thiserror", + "thiserror 2.0.11", "tinyvec", "tracing", "web-time", @@ -1509,7 +1523,7 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ - "bitflags", + "bitflags 2.8.0", ] [[package]] @@ -1743,7 +1757,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags", + "bitflags 2.8.0", "errno", "libc", "linux-raw-sys", @@ -1954,6 +1968,24 @@ dependencies = [ "loom", ] +[[package]] +name = "steamworks" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a79d6f059322f73a4586cc2d0ca595ce1583104b2b1574ae1bb87f2c05bf4c67" +dependencies = [ + "bitflags 1.3.2", + "lazy_static", + "steamworks-sys", + "thiserror 1.0.69", +] + +[[package]] +name = "steamworks-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef6b00f8fe8eaaaff22cb9b70822a48c1a5d772bc682c202a57c0b438175845" + [[package]] name = "subtle" version = "2.6.1" @@ -2016,13 +2048,33 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + [[package]] name = "thiserror" version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.11", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", ] [[package]] diff --git a/auth/Cargo.toml b/auth/Cargo.toml index 9902f64..a34cfd0 100644 --- a/auth/Cargo.toml +++ b/auth/Cargo.toml @@ -3,6 +3,10 @@ name = "auth" version = "0.1.0" edition = "2021" +[features] +steam = ["steamworks"] +default = [] + [dependencies] rocket.workspace = true libfj.workspace = true @@ -10,3 +14,5 @@ log.workspace = true env_logger.workspace = true uuid = { version = "1.12", features = [ "v4", "fast-rng" ] } rocket-client-addr = "0.5" +steamworks = { version = "0.11", optional = true } +hex = "0.4" diff --git a/auth/src/cardlife/steam.rs b/auth/src/cardlife/steam.rs index 75432a5..cbec862 100644 --- a/auth/src/cardlife/steam.rs +++ b/auth/src/cardlife/steam.rs @@ -1,57 +1,86 @@ -use std::sync::RwLock; -use std::collections::HashMap; +use rocket::{post, routes, serde::json::Json, http::Status}; -use rocket::{post, routes, serde::json::Json}; +#[cfg(feature = "steam")] +static STEAM_SERVER: std::sync::OnceLock = OnceLock::new(); -// FIXME don't have global state -static AUTH_MAP: RwLock>> = RwLock::new(None); +#[cfg(feature = "steam")] +fn init_steam() -> steamworks::Server { + let (server, single_client) = steamworks::Server::init(core::net::Ipv4Addr::new(127, 0, 0, 1), 9000, 9001, steamworks::ServerMode::NoAuthentication, "") + .expect("Steam is unavailable"); + std::thread::spawn(move || { + loop { + single_client.run_callbacks(); + std::thread::sleep(std::time::Duration::from_millis(10)); + } + }); + server.set_product("920690"); + server.log_on_anonymous(); + server +} -fn generate_auth(ticket: &str, addr: &str) -> libfj::cardlife::AuthenticationInfo { - let public_guid = uuid::Uuid::new_v4().to_string(); - log::warn!("assigning GUID {} to IP address {} (steam ticket {})", public_guid, addr, ticket); - libfj::cardlife::AuthenticationInfo { - public_id: public_guid, - email_address: "nobody@openjamgames.com".to_string(), - display_name: "gaben".to_string(), - purchases: vec![1, 2, 3], - flags: vec![], - /*flags: //vec![ - "Dev".to_string(), - "GiveInv".to_string(), - "NoDrop".to_string(), - "DekStruct".to_string(), - "BucketA".to_string(), - "BucketB".to_string(), - "userlogged".to_string(), - ],*/ - confirmed: true, - token: "1234567890-qwertyuiop-asdfghjkl-zxcvbnm".to_string(), - steam_id: Some("gaben".to_string()), - id: 123456, // FIXME - } +fn get_u64_with_offset(arr: &[u8], start: usize) -> u64 { + let arr_actual: [u8; 8] = [ + arr[start], + arr[start+1], + arr[start+2], + arr[start+3], + arr[start+4], + arr[start+5], + arr[start+6], + arr[start+7], + ]; + u64::from_le_bytes(arr_actual) } #[post("/api/auth/steamauthenticate", data = "")] -pub fn steam_auth(addr: &rocket_client_addr::ClientAddr, body: Json) -> Json { - let addr_str = addr.get_ipv4_string().unwrap_or_else(|| addr.get_ipv6_string()); - if AUTH_MAP.read().unwrap().is_none() { - let new_info = generate_auth(&body.steam_ticket, &addr_str); - let mut new_map = HashMap::new(); - new_map.insert(addr_str, new_info.clone()); - *AUTH_MAP.write().unwrap() = Some(new_map); - Json(new_info) - } else { - if let Some(auth_info) = AUTH_MAP.read().unwrap().as_ref().unwrap().get(&addr_str).map(|x| x.to_owned()) { - Json(auth_info) - } else { - let new_info = generate_auth(&body.steam_ticket, &addr_str); - AUTH_MAP.write().unwrap().as_mut().unwrap().insert(addr_str, new_info.clone()); - Json(new_info) +pub fn steam_auth(body: Json) -> Result, Status> { + log::debug!("steam ticket: {}", body.steam_ticket); + match hex::decode(&body.steam_ticket) { + Ok(ticket) => { + if ticket.len() < 72 { + return Err(Status { code: 400 }) + } + let steam_id = get_u64_with_offset(&ticket, 12 /* also at 64 ??? */); // should be 76600000000000000 > number > 76500000000000000 + log::debug!("Found steamId {}", steam_id); + #[cfg(feature = "steam")] + { + let steam = STEAM_SERVER.get_or_init(init_steam); + if let Err(e) = steam.begin_authentication_session(steamworks::SteamId::from_raw(steam_id), &ticket) { + log::error!("steam server auth session error: {}", e); + return Err(Status { code: 400 }) + } + } + Ok(Json(libfj::cardlife::AuthenticationInfo { + public_id: uuid::Uuid::from_u64_pair(steam_id, steam_id).to_string(), + email_address: "nobody@openjamgames.com".to_string(), + display_name: steam_id.to_string(), + purchases: vec![1, 2, 3], + flags: vec![], + /*flags: //vec![ + "Dev".to_string(), + "GiveInv".to_string(), + "NoDrop".to_string(), + "DekStruct".to_string(), + "BucketA".to_string(), + "BucketB".to_string(), + "userlogged".to_string(), + ],*/ + confirmed: true, + token: uuid::Uuid::from_u64_pair(steam_id, steam_id).to_string(), + steam_id: Some(steam_id.to_string()), + id: (steam_id & (i32::MAX as u64)) as i32, + })) + }, + Err(e) => { + log::error!("request with bad steam ticket: {}", e); + Err(Status { code: 400 }) } } } pub fn stage() -> rocket::fairing::AdHoc { + #[cfg(feature = "steam")] + STEAM_SERVER.get_or_init(init_steam); rocket::fairing::AdHoc::on_ignite("CardLife Steam", |rocket| async { rocket.mount("/", routes![steam_auth]) }) diff --git a/auth/src/cardlife/temporary_get_user_id.rs b/auth/src/cardlife/temporary_get_user_id.rs index 5555345..d50dae4 100644 --- a/auth/src/cardlife/temporary_get_user_id.rs +++ b/auth/src/cardlife/temporary_get_user_id.rs @@ -3,10 +3,11 @@ use rocket::{post, routes, serde::json::Json}; #[post("/api/auth/temporarygetuserid", data = "")] pub fn temp_migration(body: Json) -> Json { + let steam_id = uuid::Uuid::parse_str(&body.public_id).map(|guid| guid.as_u64_pair().0).unwrap_or(123456); Json(libfj::cardlife::TempGetUserIdResponse { public_id: body.public_id.to_owned(), token: body.token.to_owned(), - user_id: 123456, // FIXME + user_id: (steam_id & (i32::MAX as u64)) as i32, }) } diff --git a/auth/steam_appid.txt b/auth/steam_appid.txt new file mode 100644 index 0000000..c0438f3 --- /dev/null +++ b/auth/steam_appid.txt @@ -0,0 +1 @@ +920690