commit 466edec3a3f40d1c1219128e7577e2cebe35277a Author: BugisoftRSG <58910128+BugisoftRSG@users.noreply.github.com> Date: Wed Aug 9 12:43:03 2023 +0200 Release diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..61b1d01 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,26 @@ +name: Build Test + +on: + push: + branches: + - master + +jobs: + build: + name: Build on Windows and Linux + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [windows-latest, ubuntu-latest] + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Configure and Build + run: | + mkdir build + cd build + cmake .. + cmake --build . diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..badb5e2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +# IDE +.vs/ +.vscode/* +!.vscode/launch.json +.cache/ + +# output directory +build/ +out/ +__pycache__/ + +# precompiled headers +*.ipch +*.gch +*.pch \ No newline at end of file diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite new file mode 100644 index 0000000..db03315 Binary files /dev/null and b/.vs/slnx.sqlite differ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..7ecb5af --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,48 @@ +cmake_minimum_required(VERSION 3.20) + +project(SCAPI CXX ASM_MASM) + +set(SRC_DIR "${PROJECT_SOURCE_DIR}/src") + +# Fetch modules +message("\nFetching modules") +include(scripts/pugixml.cmake) +include(scripts/cpr.cmake) +include(scripts/json.cmake) + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/scripts) +find_package(botan 2.19.3 REQUIRED) +botan_generate(botan sha1 hmac rc4 rng base64 mac stream hash auto_rng win32_stats) + +# SCAPI +message(STATUS "SCAPI") +file(GLOB_RECURSE SRC_MAIN + "${SRC_DIR}/**.hpp" + "${SRC_DIR}/**.h" + "${SRC_DIR}/**.cpp" + "${SRC_DIR}/**.cc" + "${SRC_DIR}/**.cxx" + "${SRC_DIR}/**.asm" +) +add_executable(SCAPI "${SRC_MAIN}") + +set_property(GLOBAL PROPERTY USE_FOLDERS ON) +set_property(TARGET SCAPI PROPERTY CXX_STANDARD 23) # 23 Because std::format is not avalible in std:c++20 for some reason. Maybe it's because i use v142 toolset. + +source_group(TREE ${SRC_DIR} PREFIX "src" FILES ${SRC_MAIN} ) + +target_include_directories(SCAPI PRIVATE + "${SRC_DIR}" + "${json_SOURCE_DIR}/single_include" +) + +target_link_libraries(SCAPI PRIVATE botan pugixml cpr json) + +# Warnings as errors +set_property(TARGET SCAPI PROPERTY COMPILE_WARNING_AS_ERROR ON) + +add_compile_definitions(SCAPI + "_CRT_SECURE_NO_WARNINGS" + "NOMINMAX" + "WIN32_LEAN_AND_MEAN" +) \ No newline at end of file diff --git a/CMakeSettings.json b/CMakeSettings.json new file mode 100644 index 0000000..330798f --- /dev/null +++ b/CMakeSettings.json @@ -0,0 +1,15 @@ +{ + "configurations": [ + { + "name": "x64-Release", + "generator": "Ninja", + "configurationType": "RelWithDebInfo", + "inheritEnvironments": [ "msvc_x64_x64" ], + "buildRoot": "${projectDir}\\out\\build\\${name}", + "installRoot": "${projectDir}\\out\\install\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "", + "ctestCommandArgs": "" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..97e7589 --- /dev/null +++ b/README.md @@ -0,0 +1,53 @@ +# SCAPI + +This project is designed to better understand the API's from Rockstar Games used in Grand Theft Auto V. + +## Features + +### UGC +- Copy Job (From other/same platforms to PC, but not vice versa) +- Copy Local Job (Copy your own jobs) +- Delete Content (Can delete any job you created) +- Query Content (Get the job meta info of a job) +- Check Text (Checks if a given text is a profanity) +- Query Content Creators (Actual usage unknown) + +### Auth +- Create Ticket + +### Geo Location +- Get Location Info from IP (Looks like its Max Mind DB) + +### Matchmaking +- Get Matchmaking (Lists all Sessions available to join) + +### Inbox +- Send Email (May also corrupt the target's inbox if base64'd gamer handle is wrong) +- Send Bounty completed Message + +### Presence +- Send Invite (IIRC only works on friends since the ballstortue incursion) + +### Misc +- Decrypt (Allows you to decrypt an http request/response and get the raw xml) + +### Libraries + +This project was builded on Microsoft Visual Studio Community 2022 (64bit) + +Dependencies: +- [Botan](https://github.com/randombit/botan) +- [cpr](https://github.com/libcpr/cpr) +- [pugixml](https://github.com/libcpr/cpr) +- Python for Botan + +Build Instructions (Win64) +```bash +git clone https://github.com/BugisoftRSG/SCAPI.git +cd SCAPI +mkdir build && cd build +cmake .. +``` + +## Known Issues +- GetTopRatedContent returns SqlException diff --git a/bfg-1.14.0.jar b/bfg-1.14.0.jar new file mode 100644 index 0000000..688fe71 Binary files /dev/null and b/bfg-1.14.0.jar differ diff --git a/scripts/FindBotan.cmake b/scripts/FindBotan.cmake new file mode 100644 index 0000000..3311b21 --- /dev/null +++ b/scripts/FindBotan.cmake @@ -0,0 +1,140 @@ +## This module will automagically download the tarball of the specified Botan version and invoke the configure.py +## python script to generate the amalgamation files (botan_all.cpp and botan_all.h). +## +## Usage: +## find_package( +## botan 2.18.2 +## COMPONENTS +## system_rng +## argon2 +## sha3 +## REQUIRED +## ) +## +## target_link_libraries( +## MyTarget +## PRIVATE +## botan +## ) +## + +cmake_minimum_required(VERSION 3.19) +include(FetchContent) + +# Find python +find_package( + Python + COMPONENTS + Interpreter + REQUIRED +) + +# Assemble version string +set(Botan_VERSION_STRING "Botan-2.19.3") + +# Assemble download URL +set(DOWNLOAD_URL https://botan.randombit.net/releases/${Botan_VERSION_STRING}.tar.xz) + +# Just do a dummy download to see whether we can download the tarball +file( + DOWNLOAD + ${DOWNLOAD_URL} + STATUS download_status +) +if (NOT download_status EQUAL 0) + message(FATAL_ERROR "Could not download Botan tarball (status = ${download_status}): ${DOWNLOAD_URL}") +endif() + +# Download the tarball +FetchContent_Declare( + botan_upstream + URL ${DOWNLOAD_URL} +) +FetchContent_MakeAvailable(botan_upstream) + +# Heavy lifting by cmake +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Botan DEFAULT_MSG Botan_VERSION_STRING) + +## Function to generate a target named 'TARGET_NAME' with specific Botan modules enabled. +function(botan_generate TARGET_NAME MODULES) + # The last N arguments are considered to be the modules list. + # Here, we collect those in a list and join them with a comma separator ready to be passed to the configure.py script. + foreach(module_index RANGE 1 ${ARGC}-2) + list(APPEND modules_list ${ARGV${module_index}}) + + # Check if PKCS11 module is enabled + # Note: This is for a workaround, see further below for more details. + if (ARGV${module_index} STREQUAL "pkcs11") + set(PKCS11_ENABLED ON) + endif() + endforeach() + list(JOIN modules_list "," ENABLE_MODULES_LIST) + + # Determine botan compiler ID (--cc parameter of configure.py) + set(BOTAN_COMPILER_ID ${CMAKE_CXX_COMPILER_ID}) + string(TOLOWER ${BOTAN_COMPILER_ID} BOTAN_COMPILER_ID) + if (BOTAN_COMPILER_ID STREQUAL "gnu") + set(BOTAN_COMPILER_ID "gcc") + endif() + + # Run the configure.py script + add_custom_command( + OUTPUT botan_all.cpp botan_all.h + COMMENT "Generating Botan amalgamation files botan_all.cpp and botan_all.h" + COMMAND ${Python_EXECUTABLE} + ${botan_upstream_SOURCE_DIR}/configure.py + --quiet + --cc-bin=${CMAKE_CXX_COMPILER} + --cc=${BOTAN_COMPILER_ID} + $<$:--os=mingw> + --disable-shared + --amalgamation + --minimized-build + --enable-modules=${ENABLE_MODULES_LIST} + ) + + # Create target + set(TARGET ${TARGET_NAME}) + add_library(${TARGET} STATIC) + target_sources( + ${TARGET} + PUBLIC + ${CMAKE_CURRENT_BINARY_DIR}/botan_all.h + PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}/botan_all.cpp + ) + + target_include_directories( + ${TARGET} + INTERFACE + ${CMAKE_CURRENT_BINARY_DIR} + ) + set_target_properties( + ${TARGET} + PROPERTIES + POSITION_INDEPENDENT_CODE ON + ) + + # + # PKCS11 Workaround + # + # This section is a workaround to handle a "bug" in upstream Botan. + # Basically, the amalgamation build of Botan does not include the necessary PKCS11 headers when the PKCS11 module + # is enabled. + # + # See: + # - https://github.com/randombit/botan/issues/1447 + # - https://github.com/randombit/botan/issues/976 + # + if (PKCS11_ENABLED) + file(COPY ${botan_upstream_SOURCE_DIR}/src/lib/prov/pkcs11/pkcs11.h DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + file(COPY ${botan_upstream_SOURCE_DIR}/src/lib/prov/pkcs11/pkcs11f.h DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + file(COPY ${botan_upstream_SOURCE_DIR}/src/lib/prov/pkcs11/pkcs11t.h DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + target_include_directories( + ${TARGET} + PRIVATE + ${botan_upstream_SOURCE_DIR}/src/lib/prov/pkcs11 + ) + endif() +endfunction() \ No newline at end of file diff --git a/scripts/cpr.cmake b/scripts/cpr.cmake new file mode 100644 index 0000000..6918b58 --- /dev/null +++ b/scripts/cpr.cmake @@ -0,0 +1,14 @@ +include(FetchContent) + +set(BUILD_TESTING_BEFORE ${BUILD_TESTING}) +set(CURL_DISABLE_TESTS OFF) +FetchContent_Declare( + cpr + GIT_REPOSITORY https://github.com/libcpr/cpr.git + GIT_TAG 1986262ba4e0cb052161e9e7919aef5ef08217f0 + GIT_PROGRESS TRUE +) +message("cpr") +FetchContent_MakeAvailable(cpr) + +set(BUILD_TESTING ${BUILD_TESTING_BEFORE} CACHE INTERNAL "" FORCE) \ No newline at end of file diff --git a/scripts/json.cmake b/scripts/json.cmake new file mode 100644 index 0000000..cc8aae4 --- /dev/null +++ b/scripts/json.cmake @@ -0,0 +1,12 @@ +include(FetchContent) + +set(JSON_MultipleHeaders OFF) + +FetchContent_Declare( + json + GIT_REPOSITORY https://github.com/ArthurSonzogni/nlohmann_json_cmake_fetchcontent.git + GIT_TAG 67e6070f9d9a44b4dec79ebe6b591f39d2285593 + GIT_PROGRESS TRUE +) +message("json") +FetchContent_MakeAvailable(json) \ No newline at end of file diff --git a/scripts/pugixml.cmake b/scripts/pugixml.cmake new file mode 100644 index 0000000..362a9e1 --- /dev/null +++ b/scripts/pugixml.cmake @@ -0,0 +1,11 @@ +include(FetchContent) + +FetchContent_Declare( + pugixml + GIT_REPOSITORY https://github.com/zeux/pugixml.git + GIT_TAG a0e064336317c9347a91224112af9933598714e9 + GIT_PROGRESS TRUE +) +message("pugixml") +FetchContent_MakeAvailable(pugixml) +set_property(TARGET pugixml PROPERTY CXX_STANDARD 23) diff --git a/src/AccountInfo.hpp b/src/AccountInfo.hpp new file mode 100644 index 0000000..0e0fc84 --- /dev/null +++ b/src/AccountInfo.hpp @@ -0,0 +1,17 @@ +#pragma once +#include + +class AccountInfo +{ +public: + uint64_t m_rockstar_id; + int m_age; + string m_avatar_url; + string m_country_code; + string m_date_of_birth; + string m_email; + bool m_is_approx_dob; + string m_language_code; + string m_nickname; + string m_last_portal_login_date; +}; \ No newline at end of file diff --git a/src/command.cpp b/src/command.cpp new file mode 100644 index 0000000..d412b55 --- /dev/null +++ b/src/command.cpp @@ -0,0 +1,118 @@ +#include "command.hpp" +#include "ros_crypt.hpp" +#include + +ROSCrypt* command::m_launcher_ros = nullptr; +ROSCrypt* command::m_ros = nullptr; + +command::command(const string& name) : m_name(name) +{ + m_launcher_ros = new ROSCrypt(true); + m_ros = new ROSCrypt(false); + + g_commands[hash()(name)] = this; +} + +command* command::get(int command) +{ + return g_commands[command]; +} + +string command::run_raw(const string url, const string queryString, bool launcher) +{ + auto api = launcher ? m_launcher_ros : m_ros; + + string absolutePath = url.substr(url.find('/', url.find("://") + 3)); + + Botan::AutoSeeded_RNG rng; + auto challenge = rng.random_vec(8); + + cpr::Response response = cpr::Post( + cpr::Url{ url }, + cpr::Header + { + {"ros-SecurityFlags", "239" }, + {"ros-SessionTicket", SESSION_TICKET}, + {"ros-Challenge", Botan::base64_encode(challenge)}, + {"ros-HeadersHmac", Botan::base64_encode(api->HeadersHmac(challenge, "POST", absolutePath, SESSION_KEY, SESSION_TICKET)) }, + {"Content-Type", "application/x-www-form-urlencoded; charset=utf-8"}, + {"User-Agent", api->GetROSVersionString()}, + }, + cpr::Body{ queryString }); + + return response.text; +} + +string command::run(const string url, map map) +{ + auto service_type = this->get_service_type(); + + if (service_type == PROD_ROS || service_type == PROD_ROS_LAUNCHER) + { + auto api = service_type == SERVICE_TYPE::PROD_ROS_LAUNCHER ? m_launcher_ros : m_ros; + + auto params = api->BuildPostString(map); + + string queryString = api->EncryptROSData(params, SESSION_KEY); + + string response = run_raw(url, queryString, service_type == SERVICE_TYPE::PROD_ROS_LAUNCHER); + + if (!response.contains("Internal server error")) + return api->DecryptROSData(response.c_str(), response.size(), SESSION_KEY); + else { + return response; + } + } + else if (service_type == PROD_SCAPI_AMC) + { + cpr::Parameters params; + for (const auto& entry : map) { + params.Add(cpr::Parameter(entry.first, entry.second)); + } + + cpr::Response response = cpr::Get( + cpr::Url{ url }, + cpr::Header + { + {"Content-Type", "application/x-www-form-urlencoded; charset=utf-8"}, + {"X-AMC", "true"}, + {"X-Requested-With", "XMLHttpRequest"} + }, + cpr::Parameters{ params }); + + cout << response.status_code << endl; + + return response.text; + } + + return ""; +} + +string command::run(const string url, string params) +{ + string queryString = m_ros->EncryptROSData(params, SESSION_KEY); + + string response = run_raw(url, queryString); + + if (!response.contains("Internal server error")) + return m_ros->DecryptROSData(response.c_str(), response.size(), SESSION_KEY); + else { + return response; + } +} + +string command::run_anonymous(const string& url, map map) +{ + string queryString = m_ros->EncryptROSData(m_ros->BuildPostString(map)); + + cpr::Response response = cpr::Post( + cpr::Url{ url }, + cpr::Header + { + {"Content-Type", "application/x-www-form-urlencoded; charset=utf-8"}, + {"User-Agent", m_ros->GetROSVersionString()} + }, + cpr::Body{ queryString }); + + return m_ros->DecryptROSData(response.text.c_str(), response.text.size(), ""); +} \ No newline at end of file diff --git a/src/command.hpp b/src/command.hpp new file mode 100644 index 0000000..9a03313 --- /dev/null +++ b/src/command.hpp @@ -0,0 +1,45 @@ +#pragma once +#include +#include +#include +#include +#include +#include "ros_crypt.hpp" + +using namespace std; + +inline string TICKET; +inline string SESSION_TICKET; +inline string SESSION_KEY; + +enum SERVICE_TYPE +{ + UNKNOWN, + PROD_ROS, + PROD_ROS_LAUNCHER, + PROD_SCAPI_AMC, + PROD_CLOUD +}; + +class command +{ +protected: + string m_name; + + string run_raw(const string url, const string queryString, bool launcher = false); + string run(const string url, map map); + string run(const string url, string params); + string run_anonymous(const string& url, map map); +public: + + command(const string& name); + inline const string& get_name() { return m_name; } + static command* get(int command); + virtual string execute(const vector& args) = 0; + virtual SERVICE_TYPE get_service_type() = 0; + + static ROSCrypt* m_launcher_ros; + static ROSCrypt* m_ros; +}; + +inline unordered_map g_commands; \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Achievements/AwardAchievement.cpp b/src/commands/prod.ros.rockstargames.com/Achievements/AwardAchievement.cpp new file mode 100644 index 0000000..02f457f --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Achievements/AwardAchievement.cpp @@ -0,0 +1,25 @@ +#include "../../../command.hpp" +#include + +class AwardAchievement : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the achievementId:" << endl; + string achievementId; + cin >> achievementId; + + map map; + map["ticket"] = TICKET; + map["achievementId"] = achievementId; + map["achievedOffline"] = "False"; + + return run("http://gta5-prod.ros.rockstargames.com/gta5/11/gameservices/achievements.asmx/AwardAchievement", map); + } +}; + +AwardAchievement g_award_achievement("awardachievement"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Achievements/AwardAchievementProgress.cpp b/src/commands/prod.ros.rockstargames.com/Achievements/AwardAchievementProgress.cpp new file mode 100644 index 0000000..c9a1511 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Achievements/AwardAchievementProgress.cpp @@ -0,0 +1,29 @@ +#include "../../../command.hpp" +#include + +class AwardAchievementProgress : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the achievementId:" << endl; + string achievementId; + cin >> achievementId; + + cout << "Specify the achievementProgress:" << endl; + string achievementProgress; + cin >> achievementProgress; + + map map; + map["ticket"] = TICKET; + map["achievementId"] = achievementId; + map["achievedOffline"] = "False"; + + return run("http://gta5-prod.ros.rockstargames.com/gta5/11/gameservices/achievements.asmx/AwardAchievementProgress", map); + } +}; + +AwardAchievementProgress g_award_achievement_progress("awardachievementprogress"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Achievements/GetAchievementDefinitions.cpp b/src/commands/prod.ros.rockstargames.com/Achievements/GetAchievementDefinitions.cpp new file mode 100644 index 0000000..3875fee --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Achievements/GetAchievementDefinitions.cpp @@ -0,0 +1,34 @@ +#include "../../../command.hpp" +#include + +class GetAchievementDefinitions : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the pageIndex:" << endl; + string firstAchievementId; + cin >> firstAchievementId; + + cout << "Specify the maxDefinitions:" << endl; + string maxDefinitions; + cin >> maxDefinitions; + + cout << "Specify the locale (ex. en-US):" << endl; + string locale; + cin >> locale; + + map map; + map["ticket"] = TICKET; + map["firstAchievementId"] = firstAchievementId; + map["maxDefinitions"] = maxDefinitions; + map["locale"] = locale; + + return run("http://gta5-prod.ros.rockstargames.com/gta5/11/gameservices/achievements.asmx/GetAchievementDefinitions", map); + } +}; + +GetAchievementDefinitions g_get_achievement_definitions("getachievementdefinitions"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Achievements/GetPlayerAchievements.cpp b/src/commands/prod.ros.rockstargames.com/Achievements/GetPlayerAchievements.cpp new file mode 100644 index 0000000..18d066f --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Achievements/GetPlayerAchievements.cpp @@ -0,0 +1,27 @@ +#include "../../../command.hpp" +#include + +class GetPlayerAchievements : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the rockstarId:" << endl; + string rockstarId; + cin >> rockstarId; + + map map; + map["ticket"] = TICKET; + map["playerRockstarId"] = rockstarId; + map["crossTitleId"] = "11"; + map["crossTitleName"] = "gta5"; + map["crossTitlePlatformName"] = "pcros"; + + return run("http://gta5-prod.ros.rockstargames.com/gta5/11/gameservices/achievements.asmx/GetPlayerAchievements", map); + } +}; + +GetPlayerAchievements g_get_player_achievements("getplayerachievements"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Auth/CreateP2PCertificate.cpp b/src/commands/prod.ros.rockstargames.com/Auth/CreateP2PCertificate.cpp new file mode 100644 index 0000000..bda2481 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Auth/CreateP2PCertificate.cpp @@ -0,0 +1,30 @@ +#include "../../../command.hpp" + +class CreateP2PCertificate : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the pubKey" << endl; + string pubKey; + cin >> pubKey; + + cout << "Specify the sig" << endl; + string sig; + cin >> sig; + + map map; + map["ticket"] = TICKET; + map["pubKeyCurve"] = "nistP256"; + map["pubKey"] = pubKey; + map["hashAlg"] = "SHA256"; + map["sig"] = sig; + + return run("https://gta5-prod.ros.rockstargames.com/gta5/11/gameservices/auth.asmx/CreateP2PCertificate", map); + } +}; + +CreateP2PCertificate g_create_p2p_certificate("createp2pcertificate"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Auth/CreateScAuthToken.cpp b/src/commands/prod.ros.rockstargames.com/Auth/CreateScAuthToken.cpp new file mode 100644 index 0000000..cc437c7 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Auth/CreateScAuthToken.cpp @@ -0,0 +1,20 @@ +#include "../../../command.hpp" +#include + +class CreateScAuthToken : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + + map map; + map["ticket"] = TICKET; + + return run("http://gta5-prod.ros.rockstargames.com/gta5/11/gameservices/auth.asmx/CreateTicketScAuthToken2", map); + } +}; + +CreateScAuthToken g_create_sc_auth_token("createscauthtoken"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Auth/CreateTicket.cpp b/src/commands/prod.ros.rockstargames.com/Auth/CreateTicket.cpp new file mode 100644 index 0000000..989a43b --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Auth/CreateTicket.cpp @@ -0,0 +1,195 @@ +#include "../../../command.hpp" +#include "pugixml.hpp" +#include +#include +#include + +class CreateTicket : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + inline void request_socialclub_data(unordered_map& env_vars) + { + cout << "Specify your SocialClub Email" << endl; + string email; + cin >> email; + + cout << "Specify your SocialClub Profile Name" << endl; + string nickname; + cin >> nickname; + + cout << "Specify your SocialClub Password" << endl; + string password; + cin >> password; + + env_vars["EMAIL"] = email; + env_vars["NICKNAME"] = nickname; + env_vars["PASSWORD"] = password; + env_vars["PLATFORM"] = "pcros"; + + ofstream outFile(".env"); + + for (const auto& pair : env_vars) { + outFile << pair.first << "=" << pair.second << "\n"; + } + } + + inline bool request_ticket(string email, string nickname, string password, string platform, string& _response) + { + map map; + map["ticket"] = ""; + map["email"] = email; + map["nickname"] = nickname; + map["password"] = password; + map["platformName"] = platform; + + string response = run_anonymous("https://gta5-prod.ros.rockstargames.com/gta5/11/gameservices/auth.asmx/CreateTicketSc3", map); + + pugi::xml_document doc; + if (!doc.load_string(response.c_str())) return false; + + bool successfully = false; + + ofstream outFile("data.bin"); + + pugi::xml_node xml_response = doc.child("Response"); + + for (pugi::xml_node panel = xml_response.first_child(); panel; panel = panel.next_sibling()) + { + if (strcmp(panel.name(), "Ticket") == 0) + { + TICKET = panel.text().get(); + cout << "Ticket: " << TICKET << endl; + outFile << "TICKET" << "=" << TICKET << "\n"; + successfully = true; + } + else if (strcmp(panel.name(), "SessionKey") == 0) + { + SESSION_KEY = panel.text().get(); + cout << "Session Key: " << SESSION_KEY << endl; + outFile << "SESSION_KEY" << "=" << SESSION_KEY << "\n"; + } + else if (strcmp(panel.name(), "SessionTicket") == 0) + { + SESSION_TICKET = panel.text().get(); + cout << "Session Ticket: " << SESSION_TICKET << endl; + outFile << "SESSION_TICKET" << "=" << SESSION_TICKET << "\n"; + } + } + + _response = response; + + return successfully; + } + + virtual string execute(const vector& args) + { + unordered_map env_vars; + + ifstream infile("data.bin"); + + bool skip; + + if (filesystem::exists("data.bin")) + { + string line; + while (getline(infile, line)) { + size_t equal_pos = line.find('='); + if (equal_pos != string::npos) { + string key = line.substr(0, equal_pos); + string value = line.substr(equal_pos + 1); + + if (key == "TICKET") + TICKET = value; + else if (key == "SESSION_KEY") + SESSION_KEY = value; + else if (key == "SESSION_TICKET") + SESSION_TICKET = value; + } + } + + string data = command::get(hash()("getaccountinfo"))->execute({}); + if (data.empty() || data.contains("Internal Server Error") || data.contains("AuthenticationFailed")) + { + cout << "Auth -> Cached session is no longer valid... recreating now." << endl; + + if (filesystem::exists("data.bin")) + { + cout << ".env found at " << filesystem::absolute(".env") << endl; + ifstream infile(".env"); + string line; + while (getline(infile, line)) { + size_t equal_pos = line.find('='); + if (equal_pos != string::npos) { + string key = line.substr(0, equal_pos); + string value = line.substr(equal_pos + 1); + env_vars[key] = value; + } + } + infile.close(); + + bool success; + string response; + do { + success = request_ticket(env_vars.at("EMAIL"), env_vars.at("NICKNAME"), env_vars.at("PASSWORD"), env_vars.at("PLATFORM"), response); + + if (!success) + { + cout << "Auth -> Invalid credentials or rate limited" << endl; + request_socialclub_data(env_vars); + } + } while (!success); + + return response; + } + + } + else if (data.contains("Error Code")) + { + cout << "Auth -> Received Error: " << data << endl; + + bool success; + string response; + do { + request_socialclub_data(env_vars); + success = request_ticket(env_vars.at("EMAIL"), env_vars.at("NICKNAME"), env_vars.at("PASSWORD"), env_vars.at("PLATFORM"), response); + + if (!success) + { + cout << "Auth -> Invalid credentials or rate limited" << endl; + } + } while (!success); + + return response; + } + else + { + return "Auth -> Using cached session"; + } + } + else if (!filesystem::exists(".env") || !filesystem::exists("data.bin")) + { + request_socialclub_data(env_vars); + + bool success; + string response; + do { + success = request_ticket(env_vars.at("EMAIL"), env_vars.at("NICKNAME"), env_vars.at("PASSWORD"), env_vars.at("PLATFORM"), response); + + if (!success) + { + cout << "Auth -> Invalid credentials or rate limited" << endl; + request_socialclub_data(env_vars); + } + } while (!success); + + return response; + } + + return "error"; + } +}; + +CreateTicket g_create_ticket("createticket"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Clans/Disband.cpp b/src/commands/prod.ros.rockstargames.com/Clans/Disband.cpp new file mode 100644 index 0000000..7eae666 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Clans/Disband.cpp @@ -0,0 +1,24 @@ +#include "../../../command.hpp" +#include + +class Disband : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the clanId:" << endl; + string clanId; + cin >> clanId; + + map map; + map["ticket"] = TICKET; + map["clanId"] = clanId; + + return run("http://crews-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Clans.asmx/Disband", map); + } +}; + +Disband g_disband("disbandcrew"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Clans/GetAll.cpp b/src/commands/prod.ros.rockstargames.com/Clans/GetAll.cpp new file mode 100644 index 0000000..2abd728 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Clans/GetAll.cpp @@ -0,0 +1,49 @@ +#include "../../../command.hpp" +#include + +class GetAll : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the pageIndex:" << endl; + string pageIndex; + cin >> pageIndex; + + cout << "Specify the pageSize:" << endl; + string pageSize; + cin >> pageSize; + + cout << "Specify if isSystemClan (0 = no/1 = yes, -1 = any):" << endl; + string isSystemClan; + cin >> isSystemClan; + + cout << "Specify if isOpenClan (0 = no/1 = yes, -1 = any):" << endl; + string isOpenClan; + cin >> isOpenClan; + + cout << "Specify the search (Can be 0):" << endl; + string search; + cin >> search; + + cout << "Specify the sortMode (Can be 0, other values unknown yet):" << endl; + string sortMode; + cin >> sortMode; + + map map; + map["ticket"] = TICKET; + map["pageIndex"] = pageIndex; + map["pageSize"] = pageSize; + map["isSystemClan"] = isSystemClan; + map["isOpenClan"] = isOpenClan; + map["search"] = search; + map["sortMode"] = sortMode; + + return run("http://crews-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Clans.asmx/GetAll", map); + } +}; + +GetAll g_get_all("getallcrews"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Clans/GetDesc.cpp b/src/commands/prod.ros.rockstargames.com/Clans/GetDesc.cpp new file mode 100644 index 0000000..09af4ea --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Clans/GetDesc.cpp @@ -0,0 +1,24 @@ +#include "../../../command.hpp" +#include + +class GetDesc : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the clanId:" << endl; + string clanId; + cin >> clanId; + + map map; + map["ticket"] = TICKET; + map["clanId"] = clanId; + + return run("http://crews-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Clans.asmx/GetDesc", map); + } +}; + +GetDesc g_get_desc("getcrewdesc"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Clans/GetDescs.cpp b/src/commands/prod.ros.rockstargames.com/Clans/GetDescs.cpp new file mode 100644 index 0000000..662ca9d --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Clans/GetDescs.cpp @@ -0,0 +1,24 @@ +#include "../../../command.hpp" +#include + +class GetDescs : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the clanIdsCsv (ex.: 12345,56789):" << endl; + string clanIdsCsv; + cin >> clanIdsCsv; + + map map; + map["ticket"] = TICKET; + map["clanIdsCsv"] = clanIdsCsv; + + return run("http://crews-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Clans.asmx/GetDescs", map); + } +}; + +GetDescs g_get_descs("getcrewdescs"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Clans/GetFeudStats.cpp b/src/commands/prod.ros.rockstargames.com/Clans/GetFeudStats.cpp new file mode 100644 index 0000000..65f76fe --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Clans/GetFeudStats.cpp @@ -0,0 +1,29 @@ +#include "../../../command.hpp" +#include + +class GetFeudStats : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the clanId:" << endl; + string clanId; + cin >> clanId; + + cout << "Specify the since ((lastday, lastweek, last2weeks, lastmonth, last3months, last6months, alltime) / 0):" << endl; + string since; + cin >> since; + + map map; + map["ticket"] = TICKET; + map["clanId"] = clanId; + map["since"] = since; + + return run("http://crews-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Clans.asmx/GetFeudStats", map); // TODO Internal Server Error (no longer in use?) + } +}; + +GetFeudStats g_get_feud_stats("getfeudstats"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Clans/GetInvites.cpp b/src/commands/prod.ros.rockstargames.com/Clans/GetInvites.cpp new file mode 100644 index 0000000..16eb969 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Clans/GetInvites.cpp @@ -0,0 +1,29 @@ +#include "../../../command.hpp" +#include + +class GetInvites : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the pageIndex:" << endl; + string pageIndex; + cin >> pageIndex; + + cout << "Specify the pageSize:" << endl; + string pageSize; + cin >> pageSize; + + map map; + map["ticket"] = TICKET; + map["pageIndex"] = pageIndex; + map["pageSize"] = pageSize; + + return run("http://crews-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Clans.asmx/GetInvites", map); + } +}; + +GetInvites g_get_invites("getcrewinvites"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Clans/GetLeadersForClans.cpp b/src/commands/prod.ros.rockstargames.com/Clans/GetLeadersForClans.cpp new file mode 100644 index 0000000..1f270bf --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Clans/GetLeadersForClans.cpp @@ -0,0 +1,24 @@ +#include "../../../command.hpp" +#include + +class GetLeadersForClans : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the clanIdsCsv (ex.: 123456,789801):" << endl; + string clanIdsCsv; + cin >> clanIdsCsv; + + map map; + map["ticket"] = TICKET; + map["clanIdsCsv"] = clanIdsCsv; + + return run("http://crews-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Clans.asmx/GetLeadersForClans", map); + } +}; + +GetLeadersForClans g_get_leaders_for_clans("getleadersforclans"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Clans/GetMembers.cpp b/src/commands/prod.ros.rockstargames.com/Clans/GetMembers.cpp new file mode 100644 index 0000000..0f769b8 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Clans/GetMembers.cpp @@ -0,0 +1,39 @@ +#include "../../../command.hpp" +#include + +class GetCrewMembers : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the pageIndex:" << endl; + string pageIndex; + cin >> pageIndex; + + cout << "Specify the pageSize:" << endl; + string pageSize; + cin >> pageSize; + + cout << "Specify the clanId:" << endl; + string clanId; + cin >> clanId; + + cout << "Specify the clanName:" << endl; + string clanName; + cin >> clanName; + + map map; + map["ticket"] = TICKET; + map["pageIndex"] = pageIndex; + map["pageSize"] = pageSize; + map["clanId"] = clanId; + map["clanName"] = clanName; + + return run("http://crews-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Clans.asmx/GetMembers", map); + } +}; + +GetCrewMembers g_get_crew_members("getcrewmembers"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Clans/GetMembersTitleOnly.cpp b/src/commands/prod.ros.rockstargames.com/Clans/GetMembersTitleOnly.cpp new file mode 100644 index 0000000..33d32d6 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Clans/GetMembersTitleOnly.cpp @@ -0,0 +1,39 @@ +#include "../../../command.hpp" +#include + +class GetCrewMembersTitleOnly : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the pageIndex:" << endl; + string pageIndex; + cin >> pageIndex; + + cout << "Specify the pageSize:" << endl; + string pageSize; + cin >> pageSize; + + cout << "Specify the clanId:" << endl; + string clanId; + cin >> clanId; + + cout << "Specify the clanName:" << endl; + string clanName; + cin >> clanName; + + map map; + map["ticket"] = TICKET; + map["pageIndex"] = pageIndex; + map["pageSize"] = pageSize; + map["clanId"] = clanId; + map["clanName"] = clanName; + + return run("http://crews-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Clans.asmx/GetMembersTitleOnly", map); + } +}; + +GetCrewMembersTitleOnly g_get_crew_members_title_only("getcrewmemberstitleonly"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Clans/GetMetadataForClan.cpp b/src/commands/prod.ros.rockstargames.com/Clans/GetMetadataForClan.cpp new file mode 100644 index 0000000..0a132eb --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Clans/GetMetadataForClan.cpp @@ -0,0 +1,34 @@ +#include "../../../command.hpp" +#include + +class GetMetadataForClan : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the pageIndex:" << endl; + string pageIndex; + cin >> pageIndex; + + cout << "Specify the pageSize:" << endl; + string pageSize; + cin >> pageSize; + + cout << "Specify the clanId:" << endl; + string clanId; + cin >> clanId; + + map map; + map["ticket"] = TICKET; + map["pageIndex"] = pageIndex; + map["pageSize"] = pageSize; + map["clanId"] = clanId; + + return run("http://crews-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Clans.asmx/GetMetadataForClan", map); + } +}; + +GetMetadataForClan g_get_metadata_for_clan("getcrewmetadata"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Clans/GetMine.cpp b/src/commands/prod.ros.rockstargames.com/Clans/GetMine.cpp new file mode 100644 index 0000000..dbb8c65 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Clans/GetMine.cpp @@ -0,0 +1,29 @@ +#include "../../../command.hpp" +#include + +class GetMine : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the pageIndex:" << endl; + string pageIndex; + cin >> pageIndex; + + cout << "Specify the pageSize:" << endl; + string pageSize; + cin >> pageSize; + + map map; + map["ticket"] = TICKET; + map["pageIndex"] = pageIndex; + map["pageSize"] = pageSize; + + return run("http://crews-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Clans.asmx/GetMine", map); + } +}; + +GetMine g_get_mine("getmycrew"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Clans/GetPrimaryClans.cpp b/src/commands/prod.ros.rockstargames.com/Clans/GetPrimaryClans.cpp new file mode 100644 index 0000000..f3b4dab --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Clans/GetPrimaryClans.cpp @@ -0,0 +1,24 @@ +#include "../../../command.hpp" +#include + +class GetPrimaryClans : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the gamerHandlesCsv (ex.: 123456,789900):" << endl; + string gamerHandlesCsv; + cin >> gamerHandlesCsv; + + map map; + map["ticket"] = TICKET; + map["gamerHandlesCsv"] = gamerHandlesCsv; + + return run("http://crews-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Clans.asmx/GetPrimaryClans", map); // Exception, no further info + } +}; + +GetPrimaryClans g_get_primary_clans("getprimaryclans"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Clans/GetRanks.cpp b/src/commands/prod.ros.rockstargames.com/Clans/GetRanks.cpp new file mode 100644 index 0000000..53db0f1 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Clans/GetRanks.cpp @@ -0,0 +1,34 @@ +#include "../../../command.hpp" +#include + +class GetRanks : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the clanId:" << endl; + string clanId; + cin >> clanId; + + cout << "Specify the pageIndex:" << endl; + string pageIndex; + cin >> pageIndex; + + cout << "Specify the pageSize:" << endl; + string pageSize; + cin >> pageSize; + + map map; + map["ticket"] = TICKET; + map["clanId"] = clanId; + map["pageIndex"] = pageIndex; + map["pageSize"] = pageSize; + + return run("http://crews-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Clans.asmx/GetRanks", map); + } +}; + +GetRanks g_get_ranks("getcrewranks"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Clans/GetSentInvites.cpp b/src/commands/prod.ros.rockstargames.com/Clans/GetSentInvites.cpp new file mode 100644 index 0000000..f339ba2 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Clans/GetSentInvites.cpp @@ -0,0 +1,29 @@ +#include "../../../command.hpp" +#include + +class GetSentInvites : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the pageIndex:" << endl; + string pageIndex; + cin >> pageIndex; + + cout << "Specify the pageSize:" << endl; + string pageSize; + cin >> pageSize; + + map map; + map["ticket"] = TICKET; + map["pageIndex"] = pageIndex; + map["pageSize"] = pageSize; + + return run("http://crews-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Clans.asmx/GetSentInvites", map); + } +}; + +GetSentInvites g_get_sent_invites("getsentcrewinvites"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Clans/GetTopRivals.cpp b/src/commands/prod.ros.rockstargames.com/Clans/GetTopRivals.cpp new file mode 100644 index 0000000..96c052d --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Clans/GetTopRivals.cpp @@ -0,0 +1,29 @@ +#include "../../../command.hpp" +#include + +class GetTopRivals : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the clanId:" << endl; + string clanId; + cin >> clanId; + + cout << "Specify the since ((lastday, lastweek, last2weeks, lastmonth, last3months, last6months, alltime) / 0):" << endl; + string since; + cin >> since; + + map map; + map["ticket"] = TICKET; + map["clanId"] = clanId; + map["since"] = since; + + return run("http://crews-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Clans.asmx/GetTopRivals1", map); // Internal Error, no longer used? + } +}; + +GetTopRivals g_get_top_rivals("gettoprivals"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Clans/GetWallMessages.cpp b/src/commands/prod.ros.rockstargames.com/Clans/GetWallMessages.cpp new file mode 100644 index 0000000..1591e92 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Clans/GetWallMessages.cpp @@ -0,0 +1,35 @@ +#include "../../../command.hpp" +#include + +class GetWallMessages : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the pageIndex:" << endl; + string pageIndex; + cin >> pageIndex; + + cout << "Specify the pageSize:" << endl; + string pageSize; + cin >> pageSize; + + cout << "Specify the clanId:" << endl; + string clanId; + cin >> clanId; + + + map map; + map["ticket"] = TICKET; + map["pageIndex"] = pageIndex; + map["pageSize"] = pageSize; + map["clanId"] = clanId; + + return run("http://crews-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Clans.asmx/GetWallMessages", map); // Internal Server Error, great + } +}; + +GetWallMessages g_get_wall_messages("getwallmessages"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Clans/JoinClan.cpp b/src/commands/prod.ros.rockstargames.com/Clans/JoinClan.cpp new file mode 100644 index 0000000..cabaa24 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Clans/JoinClan.cpp @@ -0,0 +1,24 @@ +#include "../../../command.hpp" +#include + +class JoinCrew : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the clanId:" << endl; + string clanId; + cin >> clanId; + + map map; + map["ticket"] = TICKET; + map["clanId"] = clanId; + + return run("http://crews-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Clans.asmx/Join", map); + } +}; + +JoinCrew g_join_crew("joincrew"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Clans/Kick.cpp b/src/commands/prod.ros.rockstargames.com/Clans/Kick.cpp new file mode 100644 index 0000000..b3063f7 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Clans/Kick.cpp @@ -0,0 +1,29 @@ +#include "../../../command.hpp" +#include + +class Kick : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the clanId:" << endl; + string clanId; + cin >> clanId; + + cout << "Specify the targetGamerHandle:" << endl; + string targetGamerHandle; + cin >> targetGamerHandle; + + map map; + map["ticket"] = TICKET; + map["clanId"] = clanId; + map["targetGamerHandle"] = targetGamerHandle; + + return run("http://crews-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Clans.asmx/Kick", map); + } +}; + +Kick g_kick("kickfromcrew"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Clans/Leave.cpp b/src/commands/prod.ros.rockstargames.com/Clans/Leave.cpp new file mode 100644 index 0000000..95d00fe --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Clans/Leave.cpp @@ -0,0 +1,24 @@ +#include "../../../command.hpp" +#include + +class Leave : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the clanId:" << endl; + string clanId; + cin >> clanId; + + map map; + map["ticket"] = TICKET; + map["clanId"] = clanId; + + return run("http://crews-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Clans.asmx/Leave", map); + } +}; + +Leave g_leave("leavecrew"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Clans/MemberSetRankByRankOrder.cpp b/src/commands/prod.ros.rockstargames.com/Clans/MemberSetRankByRankOrder.cpp new file mode 100644 index 0000000..5d99c0c --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Clans/MemberSetRankByRankOrder.cpp @@ -0,0 +1,34 @@ +#include "../../../command.hpp" +#include + +class MemberSetRankByRankOrder : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the targetGamerHandle:" << endl; + string targetGamerHandle; + cin >> targetGamerHandle; + + cout << "Specify the clanId:" << endl; + string clanId; + cin >> clanId; + + cout << "Specify the rankOrder:" << endl; + string rankOrder; + cin >> rankOrder; + + map map; + map["ticket"] = TICKET; + map["targetGamerHandle"] = targetGamerHandle; + map["clanId"] = clanId; + map["rankOrder"] = rankOrder; + + return run("http://crews-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Clans.asmx/MemberSetRankByRankOrder", map); // Title or Environment not supported + } +}; + +MemberSetRankByRankOrder g_member_set_rank_by_rank_order("membersetrankbyrankorder"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Clans/MemberUpdateRankId.cpp b/src/commands/prod.ros.rockstargames.com/Clans/MemberUpdateRankId.cpp new file mode 100644 index 0000000..a94aa56 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Clans/MemberUpdateRankId.cpp @@ -0,0 +1,34 @@ +#include "../../../command.hpp" +#include + +class MemberUpdateRankId : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the targetGamerHandle:" << endl; + string targetGamerHandle; + cin >> targetGamerHandle; + + cout << "Specify the clanId:" << endl; + string clanId; + cin >> clanId; + + cout << "Specify if promote (true/false):" << endl; + string promote; + cin >> promote; + + map map; + map["ticket"] = TICKET; + map["targetGamerHandle"] = targetGamerHandle; + map["clanId"] = clanId; + map["promote"] = promote; + + return run("http://crews-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Clans.asmx/MemberUpdateRankId", map); // Invalid Argument for some reason + } +}; + +MemberUpdateRankId g_member_update_rank_id("memberupdaterankid"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Clans/RankCreate.cpp b/src/commands/prod.ros.rockstargames.com/Clans/RankCreate.cpp new file mode 100644 index 0000000..55fdaa3 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Clans/RankCreate.cpp @@ -0,0 +1,34 @@ +#include "../../../command.hpp" +#include + +class RankCreate : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the clanId:" << endl; + string clanId; + cin >> clanId; + + cout << "Specify the rankName (0-4):" << endl; //? + string rankName; + cin >> rankName; + + cout << "Specify the initialSystemFlags:" << endl; + string initialSystemFlags; + cin >> initialSystemFlags; + + map map; + map["ticket"] = TICKET; + map["clanId"] = clanId; + map["rankName"] = rankName; + map["initialSystemFlags"] = initialSystemFlags; + + return run("http://crews-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Clans.asmx/RankCreate", map); // Error: OutOfRange -> ClanRankLength + } +}; + +RankCreate g_rank_create("createcrewrank"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Clans/RankDelete.cpp b/src/commands/prod.ros.rockstargames.com/Clans/RankDelete.cpp new file mode 100644 index 0000000..57f8ad8 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Clans/RankDelete.cpp @@ -0,0 +1,29 @@ +#include "../../../command.hpp" +#include + +class RankDelete : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the clanId:" << endl; + string clanId; + cin >> clanId; + + cout << "Specify the rankId:" << endl; + string rankId; + cin >> rankId; + + map map; + map["ticket"] = TICKET; + map["clanId"] = clanId; + map["rankId"] = rankId; + + return run("http://crews-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Clans.asmx/RankDelete", map); + } +}; + +RankDelete g_rank_delete("deletecrewrank"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Clans/SetPrimaryClan.cpp b/src/commands/prod.ros.rockstargames.com/Clans/SetPrimaryClan.cpp new file mode 100644 index 0000000..315c12f --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Clans/SetPrimaryClan.cpp @@ -0,0 +1,24 @@ +#include "../../../command.hpp" +#include + +class SetPrimaryClan : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the clanId:" << endl; + string clanId; + cin >> clanId; + + map map; + map["ticket"] = TICKET; + map["clanId"] = clanId; + + return run("http://crews-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Clans.asmx/SetPrimaryClan", map); + } +}; + +SetPrimaryClan g_set_primary_clan("setprimaryclan"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Clans/WriteWallMessage.cpp b/src/commands/prod.ros.rockstargames.com/Clans/WriteWallMessage.cpp new file mode 100644 index 0000000..901e3a2 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Clans/WriteWallMessage.cpp @@ -0,0 +1,29 @@ +#include "../../../command.hpp" +#include + +class WriteWallMessage : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the clanId:" << endl; + string clanId; + cin >> clanId; + + cout << "Specify the message:" << endl; + string message; + cin >> message; + + map map; + map["ticket"] = TICKET; + map["clanId"] = clanId; + map["message"] = message; + + return run("http://crews-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Clans.asmx/WriteWallMessage", map); // Internal Server Error, no longer in use? + } +}; + +WriteWallMessage write_wall_message("writecrewwallmessage"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Decrypt.cpp b/src/commands/prod.ros.rockstargames.com/Decrypt.cpp new file mode 100644 index 0000000..39c9340 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Decrypt.cpp @@ -0,0 +1,23 @@ +#include "../../command.hpp" +#include +#include +#include +#include "../../ros_crypt.hpp" + +class Decrypt : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + ifstream infile(R"(C:\Users\Bugisoft\Downloads\GTA_Reverse\request_content.txt)", ios_base::binary); + + vector bytes((istreambuf_iterator(infile)), (istreambuf_iterator())); + + return m_ros->DecryptROSData(&bytes[0], bytes.size(), SESSION_KEY); + } +}; + +Decrypt g_decrypt("decrypt"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Friends/AcceptFriendRequest.cpp b/src/commands/prod.ros.rockstargames.com/Friends/AcceptFriendRequest.cpp new file mode 100644 index 0000000..d3c5ead --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Friends/AcceptFriendRequest.cpp @@ -0,0 +1,24 @@ +#include "../../../command.hpp" +#include + +class AcceptFriendRequest : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the rockstarId:" << endl; + string rockstarId; + cin >> rockstarId; + + map map; + map["ticket"] = TICKET; + map["rockstarId"] = rockstarId; + + return run("http://gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Friends.asmx/AcceptInvite", map); // Missleading name, friend request not session invite + } +}; + +AcceptFriendRequest g_accept_friend_request("acceptfriendrequest"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Friends/AddFriendByNickname.cpp b/src/commands/prod.ros.rockstargames.com/Friends/AddFriendByNickname.cpp new file mode 100644 index 0000000..46c2f2d --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Friends/AddFriendByNickname.cpp @@ -0,0 +1,24 @@ +#include "../../../command.hpp" +#include + +class InviteByNickname : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the nickname:" << endl; + string nickname; + cin >> nickname; + + map map; + map["ticket"] = TICKET; + map["nickName"] = nickname; + + return run("http://gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Friends.asmx/InviteByNickname", map); // This name is missleading since you doesnt actually "invite" a friend instead send a friend request + } +}; + +InviteByNickname g_invite_by_nickname("addfriendbyname"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Friends/AddFriendByRockstarId.cpp b/src/commands/prod.ros.rockstargames.com/Friends/AddFriendByRockstarId.cpp new file mode 100644 index 0000000..e6dcf77 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Friends/AddFriendByRockstarId.cpp @@ -0,0 +1,24 @@ +#include "../../../command.hpp" +#include + +class InviteByRockstarId : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the rockstar id:" << endl; + string rockstarId; + cin >> rockstarId; + + map map; + map["ticket"] = TICKET; + map["rockstarId"] = rockstarId; + + return run("http://gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Friends.asmx/InviteByRockstarId", map); // This name is missleading since you doesnt actually "invite" a friend instead send a friend request + } +}; + +InviteByRockstarId g_invite_by_rockstarid("addfriendbyrid"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Friends/BlockCommunications.cpp b/src/commands/prod.ros.rockstargames.com/Friends/BlockCommunications.cpp new file mode 100644 index 0000000..95bd7a5 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Friends/BlockCommunications.cpp @@ -0,0 +1,24 @@ +#include "../../../command.hpp" +#include + +class BlockCommunications : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the rockstarId:" << endl; + string rockstarId; + cin >> rockstarId; + + map map; + map["ticket"] = TICKET; + map["rockstarId"] = rockstarId; + + return run("http://gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Friends.asmx/Block", map); // Missleading name, dont have to be a friend + } +}; + +BlockCommunications g_block_communications("blockcoms"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Friends/CancelFriendRequest.cpp b/src/commands/prod.ros.rockstargames.com/Friends/CancelFriendRequest.cpp new file mode 100644 index 0000000..d035b3c --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Friends/CancelFriendRequest.cpp @@ -0,0 +1,24 @@ +#include "../../../command.hpp" +#include + +class CancelFriendRequest : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the rockstar id:" << endl; + string rockstarId; + cin >> rockstarId; + + map map; + map["ticket"] = TICKET; + map["rockstarId"] = rockstarId; + + return run("http://gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Friends.asmx/CancelInvite", map); + } +}; + +CancelFriendRequest g_cancel_invite("cancelfriendrequest"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Friends/CountAll.cpp b/src/commands/prod.ros.rockstargames.com/Friends/CountAll.cpp new file mode 100644 index 0000000..a324dfe --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Friends/CountAll.cpp @@ -0,0 +1,27 @@ +#include "../../../command.hpp" +#include + +class CountAll : command +{ + using command::command; + + /* + * Response: + * b -> ? + * f -> Friend Count + * ir -> Friend Requests Received (See: getfriendrequestssent) + * is -> Friend Requests Sent (See: + */ + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + map map; + map["ticket"] = TICKET; + + return run("http://gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Friends.asmx/CountAll", map); + } +}; + +CountAll g_count_all_friends("countallfriends"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Friends/DeclineFriendRequest.cpp b/src/commands/prod.ros.rockstargames.com/Friends/DeclineFriendRequest.cpp new file mode 100644 index 0000000..e293624 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Friends/DeclineFriendRequest.cpp @@ -0,0 +1,24 @@ +#include "../../../command.hpp" +#include + +class DeclineFriendRequest : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the rockstarId:" << endl; + string rockstarId; + cin >> rockstarId; + + map map; + map["ticket"] = TICKET; + map["rockstarId"] = rockstarId; + + return run("http://gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Friends.asmx/DeclineInvite", map); // Missleading name, friend request not session invite + } +}; + +DeclineFriendRequest g_decline_friend_request("declinefriendrequest"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Friends/GetBlocked.cpp b/src/commands/prod.ros.rockstargames.com/Friends/GetBlocked.cpp new file mode 100644 index 0000000..e9aa0d1 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Friends/GetBlocked.cpp @@ -0,0 +1,29 @@ +#include "../../../command.hpp" +#include + +class GetBlocked : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the page index:" << endl; + string pageIndex; + cin >> pageIndex; + + cout << "Specify the page size:" << endl; + string pageSize; + cin >> pageSize; + + map map; + map["ticket"] = TICKET; + map["pageIndex"] = pageIndex; + map["pageSize"] = pageSize; + + return run("http://gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Friends.asmx/GetBlocked", map); // Missleading name, not blocked friends just overall blocked players + } +}; + +GetBlocked g_get_blocked("getblocked"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Friends/GetFriendRequestsReceived.cpp b/src/commands/prod.ros.rockstargames.com/Friends/GetFriendRequestsReceived.cpp new file mode 100644 index 0000000..e9a0b3a --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Friends/GetFriendRequestsReceived.cpp @@ -0,0 +1,29 @@ +#include "../../../command.hpp" +#include + +class GetFriendRequestsReceived : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the page index:" << endl; + string pageIndex; + cin >> pageIndex; + + cout << "Specify the page size:" << endl; + string pageSize; + cin >> pageSize; + + map map; + map["ticket"] = TICKET; + map["pageIndex"] = pageIndex; + map["pageSize"] = pageSize; + + return run("http://gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Friends.asmx/GetInvitesReceived", map); // Again missleading name + } +}; + +GetFriendRequestsReceived g_get_friend_requests_received("getfriendrequestsreceived"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Friends/GetFriendRequestsSent.cpp b/src/commands/prod.ros.rockstargames.com/Friends/GetFriendRequestsSent.cpp new file mode 100644 index 0000000..ccd6c65 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Friends/GetFriendRequestsSent.cpp @@ -0,0 +1,29 @@ +#include "../../../command.hpp" +#include + +class GetFriendRequestsSent : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the page index:" << endl; + string pageIndex; + cin >> pageIndex; + + cout << "Specify the page size:" << endl; + string pageSize; + cin >> pageSize; + + map map; + map["ticket"] = TICKET; + map["pageIndex"] = pageIndex; + map["pageSize"] = pageSize; + + return run("http://gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Friends.asmx/GetInvitesSent", map); // Again missleading name + } +}; + +GetFriendRequestsSent g_get_friend_requests("getfriendrequestssent"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Friends/GetFriends.cpp b/src/commands/prod.ros.rockstargames.com/Friends/GetFriends.cpp new file mode 100644 index 0000000..638d189 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Friends/GetFriends.cpp @@ -0,0 +1,29 @@ +#include "../../../command.hpp" +#include + +class GetFriends : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the page index:" << endl; + string pageIndex; + cin >> pageIndex; + + cout << "Specify the page size:" << endl; + string pageSize; + cin >> pageSize; + + map map; + map["ticket"] = TICKET; + map["pageIndex"] = pageIndex; + map["pageSize"] = pageSize; + + return run("http://gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Friends.asmx/GetFriends", map); + } +}; + +GetFriends g_get_friends("getfriends"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Friends/GetFriendsAndRequestsSent.cpp b/src/commands/prod.ros.rockstargames.com/Friends/GetFriendsAndRequestsSent.cpp new file mode 100644 index 0000000..e90e20d --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Friends/GetFriendsAndRequestsSent.cpp @@ -0,0 +1,31 @@ +#include "../../../command.hpp" +#include + +// Basically this just also includes the crew name and id + +class GetFriendsAndRequestsSent : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the page index:" << endl; + string pageIndex; + cin >> pageIndex; + + cout << "Specify the page size:" << endl; + string pageSize; + cin >> pageSize; + + map map; + map["ticket"] = TICKET; + map["pageIndex"] = pageIndex; + map["pageSize"] = pageSize; + + return run("http://gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Friends.asmx/GetFriendsAndInvitesSent", map); // missleading name + } +}; + +GetFriendsAndRequestsSent g_get_friends_and_requests_sent("getfriendsandrequestssent"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Friends/RemoveFriend.cpp b/src/commands/prod.ros.rockstargames.com/Friends/RemoveFriend.cpp new file mode 100644 index 0000000..b6bbafc --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Friends/RemoveFriend.cpp @@ -0,0 +1,24 @@ +#include "../../../command.hpp" +#include + +class RemoveFriend : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the rockstar id:" << endl; + string rockstarId; + cin >> rockstarId; + + map map; + map["ticket"] = TICKET; + map["rockstarId"] = rockstarId; + + return run("http://gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Friends.asmx/RemoveFriend", map); + } +}; + +RemoveFriend g_remove_friend("removefriend"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Friends/UnblockCommunications.cpp b/src/commands/prod.ros.rockstargames.com/Friends/UnblockCommunications.cpp new file mode 100644 index 0000000..94681d2 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Friends/UnblockCommunications.cpp @@ -0,0 +1,24 @@ +#include "../../../command.hpp" +#include + +class UnblockCommunications : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the rockstarId:" << endl; + string rockstarId; + cin >> rockstarId; + + map map; + map["ticket"] = TICKET; + map["rockstarId"] = rockstarId; + + return run("http://gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Friends.asmx/Unblock", map); // Missleading name, dont have to be a friend + } +}; + +UnblockCommunications g_unblock_communications("unblockcoms"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/GeoLocation/GetLocationInfoFromIP.cpp b/src/commands/prod.ros.rockstargames.com/GeoLocation/GetLocationInfoFromIP.cpp new file mode 100644 index 0000000..41f4d0d --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/GeoLocation/GetLocationInfoFromIP.cpp @@ -0,0 +1,23 @@ +#include "../../../command.hpp" + +class GetLocationInfoFromIP : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the ip:" << endl; + string target_rid; + cin >> target_rid; + + map map; + map["ticket"] = TICKET; + map["ipAddrStr"] = target_rid; + + return run("http://gta5-prod.ros.rockstargames.com/gta5/11/gameservices/GeoLocation.asmx/GetLocationInfoFromIP", map); + } +}; + +GetLocationInfoFromIP g_get_location_info_from_ip("getlocationinfofromip"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/GeoLocation/GetRelayServers.cpp b/src/commands/prod.ros.rockstargames.com/GeoLocation/GetRelayServers.cpp new file mode 100644 index 0000000..0d7bc54 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/GeoLocation/GetRelayServers.cpp @@ -0,0 +1,25 @@ +#include "../../../command.hpp" +#include + +class GetRelayServers : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the ipAddrStr:" << endl; + string ipAddrStr; + cin >> ipAddrStr; + + map map; + map["ticket"] = TICKET; + map["ipAddrStr"] = ipAddrStr; + map["secure"] = "false"; + + return run("http://gta5-prod.ros.rockstargames.com/gta5/11/gameservices/GeoLocation.asmx/GetRelayServers", map); + } +}; + +GetRelayServers g_get_relay_servers("getrelayservers"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Inbox/SendAward.cpp b/src/commands/prod.ros.rockstargames.com/Inbox/SendAward.cpp new file mode 100644 index 0000000..4186bb2 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Inbox/SendAward.cpp @@ -0,0 +1,31 @@ +#include "../../../command.hpp" +#include +#include + +class SendAwardMsg : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the target rid:" << endl; + string target_rid; + cin >> target_rid; + + cout << "Specify the sender name:" << endl; + string senderGamerTag; + cin >> senderGamerTag; + + map map; + map["ticket"] = TICKET; + map["recipientsCsv"] = target_rid; + map["message"] = format(R"("ros.publish":{{"channel":"friends","msg":{{"gm.evt":{{"e":"StatUpdate","d":{{"stat":1488317176,"from":"{}","ival":100}}}}}}}})", senderGamerTag); + map["ttlSeconds"] = "0"; + + return run("http://prs-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Presence.asmx/MultiPostMessage", map); + } +}; + +SendAwardMsg g_send_award_msg("sendawardmessage"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Inbox/SendBounty.cpp b/src/commands/prod.ros.rockstargames.com/Inbox/SendBounty.cpp new file mode 100644 index 0000000..eb9820f --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Inbox/SendBounty.cpp @@ -0,0 +1,47 @@ +#include "../../../command.hpp" +#include + +class BountyCompletedMsg : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the target rid:" << endl; + string target_rid; + cin >> target_rid; + + cout << "Specify the tl31FromGamerTag:" << endl; + string tl31FromGamerTag; + cin >> tl31FromGamerTag; + + cout << "Specify the tl31TargetGamerTag:" << endl; + string tl31TargetGamerTag; + cin >> tl31TargetGamerTag; + + cout << "Specify the iOutcome:" << endl; + string iOutcome; + cin >> iOutcome; + + cout << "Specify the iCash:" << endl; + string iCash; + cin >> iCash; + + cout << "Specify the iRank:" << endl; + string iRank; + cin >> iRank; + + map map; + map["ticket"] = TICKET; + map["userIds"] = target_rid; + map["message"] = format(R"({{"gm.evt":{{"e":"bounty","d":{{"Ft":"{}","Tt":"{}","o":{},"c":{},"r":{},"t":1690670145566}}}}}})", tl31FromGamerTag, tl31TargetGamerTag, iOutcome, iCash, iRank); + map["tagsCsv"] = "gta5"; + map["ttlSeconds"] = "1800"; + + return run("http://inbox-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Inbox.asmx/PostMessageToRecipients", map); + } +}; + +BountyCompletedMsg g_send_bounty_completed_msg("sendbountycompletedmsg"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Inbox/SendEmail.cpp b/src/commands/prod.ros.rockstargames.com/Inbox/SendEmail.cpp new file mode 100644 index 0000000..e744cbc --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Inbox/SendEmail.cpp @@ -0,0 +1,76 @@ +#include "../../../command.hpp" +#include + +class SendEmail : command +{ + using command::command; + + class rlGamerHandle + { + public: + uint64_t m_rockstar_id; //0x0000 + uint8_t m_platform = 3; //0x0008 + uint8_t unk_0009; //0x0009 + }; //Size: 0x0010 + static_assert(sizeof(rlGamerHandle) == 0x10); + + string rlGamerHandleToBase64(const rlGamerHandle& handle) + { + const char* base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + vector bytes(sizeof(rlGamerHandle)); + memcpy(bytes.data(), &handle, sizeof(rlGamerHandle)); + + string result; + size_t paddingCount = (3 - bytes.size() % 3) % 3; + + for (size_t i = 0; i < bytes.size(); i += 3) + { + uint32_t value = (bytes[i] << 16) | ((i + 1 < bytes.size() ? bytes[i + 1] : 0) << 8) | ((i + 2 < bytes.size() ? bytes[i + 2] : 0)); + result += base64Chars[(value >> 18) & 0x3F]; + result += base64Chars[(value >> 12) & 0x3F]; + result += (i + 1 < bytes.size() || paddingCount < 2) ? base64Chars[(value >> 6) & 0x3F] : '='; + result += (i + 2 < bytes.size() || paddingCount < 1) ? base64Chars[value & 0x3F] : '='; + } + + return result; + } + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the sender rid:" << endl; + string sender_rid; + cin >> sender_rid; + + cout << "Specify the target rid:" << endl; + string target_rid; + cin >> target_rid; + + cin.ignore(1000000, '\n'); + + cout << "Specify the subject:" << endl; + string subject; + getline(cin, subject); + + cin.ignore(1000000, '\n'); + + cout << "Specify the content:" << endl; + string content; + getline(cin, content); + + rlGamerHandle handle = rlGamerHandle(stoull(sender_rid)); + + map map; + map["ticket"] = TICKET; + map["userIds"] = target_rid; + map["message"] = format(R"({{"email":{{"gh":"{}","sb":"{}","cn":"{}"}}}})", rlGamerHandleToBase64(handle), subject, content); + map["tagsCsv"] = "gta5email"; // gta5marketing + map["ttlSeconds"] = "2592000"; // 1800 + + return run("http://inbox-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Inbox.asmx/PostMessageToRecipients", map); + } +}; + +SendEmail g_send_email("sendemail"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Matchmaking/Matchmaking.cpp b/src/commands/prod.ros.rockstargames.com/Matchmaking/Matchmaking.cpp new file mode 100644 index 0000000..d6f29e4 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Matchmaking/Matchmaking.cpp @@ -0,0 +1,24 @@ +#include "../../../command.hpp" +#include + +class Matchmaking : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + map map; + map["ticket"] = TICKET; + map["availableSlots"] = "1"; + map["filterName"] = "Group"; + // filterParamsJson={"GAME_MODE":0,"MMATTR_REGION":0} + map["filterParamsJson"] = R"({"GAME_MODE":0,"MMATTR_MM_GROUP_2":30,"MMATTR_REGION":3})"; + map["maxResults"] = "999999"; + + return run("http://mm-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/matchmaking.asmx/Find", map); + } +}; + +Matchmaking g_matchmaking("matchmaking"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Presence/QueryWithMaxRecordLength.cpp b/src/commands/prod.ros.rockstargames.com/Presence/QueryWithMaxRecordLength.cpp new file mode 100644 index 0000000..d678201 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Presence/QueryWithMaxRecordLength.cpp @@ -0,0 +1,29 @@ +#include "../../../command.hpp" +#include +#include + +class QueryWithMaxRecordLength : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the target rid:" << endl; + string target_rid; + cin >> target_rid; + + map map; + map["ticket"] = TICKET; + map["queryName"] = "SessionByGamerHandle"; + map["paramNameValueCsv"] = format(R"(@ghandle,"SC+{}")", target_rid); + map["offset"] = "0"; + map["count"] = "20"; + map["maxQueryBufferSize"] = "7680"; + + return run("http://prs-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Presence.asmx/QueryWithMaxRecordLength", map); + } +}; + +QueryWithMaxRecordLength query_with_max_record_length("querywithmaxrecordlength"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Presence/SendInvite.cpp b/src/commands/prod.ros.rockstargames.com/Presence/SendInvite.cpp new file mode 100644 index 0000000..26548fe --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Presence/SendInvite.cpp @@ -0,0 +1,35 @@ +#include "../../../command.hpp" +#include + +class SendInvite : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the sender rid:" << endl; + string sender_rid; + cin >> sender_rid; + cout << "Specify the sender name:" << endl; + string sender_name; + cin >> sender_name; + cout << "Specify the target rid:" << endl; + string target_rid; + cin >> target_rid; + cout << "Specify the session info:" << endl; + string session_info; + cin >> session_info; + + map map; + map["ticket"] = TICKET; + map["recipientsCsv"] = "SC+" + target_rid; + map["message"] = format(R"("ros.mp.invite":{{"h":"SC+{}","n":"{}","s":"{}"}})", sender_rid, sender_name, session_info); + map["ttlSeconds"] = "0"; + + return run("http://prs-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/Presence.asmx/MultiPostMessage", map); + } +}; + +SendInvite g_send_invite("sendinvite"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/ProfileStatGroups/ReadGameConfig.cpp b/src/commands/prod.ros.rockstargames.com/ProfileStatGroups/ReadGameConfig.cpp new file mode 100644 index 0000000..8c3d63e --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/ProfileStatGroups/ReadGameConfig.cpp @@ -0,0 +1,23 @@ +#include "../../../command.hpp" +#include +//#include + +class ReadGameConfig : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + map map; + map["ticket"] = TICKET; + + //ofstream of("readgameconfig.txt"); + //of << run("http://gta5-prod.ros.rockstargames.com/gta5/11/gameservices/ProfileStatGroups.asmx/ReadGameConfig", map); + + return run("http://gta5-prod.ros.rockstargames.com/gta5/11/gameservices/ProfileStatGroups.asmx/ReadGameConfig", map); // Response text is too large for console + } +}; + +ReadGameConfig g_read_game_config("readgameconfig"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/ProfileStats/ReadAllStats.cpp b/src/commands/prod.ros.rockstargames.com/ProfileStats/ReadAllStats.cpp new file mode 100644 index 0000000..5d70738 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/ProfileStats/ReadAllStats.cpp @@ -0,0 +1,19 @@ +#include "../../../command.hpp" +#include + +class ReadAllStats : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + map map; + map["ticket"] = TICKET; + + return run("https://ps-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/socialclub.asmx/ReadAllStats", map); // loads infinite? + } +}; + +ReadAllStats g_read_all_stats("readallstats"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Socialclub/CreateAccountSc.cpp b/src/commands/prod.ros.rockstargames.com/Socialclub/CreateAccountSc.cpp new file mode 100644 index 0000000..e4132c3 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Socialclub/CreateAccountSc.cpp @@ -0,0 +1,55 @@ +#include "../../../command.hpp" +#include + +class CreateAccountSc : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the country code" << endl; + string countryCode; + cin >> countryCode; + + cout << "Specify the date of bearth (dd/mm/yyyy)" << endl; + string dob; + cin >> dob; + + cout << "Specify the email" << endl; + string email; + cin >> email; + + cout << "Specify the language code" << endl; + string languageCode; + cin >> languageCode; + + cout << "Specify the nickname" << endl; + string nickname; + cin >> nickname; + + cout << "Specify the password" << endl; + string password; + cin >> password; + + map map; + map["acceptNewsletter"] = "false"; + map["avatarUrl"] = "https://prod-avatars.akamaized.net/stock-avatars/n/GTAO/CASINO_2.png"; + map["countryCode"] = countryCode; + map["dob"] = dob; + map["email"] = email; + map["isApproxDob"] = "False"; + map["languageCode"] = languageCode; + map["nickname"] = nickname; + map["password"] = password; + map["phone"] = ""; + map["platform"] = "pcros"; + map["zipCode"] = "1379800"; + + + return run("http://prod.ros.rockstargames.com/gta5/11/gameservices/socialclub.asmx/CreateAccountSc", map); + } +}; + +CreateAccountSc g_create_account_sc("createaccountsc"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Socialclub/GetAccountInfo.cpp b/src/commands/prod.ros.rockstargames.com/Socialclub/GetAccountInfo.cpp new file mode 100644 index 0000000..2ad83ff --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Socialclub/GetAccountInfo.cpp @@ -0,0 +1,19 @@ +#include "../../../command.hpp" +#include + +class GetAccountInfo : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + map map; + map["ticket"] = TICKET; + + return run("http://prod.ros.rockstargames.com/gta5/11/gameservices/socialclub.asmx/GetAccountInfo", map); + } +}; + +GetAccountInfo g_get_account_info("getaccountinfo"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Socialclub/GetScAuthToken.cpp b/src/commands/prod.ros.rockstargames.com/Socialclub/GetScAuthToken.cpp new file mode 100644 index 0000000..ad9a15f --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Socialclub/GetScAuthToken.cpp @@ -0,0 +1,19 @@ +#include "../../../command.hpp" +#include + +class GetScAuthToken : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + map map; + map["ticket"] = TICKET; + + return run("http://prod.ros.rockstargames.com/gta5/11/gameservices/socialclub.asmx/GetScAuthToken", map); + } +}; + +GetScAuthToken g_get_sc_auth_token("getscauthtoken"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Socialclub/LinkAccount2.cpp b/src/commands/prod.ros.rockstargames.com/Socialclub/LinkAccount2.cpp new file mode 100644 index 0000000..cfb04f7 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Socialclub/LinkAccount2.cpp @@ -0,0 +1,34 @@ +#include "../../../command.hpp" +#include + +class LinkAccount2 : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the email:" << endl; + string email; + cin >> email; + + cout << "Specify the nickname:" << endl; + string nickname; + cin >> nickname; + + cout << "Specify the password:" << endl; + string password; + cin >> password; + + map map; + map["ticket"] = TICKET; + map["email"] = email; + map["nickname"] = nickname; + map["password"] = password; + + return run("http://prod.ros.rockstargames.com/gta5/11/gameservices/socialclub.asmx/LinkAccount2", map); + } +}; + +LinkAccount2 g_link_account_2("linkaccount2"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/Socialclub/UpdateAccount.cpp b/src/commands/prod.ros.rockstargames.com/Socialclub/UpdateAccount.cpp new file mode 100644 index 0000000..3f8d388 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/Socialclub/UpdateAccount.cpp @@ -0,0 +1,62 @@ +#include "../../../command.hpp" +#include +#include "AccountInfo.hpp" + +class UpdateAccount : command +{ + using command::command; + + inline AccountInfo GetAccountInfo() + { + string data = command::get(hash()("getaccountinfo"))->execute({}); + pugi::xml_document doc; + AccountInfo accountInfo{}; + + if (doc.load_string(data.c_str())) + { + auto path = doc.select_node("//Response/RockstarAccount"); + auto node = path.node(); + + accountInfo.m_rockstar_id = node.child("RockstarId").text().as_uint(); + accountInfo.m_age = node.child("Age").text().as_int(); + accountInfo.m_avatar_url = node.child("AvatarUrl").text().as_string(); + accountInfo.m_country_code = node.child("CountryCode").text().as_string(); + accountInfo.m_date_of_birth = node.child("Dob").text().as_string(); + accountInfo.m_email = node.child("Email").text().as_string(); + accountInfo.m_is_approx_dob = node.child("IsApproxDob").text().as_bool(); // TODO + accountInfo.m_language_code = node.child("LanguageCode").text().as_string(); + accountInfo.m_nickname = node.child("Nickname").text().as_string(); + accountInfo.m_last_portal_login_date = node.child("LastPortalLoginDate").text().as_string(); + } + + return accountInfo; + } + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + AccountInfo accountInfo = GetAccountInfo(); + + cout << "Specify the email:" << endl; + string email; + cin >> email; + + map map; + map["ticket"] = TICKET; + map["avatarUrl"] = "null"; // if this invalid, it will be skipped, you can't just put a .jpg or .png there + map["countryCode"] = accountInfo.m_country_code; + map["dob"] = accountInfo.m_date_of_birth; + map["email"] = email; + map["isApproxDob"] = accountInfo.m_is_approx_dob ? "True" : "False"; + map["languageCode"] = accountInfo.m_language_code; + map["nickname"] = accountInfo.m_nickname; + map["phone"] = ""; + map["zipCode"] = ""; + + + return run("http://prod.ros.rockstargames.com/gta5/11/gameservices/socialclub.asmx/UpdateAccount", map); + } +}; + +UpdateAccount g_update_account("updateaccount"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/UGC/CheckText.cpp b/src/commands/prod.ros.rockstargames.com/UGC/CheckText.cpp new file mode 100644 index 0000000..a4c18b8 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/UGC/CheckText.cpp @@ -0,0 +1,29 @@ +#include "../../../command.hpp" +#include + +class CheckText : command +{ + // Tested from UGC Creator -> Job Title + + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the text to check:" << endl; + string text; + cin >> text; + + map map; + map["ticket"] = TICKET; + map["languageCode"] = ""; // Can be empty + map["contentName"] = ""; // Can be empty + map["description"] = text; // Text to check + map["tagCsv"] = ""; // Can be empty + + return run("http://ugc-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/ugc.asmx/CheckText", map); + } +}; + +CheckText g_check_text("checktext"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/UGC/CopyJob.cpp b/src/commands/prod.ros.rockstargames.com/UGC/CopyJob.cpp new file mode 100644 index 0000000..1fa3866 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/UGC/CopyJob.cpp @@ -0,0 +1,189 @@ +#include "../../../command.hpp" +#include +#include "../../../ros_crypt.hpp" +#include +#include +#include +#include +#include + +class CopyJob : command +{ + using command::command; + + inline bool GetJobDetails(string_view content_id, string& title, string& description, string& type, vector& tags, string& image) + { + cpr::Response response = cpr::Get( + cpr::Url{ "https://scapi.rockstargames.com/ugc/mission/details" }, + cpr::Header{ {"X-AMC", "true" }, { "X-Requested-With", "XMLHttpRequest"} }, + cpr::Parameters{ {"title", "gtav"}, {"contentId", content_id.data()} }); + + nlohmann::json job_details = nlohmann::json::parse(string{ response.text }); + + if (job_details["content"].is_object()) + { + nlohmann::json content = job_details["content"]; + + title = content["name"]; + description = content["desc"]; + type = content["type"]; + tags = content["userTags"]; + image = content["imgSrc"]; + + return true; + } + + return false; + } + + inline bool GetJobMetaData(string_view content_id, string& result) + { + string data = command::get(hash()("querycontent"))->execute({ "GetLatestVersionByContentId", content_id.data() }); + pugi::xml_document doc; + int f0 = 0, f1 = 0; + string lang; + + if (doc.load_string(data.c_str())) + { + auto path = doc.select_node("//Response/Result/r/m"); + auto node = path.node(); + + f1 = node.attribute("f1").as_int(); + f0 = node.attribute("f0").as_int(); + lang = node.attribute("l").as_string(); + } + + cpr::Response response = cpr::Get(cpr::Url{ format("https://prod.cloud.rockstargames.com/ugc/gta5mission/{}/{}_{}_{}.json", content_id, f1 < 0 ? 0 : f1, f0 < 0 ? 0 : f0, lang.empty() ? "en" : lang) }); + + result = response.text; + + return response.status_code == 200; + } + + vector HexToBytes(const string& hex) { + vector bytes; + + for (unsigned int i = 0; i < hex.length(); i += 2) { + string byteString = hex.substr(i, 2); + unsigned char byte = (unsigned char)strtol(byteString.c_str(), NULL, 16); + bytes.push_back(byte); + } + + return bytes; + } + + vector get_data_len(size_t data_len, bool image) // should be 107684 + { + stringstream ss; + ss << hex << data_len; + string data_len_hex = ss.str(); + + + if (data_len_hex.length() % 2 != 0) { + data_len_hex = "0" + data_len_hex; + } + + vector data_len_bytes = HexToBytes(data_len_hex); // should be \x01\xa4\xa4 + + switch (data_len_bytes.size()) { + case 1: + data_len_bytes.insert(data_len_bytes.begin(), 3, 0); + break; + case 2: + data_len_bytes.insert(data_len_bytes.begin(), 2, 0); + break; + case 3: + data_len_bytes.insert(data_len_bytes.begin(), 1, 0); + break; + default: + break; + } + + data_len_bytes.insert(data_len_bytes.end(), 3, 0); + if (image) + data_len_bytes.push_back(2); + else + data_len_bytes.push_back(0); + + return data_len_bytes; + } + + string replaceAll(string const& original, string const& from, string const& to) + { + string results; + string::const_iterator end = original.end(); + string::const_iterator current = original.begin(); + string::const_iterator next = search(current, end, from.begin(), from.end()); + while (next != end) { + results.append(current, next); + results.append(to); + current = next + from.size(); + next = search(current, end, from.begin(), from.end()); + } + results.append(current, next); + return results; + } + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the content id:" << endl; + string content_id; + cin >> content_id; + + string title, description, type, image; + vector tags; + string metadata; + + if (GetJobDetails(content_id, title, description, type, tags, image)) + { + if (!GetJobMetaData(content_id, metadata)) + { + return "Couldn't download job metadata"; + } + } + + map map; + + ofstream of("2_0.jpg", ios::binary); + cpr::Response r = cpr::Download(of, cpr::Url{ image }); + ifstream input("2_0.jpg", ios_base::binary); + vector image_bytes((istreambuf_iterator(input)), (istreambuf_iterator())); + + nlohmann::json meta_json = nlohmann::json::parse(metadata); + + vector data_len = get_data_len(meta_json.dump().size(), false); + vector image_data_len = get_data_len(image_bytes.size(), true); + + nlohmann::json datajson; + datajson["meta"] = meta_json["meta"]; + datajson["mission"] = meta_json["mission"]; + datajson["version"] = 2; + + string temp = format("ticket={}&contentType=gta5mission¶msJson=", m_ros->url_encode(TICKET)); + + temp += m_ros->ex_url_encode(format(R"({{"ContentName":"{}","DataJson":"{}","Description":"{}","Publish":true,"Language":"{}","TagCsv":"{}"}})", title, replaceAll(datajson.dump(), "\"", "\\\""), description, "en", "")); + temp += "&data="; + + for (auto& i : data_len) + { + temp += i; + } + + temp += meta_json.dump(); + + for (auto& i : image_data_len) + { + temp += i; + } + for (auto& i : image_bytes) + { + temp += i; + } + + return run("http://ugc-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/ugc.asmx/CreateContent", temp); + } +}; + +CopyJob g_copy_job("copyjob"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/UGC/CopyLocalContent.cpp b/src/commands/prod.ros.rockstargames.com/UGC/CopyLocalContent.cpp new file mode 100644 index 0000000..17526f6 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/UGC/CopyLocalContent.cpp @@ -0,0 +1,21 @@ +#include "../../../command.hpp" +#include + +class CopyLocalContent : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + map map; + map["ticket"] = TICKET; + map["contentType"] = "gta5mission"; + map["contentId"] = "Qa2frulcv0u2eHmWg7KSHA"; // TODO + + return run("http://ugc-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/ugc.asmx/CopyContent", map); + } +}; + +CopyLocalContent g_copy_local_content("copylocalcontent"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/UGC/DeleteContent.cpp b/src/commands/prod.ros.rockstargames.com/UGC/DeleteContent.cpp new file mode 100644 index 0000000..99f6d63 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/UGC/DeleteContent.cpp @@ -0,0 +1,26 @@ +#include "../../../command.hpp" +#include + +class DeleteContent : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the content id:" << endl; + string contentId; + cin >> contentId; + + map map; + map["ticket"] = TICKET; + map["contentType"] = "gta5mission"; + map["contentId"] = contentId; + map["deleted"] = "true"; + + return run("http://ugc-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/ugc.asmx/SetDeleted", map); + } +}; + +DeleteContent g_delete_content("deletecontent"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/UGC/QueryContent.cpp b/src/commands/prod.ros.rockstargames.com/UGC/QueryContent.cpp new file mode 100644 index 0000000..f8e5fe0 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/UGC/QueryContent.cpp @@ -0,0 +1,110 @@ +#include "../../../command.hpp" +#include + +class QueryContent : command +{ + using command::command; + + enum QueryType { + GetLatestVersionByContentId = 1, + GetMyBookmarkedContent, + GetMyContent, + GetRecentlyCreatedContent, + GetMyRecentlyPlayedContent, + GetFriendContent, + GetTopRatedContent + }; + + QueryType getQueryType(const vector& args) { + if (args.empty()) { + cout << "Select one of the following query names:" << endl; + cout << "(1) GetLatestVersionByContentId" << endl; + cout << "(2) GetMyBookmarkedContent" << endl; + cout << "(3) GetMyContent" << endl; + cout << "(4) GetRecentlyCreatedContent" << endl; + cout << "(5) GetMyRecentlyPlayedContent" << endl; + cout << "(6) GetFriendContent" << endl; + cout << "(7) GetTopRatedContent" << endl; + + int type; + cin >> type; + + return static_cast(type); + } + else { + return static_cast(stoi(args[0])); + } + } + + string getQueryName(QueryType type) { + switch (type) { + case GetLatestVersionByContentId: + return "GetLatestVersionByContentId"; + case GetMyBookmarkedContent: + return "GetMyBookmarkedContent"; + case GetMyContent: + return "GetMyContent"; + case GetRecentlyCreatedContent: + return "GetRecentlyCreatedContent"; + case GetMyRecentlyPlayedContent: + return "GetMyRecentlyPlayedContent"; + case GetFriendContent: + return "GetFriendContent"; + case GetTopRatedContent: + return "GetTopRatedContent"; + } + return ""; + } + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + string contentId; + string queryName; + string count; + + map params; + params["ticket"] = TICKET; + params["queryName"] = queryName; + + QueryType queryType = getQueryType(args); + params["queryName"] = getQueryName(queryType); + + if (!args.empty()) + contentId = args[1]; + else if (queryType == QueryType::GetLatestVersionByContentId) + { + cout << "Specify the contentId:" << endl; + cin >> contentId; + } + + switch (queryType) { + case GetLatestVersionByContentId: + + params["contentType"] = "gta5mission"; + params["queryParams"] = "{contentids:[\"" + contentId + "\"], lang: ['en', 'fr', 'de', 'it', 'es', 'pt', 'pl', 'ru', 'es-mx'] }"; + params["offset"] = "0"; + params["count"] = "1"; + break; + case GetMyBookmarkedContent: + case GetMyContent: + case GetRecentlyCreatedContent: + case GetMyRecentlyPlayedContent: + case GetFriendContent: + case GetTopRatedContent: + cout << "Specify the count:" << endl; + cin >> count; + + params["contentType"] = "gta5mission"; + params["queryParams"] = "{lang:['de','en','fr','it','es','pt','pl','ru','es-mx']}"; + params["offset"] = "0"; + params["count"] = count; + break; + } + + return run("http://ugc-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/ugc.asmx/QueryContent", params); + } +}; + +QueryContent g_query_content("querycontent"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/UGC/QueryContentCreators.cpp b/src/commands/prod.ros.rockstargames.com/UGC/QueryContentCreators.cpp new file mode 100644 index 0000000..083c326 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/UGC/QueryContentCreators.cpp @@ -0,0 +1,30 @@ +#include "../../../command.hpp" +#include + +class QueryContentCreators : command +{ + // No clue for what this is used and why but GetByUserId seems to be the only queryName + + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the content creator RID:" << endl; // TODO support multiple + string contentCreators; + cin >> contentCreators; + + map map; + map["ticket"] = TICKET; + map["contentType"] = "gta5mission"; + map["queryName"] = "GetByUserId"; + map["queryParams"] = "{userids:[" + contentCreators + "]}"; // You can input here multiple seperated by a comma + map["offset"] = "0"; + map["count"] = "10"; + + return run("http://ugc-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/ugc.asmx/QueryContentCreators", map); + } +}; + +QueryContentCreators g_query_content_creators("querycontentcreators"); \ No newline at end of file diff --git a/src/commands/prod.ros.rockstargames.com/UGC/SetBookmarked.cpp b/src/commands/prod.ros.rockstargames.com/UGC/SetBookmarked.cpp new file mode 100644 index 0000000..7f09814 --- /dev/null +++ b/src/commands/prod.ros.rockstargames.com/UGC/SetBookmarked.cpp @@ -0,0 +1,30 @@ +#include "../../../command.hpp" +#include + +class SetBookmarked : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_ROS; } + + virtual string execute(const vector& args) + { + cout << "Specify the content id:" << endl; + string contentId; + cin >> contentId; + + cout << "Specify if it should be bookmarked (true/false):" << endl; + string bookmarked; + cin >> bookmarked; + + map map; + map["ticket"] = TICKET; + map["contentType"] = "gta5mission"; + map["contentId"] = contentId; + map["bookmarked"] = bookmarked; + + return run("http://ugc-gta5-prod.ros.rockstargames.com/gta5/11/gameservices/ugc.asmx/SetBookmarked", map); + } +}; + +SetBookmarked g_set_bookmarked("setbookmarked"); \ No newline at end of file diff --git a/src/commands/scapi.rockstargames.com/Search/SearchMission.cpp b/src/commands/scapi.rockstargames.com/Search/SearchMission.cpp new file mode 100644 index 0000000..4c2aec9 --- /dev/null +++ b/src/commands/scapi.rockstargames.com/Search/SearchMission.cpp @@ -0,0 +1,21 @@ +#include "../../../command.hpp" +#include + +class SearchMission : command +{ + using command::command; + + SERVICE_TYPE get_service_type() { return SERVICE_TYPE::PROD_SCAPI_AMC; } + + virtual string execute(const vector& args) + { + map map; + map["title"] = "gtav"; + map["platform"] = "pc"; + map["includeCommentCount"] = "false"; + + return run("https://scapi.rockstargames.com/search/mission", map); + } +}; + +SearchMission g_search_mission("searchmission"); \ No newline at end of file diff --git a/src/common.hpp b/src/common.hpp new file mode 100644 index 0000000..430ed40 --- /dev/null +++ b/src/common.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "command.hpp" \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..d368356 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,157 @@ +#include +#include +#include +#include +#include +#include "command.hpp" +#include +#include "cpr/cpr.h" +#include +#include "AccountInfo.hpp" +#include + +#ifdef _WIN32 + #include + #include +#endif + +using namespace std; + +#ifdef _WIN32 + uintptr_t GetModuleBaseAddress(DWORD procId, const char* modName) + { + uintptr_t modBaseAddr = 0; + HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId); + if (hSnap != INVALID_HANDLE_VALUE) + { + MODULEENTRY32 modEntry; + modEntry.dwSize = sizeof(modEntry); + if (Module32First(hSnap, &modEntry)) + { + do + { + if (!strcmp(modEntry.szModule, modName)) + { + modBaseAddr = (uintptr_t)modEntry.modBaseAddr; + break; + } + } while (Module32Next(hSnap, &modEntry)); + } + } + CloseHandle(hSnap); + return modBaseAddr; + } +#endif + +AccountInfo GetAccountInfo() +{ + string data = command::get(hash()("getaccountinfo"))->execute({}); + pugi::xml_document doc; + AccountInfo accountInfo{}; + + if (doc.load_string(data.c_str())) + { + auto path = doc.select_node("//Response/RockstarAccount"); + auto node = path.node(); + + accountInfo.m_rockstar_id = node.child("RockstarId").text().as_uint(); + accountInfo.m_age = node.child("Age").text().as_int(); + accountInfo.m_avatar_url = node.child("AvatarUrl").text().as_string(); + accountInfo.m_country_code = node.child("CountryCode").text().as_string(); + accountInfo.m_date_of_birth = node.child("Dob").text().as_string(); + accountInfo.m_email = node.child("Email").text().as_string(); + accountInfo.m_is_approx_dob = node.child("IsApproxDob").text().as_bool(); // TODO + accountInfo.m_language_code = node.child("LanguageCode").text().as_string(); + accountInfo.m_nickname = node.child("Nickname").text().as_string(); + accountInfo.m_last_portal_login_date = node.child("LastPortalLoginDate").text().as_string(); + } + + return accountInfo; +} + +/* +* + + + + + + + + + + + + + +*/ + +int main() +{ + string endpoint; + +#ifdef _WIN64 + SetConsoleOutputCP(CP_UTF8); + + HWND hwnd = FindWindowA(NULL, "Grand Theft Auto V"); + if (hwnd) + { + DWORD pid; + GetWindowThreadProcessId(hwnd, &pid); + HANDLE phandle = OpenProcess(PROCESS_ALL_ACCESS, 0, pid); + uintptr_t base_address = GetModuleBaseAddress(pid, "GTA5.exe"); + + char ticket[208]{}; + ReadProcessMemory(phandle, (void*)(base_address + 0x2E7B300), &ticket, 208, 0); + + char session_ticket[88]{}; + ReadProcessMemory(phandle, (void*)(base_address + 0x2E7B300 + 0x200), &session_ticket, 88, 0); + + unsigned char session_key[16]{}; + ReadProcessMemory(phandle, (void*)(base_address + 0x2E7B300 + 0x608), &session_key, 16, 0); + + TICKET = ticket; + SESSION_TICKET = string(session_ticket, 88); + SESSION_KEY = Botan::base64_encode(reinterpret_cast(session_key), sizeof(session_key)); + } +#endif + + cout << "Help:" << endl; + for (auto& it : g_commands) { + cout << it.second->get_name() << endl; + } + + if (!TICKET.empty()) + { + cout << "Ticket " << TICKET << endl; + cout << "Session Ticket " << SESSION_TICKET << endl; + cout << "Session Key " << SESSION_KEY << endl; + + cout << "Enter the endpoint:" << endl; + cin >> ws >> endpoint; + } + else + { + string response = command::get(hash()("createticket"))->execute({}); + + if (TICKET.length() > 20) + { + cout << "Ticket " << TICKET << endl; + cout << "Session Ticket " << SESSION_TICKET << endl; + cout << "Session Key " << SESSION_KEY << endl; + } + } + + while (true) + { + transform(endpoint.begin(), endpoint.end(), endpoint.begin(), ::tolower); + static command* command = command::get(hash()(endpoint)); + + if (command) { + cout << command->execute({ }) << endl; + } + cout << "Enter the endpoint:" << endl; + cin >> ws >> endpoint; + command = command::get(hash()(endpoint)); + } +} \ No newline at end of file diff --git a/src/ros_crypt.cpp b/src/ros_crypt.cpp new file mode 100644 index 0000000..1f11f14 --- /dev/null +++ b/src/ros_crypt.cpp @@ -0,0 +1,277 @@ +#include "ros_crypt.hpp" +#include +#include +#include +#include +#include + +ROSCryptoState::ROSCryptoState(const string& platformKey) +{ + Botan::secure_vector platformStr = Botan::base64_decode(platformKey); + + memcpy(m_rc4Key, &platformStr[1], sizeof(m_rc4Key)); + memcpy(m_xorKey, &platformStr[33], sizeof(m_xorKey)); + memcpy(m_hashKey, &platformStr[49], sizeof(m_hashKey)); + + m_rc4 = Botan::StreamCipher::create("RC4")->clone(); + m_rc4->set_key(m_rc4Key, sizeof(m_rc4Key)); + m_rc4->cipher1(m_xorKey, sizeof(m_xorKey)); + m_rc4->set_key(m_rc4Key, sizeof(m_rc4Key)); + m_rc4->cipher1(m_hashKey, sizeof(m_hashKey)); + + delete m_rc4; +} + +ROSCryptoState::~ROSCryptoState() +{ + delete m_rc4; +} + +const uint8_t* ROSCryptoState::GetXorKey() const +{ + return m_xorKey; +} + +const uint8_t* ROSCryptoState::GetHashKey() const +{ + return m_hashKey; +} + +string ROSCrypt::DecryptROSData(const char* data, size_t size, const string& sessionKey) +{ + auto cryptoState = m_cryptoState.get(); + + uint8_t rc4Key[16]; + + bool hasSecurity = (!sessionKey.empty()); + + uint8_t sessKey[16]; + + if (hasSecurity) + { + auto keyData = Botan::base64_decode(sessionKey.data()); + memcpy(sessKey, keyData.data(), sizeof(sessKey)); + } + + for (int i = 0; i < sizeof(rc4Key); i++) + { + rc4Key[i] = data[i] ^ cryptoState->GetXorKey()[i]; + + if (hasSecurity) + { + rc4Key[i] ^= sessKey[i]; + } + } + + Botan::StreamCipher* rc4 = Botan::StreamCipher::create("RC4")->clone(); + rc4->set_key(rc4Key, sizeof(rc4Key)); + + uint8_t blockSizeData[4]; + uint8_t blockSizeDataLE[4]; + rc4->cipher(reinterpret_cast(&data[16]), blockSizeData, 4); + + blockSizeDataLE[3] = blockSizeData[0]; + blockSizeDataLE[2] = blockSizeData[1]; + blockSizeDataLE[1] = blockSizeData[2]; + blockSizeDataLE[0] = blockSizeData[3]; + + uint32_t blockSize = (*(uint32_t*)&blockSizeDataLE) + 20; + + vector blockData(blockSize); + + stringstream result; + + size_t start = 20; + + while (start < size) + { + int end = min(size, start + blockSize); + + end -= 20; + + int thisLen = end - start; + + if (thisLen < 0) + { + return string{data, size}; + } + + rc4->cipher(reinterpret_cast(&data[start]), &blockData[0], thisLen); + + result << string(reinterpret_cast(&blockData[0]), thisLen); + + start += blockSize; + } + + delete rc4; + + return result.str(); +} + +string ROSCrypt::EncryptROSData(const string& input, const string& sessionKey) +{ + auto state = m_cryptoState.get(); + stringstream output; + + bool hasSecurity = (!sessionKey.empty()); + + uint8_t sessKey[16]; + + if (hasSecurity) + { + auto keyData = Botan::base64_decode(sessionKey); + memcpy(sessKey, keyData.data(), sizeof(sessKey)); + } + + uint8_t rc4Key[16]; + + Botan::AutoSeeded_RNG rng; + rng.randomize(rc4Key, sizeof(rc4Key)); + + for (int i = 0; i < sizeof(rc4Key); i++) + { + char thisChar = rc4Key[i] ^ state->GetXorKey()[i]; + + output << string(&thisChar, 1); + + if (hasSecurity) + { + rc4Key[i] ^= sessKey[i]; + } + } + + Botan::StreamCipher* rc4 = Botan::StreamCipher::create("RC4")->clone(); + rc4->set_key(rc4Key, sizeof(rc4Key)); + + vector inData(input.size()); + memcpy(&inData[0], input.c_str(), inData.size()); + + rc4->encipher(inData); + + output << string(reinterpret_cast(&inData[0]), inData.size()); + + string tempContent = output.str(); + + Botan::Buffered_Computation* sha1; + + if (!hasSecurity) + { + sha1 = Botan::HashFunction::create("SHA1")->clone(); + } + else + { + auto hmac = Botan::MessageAuthenticationCode::create("HMAC(SHA1)")->clone(); + hmac->set_key(rc4Key, sizeof(rc4Key)); + + sha1 = hmac; + } + + sha1->update(reinterpret_cast(tempContent.c_str()), tempContent.size()); + sha1->update(state->GetHashKey(), 16); + + auto hashData = sha1->final(); + + delete rc4; + delete sha1; + + return tempContent + string(reinterpret_cast(&hashData[0]), hashData.size()); +} + +string ROSCrypt::url_encode(const string& value) +{ + ostringstream escaped; + escaped.fill('0'); + escaped << hex; + + for (string::const_iterator i = value.begin(), n = value.end(); i != n; ++i) + { + string::value_type c = (*i); + if (((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '_' || c == '.' || c == '~') && c != '+') + { + escaped << c; + } + else if (c == ' ') + { + escaped << '+'; + } + else + { + escaped << '%' << setw(2) << ((int)(uint8_t)c) << setw(0); + } + } + + return string(escaped.str().c_str()); +} + +string ROSCrypt::ex_url_encode(const string& value) +{ + ostringstream escaped; + escaped.fill('0'); + escaped << hex; + + for (string::const_iterator i = value.begin(), n = value.end(); i != n; ++i) + { + string::value_type c = (*i); + if (((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '_' || c == '.' || c == '~') || c == '+') + { + escaped << c; + } + else if (c == ' ') + { + escaped << '+'; + } + else + { + escaped << uppercase << '%' << setw(2) << ((int)(uint8_t)c) << setw(0); + } + } + + return string(escaped.str().c_str()); +} + +string ROSCrypt::BuildPostString(const map& fields) +{ + stringstream retval; + + for (auto& field : fields) + { + retval << field.first << "=" << url_encode(field.second) << "&"; + } + + string str = string(retval.str().c_str()); + return str.substr(0, str.length() - 1); +} + +string ROSCrypt::GetROSVersionString() +{ + string baseString; + if (m_launcher) + baseString = "e=1,t=launcher,p=pcros,v=11"; + else + baseString = "e=1,t=gta5,p=pcros,v=11"; + + vector xorBuffer(baseString.length() + 4); + + if (m_launcher) + { + *(uint32_t*)&xorBuffer[0] = 0xC5C5C5C5; + + for (int i = 4; i < xorBuffer.size(); i++) + { + xorBuffer[i] = baseString[i - 4] ^ 0xC5; + } + } + else + { + *(uint32_t*)&xorBuffer[0] = 0xCDCDCDCD; + + for (int i = 4; i < xorBuffer.size(); i++) + { + xorBuffer[i] = baseString[i - 4] ^ 0xCD; + } + } + + string base64str = Botan::base64_encode(reinterpret_cast(&xorBuffer[0]), xorBuffer.size()); + + return format("ros {}", base64str); +} diff --git a/src/ros_crypt.hpp b/src/ros_crypt.hpp new file mode 100644 index 0000000..fb52e8c --- /dev/null +++ b/src/ros_crypt.hpp @@ -0,0 +1,106 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include "botan_all.h" + +using namespace std; + +class ROSCryptoState +{ +private: + Botan::StreamCipher* m_rc4; + uint8_t m_rc4Key[32]; + uint8_t m_xorKey[16]; + uint8_t m_hashKey[16]; + +public: + ROSCryptoState(const string& platformKey); + ~ROSCryptoState(); + + const uint8_t* GetXorKey() const; + const uint8_t* GetHashKey() const; +}; + +class ROSCrypt +{ +public: + constexpr ROSCrypt(const bool launcher) : m_launcher(launcher) + { + constexpr const char* launcherPlatformKey = "C6fU6TQTPgUVmy3KIB5g8ElA7DrenVpGogSZjsh+lqJaQHqv4Azoctd/v4trfX6cBjbEitUKBG/hRINF4AhQqcg="; + constexpr const char* platformKey = "C4pWJwWIKGUxcHd69eGl2AOwH2zrmzZAoQeHfQFcMelybd32QFw9s10px6k0o75XZeB5YsI9Q9TdeuRgdbvKsxc="; + + m_cryptoState = make_unique(launcher ? launcherPlatformKey : platformKey); + } + + string EncryptROSData(const string& input, const string& sessionKey = ""); + string DecryptROSData(const char* data, size_t size, const string& sessionKey); + + string url_encode(const string& value); + string ex_url_encode(const string& value); + + string BuildPostString(const map& fields); + + string GetROSVersionString(); + + template + auto HeadersHmac(const vector& challenge, const char* method, const string& path, const string& sessionKey, const string& sessionTicket); + +private: + unique_ptr m_cryptoState; + bool m_launcher; +}; + +// TODO compiler error when in .cpp? +template +inline auto ROSCrypt::HeadersHmac(const vector& challenge, const char* method, const string& path, const string& sessionKey, const string& sessionTicket) +{ + auto hmac = unique_ptr(Botan::MessageAuthenticationCode::create("HMAC(SHA1)")->clone()); + + auto cryptoState = m_cryptoState.get(); + + // set the key + uint8_t hmacKey[16]; + + // xor the RC4 key with the platform key (and optionally the session key) + auto rc4Xor = Botan::base64_decode(sessionKey); + + for (int i = 0; i < sizeof(hmacKey); i++) + { + hmacKey[i] = rc4Xor[i] ^ cryptoState->GetXorKey()[i]; + } + + hmac->set_key(hmacKey, sizeof(hmacKey)); + + // method + hmac->update(method); + hmac->update(0); + + // path + hmac->update(path); + hmac->update(0); + + // ros-SecurityFlags + hmac->update("239"); + hmac->update(0); + + // ros-SessionTicket + hmac->update(sessionTicket); + hmac->update(0); + + // ros-Challenge + hmac->update(Botan::base64_encode(challenge)); + hmac->update(0); + + // platform hash key + hmac->update(cryptoState->GetHashKey(), 16); + + // set the request header + auto hmacValue = hmac->final(); + + return hmacValue; +}