Merge pull request #789 from 0-Kutya-0/HWID-support

add HWID support
This commit is contained in:
parhelia512 2025-09-22 15:04:48 +08:00 committed by GitHub
commit dc8a5e5ff8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 240 additions and 0 deletions

View File

@ -64,6 +64,7 @@ set(PROJECT_SOURCES
src/global/Configs.cpp
src/global/Utils.cpp
src/global/HTTPRequestHelper.cpp
src/global/DeviceDetailsHelper.cpp
3rdparty/base64.cpp
3rdparty/qrcodegen.cpp

View File

@ -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;

View File

@ -0,0 +1,12 @@
#pragma once
#include <QString>
struct DeviceDetails {
QString hwid;
QString os;
QString osVersion;
QString model;
};
DeviceDetails GetDeviceDetails();

View File

@ -551,6 +551,16 @@
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QCheckBox" name="sub_send_hwid">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;HWID=%1&lt;/p&gt;&lt;p&gt;OS=%2&lt;/p&gt;&lt;p&gt;OS Version=%3&lt;/p&gt;&lt;p&gt;Model=%4&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Enable sending HWID, device model, and OS version when updating subscription</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_20">
<property name="sizePolicy">

View File

@ -90,6 +90,14 @@
<message>
<source>Clear servers before updating subscription</source>
<translation>Очищать список серверов перед обновлением подписки</translation>
</message>
<message>
<source>Enable sending HWID, device model, and OS version when updating subscription</source>
<translation>Включить отправку HWID, модели устройства и версии ОС при обновлении подписки</translation>
</message>
<message>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;HWID=%1&lt;/p&gt;&lt;p&gt;OS=%2&lt;/p&gt;&lt;p&gt;OS Version=%3&lt;/p&gt;&lt;p&gt;Model=%4&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;HWID=%1&lt;/p&gt;&lt;p&gt;ОС=%2&lt;/p&gt;&lt;p&gt;Версия ОС=%3&lt;/p&gt;&lt;p&gt;Модель=%4&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<source>Core</source>

View File

@ -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));

View File

@ -0,0 +1,183 @@
#include "include/global/DeviceDetailsHelper.hpp"
#include <QString>
#include <QSysInfo>
#include <QFile>
#include <vector>
#include <string>
#ifdef Q_OS_WIN
#include <windows.h>
#include "include/sys/windows/WinVersion.h"
#include <include/sys/Process.hpp>
#include <Wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
#endif
#ifdef Q_OS_WIN
static QString queryWmiProperty(const QString& wmiClass, const QString& property) {
HRESULT hres;
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres)) return QString();
hres = CoInitializeSecurity(
NULL, -1, NULL, NULL,
RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL, EOAC_NONE, NULL
);
if (FAILED(hres) && hres != RPC_E_TOO_LATE) {
CoUninitialize();
return QString();
}
IWbemLocator* pLoc = NULL;
hres = CoCreateInstance(
CLSID_WbemLocator, 0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID*)&pLoc
);
if (FAILED(hres)) {
CoUninitialize();
return QString();
}
IWbemServices* pSvc = NULL;
BSTR bstrNamespace = SysAllocString(L"ROOT\\CIMV2");
hres = pLoc->ConnectServer(
bstrNamespace,
NULL, NULL, NULL, 0, NULL, 0, &pSvc
);
SysFreeString(bstrNamespace);
if (FAILED(hres)) {
pLoc->Release();
CoUninitialize();
return QString();
}
hres = CoSetProxyBlanket(
pSvc,
RPC_C_AUTHN_WINNT,
RPC_C_AUTHZ_NONE,
NULL,
RPC_C_AUTHN_LEVEL_CALL,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
EOAC_NONE
);
if (FAILED(hres)) {
pSvc->Release();
pLoc->Release();
CoUninitialize();
return QString();
}
IEnumWbemClassObject* pEnumerator = NULL;
QString query = QString("SELECT %1 FROM %2").arg(property, wmiClass);
BSTR bstrWQL = SysAllocString(L"WQL");
BSTR bstrQuery = SysAllocString(query.toStdWString().c_str());
hres = pSvc->ExecQuery(
bstrWQL,
bstrQuery,
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator
);
SysFreeString(bstrWQL);
SysFreeString(bstrQuery);
if (FAILED(hres)) {
pSvc->Release();
pLoc->Release();
CoUninitialize();
return QString();
}
IWbemClassObject* pclsObj = NULL;
ULONG uReturn = 0;
QString result;
if (pEnumerator) {
HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
if (uReturn) {
VARIANT vtProp;
VariantInit(&vtProp);
hr = pclsObj->Get(property.toStdWString().c_str(), 0, &vtProp, 0, 0);
if (SUCCEEDED(hr) && vtProp.vt == VT_BSTR) {
result = QString::fromWCharArray(vtProp.bstrVal);
}
VariantClear(&vtProp);
pclsObj->Release();
}
pEnumerator->Release();
}
pSvc->Release();
pLoc->Release();
CoUninitialize();
return result;
}
static QString winBaseBoard() {
return queryWmiProperty("Win32_BaseBoard", "Product");
}
static QString winModel() {
return queryWmiProperty("Win32_ComputerSystem", "Model");
}
#endif
DeviceDetails GetDeviceDetails() {
static const DeviceDetails details = []() {
DeviceDetails d;
#ifdef Q_OS_WIN
d.hwid = QSysInfo::machineUniqueId();
if (d.hwid.isEmpty()) {
auto productType = QSysInfo::productType().toUtf8();
d.hwid = QString("%1-%2").arg(QSysInfo::machineHostName(), QString::fromUtf8(productType));
}
d.os = QStringLiteral("Windows");
VersionInfo info;
WinVersion::GetVersion(info);
d.osVersion = QString("%1.%2.%3").arg(info.Major).arg(info.Minor).arg(info.BuildNum);
auto wm = winModel();
auto wbb = winBaseBoard();
d.model = (wm == wbb) ? wm : wm + "/" + wbb;
if (d.hwid.isEmpty()) d.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();
}
}
d.hwid = mid;
d.os = QStringLiteral("Linux");
d.osVersion = QSysInfo::kernelVersion();
d.model = QSysInfo::prettyProductName();
#elif defined(Q_OS_MACOS)
d.hwid = QSysInfo::machineUniqueId();
d.os = QStringLiteral("macOS");
d.osVersion = QSysInfo::productVersion();
d.model = QSysInfo::prettyProductName();
#else
d.hwid = QSysInfo::machineUniqueId();
d.os = QSysInfo::productType();
d.osVersion = QSysInfo::productVersion();
d.model = QSysInfo::prettyProductName();
#endif
return d;
}();
return details;
}

View File

@ -10,6 +10,7 @@
#include "include/global/Configs.hpp"
#include "include/ui/mainwindow.h"
#include "include/global/DeviceDetailsHelper.hpp"
namespace Configs_network {
@ -35,6 +36,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<QSslError> &errors) {

View File

@ -54,6 +54,7 @@
#include <3rdparty/QHotkey/qhotkey.h>
#include <3rdparty/qv2ray/v2/proxy/QvProxyConfigurator.hpp>
#include <include/global/HTTPRequestHelper.hpp>
#include "include/global/DeviceDetailsHelper.hpp"
#include "include/sys/macos/MacOS.h"
@ -133,6 +134,9 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
Configs::dataStore->inbound_socks_port = MkPort();
}
//init HWID data
runOnNewThread([=, this] {GetDeviceDetails(); });
// Prepare core
Configs::dataStore->core_port = MkPort();
if (Configs::dataStore->core_port <= 0) Configs::dataStore->core_port = 19810;

View File

@ -7,6 +7,7 @@
#include "include/global/GuiUtils.hpp"
#include "include/global/Configs.hpp"
#include "include/global/HTTPRequestHelper.hpp"
#include "include/global/DeviceDetailsHelper.hpp"
#include <QStyleFactory>
#include <QFileDialog>
@ -116,7 +117,15 @@ 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)
auto details = GetDeviceDetails();
ui->sub_send_hwid->setToolTip(
ui->sub_send_hwid->toolTip()
.arg(details.hwid.isEmpty() ? "N/A" : details.hwid,
details.os.isEmpty() ? "N/A" : details.os,
details.osVersion.isEmpty() ? "N/A" : details.osVersion,
details.model.isEmpty() ? "N/A" : details.model));
// Core
ui->groupBox_core->setTitle(software_core_name);
@ -200,6 +209,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