From 488d6f4aa466c81c2b55e279d3a09cd5e2808c77 Mon Sep 17 00:00:00 2001 From: Stefanuk12 <42220813+Stefanuk12@users.noreply.github.com> Date: Wed, 28 Dec 2022 21:18:05 +0000 Subject: [PATCH] Added "Generate RoPro Verification Token" option, need to fix --- Cargo.toml | 4 +- README.md | 11 ++++- src/main.rs | 127 +++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 129 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7e1c55d..a1f110b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,11 @@ [package] name = "ropro-patcher" -version = "0.1.1" +version = "0.1.2" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +serde = { version = "1.0", features = ["derive"] } +reqwest = { version = "0.11", features = ["json", "blocking"] } platform-dirs = "0.3.0" \ No newline at end of file diff --git a/README.md b/README.md index 92a0265..b8ebb47 100644 --- a/README.md +++ b/README.md @@ -14,4 +14,13 @@ This currently does not support Firefox but it easily can be done manually. ## NOTE Chrome (and possibly other browsers) have a feature that checks the hash of the extension. This means that it will flag as corrupted. Therefore, you will have to download the extension, patch it with a custom path and use developer mode to load an unpacked extension. -- an exception to this rule is Opera GX \ No newline at end of file +- an exception to this rule is Opera GX + +# Getting RoPro Verification Token +You may use the patcher to get this token, however, you might find it easier to do it another way: +- Go to your extensions in your browser, e.g. `chrome://extensions` +- You should see something like `Inspect views background page` under RoPro +- Press on the underlined __background page__ +- The developer console for the extensions should open, go to the console tab +- Execute this `await getStorage("userVerification")` +- The format will be `{USERID: 'TOKEN'}` \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 0a343d8..932ccad 100644 --- a/src/main.rs +++ b/src/main.rs @@ -47,39 +47,144 @@ fn patch(path: PathBuf) { fs::write(options.clone(), options_contents).expect("Unable to write file contents (options.js)"); } +// Converts Roblox cookie to CSRF +fn grab_csrf(cookie: String) -> String { + // Create the request + let client = reqwest::blocking::Client::new(); + let response = client.post("https://catalog.roblox.com/v1/catalog/items/details") + .header("Cookie", format!(".ROBLOSECURITY={};", cookie)) + .header("content-length", 0) + .send() + .unwrap(); + + // Return header + let csrf = response.headers()["x-csrf-token"].to_str().unwrap().to_owned(); + return csrf; +} + +// Grab verification metadata from RoPro +#[derive(serde::Deserialize)] +struct Verification { + universeId: i64 +} +fn grab_verification_md() -> i64 { + // Create the request + let client = reqwest::blocking::Client::new(); + let response: Verification = client.post("https://api.ropro.io/verificationMetadata.php") + .header("content-length", 0) + .send() + .unwrap() + .json() + .unwrap(); + + // Return + return response.universeId; +} + +// (Un)favourite a Roblox universe +fn favourite_universe(cookie: String, csrf: String, universe_id: i64, unfavourite: bool) { + // Create the request + let client = reqwest::blocking::Client::new(); + let mut data = std::collections::HashMap::new(); + data.insert("isFavorited", !unfavourite); + let response = client.post(format!("https://games.roblox.com/v1/games/{}/favorites", universe_id)) + .header("Cookie", format!(".ROBLOSECURITY={};", cookie)) + .header("x-csrf-token", csrf) + .json(&data) + .send(); + + // Check for error + if response.is_err() { + println!("Unable to (un)favourite universe for unknown reason") + } +} + +// Get the verification token +#[derive(serde::Deserialize)] +struct VerificationResponse { + success: bool, + error_code: Option, + token: Option +} +fn get_verification() -> String { + // Create the request + let client = reqwest::blocking::Client::new(); + let response: VerificationResponse = client.post("https://api.ropro.io/generateVerificationToken.php") + .header("content-length", 0) + .send() + .unwrap() + .json() + .unwrap(); + + // Return + if response.success == false { + return response.error_code.unwrap().to_string(); + } else { + return response.token.unwrap(); + } +} + // Main fn main() { // Grab the input directory let mut input_dir = String::new(); - print!("Thanks for using Stefanuk12's RoPro Patcher.\n\nPlease select an option:\n\n1. Opera GX\n2. Google Chrome\n3. Custom Path\n> "); + print!("Thanks for using Stefanuk12's RoPro Patcher.\n\nPlease select an option:\n\n0. Generate RoPro Verification Token\n1. Opera GX\n2. Custom Path\n> "); stdout().flush().unwrap(); stdin().read_line(&mut input_dir).ok().expect("Failed to get user input"); // All of the options let path: PathBuf; match input_dir.trim() { + // Generate RoPro Verification Token + "0" => { + // Ask for their Roblox cookie + let mut cookie = String::new(); + cookie.clear(); + print!("Please enter your Roblox cookie (without the '.ROBLOSECURITY=' part)\n> "); + stdout().flush().unwrap(); + stdin().read_line(&mut cookie).ok().expect("Failed to get user input"); + cookie = cookie.trim().to_string(); + + // Resolve to CSRF + let csrf = grab_csrf(cookie.to_owned()); + + // Favourite, grab token, unfavourite + let universe_id = grab_verification_md(); + favourite_universe(cookie.to_owned(), csrf.to_owned(), universe_id, false); + let token = get_verification(); + favourite_universe(cookie.to_owned(), csrf.to_owned(), universe_id, true); + + // Check + if token.len() == 25 { + println!("Got your RoPro verification token: {}", token); + } else { + println!("There was an issue with getting your token (Error {})", token) + } + + // + pause(); + } // Opera GX "1" => { path = fs::read_dir(AppDirs::new(Some(r"Opera Software\Opera GX Stable\Extensions\adbacgifemdbhdkfppmeilbgppmhaobf"), false).unwrap().config_dir).expect("Unable to grab Opera GX extension.").next().unwrap().unwrap().path(); - } - // Google Chrome - "2" => { - path = fs::read_dir(AppDirs::new(Some(r"Google\Chrome\User Data\Default\Extensions\adbacgifemdbhdkfppmeilbgppmhaobf"), false).unwrap().cache_dir).expect("Unable to grab Google Chrome extension.").next().unwrap().unwrap().path(); + + patch(path); + println!("Patched!"); + pause(); } // Custom Path - "3" => { + "2" => { input_dir.clear(); print!("Please enter the path: "); stdout().flush().unwrap(); stdin().read_line(&mut input_dir).ok().expect("Failed to get user input"); path = PathBuf::from(input_dir.trim().to_string()); + + patch(path); + println!("Patched!"); + pause(); } // Neither of above _ => panic!("Invalid option") } - - // Patching - patch(path); - println!("Patched!"); - pause(); } \ No newline at end of file