From 6f003af5316494f4ab09fbf9490ab990a1b1edca Mon Sep 17 00:00:00 2001 From: Edoardo Borgia Leiva Date: Wed, 18 Dec 2024 02:44:51 +0100 Subject: [PATCH] Managed to launch game correctly --- src/auth.rs | 156 ++++++++++++++++++++++++++++++++++++++++++++++++---- src/main.rs | 87 ++++++++++++++++++++++++++--- 2 files changed, 224 insertions(+), 19 deletions(-) diff --git a/src/auth.rs b/src/auth.rs index 40f0a65..53fbf9c 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -10,24 +10,27 @@ const OAUTH_TOKEN : (&str, &str)= ( #[derive(Debug)] pub struct DeviceCredentials { access_token : String, - account_id : String, + pub account_id : String, device_id : String, + secret: String, } + impl DeviceCredentials { pub fn new() -> DeviceCredentials { DeviceCredentials{ device_id: String::new(), account_id: String::new(), access_token: String::new(), + secret: String::new(), } } pub fn get_access_token_and_account_id(&mut self, http_client: &Client, authcode: &str) { - + if authcode.is_empty() { error!("Authentication Code cannot be empty"); return; } - + #[derive(Debug, Deserialize)] struct ResponseStruct { access_token: String, @@ -77,9 +80,9 @@ impl DeviceCredentials { _ => { error!("Failed to get access token!"); }, } } - - pub fn get_device_auth(&mut self, http_client: &Client) { - + + pub fn get_device_auth_and_secret(&mut self, http_client: &Client) { + if self.access_token.is_empty() || self.account_id.is_empty() { error!("Device access token cannot be empty!"); return; @@ -94,7 +97,7 @@ impl DeviceCredentials { it.starts_with("one thing"); // Just discovered String.starts_with() KEKW */ - + #[derive(Debug, Deserialize)] struct CreatedObject { location: String, @@ -123,6 +126,7 @@ impl DeviceCredentials { match response_data.json::().ok() { Some(response_json) => { self.device_id = response_json.deviceId; + self.secret = response_json.secret; } None => { error!("Failed to parse device_id!"); @@ -132,13 +136,13 @@ impl DeviceCredentials { _ => { error!("Failed to get device_id!"); }, } } - pub fn get_device_auth_from(&mut self, http_client: &Client, access_token: &str, account_id: &str) { - + pub fn get_device_auth_and_secret_from(&mut self, http_client: &Client, access_token: &str, account_id: &str) { + if access_token.is_empty() || account_id.is_empty() { error!("Device access token cannot be empty!"); return; } - + let mut url : String = String::from("https://account-public-service-prod.ol.epicgames.com/account/api/public/account/"); url.push_str(account_id); url.push_str("/deviceAuth"); @@ -177,6 +181,7 @@ impl DeviceCredentials { match response_data.json::().ok() { Some(response_json) => { self.device_id = response_json.deviceId; + self.secret = response_json.secret; } None => { error!("Failed to parse device_id!"); @@ -186,8 +191,135 @@ impl DeviceCredentials { _ => { error!("Failed to get device_id!"); }, } } - - pub fn get_exchange_code() { + + pub fn get_exchange_code() -> String { todo!(); } } + +#[derive(Debug)] +pub struct TemporaryCredentials { + access_token : String, + pub exchange_code : String, +} + +impl TemporaryCredentials { + pub fn new() -> TemporaryCredentials { + TemporaryCredentials { + access_token : String::new(), + exchange_code : String::new(), + } + } + + pub fn get_access_token(&mut self, http_client: &Client, device_credentials: &DeviceCredentials) { + + #[derive(Debug, Deserialize)] + struct ResponseStruct { + access_token: String, + expires_in: u16, + expires_at: String, + token_type: String, + refresh_token: String, + refresh_expires: u16, + refresh_expires_at: String, + account_id: String, + client_id: String, + internal_client: bool, + client_service: String, + displayName: String, + app: String, + in_app_id: String, + product_id: String, + application_id: String, + acr: String, + auth_time: String + } + + let mut request_body = String::new(); + { + // Grant type + request_body.push_str("grant_type=device_auth" + .trim()); + + // AccountID + request_body.push_str("&account_id="); + request_body.push_str(device_credentials.account_id + .as_str() + .trim()); + + // DeviceID + request_body.push_str("&device_id="); + request_body.push_str(device_credentials.device_id + .as_str() + .trim()); + + // Secret + request_body.push_str("&secret="); + request_body.push_str(device_credentials.secret + .as_str() + .trim()); + + request_body = request_body.trim().to_string(); + } + + let url : &str = "https://account-public-service-prod.ol.epicgames.com/account/api/oauth/token"; + + let response = Client::post(&http_client, url) + .body(request_body) + .header("Content-Type", "application/x-www-form-urlencoded") + .header("Authorization", + "Basic M2Y2OWU1NmM3NjQ5NDkyYzhjYzI5ZjFhZjA4YThhMTI6YjUxZWU5Y2IxMjIzNGY1MGE2OWVmYTY3ZWY1MzgxMmU=") + .send(); + + match response { + Ok(response_data) => { + match response_data.json::().ok() { + Some(response) => { + self.access_token = response.access_token; + }, + None => { + error!("Failed to parse access_token!"); + } + } + }, + _ => { error!("Failed to get access token!"); }, + } + } + pub fn get_exchange_code(&mut self, http_client: &Client) { + + #[derive(Debug,Deserialize)] + struct ResponseStruct { + expiresInSeconds: u16, + code: String, + creatingClientId: String, + } + + let mut bearer_header = String::from("Bearer "); + bearer_header.push_str(self.access_token.as_str()); + + let url: &str = "https://account-public-service-prod.ol.epicgames.com/account/api/oauth/exchange"; + let response = Client::get(&http_client, url) + .header("Authorization", bearer_header.as_str()) + .send(); + + + + match response { + Ok(response_data) => { + match response_data.json::().ok() { + Some(response_json) => { + self.exchange_code = response_json.code; + } + None => { + error!("Failed to parse Exchange code!"); + }, + } + }, + _ => { error!("Failed to get Exchange code!"); }, + } + + + } + pub fn get_exchange_code_from(&mut self, http_client: &Client, access_token: &str) {todo!();} + +} diff --git a/src/main.rs b/src/main.rs index cf998cc..4c0c3c2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,15 @@ mod auth; +use std::process::exit; use log::*; use colog; use std::env::args; use std::io::Write; -use crate::auth::DeviceCredentials; + +use std::process::Command; +use std::process::Stdio; + +use crate::auth::*; fn main() { /* Initial initializations */ @@ -55,14 +60,82 @@ fn main() { print!("Insert AuthCode > "); std::io::stdout().flush().unwrap(); + + // Getting temporal info to create persistent login info let mut auth_code: String = "".to_string(); let _ = std::io::stdin().read_line(&mut auth_code).unwrap(); - - let mut credentials : DeviceCredentials = DeviceCredentials::new(); - credentials.get_access_token_and_account_id(&http_client, &auth_code); - credentials.get_device_auth(&http_client); - dbg!(&credentials); - + + let mut persistent_credentials: DeviceCredentials = DeviceCredentials::new(); + { + persistent_credentials.get_access_token_and_account_id(&http_client, &auth_code); + persistent_credentials.get_device_auth_and_secret(&http_client); + dbg!(&persistent_credentials); + } + + let mut login_credentials: TemporaryCredentials = TemporaryCredentials::new(); + { + login_credentials.get_access_token(&http_client, &persistent_credentials); + login_credentials.get_exchange_code(&http_client); + dbg!(&login_credentials); + } + /* Game Launching*/ + let mut auth_password_argument = String::from("-AUTH_PASSWORD="); + auth_password_argument.push_str(login_credentials.exchange_code.as_str()); + + let mut uid_argument = String::from("-epicuserid="); + uid_argument.push_str(persistent_credentials.account_id.as_str()); + + /*let game_path = "D:\\Games\\Epic Games\\Fortnite\\FortniteGame\\Binaries\\Win64\\FortniteLauncher.exe"; + let game_arguments = vec![ + "/d", + "D:\\Games\\Epic Games\\Fortnite\\FortniteGame\\Binaries\\Win64\\FortniteLauncher.exe", "FortniteLauncher.exe", + "-obfuscationid=iDkaKzl08diwOpawKkaeEkwihUB0Og", + "-AUTH_LOGIN=unused", + &auth_password_argument, + "-AUTH_TYPE=exchangecode", + "-epicapp=Fortnite", + "-epicenv=Prod", + "-EpicPortal", + "-steamimportavailable", + &uid_argument, + "-epiclocale=en", + "-epicsandboxid=fn", + ];*/ + /* + Command::new(game_path) + .args(game_arguments) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn() + .unwrap(); + */ + + let command = Command::new("cmd") + .arg("/C") // '/C' executes the command and terminates the command shell + .arg("start") + .arg("/d") + .arg("D:\\Games\\Epic Games\\Fortnite\\FortniteGame\\Binaries\\Win64") // Path to the directory + .arg("FortniteLauncher.exe") // The executable + .arg("-AUTH_LOGIN=unused") + .arg(&auth_password_argument) + .arg("-AUTH_TYPE=exchangecode") + .arg("-epicapp=Fortnite") + .arg("-epicenv=Prod") + .arg("-EpicPortal") + .arg(&uid_argument) + .spawn(); + + match command { + Ok(mut child) => { + // Optionally, you can wait for the process to complete + let status = child.wait().expect("Failed to wait on child"); + println!("Command executed with status: {}", status); + } + Err(e) => { + eprintln!("Error executing command: {}", e); + exit(1); + } + } }