diff --git a/PolygonClientUtilities/Crypt.cpp b/PolygonClientUtilities/Crypt.cpp index c0ac3bc..4b8e85b 100644 --- a/PolygonClientUtilities/Crypt.cpp +++ b/PolygonClientUtilities/Crypt.cpp @@ -50,7 +50,7 @@ bool Crypt::verifySignatureBase64(std::string message, std::string signatureBase if (!CryptCreateHash(context, algorithm, NULL, 0, &hash)) { - return false; + throw std::runtime_error(""); } try @@ -88,6 +88,8 @@ bool Crypt::verifySignatureBase64(std::string message, std::string signatureBase } ::CryptDestroyHash(hash); + + return true; } Crypt__verifySignatureBase64_t Crypt__verifySignatureBase64 = (Crypt__verifySignatureBase64_t)ADDRESS_CRYPT__VERIFYSIGNATUREBASE64; diff --git a/PolygonClientUtilities/Http.cpp b/PolygonClientUtilities/Http.cpp index 74261cc..cb36df8 100644 --- a/PolygonClientUtilities/Http.cpp +++ b/PolygonClientUtilities/Http.cpp @@ -51,20 +51,45 @@ void __fastcall Http__httpGetPostWinInet_hook(Http* _this, void*, bool isPost, i } else if (_path == "/thumbs/asset.ashx" || _path == "/thumbs/avatar.ashx") { - // https://www.roblox.com/asset/request-thumbnail-fix?assetId=1818&assetVersionId=0&width=420&height=420&imageFormat=Png&thumbnailFormatId=296&overrideModeration=false - // https://www.roblox.com/avatar/request-thumbnail-fix?userId=86890093&width=100&height=100&imageFormat=Png&thumbnailFormatId=41&dummy=false - // https://www.roblox.com/asset/request-thumbnail-fix for asset.ashx ; needs assetId - // https://www.roblox.com/avatar/request-thumbnail-fix for avatar.ashx ; needs userId + /* + Both Roblox endpoints require thumbnailFormatId to be set. We will make the default value for it as 0. - std::string replaceWith = _path == "/thumbs/asset.ashx" ? "assetId" : "userId"; - std::string apiUrl = "https://www.roblox.com/" + std::string(_path == "/thumbs/asset.ashx" ? "asset" : "avatar") + "/request-thumbnail-fix?"; + Asset.ashx -> requires overrideModeration (default false) -> /asset/request-thumbnail-fix + Avatar.ashx -> requires dummy (default false) -> /avatar/request-thumbnail-fix - // parse query stuff here - std::string query = ""; - apiUrl += query; + 1. Parse query + 2. Construct a brand new blank query with thumbnailFormatId as 0 and dummy/overrideModeration as false (if Avatar.ashx or Asset.ashx) + 3. Merge the old query with priority over the old query so that if they declared any of the special variables, ours gets overwritten + 4. Rename id (if found) to assetId or userId (specific to the endpoint) + 5. Append to the Roblox url (specific to the endpoint) + 6. Fetch Roblox API + 7. Parse JSON + 8. Set the URL as the given url + */ - printf("\napiUrl: %s\n", apiUrl.c_str()); + std::string api = "https://www.roblox.com/" + std::string(_path == "/thumbs/asset.ashx" ? "asset" : "avatar") + "/request-thumbnail-fix"; + std::map source = Util::parseQueryString(query); + std::map fixed = { + { _path == "/thumbs/asset.ashx" ? "overrideModeration" : "dummy", "false" }, + { "thumbnailFormatId", "0" } + }; + + for (auto& pair : source) + { + fixed[pair.first] = pair.second; + } + + if (fixed.find("id") != fixed.end()) + { + auto handler = fixed.extract("id"); + handler.key() = _path == "/thumbs/asset.ashx" ? "assetId" : "userId"; + + fixed.insert(std::move(handler)); + } + + api += Util::joinQueryString(fixed); + // get the api response CURL* curl = curl_easy_init(); CURLcode result; @@ -76,7 +101,7 @@ void __fastcall Http__httpGetPostWinInet_hook(Http* _this, void*, bool isPost, i throw std::runtime_error("Failed to initialize cURL"); } - curl_easy_setopt(curl, CURLOPT_URL, apiUrl); + curl_easy_setopt(curl, CURLOPT_URL, api); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data); diff --git a/PolygonClientUtilities/Util.cpp b/PolygonClientUtilities/Util.cpp index cf7ddb0..e78a7e3 100644 --- a/PolygonClientUtilities/Util.cpp +++ b/PolygonClientUtilities/Util.cpp @@ -130,4 +130,40 @@ std::vector Util::base64Decode(const std::string_view data) } return out; +} + +// https://stackoverflow.com/a/28269049 +std::map Util::parseQueryString(std::string query) +{ + std::istringstream stream(query); + std::map parsed; + std::string pair, key, value; + + while (std::getline(stream, pair, '&')) // split each term + { + std::istringstream term(pair); + + if (std::getline(std::getline(term, key, '='), value)) + { + parsed[key] = value; + } + } + + return parsed; +} + +std::string Util::joinQueryString(std::map query) +{ + std::stringstream stream; + stream << "?"; + + for (auto const& pair : query) + { + stream << pair.first << "=" << pair.second << "&"; + } + + std::string result = stream.str(); + result.pop_back(); // remove ending ampersand + + return result; } \ No newline at end of file diff --git a/PolygonClientUtilities/Util.h b/PolygonClientUtilities/Util.h index b2aa6bf..724f8db 100644 --- a/PolygonClientUtilities/Util.h +++ b/PolygonClientUtilities/Util.h @@ -14,4 +14,6 @@ public: static bool isASCII(const std::string& s); static std::string toLower(std::string s); static std::vector base64Decode(const std::string_view data); + static std::map parseQueryString(std::string query); + static std::string joinQueryString(std::map query); }; \ No newline at end of file