From d448ab12ed0b8bda10a17ced92123b91a2ef06ad Mon Sep 17 00:00:00 2001 From: shadow <81448108+shdwmtr@users.noreply.github.com> Date: Sun, 10 Nov 2024 01:50:39 -0400 Subject: [PATCH 01/18] fix: Hopefully help prevent false positives --- CMakeLists.txt | 6 +++++- scripts/version.rc | 4 ++-- src/main.cc | 4 +--- win32/CMakeLists.txt | 25 +++++++++++++++++++++++++ win32/main.cc | 40 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 73 insertions(+), 6 deletions(-) create mode 100644 win32/CMakeLists.txt create mode 100644 win32/main.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ed41732..20b86e02 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,6 +64,10 @@ add_compile_definitions( _CRT_SECURE_NO_WARNINGS ) +if (WIN32) + add_subdirectory(win32) +endif() + add_subdirectory(cli) find_package(CURL REQUIRED) # used for web requests. @@ -120,7 +124,7 @@ if (NOT APPLE) endif() if (WIN32) - set_target_properties(Millennium PROPERTIES OUTPUT_NAME "user32") + set_target_properties(Millennium PROPERTIES OUTPUT_NAME "millennium") set_target_properties(Millennium PROPERTIES PREFIX "") set_target_properties(Millennium PROPERTIES NO_EXPORT TRUE) endif() diff --git a/scripts/version.rc b/scripts/version.rc index 512e0e51..b0dd4a3e 100644 --- a/scripts/version.rc +++ b/scripts/version.rc @@ -5,8 +5,8 @@ #define VER_COMPANYNAME_STR "Steam Homebrew\0" #define VER_FILEDESCRIPTION_STR "A plugin loader for the modern Steam Client\0" -#define VER_INTERNALNAME_STR "user32.dll\0" -#define VER_ORIGINALFILENAME_STR "user32.dll\0" +#define VER_INTERNALNAME_STR "millennium.dll\0" +#define VER_ORIGINALFILENAME_STR "millennium.dll\0" #define VER_LEGALCOPYRIGHT_STR "Steam Homebrew 2024\0" #define VER_LEGALTRADEMARKS1_STR "All Rights Reserved\0" #define VER_LEGALTRADEMARKS2_STR "\0" diff --git a/src/main.cc b/src/main.cc index e03fa583..d9851276 100644 --- a/src/main.cc +++ b/src/main.cc @@ -80,8 +80,6 @@ const static void EntryMain() backendThread.join(); frontendThreads.join(); - - // std::this_thread::sleep_for(std::chrono::milliseconds(10000)); } #ifdef _WIN32 @@ -98,7 +96,7 @@ int __stdcall DllMain(void*, unsigned long fdwReason, void*) } case DLL_PROCESS_DETACH: { - Logger.PrintMessage(" MAIN ", "Shutting down Millennium...", COL_MAGENTA); + Logger.Log("Shutting down Millennium..."); std::exit(EXIT_SUCCESS); g_threadTerminateFlag->flag.store(true); Sockets::Shutdown(); diff --git a/win32/CMakeLists.txt b/win32/CMakeLists.txt new file mode 100644 index 00000000..78eaf421 --- /dev/null +++ b/win32/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.10) + +# Set the project name +project(ShimDll) + +# Specify the C++ standard +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +if (WIN32 AND NOT GITHUB_ACTION_BUILD) + # debug output paths + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "C:/Program Files (x86)/Steam") + set(LIBRARY_OUTPUT_DIRECTORY "C:/Program Files (x86)/Steam") +elseif(UNIX AND NOT GITHUB_ACTION_BUILD) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "$ENV{HOME}/.millennium/") + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "$ENV{HOME}/.millennium/") +endif() + +# Add the executable +add_library(ShimDll SHARED main.cc) + +set_target_properties(ShimDll PROPERTIES OUTPUT_NAME "user32") +set_target_properties(ShimDll PROPERTIES PREFIX "") +set_target_properties(ShimDll PROPERTIES NO_EXPORT TRUE) + diff --git a/win32/main.cc b/win32/main.cc new file mode 100644 index 00000000..b5be2584 --- /dev/null +++ b/win32/main.cc @@ -0,0 +1,40 @@ +#include + +const void ShutdownShim(HINSTANCE hinstDLL) +{ + // Unload current module + FreeLibraryAndExitThread(hinstDLL, 0); +} + +const void LoadMillennium(HINSTANCE hinstDLL) +{ + HMODULE hMillennium = LoadLibrary(TEXT("millennium.dll")); + if (hMillennium == nullptr) { + MessageBoxA(nullptr, "Failed to load millennium.dll", "Error", MB_ICONERROR); + return; // Exit with error code + } + + CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)ShutdownShim, hinstDLL, 0, nullptr); +} + +BOOL WINAPI DllMain( + HINSTANCE hinstDLL, // handle to DLL module + DWORD fdwReason, // reason for calling function + LPVOID lpvReserved ) // reserved +{ + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + { + LoadMillennium(hinstDLL); + break; + } + case DLL_PROCESS_DETACH: + { + // ShutdownShim(); + break; + } + } + + return true; +} \ No newline at end of file From 0e45046e9eea6cc6ca7b181bd5371b910c36b8cc Mon Sep 17 00:00:00 2001 From: shadow <81448108+shdwmtr@users.noreply.github.com> Date: Sun, 10 Nov 2024 02:03:04 -0400 Subject: [PATCH 02/18] chore: Cleanup code --- win32/main.cc | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/win32/main.cc b/win32/main.cc index b5be2584..9497cdbb 100644 --- a/win32/main.cc +++ b/win32/main.cc @@ -2,38 +2,26 @@ const void ShutdownShim(HINSTANCE hinstDLL) { - // Unload current module FreeLibraryAndExitThread(hinstDLL, 0); } const void LoadMillennium(HINSTANCE hinstDLL) { HMODULE hMillennium = LoadLibrary(TEXT("millennium.dll")); - if (hMillennium == nullptr) { + if (hMillennium == nullptr) + { MessageBoxA(nullptr, "Failed to load millennium.dll", "Error", MB_ICONERROR); - return; // Exit with error code + return; } CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)ShutdownShim, hinstDLL, 0, nullptr); } -BOOL WINAPI DllMain( - HINSTANCE hinstDLL, // handle to DLL module - DWORD fdwReason, // reason for calling function - LPVOID lpvReserved ) // reserved +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { - switch (fdwReason) + if (fdwReason == DLL_PROCESS_ATTACH) { - case DLL_PROCESS_ATTACH: - { - LoadMillennium(hinstDLL); - break; - } - case DLL_PROCESS_DETACH: - { - // ShutdownShim(); - break; - } + LoadMillennium(hinstDLL); } return true; From 559ae6617d79f2772bace63d3df1b4f049b764c2 Mon Sep 17 00:00:00 2001 From: shadow <81448108+shdwmtr@users.noreply.github.com> Date: Sun, 10 Nov 2024 14:42:30 -0400 Subject: [PATCH 03/18] fix: Fix theme installer not working --- assets/core/util/theme_installer.py | 2 +- src/pipes/terminal_pipe.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/core/util/theme_installer.py b/assets/core/util/theme_installer.py index d604beae..2365b44e 100644 --- a/assets/core/util/theme_installer.py +++ b/assets/core/util/theme_installer.py @@ -122,7 +122,7 @@ def __init__(self, host="localhost", port=9123): self.thread = None self.stop_event = asyncio.Event() - async def handler(self, websocket, path): + async def handler(self, websocket): logger.log("Client connected") try: diff --git a/src/pipes/terminal_pipe.h b/src/pipes/terminal_pipe.h index 386153bd..1f2fa4ad 100644 --- a/src/pipes/terminal_pipe.h +++ b/src/pipes/terminal_pipe.h @@ -9,7 +9,7 @@ #ifdef _WIN32 extern "C" { - __declspec(dllexport) const int CreateTerminalPipe() + const int CreateTerminalPipe() { HANDLE hPipe = CreateFileA(R"(\\.\pipe\MillenniumStdoutPipe)", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); From 447e80f95e826f1ca278844506c093e86244cff4 Mon Sep 17 00:00:00 2001 From: shadow <81448108+shdwmtr@users.noreply.github.com> Date: Tue, 12 Nov 2024 14:30:52 -0400 Subject: [PATCH 04/18] chore: Update CI to contain new assets --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 87016434..55628504 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -104,6 +104,7 @@ jobs: cmake --build build --config Release cp D:/a/Millennium/Millennium/Python-3.11.8/PCbuild/win32/python311.dll D:/a/env/python311.dll cp /d/a/Millennium/Millennium/build/user32.dll D:/a/env/user32.dll + cp /d/a/Millennium/Millennium/build/millennium.dll D:/a/env/millennium.dll mkdir D:/a/env/ext/bin # Disable Millennium CLI for now, as it keeps get false positive detections for no apparent reason # cp /d/a/Millennium/Millennium/build/cli/millennium.exe D:/a/env/ext/bin/millennium.exe From 7c29d23fecaf2f3f6b760bf95f5d368db87e2a3f Mon Sep 17 00:00:00 2001 From: shadow <81448108+shdwmtr@users.noreply.github.com> Date: Tue, 12 Nov 2024 14:42:53 -0400 Subject: [PATCH 05/18] fix: Fix the CI --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55628504..5d4dfc53 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -103,7 +103,7 @@ jobs: mkdir D:/a/Millennium/Millennium/build/artifacts cmake --build build --config Release cp D:/a/Millennium/Millennium/Python-3.11.8/PCbuild/win32/python311.dll D:/a/env/python311.dll - cp /d/a/Millennium/Millennium/build/user32.dll D:/a/env/user32.dll + cp /d/a/Millennium/Millennium/build/bin/user32.dll D:/a/env/user32.dll cp /d/a/Millennium/Millennium/build/millennium.dll D:/a/env/millennium.dll mkdir D:/a/env/ext/bin # Disable Millennium CLI for now, as it keeps get false positive detections for no apparent reason From 9d46d668319b2fcfe8c2ffd301cb31181cdcb1ab Mon Sep 17 00:00:00 2001 From: shadow <81448108+shdwmtr@users.noreply.github.com> Date: Tue, 12 Nov 2024 14:56:53 -0400 Subject: [PATCH 06/18] chore: Update ci.yml --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5d4dfc53..5916e6ad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -103,7 +103,7 @@ jobs: mkdir D:/a/Millennium/Millennium/build/artifacts cmake --build build --config Release cp D:/a/Millennium/Millennium/Python-3.11.8/PCbuild/win32/python311.dll D:/a/env/python311.dll - cp /d/a/Millennium/Millennium/build/bin/user32.dll D:/a/env/user32.dll + cp /d/a/Millennium/Millennium/build/win32/user32.dll D:/a/env/user32.dll cp /d/a/Millennium/Millennium/build/millennium.dll D:/a/env/millennium.dll mkdir D:/a/env/ext/bin # Disable Millennium CLI for now, as it keeps get false positive detections for no apparent reason From 4a0d08b98502011ef4f5d5f51a5bc3d74a6ef9d1 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Tue, 12 Nov 2024 19:07:04 +0000 Subject: [PATCH 07/18] chore(release): bump version to v2.14.2 [skip ci] --- version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version b/version index 4d033f7f..fc413c2c 100644 --- a/version +++ b/version @@ -1,2 +1,2 @@ # current version of millennium -v2.14.1 +v2.14.2 From 35a4b13575bbc5a9e29ec2f22bcaf4f18aba3110 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 12 Nov 2024 19:07:17 +0000 Subject: [PATCH 08/18] chore(release): 2.14.2 [skip ci] ## [2.14.2](https://github.com/shdwmtr/millennium/compare/v2.14.1...v2.14.2) (2024-11-12) ### Bug Fixes * Fix the CI ([7c29d23](https://github.com/shdwmtr/millennium/commit/7c29d23fecaf2f3f6b760bf95f5d368db87e2a3f)) * Fix theme installer not working ([559ae66](https://github.com/shdwmtr/millennium/commit/559ae6617d79f2772bace63d3df1b4f049b764c2)) * Hopefully help prevent false positives ([d448ab1](https://github.com/shdwmtr/millennium/commit/d448ab12ed0b8bda10a17ced92123b91a2ef06ad)) --- docs/CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 1a0891b8..5c811ef8 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,3 +1,12 @@ +## [2.14.2](https://github.com/shdwmtr/millennium/compare/v2.14.1...v2.14.2) (2024-11-12) + + +### Bug Fixes + +* Fix the CI ([7c29d23](https://github.com/shdwmtr/millennium/commit/7c29d23fecaf2f3f6b760bf95f5d368db87e2a3f)) +* Fix theme installer not working ([559ae66](https://github.com/shdwmtr/millennium/commit/559ae6617d79f2772bace63d3df1b4f049b764c2)) +* Hopefully help prevent false positives ([d448ab1](https://github.com/shdwmtr/millennium/commit/d448ab12ed0b8bda10a17ced92123b91a2ef06ad)) + ## [2.14.1](https://github.com/shdwmtr/millennium/compare/v2.14.0...v2.14.1) (2024-11-09) From 45734f2be936a2ed58072f96d52c5d68945d6e71 Mon Sep 17 00:00:00 2001 From: shadow <81448108+shdwmtr@users.noreply.github.com> Date: Tue, 12 Nov 2024 16:15:34 -0400 Subject: [PATCH 09/18] feat: Binary stripping on release modules to drastically reduce binary size --- CMakeLists.txt | 5 +++++ src/core/py_controller/logger.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 20b86e02..85c4f090 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,11 @@ if (NOT APPLE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32") endif() +if (WIN32) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -s") + set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS OFF) +endif() + project(Millennium LANGUAGES CXX) if (WIN32 AND NOT GITHUB_ACTION_BUILD) diff --git a/src/core/py_controller/logger.h b/src/core/py_controller/logger.h index fa5889a0..f4969368 100644 --- a/src/core/py_controller/logger.h +++ b/src/core/py_controller/logger.h @@ -105,4 +105,4 @@ typedef struct LoggerObject; extern PyTypeObject LoggerType; -PyMODINIT_FUNC PyInit_Logger(void); +PyObject* PyInit_Logger(void); From 737dadc540948300da9dbe4b5dd1b19a588cb724 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Tue, 12 Nov 2024 20:31:26 +0000 Subject: [PATCH 10/18] chore(release): bump version to v2.15.0 [skip ci] --- version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version b/version index fc413c2c..bae4f52a 100644 --- a/version +++ b/version @@ -1,2 +1,2 @@ # current version of millennium -v2.14.2 +v2.15.0 From a6e8a30e7a99e6c5bba2200e9530c118164706bd Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 12 Nov 2024 20:31:39 +0000 Subject: [PATCH 11/18] chore(release): 2.15.0 [skip ci] # [2.15.0](https://github.com/shdwmtr/millennium/compare/v2.14.2...v2.15.0) (2024-11-12) ### Features * Binary stripping on release modules to drastically reduce binary size ([45734f2](https://github.com/shdwmtr/millennium/commit/45734f2be936a2ed58072f96d52c5d68945d6e71)) --- docs/CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 5c811ef8..80c413b8 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,3 +1,10 @@ +# [2.15.0](https://github.com/shdwmtr/millennium/compare/v2.14.2...v2.15.0) (2024-11-12) + + +### Features + +* Binary stripping on release modules to drastically reduce binary size ([45734f2](https://github.com/shdwmtr/millennium/commit/45734f2be936a2ed58072f96d52c5d68945d6e71)) + ## [2.14.2](https://github.com/shdwmtr/millennium/compare/v2.14.1...v2.14.2) (2024-11-12) From 6575f0eb6a7684fb5fc7bb12104d959f4d5a7d26 Mon Sep 17 00:00:00 2001 From: shadow <81448108+shdwmtr@users.noreply.github.com> Date: Tue, 12 Nov 2024 16:42:01 -0400 Subject: [PATCH 12/18] chore: Update uninstaller to remove millennium.dll --- scripts/uninstall.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/uninstall.ps1 b/scripts/uninstall.ps1 index 91e2f8c9..8b20ce34 100644 --- a/scripts/uninstall.ps1 +++ b/scripts/uninstall.ps1 @@ -225,7 +225,7 @@ function PrettyPrintSizeOnDisk { } $assets = @( - "Millennium", @("user32.dll", "python311.dll") + "Millennium", @("user32.dll", "python311.dll", "millennium.dll") "Core Modules", "ext/data/assets" "Python Cache", "ext/data/cache" "User Plugins", "plugins" From eda0f5460061075e0e389c9cacbd270a97c18739 Mon Sep 17 00:00:00 2001 From: shadow <81448108+shdwmtr@users.noreply.github.com> Date: Wed, 13 Nov 2024 19:00:30 -0400 Subject: [PATCH 13/18] feat: Added CPS bypass & Added Millennium API to webkit modules --- src/core/hooks/web_load.cc | 191 ++++++++++++++++++++++++++++++++++++- src/core/hooks/web_load.h | 3 + src/core/loader.cc | 5 +- src/sys/http.h | 61 ++++++++++++ 4 files changed, 255 insertions(+), 5 deletions(-) diff --git a/src/core/hooks/web_load.cc b/src/core/hooks/web_load.cc index aa8ccdb1..de95e541 100644 --- a/src/core/hooks/web_load.cc +++ b/src/core/hooks/web_load.cc @@ -3,6 +3,8 @@ #include #include #include +#include +#include // #include WebkitHandler WebkitHandler::get() @@ -19,6 +21,8 @@ void WebkitHandler::SetupGlobalHooks() { "patterns", { { { "urlPattern", "https://*.*.com/public/shared/css/buttons.css*" }, { "resourceType", "Stylesheet" }, { "requestStage", "Response" } }, { { "urlPattern", "https://*.*.com/public/shared/javascript/shared_global.js*" }, { "resourceType", "Script" }, { "requestStage", "Response" } }, + { { "urlPattern", "*" }, { "resourceType", "Document" }, { "requestStage", "Request" } }, + { { "urlPattern", fmt::format("{}*", this->m_javaScriptVirtualUrl) }, { "requestStage", "Request" } } } @@ -34,6 +38,127 @@ bool WebkitHandler::IsGetBodyCall(nlohmann::basic_json<> message) std::string WebkitHandler::HandleJsHook(std::string body) { + const static std::string API = R"( + + if (typeof window.MILLENNIUM_BACKEND_IPC === 'undefined') + { + const IPCMain = { + postMessage: function(messageId, contents) { + return new Promise(function(resolve) { + + const message = { id: messageId, iteration: window.CURRENT_IPC_CALL_COUNT++, data: contents }; + + const messageHandler = function(data) { + const json = JSON.parse(data.data); + + // Wait to receive the correct message id from the backend + if (json.id !== message.iteration) return; + + resolve(json); + window.MILLENNIUM_IPC_SOCKET.removeEventListener('message', messageHandler); + }; + + window.MILLENNIUM_IPC_SOCKET.addEventListener('message', messageHandler); + window.MILLENNIUM_IPC_SOCKET.send(JSON.stringify(message)); + }); + } + }; + + window.MILLENNIUM_BACKEND_IPC = IPCMain; + + window.Millennium = { + callServerMethod: function(pluginName, methodName, kwargs) { + return new Promise(function(resolve, reject) { + const query = { + pluginName: pluginName, + methodName: methodName, + ...(kwargs && { argumentList: kwargs }) + }; + + // Call handled from "src\core\ipc\pipe.cpp @ L:67" + window.MILLENNIUM_BACKEND_IPC.postMessage(0, query).then(function(response) { + if (response && response.failedRequest) { + reject(`IPC call from [name: ${pluginName}, method: ${methodName}] failed on exception -> ${response.failMessage}`); + } + + const responseStream = response.returnValue; + // FFI backend encodes string responses in base64 to avoid encoding issues + resolve(typeof responseStream === 'string' ? atob(responseStream) : responseStream); + }); + }); + }, + findElement: function(privateDocument, querySelector, timeout) { + return new Promise(function(resolve, reject) { + const matchedElements = privateDocument.querySelectorAll(querySelector); + + // Node is already in DOM and doesn't require watchdog + if (matchedElements.length) { + resolve(matchedElements); + return; + } + + let timer = null; + + const observer = new MutationObserver(function() { + const matchedElements = privateDocument.querySelectorAll(querySelector); + if (matchedElements.length) { + if (timer) clearTimeout(timer); + + observer.disconnect(); + resolve(matchedElements); + } + }); + + // Observe the document body for item changes, assuming we are waiting for target element + observer.observe(privateDocument.body, { + childList: true, + subtree: true + }); + + if (timeout) { + timer = setTimeout(function() { + observer.disconnect(); + reject(); + }, timeout); + } + }); + } + }; + + + function createWebSocket(url) { + return new Promise((resolve, reject) => { + const startTime = Date.now(); // Record the start time + + try { + let socket = new WebSocket(url); + socket.addEventListener('open', () => { + const endTime = Date.now(); // Record the end time + const connectionTime = endTime - startTime; // Calculate the connection time + console.log('%c Millennium ', 'background: black; color: white', + `Successfully connected to IPC server. Connection time: ${connectionTime}ms.`); + resolve(socket); + }); + socket.addEventListener('close', () => { + setTimeout(() => { + createWebSocket(url).then(resolve).catch(reject); + }, 100); + }); + } + catch (error) { + console.warn('Failed to connect to IPC server:', error); + } + }); + } + + createWebSocket('ws://localhost:)" + std::to_string(m_ipcPort) + R"(').then((socket) => { + window.MILLENNIUM_IPC_SOCKET = socket; + window.CURRENT_IPC_CALL_COUNT = 0; + }) + .catch((error) => console.error('Initial WebSocket connection failed:', error)); + } + )"; + std::string scriptTagInject; for (auto& hookItem : *m_hookListPtr) @@ -46,8 +171,8 @@ std::string WebkitHandler::HandleJsHook(std::string body) std::filesystem::path relativePath = std::filesystem::relative(hookItem.path, SystemIO::GetSteamPath()); scriptTagInject.append(fmt::format( - "document.head.appendChild(Object.assign(document.createElement('script'), {{ src: '{}{}', type: 'module', id: 'millennium-injected' }}));\n", - this->m_javaScriptVirtualUrl, relativePath.generic_string() + "{}\ndocument.head.appendChild(Object.assign(document.createElement('script'), {{ src: '{}{}', type: 'module', id: 'millennium-injected' }}));\n", + API, this->m_javaScriptVirtualUrl, relativePath.generic_string() )); } return scriptTagInject + body; @@ -139,7 +264,7 @@ void WebkitHandler::HandleHooks(nlohmann::basic_json<> message) { auto [id, request_id, type] = (*requestIterator); - if (message["id"] != id || !message["result"]["base64Encoded"]) + if (type == "Document" || message["id"] != id || !message["result"]["base64Encoded"]) { requestIterator++; continue; @@ -181,11 +306,69 @@ void WebkitHandler::HandleHooks(nlohmann::basic_json<> message) void WebkitHandler::DispatchSocketMessage(nlohmann::basic_json<> message) { + // if (message.value("method", "").find("Debugger.") == std::string::npos) + // { + // Logger.Log(message.dump(4)); + // } + try { if (message["method"] == "Fetch.requestPaused") { - switch (this->IsGetBodyCall(message)) + if (message["params"]["resourceType"] == "Document") + { + + std::string requestId = message["params"]["requestId"].get(); + std::string requestUrl = message["params"]["request"]["url"].get(); + nlohmann::json requestHeaders = message["params"]["request"]["headers"]; + + nlohmann::json responseHeaders = nlohmann::json::array({ + { + { "name", "Content-Security-Policy" }, + { "value", "default-src * 'unsafe-inline' 'unsafe-eval' data: blob:; script-src * 'unsafe-inline' 'unsafe-eval' data: blob:;" } + }, + { + { "name", "Access-Control-Allow-Origin" }, + { "value", "*" } + } + }); + + for (auto& [key, value] : requestHeaders.items()) + { + responseHeaders.push_back({ { "name", key }, { "value", value } }); + } + + nlohmann::json responseHeadersJson; + + const auto [originalContent, statusCode] = Http::GetWithHeaders(requestUrl.c_str(), requestHeaders, requestHeaders.value("User-Agent", ""), responseHeadersJson); + + for (const auto& item : responseHeadersJson) + { + bool keyExists = std::any_of(responseHeaders.begin(), responseHeaders.end(), + [&](const nlohmann::json& existingHeader) { + return existingHeader.at("name") == item.at("name"); + }); + + if (!keyExists) { + responseHeaders.push_back(item); + } + } + + nlohmann::json message = { + { "id", 63453 }, + { "method", "Fetch.fulfillRequest" }, + { "params", { + { "requestId", requestId }, + { "responseCode", statusCode }, + { "responseHeaders", responseHeaders }, + { "body", Base64Encode(originalContent) } + }} + }; + + Sockets::PostGlobal(message); + + } + else switch (this->IsGetBodyCall(message)) { case true: { diff --git a/src/core/hooks/web_load.h b/src/core/hooks/web_load.h index 8e5a045a..f379b22e 100644 --- a/src/core/hooks/web_load.h +++ b/src/core/hooks/web_load.h @@ -27,7 +27,10 @@ class WebkitHandler void DispatchSocketMessage(nlohmann::basic_json<> message); void SetupGlobalHooks(); + void SetIPCPort(uint16_t ipcPort) { m_ipcPort = ipcPort; } + private: + uint16_t m_ipcPort; long long hookMessageId = -69; // must share the same base url, or be whitelisted. diff --git a/src/core/loader.cc b/src/core/loader.cc index b0911873..27fd742b 100644 --- a/src/core/loader.cc +++ b/src/core/loader.cc @@ -148,7 +148,10 @@ class CEFBrowser webKitHandler.SetupGlobalHooks(); } - CEFBrowser(uint16_t fptPort, uint16_t ipcPort) : m_ftpPort(fptPort), m_ipcPort(ipcPort), webKitHandler(WebkitHandler::get()) { } + CEFBrowser(uint16_t fptPort, uint16_t ipcPort) : m_ftpPort(fptPort), m_ipcPort(ipcPort), webKitHandler(WebkitHandler::get()) + { + webKitHandler.SetIPCPort(ipcPort); + } }; const void PluginLoader::Initialize() diff --git a/src/sys/http.h b/src/sys/http.h index cd5a56e5..2f4db052 100644 --- a/src/sys/http.h +++ b/src/sys/http.h @@ -44,6 +44,67 @@ namespace Http return response; } + static nlohmann::json ParseHeaders(const std::string& headers) + { + nlohmann::json jsonHeaders = nlohmann::json::array(); + std::istringstream stream(headers); + std::string line; + + while (std::getline(stream, line)) + { + if (line.find(':') != std::string::npos) + { + std::string name = line.substr(0, line.find(':')); + std::string value = line.substr(line.find(':') + 1); + + value.erase(0, value.find_first_not_of(" \t")); + value.erase(value.find_last_not_of(" \t\r\n") + 1); + + jsonHeaders.push_back({{"name", name}, {"value", value}}); + } + } + return jsonHeaders; + } + + static std::pair GetWithHeaders(const char* url, nlohmann::json headers, std::string userAgent, nlohmann::json& responseHeadersJson) + { + struct curl_slist* headersList = NULL; + + for (auto& [key, value] : headers.items()) + { + headersList = curl_slist_append(headersList, fmt::format("{}: {}", key, value.get()).c_str()); + } + + CURL* curl; + CURLcode res; + std::string response; + std::string responseHeaders; + long statusCode = 0; + + curl = curl_easy_init(); + if (curl) + { + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); + curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent.c_str()); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headersList); + + curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, +[](char* buffer, size_t size, size_t nitems, std::string* userdata) -> size_t { + userdata->append(buffer, size * nitems); + return size * nitems; + }); + curl_easy_setopt(curl, CURLOPT_HEADERDATA, &responseHeaders); + res = curl_easy_perform(curl); + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &statusCode); + responseHeadersJson = ParseHeaders(responseHeaders); + curl_easy_cleanup(curl); + } + curl_slist_free_all(headersList); + + return {response, statusCode}; + } + static bool DownloadFile(const char* url, const char* filename) { CURL* curl; From 3faf7111cbecab18d6351abc9a8d55746c88085e Mon Sep 17 00:00:00 2001 From: shadow <81448108+shdwmtr@users.noreply.github.com> Date: Wed, 13 Nov 2024 19:01:27 -0400 Subject: [PATCH 14/18] fix: Fix the artifact CI --- .github/workflows/artifact.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/artifact.yml b/.github/workflows/artifact.yml index 3095405b..b816dc17 100644 --- a/.github/workflows/artifact.yml +++ b/.github/workflows/artifact.yml @@ -103,7 +103,8 @@ jobs: mkdir D:/a/Millennium/Millennium/build/artifacts cmake --build build --config Release cp D:/a/Millennium/Millennium/Python-3.11.8/PCbuild/win32/python311.dll D:/a/env/python311.dll - cp /d/a/Millennium/Millennium/build/user32.dll D:/a/env/user32.dll + cp /d/a/Millennium/Millennium/build/win32/user32.dll D:/a/env/user32.dll + cp /d/a/Millennium/Millennium/build/millennium.dll D:/a/env/millennium.dll mkdir D:/a/env/ext/bin # Disable Millennium CLI for now, as it keeps get false positive detections for no apparent reason # cp /d/a/Millennium/Millennium/build/cli/millennium.exe D:/a/env/ext/bin/millennium.exe From cfd961c54b59808b625a9dfbe077ae29940998b5 Mon Sep 17 00:00:00 2001 From: SpaceEnergy <93218131+SpaceEnergy@users.noreply.github.com> Date: Sun, 24 Nov 2024 02:23:35 +0100 Subject: [PATCH 15/18] fix: Close installer after successful install * change: install.ps1 When the installation is complete, the window is automatically closed. * change: $message check * fix: match message Co-Authored-By: Noxy <107372460+noxygalaxy@users.noreply.github.com> --------- Co-authored-by: Noxy <107372460+noxygalaxy@users.noreply.github.com> --- scripts/install.ps1 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scripts/install.ps1 b/scripts/install.ps1 index 8ad2d5bc..ee3356d3 100644 --- a/scripts/install.ps1 +++ b/scripts/install.ps1 @@ -440,6 +440,13 @@ while ($pipeServer.IsConnected) { if ($bytesRead -gt 0) { $message = [System.Text.Encoding]::UTF8.GetString($buffer, 0, $bytesRead) [Console]::Write($message) + + # Check if the message contains "SteamUI successfully loaded" + if ($message -match "SteamUI successfully loaded!") { + Write-Host "`n${BoldGreen}++${ResetColor} Millennium has successfully loaded. Installation complete!" + Start-Sleep -Seconds 2 + exit + } } } From e05ec1962999e57a4662b8391a0b379e3a2c82ee Mon Sep 17 00:00:00 2001 From: shadow <81448108+shdwmtr@users.noreply.github.com> Date: Sat, 23 Nov 2024 21:34:43 -0400 Subject: [PATCH 16/18] fix: Fix typo on themes page #168 --- assets/src/tabs/Themes.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/src/tabs/Themes.tsx b/assets/src/tabs/Themes.tsx index f5f92a48..57b8519e 100644 --- a/assets/src/tabs/Themes.tsx +++ b/assets/src/tabs/Themes.tsx @@ -263,7 +263,7 @@ const ThemeViewModal: React.FC = () => { {cssState !== undefined && ( From e0f9af0ecd06e064abb3fdb3e6b0281d3dabc93b Mon Sep 17 00:00:00 2001 From: shadow <81448108+shdwmtr@users.noreply.github.com> Date: Sat, 23 Nov 2024 21:35:29 -0400 Subject: [PATCH 17/18] chore: Oops I changed the wrong one #168 --- assets/src/tabs/Themes.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/src/tabs/Themes.tsx b/assets/src/tabs/Themes.tsx index 57b8519e..f741fc84 100644 --- a/assets/src/tabs/Themes.tsx +++ b/assets/src/tabs/Themes.tsx @@ -254,7 +254,7 @@ const ThemeViewModal: React.FC = () => { {jsState !== undefined && ( @@ -263,7 +263,7 @@ const ThemeViewModal: React.FC = () => { {cssState !== undefined && ( From 2eb7a943a951fe965d5e749c6b04b0573918d1d8 Mon Sep 17 00:00:00 2001 From: shadow <81448108+shdwmtr@users.noreply.github.com> Date: Sun, 24 Nov 2024 15:02:11 -0400 Subject: [PATCH 18/18] fix: Fix system accent color not working on some startups --- assets/src/index.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/assets/src/index.tsx b/assets/src/index.tsx index cf8dc491..476a0a10 100644 --- a/assets/src/index.tsx +++ b/assets/src/index.tsx @@ -137,7 +137,10 @@ export default async function PluginMain() { const startTime = performance.now(); pluginSelf.WatchDog = WatchDog // Expose WatchDog to the global scope - Settings.FetchAllSettings().then((result: SettingsProps) => InitializePatcher(startTime, result)) + Settings.FetchAllSettings().then((result: SettingsProps) => { + InitializePatcher(startTime, result) + Millennium.AddWindowCreateHook(windowCreated) + }) // @todo: fix notificaitons modal // Millennium.callServerMethod("updater.get_update_list") @@ -151,6 +154,4 @@ export default async function PluginMain() { // console.error("Failed to fetch updates") // pluginSelf.connectionFailed = true // }) - - Millennium.AddWindowCreateHook(windowCreated) } \ No newline at end of file