mirror of
https://git.ngram.ca/OpenJam/rc-servers
synced 2026-08-23 23:08:52 +00:00
Use steam ID for reliable, persistent CL user auth
This commit is contained in:
64
Cargo.lock
generated
64
Cargo.lock
generated
@@ -159,10 +159,12 @@ name = "auth"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"env_logger",
|
"env_logger",
|
||||||
|
"hex",
|
||||||
"libfj",
|
"libfj",
|
||||||
"log",
|
"log",
|
||||||
"rocket",
|
"rocket",
|
||||||
"rocket-client-addr",
|
"rocket-client-addr",
|
||||||
|
"steamworks",
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -199,6 +201,12 @@ version = "0.1.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72"
|
checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.8.0"
|
version = "2.8.0"
|
||||||
@@ -359,7 +367,7 @@ version = "0.4.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b035a542cf7abf01f2e3c4d5a7acbaebfefe120ae4efc7bde3df98186e4b8af7"
|
checksum = "b035a542cf7abf01f2e3c4d5a7acbaebfefe120ae4efc7bde3df98186e4b8af7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags 2.8.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"proc-macro2-diagnostics",
|
"proc-macro2-diagnostics",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -642,6 +650,12 @@ version = "0.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
|
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "highhash"
|
name = "highhash"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@@ -1388,7 +1402,7 @@ dependencies = [
|
|||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"rustls",
|
"rustls",
|
||||||
"socket2",
|
"socket2",
|
||||||
"thiserror",
|
"thiserror 2.0.11",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
@@ -1407,7 +1421,7 @@ dependencies = [
|
|||||||
"rustls",
|
"rustls",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"slab",
|
"slab",
|
||||||
"thiserror",
|
"thiserror 2.0.11",
|
||||||
"tinyvec",
|
"tinyvec",
|
||||||
"tracing",
|
"tracing",
|
||||||
"web-time",
|
"web-time",
|
||||||
@@ -1509,7 +1523,7 @@ version = "0.5.8"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
|
checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags 2.8.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1743,7 +1757,7 @@ version = "0.38.44"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags 2.8.0",
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys",
|
||||||
@@ -1954,6 +1968,24 @@ dependencies = [
|
|||||||
"loom",
|
"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]]
|
[[package]]
|
||||||
name = "subtle"
|
name = "subtle"
|
||||||
version = "2.6.1"
|
version = "2.6.1"
|
||||||
@@ -2016,13 +2048,33 @@ dependencies = [
|
|||||||
"windows-sys 0.59.0",
|
"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]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "2.0.11"
|
version = "2.0.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc"
|
checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc"
|
||||||
dependencies = [
|
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]]
|
[[package]]
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ name = "auth"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
steam = ["steamworks"]
|
||||||
|
default = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rocket.workspace = true
|
rocket.workspace = true
|
||||||
libfj.workspace = true
|
libfj.workspace = true
|
||||||
@@ -10,3 +14,5 @@ log.workspace = true
|
|||||||
env_logger.workspace = true
|
env_logger.workspace = true
|
||||||
uuid = { version = "1.12", features = [ "v4", "fast-rng" ] }
|
uuid = { version = "1.12", features = [ "v4", "fast-rng" ] }
|
||||||
rocket-client-addr = "0.5"
|
rocket-client-addr = "0.5"
|
||||||
|
steamworks = { version = "0.11", optional = true }
|
||||||
|
hex = "0.4"
|
||||||
|
|||||||
@@ -1,18 +1,59 @@
|
|||||||
use std::sync::RwLock;
|
use rocket::{post, routes, serde::json::Json, http::Status};
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use rocket::{post, routes, serde::json::Json};
|
#[cfg(feature = "steam")]
|
||||||
|
static STEAM_SERVER: std::sync::OnceLock<steamworks::Server> = OnceLock::new();
|
||||||
|
|
||||||
// FIXME don't have global state
|
#[cfg(feature = "steam")]
|
||||||
static AUTH_MAP: RwLock<Option<HashMap<String, libfj::cardlife::AuthenticationInfo>>> = RwLock::new(None);
|
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 {
|
fn get_u64_with_offset(arr: &[u8], start: usize) -> u64 {
|
||||||
let public_guid = uuid::Uuid::new_v4().to_string();
|
let arr_actual: [u8; 8] = [
|
||||||
log::warn!("assigning GUID {} to IP address {} (steam ticket {})", public_guid, addr, ticket);
|
arr[start],
|
||||||
libfj::cardlife::AuthenticationInfo {
|
arr[start+1],
|
||||||
public_id: public_guid,
|
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 = "<body>")]
|
||||||
|
pub fn steam_auth(body: Json<libfj::cardlife::SteamAuthenticationPayload>) -> Result<Json<libfj::cardlife::AuthenticationInfo>, 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(),
|
email_address: "nobody@openjamgames.com".to_string(),
|
||||||
display_name: "gaben".to_string(),
|
display_name: steam_id.to_string(),
|
||||||
purchases: vec![1, 2, 3],
|
purchases: vec![1, 2, 3],
|
||||||
flags: vec![],
|
flags: vec![],
|
||||||
/*flags: //vec![
|
/*flags: //vec![
|
||||||
@@ -25,33 +66,21 @@ fn generate_auth(ticket: &str, addr: &str) -> libfj::cardlife::AuthenticationInf
|
|||||||
"userlogged".to_string(),
|
"userlogged".to_string(),
|
||||||
],*/
|
],*/
|
||||||
confirmed: true,
|
confirmed: true,
|
||||||
token: "1234567890-qwertyuiop-asdfghjkl-zxcvbnm".to_string(),
|
token: uuid::Uuid::from_u64_pair(steam_id, steam_id).to_string(),
|
||||||
steam_id: Some("gaben".to_string()),
|
steam_id: Some(steam_id.to_string()),
|
||||||
id: 123456, // FIXME
|
id: (steam_id & (i32::MAX as u64)) as i32,
|
||||||
}
|
}))
|
||||||
}
|
},
|
||||||
|
Err(e) => {
|
||||||
#[post("/api/auth/steamauthenticate", data = "<body>")]
|
log::error!("request with bad steam ticket: {}", e);
|
||||||
pub fn steam_auth(addr: &rocket_client_addr::ClientAddr, body: Json<libfj::cardlife::SteamAuthenticationPayload>) -> Json<libfj::cardlife::AuthenticationInfo> {
|
Err(Status { code: 400 })
|
||||||
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 stage() -> rocket::fairing::AdHoc {
|
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::fairing::AdHoc::on_ignite("CardLife Steam", |rocket| async {
|
||||||
rocket.mount("/", routes![steam_auth])
|
rocket.mount("/", routes![steam_auth])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,10 +3,11 @@ use rocket::{post, routes, serde::json::Json};
|
|||||||
|
|
||||||
#[post("/api/auth/temporarygetuserid", data = "<body>")]
|
#[post("/api/auth/temporarygetuserid", data = "<body>")]
|
||||||
pub fn temp_migration(body: Json<libfj::cardlife::TempGetUserIdPayload>) -> Json<libfj::cardlife::TempGetUserIdResponse> {
|
pub fn temp_migration(body: Json<libfj::cardlife::TempGetUserIdPayload>) -> Json<libfj::cardlife::TempGetUserIdResponse> {
|
||||||
|
let steam_id = uuid::Uuid::parse_str(&body.public_id).map(|guid| guid.as_u64_pair().0).unwrap_or(123456);
|
||||||
Json(libfj::cardlife::TempGetUserIdResponse {
|
Json(libfj::cardlife::TempGetUserIdResponse {
|
||||||
public_id: body.public_id.to_owned(),
|
public_id: body.public_id.to_owned(),
|
||||||
token: body.token.to_owned(),
|
token: body.token.to_owned(),
|
||||||
user_id: 123456, // FIXME
|
user_id: (steam_id & (i32::MAX as u64)) as i32,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
1
auth/steam_appid.txt
Normal file
1
auth/steam_appid.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
920690
|
||||||
Reference in New Issue
Block a user