diff --git a/dll/base64.cpp b/dll/base64.cpp new file mode 100644 index 00000000..fda186f0 --- /dev/null +++ b/dll/base64.cpp @@ -0,0 +1,72 @@ +/* Copyright (C) 2019 Mr Goldberg + This file is part of the Goldberg Emulator + + The Goldberg Emulator is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + The Goldberg Emulator is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the Goldberg Emulator; if not, see + . */ + +#include "dll/base64.h" + +// Base64 character table +static const std::string base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + +// Check if a character is a valid base64 character +static inline bool is_base64(unsigned char c) { + return (isalnum(c) || (c == '+') || (c == '/')); +} + +// Decode a base64 encoded string into a byte vector +std::vector base64_decode(const std::string& encoded_string) { + int in_len = encoded_string.size(); + int i = 0; + int j = 0; + int in_ = 0; + unsigned char char_array_4[4], char_array_3[3]; + std::vector ret; + + while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { + char_array_4[i++] = encoded_string[in_]; in_++; + if (i == 4) { + for (i = 0; i < 4; i++) + char_array_4[i] = base64_chars.find(char_array_4[i]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (i = 0; (i < 3); i++) + ret.push_back(char_array_3[i]); + i = 0; + } + } + + if (i) { + for (j = i; j < 4; j++) + char_array_4[j] = 0; + + for (j = 0; j < 4; j++) + char_array_4[j] = base64_chars.find(char_array_4[j]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (j = 0; (j < i - 1); j++) + ret.push_back(char_array_3[j]); + } + + return ret; +} \ No newline at end of file diff --git a/dll/dll/base64.h b/dll/dll/base64.h new file mode 100644 index 00000000..1ba693c3 --- /dev/null +++ b/dll/dll/base64.h @@ -0,0 +1,23 @@ +/* Copyright (C) 2019 Mr Goldberg + This file is part of the Goldberg Emulator + + The Goldberg Emulator is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + The Goldberg Emulator is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the Goldberg Emulator; if not, see + . */ + +#pragma once +#include +#include + +// Decodes a base64 encoded string into a byte vector +std::vector base64_decode(const std::string& encoded_string); \ No newline at end of file diff --git a/dll/dll/settings.h b/dll/dll/settings.h index 0d3804af..1ca48ace 100644 --- a/dll/dll/settings.h +++ b/dll/dll/settings.h @@ -232,6 +232,9 @@ public: constexpr const static int INVALID_IMAGE_HANDLE = 0; constexpr const static int UNLOADED_IMAGE_HANDLE = -1; + // Base64 encoded token for EncryptedAppTicket + std::string encrypted_app_ticket_token{}; + //Depots std::vector depots{}; @@ -428,6 +431,8 @@ public: bool hasOverlayAutoAcceptInviteFromFriend(uint64_t friend_id) const; size_t overlayAutoAcceptInvitesCount() const; + // Method to load token from configs.user.ini + bool load_token_from_config(); }; -#endif // SETTINGS_INCLUDE_H +#endif // SETTINGS_INCLUDE_H \ No newline at end of file diff --git a/dll/settings.cpp b/dll/settings.cpp index eb19297f..b0387c60 100644 --- a/dll/settings.cpp +++ b/dll/settings.cpp @@ -17,6 +17,7 @@ #include "dll/settings.h" #include "dll/steam_app_ids.h" +#include std::string Settings::sanitize(const std::string &name) @@ -84,6 +85,7 @@ Settings::Settings(CSteamID steam_id, CGameID game_id, const std::string &name, this->language = lang; this->offline = offline; + this->encrypted_app_ticket_token = ""; // Initialize token field } // user id @@ -417,3 +419,32 @@ size_t Settings::overlayAutoAcceptInvitesCount() const { return auto_accept_overlay_invites_friends.size(); } + +// Load token from configs.user.ini +bool Settings::load_token_from_config() +{ + encrypted_app_ticket_token.clear(); + + std::string config_path = Local_Storage::get_game_settings_path() + "configs.user.ini"; + PRINT_DEBUG("Attempting to read token from %s\n", config_path.c_str()); + + std::ifstream config_file(utf8_decode(config_path)); + if (!config_file.is_open()) { + PRINT_DEBUG("Failed to open configs.user.ini for token reading\n"); + return false; + } + + std::string line; + while (std::getline(config_file, line)) { + // Look for "token=" at the beginning of line + if (line.find("token=") == 0) { + // Token found - extract everything after "token=" + encrypted_app_ticket_token = line.substr(6); // "token=" is 6 characters long + PRINT_DEBUG("Found token in configs.user.ini, length: %zu\n", encrypted_app_ticket_token.length()); + return true; + } + } + + PRINT_DEBUG("No token found in configs.user.ini\n"); + return false; +} \ No newline at end of file diff --git a/dll/steam_user.cpp b/dll/steam_user.cpp index 0d942e4c..9d850494 100644 --- a/dll/steam_user.cpp +++ b/dll/steam_user.cpp @@ -18,6 +18,7 @@ #include "dll/steam_user.h" #include "dll/auth.h" #include "dll/appticket.h" +#include "dll/base64.h" Steam_User::Steam_User(Settings *settings, Local_Storage *local_storage, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks) { @@ -761,6 +762,35 @@ SteamAPICall_t Steam_User::RequestEncryptedAppTicket( void *pDataToInclude, int bool Steam_User::GetEncryptedAppTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket ) { PRINT_DEBUG("%i %p %p", cbMaxTicket, pTicket, pcbTicket); + + // Try to load a token from configs.user.ini first + if (settings->load_token_from_config() && !settings->encrypted_app_ticket_token.empty()) { + PRINT_DEBUG("Using token from configs.user.ini\n"); + + // Decode token from Base64 + std::vector ticket_data = base64_decode(settings->encrypted_app_ticket_token); + + if (ticket_data.empty()) { + PRINT_DEBUG("Failed to decode token from base64\n"); + } else { + uint32 ticket_size = static_cast(ticket_data.size()); + if (pcbTicket) *pcbTicket = ticket_size; + + if (cbMaxTicket <= 0) { + if (!pcbTicket) return false; + return true; + } + + if (!pTicket) return false; + if (ticket_size > static_cast(cbMaxTicket)) return false; + + memcpy(pTicket, ticket_data.data(), ticket_size); + PRINT_DEBUG("Successfully used token from configs.user.ini (%u bytes)\n", ticket_size); + return true; + } + } + + // Fallback to the standard ticket generation if no token was found or decoded uint32 ticket_size = static_cast(encrypted_app_ticket.size()); if (pcbTicket) *pcbTicket = ticket_size; @@ -860,4 +890,4 @@ bool Steam_User::BSetDurationControlOnlineState( EDurationControlOnlineState eNe { PRINT_DEBUG_ENTRY(); return false; -} +} \ No newline at end of file