diff --git a/include/global/DataStore.hpp b/include/global/DataStore.hpp index 3d0cd31..a72d962 100644 --- a/include/global/DataStore.hpp +++ b/include/global/DataStore.hpp @@ -95,6 +95,7 @@ namespace Configs { bool sub_clear = false; bool sub_insecure = false; int sub_auto_update = -30; + bool sub_send_hwid = false; // Security bool skip_cert = false; diff --git a/include/ui/setting/dialog_basic_settings.ui b/include/ui/setting/dialog_basic_settings.ui index bb06225..e71e833 100644 --- a/include/ui/setting/dialog_basic_settings.ui +++ b/include/ui/setting/dialog_basic_settings.ui @@ -551,6 +551,13 @@ + + + + Includes sending HWID, model, and OS version + + + diff --git a/src/global/Configs.cpp b/src/global/Configs.cpp index ad509ce..1a41674 100644 --- a/src/global/Configs.cpp +++ b/src/global/Configs.cpp @@ -279,6 +279,7 @@ namespace Configs { _add(new configItem("sub_clear", &sub_clear, itemType::boolean)); _add(new configItem("sub_insecure", &sub_insecure, itemType::boolean)); _add(new configItem("sub_auto_update", &sub_auto_update, itemType::integer)); + _add(new configItem("sub_send_hwid", &sub_send_hwid, itemType::boolean)); _add(new configItem("start_minimal", &start_minimal, itemType::boolean)); _add(new configItem("max_log_line", &max_log_line, itemType::integer)); _add(new configItem("splitter_state", &splitter_state, itemType::string)); diff --git a/src/global/HTTPRequestHelper.cpp b/src/global/HTTPRequestHelper.cpp index 1f7ff81..dd01bda 100644 --- a/src/global/HTTPRequestHelper.cpp +++ b/src/global/HTTPRequestHelper.cpp @@ -1,3 +1,9 @@ +#include +#ifdef Q_OS_WIN + #include +#endif +#undef boolean + #include "include/global/HTTPRequestHelper.hpp" #include @@ -13,6 +19,91 @@ namespace Configs_network { + namespace { + struct DeviceDetails { + QString hwid; + QString os; + QString osVersion; + QString model; + }; + +#ifdef Q_OS_WIN + static QString readRegistryStringValue(const QString &keyPath, const QString &valueName) { + HKEY hKey = nullptr; + std::wstring keyPathW = keyPath.toStdWString(); + LONG res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyPathW.c_str(), 0, KEY_READ | KEY_WOW64_64KEY, &hKey); + if (res != ERROR_SUCCESS) return QString(); + DWORD type = 0; + DWORD cbData = 0; + res = RegQueryValueExW(hKey, (LPCWSTR)valueName.utf16(), nullptr, &type, nullptr, &cbData); + if (res != ERROR_SUCCESS || type != REG_SZ) { + RegCloseKey(hKey); + return QString(); + } + std::vector buffer(cbData/sizeof(wchar_t) + 1); + res = RegQueryValueExW(hKey, (LPCWSTR)valueName.utf16(), nullptr, nullptr, reinterpret_cast(buffer.data()), &cbData); + if (res != ERROR_SUCCESS) { + RegCloseKey(hKey); + return QString(); + } + RegCloseKey(hKey); + return QString::fromWCharArray(buffer.data()); + } +#endif + + static DeviceDetails GetDeviceDetails() { + DeviceDetails details; + +#ifdef Q_OS_WIN + const QString regPath = QString::fromUtf8("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SoftwareProtectionPlatform\\Plugins\\Objects\\msft:rm/algorithm/hwid/4.0"); + const QString valueName = QString::fromUtf8("ModuleId"); + details.hwid = readRegistryStringValue(regPath, valueName); + + if (details.hwid.isEmpty()) { + auto productId = QSysInfo::machineUniqueId(); + if (productId.isEmpty()) productId = QSysInfo::productType().toUtf8(); + details.hwid = QString("%1-%2").arg(QSysInfo::machineHostName(), QString::fromUtf8(productId)); + } + + details.os = QStringLiteral("Windows"); + + VersionInfo info; + WinVersion::GetVersion(info); + details.osVersion = QString("%1.%2.%3").arg(info.Major).arg(info.Minor).arg(info.BuildNum); + + details.model = QSysInfo::prettyProductName(); +#elif defined(Q_OS_LINUX) + QString mid; + QFile f1("/etc/machine-id"); + if (f1.exists() && f1.open(QIODevice::ReadOnly | QIODevice::Text)) { + mid = QString::fromUtf8(f1.readAll()).trimmed(); + f1.close(); + } else { + QFile f2("/var/lib/dbus/machine-id"); + if (f2.exists() && f2.open(QIODevice::ReadOnly | QIODevice::Text)) { + mid = QString::fromUtf8(f2.readAll()).trimmed(); + f2.close(); + } + } + details.hwid = mid; + details.os = QStringLiteral("Linux"); + details.osVersion = QSysInfo::kernelVersion(); + details.model = QSysInfo::prettyProductName(); +#elif defined(Q_OS_MACOS) + details.hwid = QSysInfo::machineUniqueId(); + details.os = QStringLiteral("macOS"); + details.osVersion = QSysInfo::productVersion(); + details.model = QSysInfo::prettyProductName(); +#else + details.hwid = QSysInfo::machineUniqueId(); + details.os = QSysInfo::productType(); + details.osVersion = QSysInfo::productVersion(); + details.model = QSysInfo::prettyProductName(); +#endif + return details; + } +} + HTTPResponse NetworkRequestHelper::HttpGet(const QString &url) { QNetworkRequest request; QNetworkAccessManager accessManager; @@ -35,6 +126,15 @@ namespace Configs_network { c.setPeerVerifyMode(QSslSocket::PeerVerifyMode::VerifyNone); request.setSslConfiguration(c); } + //Attach HWID and device info headers if enabled in settings + if (Configs::dataStore->sub_send_hwid && !request.url().toString().contains("/throneproj/")) { + auto details = GetDeviceDetails(); + + if (!details.hwid.isEmpty()) request.setRawHeader("x-hwid", details.hwid.toUtf8()); + if (!details.os.isEmpty()) request.setRawHeader("x-device-os", details.os.toUtf8()); + if (!details.osVersion.isEmpty()) request.setRawHeader("x-ver-os", details.osVersion.toUtf8()); + if (!details.model.isEmpty()) request.setRawHeader("x-device-model", details.model.toUtf8()); + } // auto _reply = accessManager.get(request); connect(_reply, &QNetworkReply::sslErrors, _reply, [](const QList &errors) { diff --git a/src/ui/setting/dialog_basic_settings.cpp b/src/ui/setting/dialog_basic_settings.cpp index 76c2d6c..34fe948 100644 --- a/src/ui/setting/dialog_basic_settings.cpp +++ b/src/ui/setting/dialog_basic_settings.cpp @@ -116,6 +116,7 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent) D_LOAD_BOOL(sub_use_proxy) D_LOAD_BOOL(sub_clear) D_LOAD_BOOL(sub_insecure) + D_LOAD_BOOL(sub_send_hwid) D_LOAD_INT_ENABLE(sub_auto_update, sub_auto_update_enable) // Core @@ -200,6 +201,7 @@ void DialogBasicSettings::accept() { D_SAVE_BOOL(sub_use_proxy) D_SAVE_BOOL(sub_clear) D_SAVE_BOOL(sub_insecure) + D_SAVE_BOOL(sub_send_hwid) D_SAVE_INT_ENABLE(sub_auto_update, sub_auto_update_enable) // Core