From 3d0ccc1db148e710da672934b60c60c7b62837c8 Mon Sep 17 00:00:00 2001 From: Zephyron Date: Sat, 1 Nov 2025 21:56:37 +1000 Subject: [PATCH] Fix Windows auto updater with deferred update helper and TLS support Windows auto updater failed due to: 1. File locking - can't overwrite running .exe files 2. Missing Qt 6 TLS plugins - can't connect via HTTPS Solution: - Implement helper batch script that applies updates after app exits - Automate TLS plugin copying in CMake (qschannelbackend.dll, qopensslbackend.dll) - Add enhanced SSL debugging and error messages Windows updates now work. Linux continues to work as before. Signed-off-by: Zephyron --- src/citron/CMakeLists.txt | 32 ++++++++++++++++++++++++++ src/citron/updater/updater_service.cpp | 21 ++++++++++++++++- src/citron/updater/updater_service.h | 5 +++- src/core/CMakeLists.txt | 10 ++++++++ 4 files changed, 66 insertions(+), 2 deletions(-) diff --git a/src/citron/CMakeLists.txt b/src/citron/CMakeLists.txt index efa38e944..dfca26cb1 100644 --- a/src/citron/CMakeLists.txt +++ b/src/citron/CMakeLists.txt @@ -512,6 +512,38 @@ if (WIN32 AND QT_VERSION VERSION_GREATER_EQUAL 6) COMMAND ${CMAKE_COMMAND} -E make_directory "${CITRON_EXE_DIR}/user" COMMENT "Creating portable user directory" ) + + # Copy Qt TLS plugins for SSL/TLS support (required for auto updater and HTTPS) + # Qt 6 uses a plugin architecture for TLS backends + if (CITRON_USE_AUTO_UPDATER OR ENABLE_OPENSSL) + set(Qt6_TLS_PLUGINS_DIR "${Qt6_DIR}/../../../plugins/tls") + + # Create tls directory + add_custom_command(TARGET citron POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory "${CITRON_EXE_DIR}/tls" + COMMENT "Creating TLS plugin directory for SSL support" + ) + + # Copy Windows native Schannel backend (no external dependencies) + if (EXISTS "${Qt6_TLS_PLUGINS_DIR}/qschannelbackend.dll") + add_custom_command(TARGET citron POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${Qt6_TLS_PLUGINS_DIR}/qschannelbackend.dll" + "${CITRON_EXE_DIR}/tls/qschannelbackend.dll" + COMMENT "Copying Qt Schannel TLS plugin (Windows native SSL)" + ) + endif() + + # Copy OpenSSL backend as fallback (requires OpenSSL DLLs) + if (EXISTS "${Qt6_TLS_PLUGINS_DIR}/qopensslbackend.dll") + add_custom_command(TARGET citron POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${Qt6_TLS_PLUGINS_DIR}/qopensslbackend.dll" + "${CITRON_EXE_DIR}/tls/qopensslbackend.dll" + COMMENT "Copying Qt OpenSSL TLS plugin (fallback)" + ) + endif() + endif() endif() if (CITRON_USE_BUNDLED_QT) diff --git a/src/citron/updater/updater_service.cpp b/src/citron/updater/updater_service.cpp index 7ab46f734..2ad5f6853 100644 --- a/src/citron/updater/updater_service.cpp +++ b/src/citron/updater/updater_service.cpp @@ -83,10 +83,27 @@ UpdaterService::~UpdaterService() { void UpdaterService::InitializeSSL() { LOG_INFO(Frontend, "Attempting to initialize SSL support..."); + + // Check if SSL is supported if (!QSslSocket::supportsSsl()) { LOG_WARNING(Frontend, "SSL support not available"); + LOG_WARNING(Frontend, "Build-time SSL version: {}", QSslSocket::sslLibraryBuildVersionString().toStdString()); + LOG_WARNING(Frontend, "Runtime SSL version: {}", QSslSocket::sslLibraryVersionString().toStdString()); + +#ifdef _WIN32 + // Try to provide helpful information about missing DLLs + std::filesystem::path app_dir = std::filesystem::path(QCoreApplication::applicationDirPath().toStdString()); + std::filesystem::path crypto_dll = app_dir / "libcrypto-3-x64.dll"; + std::filesystem::path ssl_dll = app_dir / "libssl-3-x64.dll"; + + LOG_WARNING(Frontend, "libcrypto-3-x64.dll exists: {}", std::filesystem::exists(crypto_dll)); + LOG_WARNING(Frontend, "libssl-3-x64.dll exists: {}", std::filesystem::exists(ssl_dll)); +#endif return; } + + LOG_INFO(Frontend, "SSL library version: {}", QSslSocket::sslLibraryVersionString().toStdString()); + QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration(); auto certs = QSslConfiguration::systemCaCertificates(); if (!certs.isEmpty()) { @@ -612,9 +629,11 @@ bool UpdaterService::LaunchUpdateHelper() { // Launch the batch script as a detached process QString script_path_str = QString::fromStdString(script_path.string()); QStringList arguments; + arguments << QStringLiteral("/C"); + arguments << script_path_str; // Use cmd.exe to run the batch file in a hidden window - bool launched = QProcess::startDetached("cmd.exe", QStringList() << "/C" << script_path_str); + bool launched = QProcess::startDetached(QStringLiteral("cmd.exe"), arguments); if (launched) { LOG_INFO(Frontend, "Update helper script launched successfully"); diff --git a/src/citron/updater/updater_service.h b/src/citron/updater/updater_service.h index 78e1c3008..c8bccf3fa 100644 --- a/src/citron/updater/updater_service.h +++ b/src/citron/updater/updater_service.h @@ -53,6 +53,10 @@ public: static bool HasStagedUpdate(const std::filesystem::path& app_directory); static bool ApplyStagedUpdate(const std::filesystem::path& app_directory); + #ifdef _WIN32 + bool LaunchUpdateHelper(); + #endif + signals: void UpdateCheckCompleted(bool has_update, const UpdateInfo& update_info); void UpdateDownloadProgress(int percentage, qint64 bytes_received, qint64 bytes_total); @@ -80,7 +84,6 @@ private: bool CreateBackup(); bool RestoreBackup(); bool CreateUpdateHelperScript(const std::filesystem::path& staging_path); - bool LaunchUpdateHelper(); #endif bool CleanupFiles(); std::filesystem::path GetTempDirectory() const; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 34c236ae9..27bbfe9e9 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -49,8 +49,14 @@ add_library(core STATIC file_sys/common_funcs.h file_sys/content_archive.cpp file_sys/content_archive.h + file_sys/content_exporter.cpp + file_sys/content_exporter.h file_sys/control_metadata.cpp file_sys/control_metadata.h + file_sys/decrypted_nsp.cpp + file_sys/decrypted_nsp.h + file_sys/decrypted_xci.cpp + file_sys/decrypted_xci.h file_sys/errors.h file_sys/fs_directory.h file_sys/fs_file.h @@ -1183,10 +1189,14 @@ add_library(core STATIC loader/nca.h loader/nro.cpp loader/nro.h + loader/nsd.cpp + loader/nsd.h loader/nso.cpp loader/nso.h loader/nsp.cpp loader/nsp.h + loader/xcd.cpp + loader/xcd.h loader/xci.cpp loader/xci.h memory.cpp