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