diff --git a/devel/200_48.md b/devel/200_48.md new file mode 100644 index 0000000000..2e27aa6cfc --- /dev/null +++ b/devel/200_48.md @@ -0,0 +1,26 @@ +# [200_48] User-Agent and Device ID + +## 2026/02/11 添加 User-Agent and Device ID 函数 +### 如何测试 +点击`插入交互对话`,使用`scheme`,输入: +``` +(stem-user-agent) +;;期望返回类似:LiiiSTEM-v2026.2.0-rc2 Debian_GNU/Linux_13_(trixie) x86_64 +(stem-device-id) +;;期望返回类似:469709a0db73706427292c7019d41d55f64de1d965367da4206d9d952849120e +``` + +### What +提供 HTTP 请求所需的 User-Agent 和设备唯一标识符功能。 +- **User-Agent**: 在 HTTP 请求头中携带客户端信息(应用版本、操作系统、架构),便于服务器识别客户端环境 + ``` + LiiiSTEM-v2026.2.1 Windows_11_10.0.26100 x86_64 + LiiiSTEM-v2026.2.1 macOS_15.3_(arm64) arm64 + LiiiSTEM-v2026.2.1 Debian_GNU/Linux_13_(trixie) x86_64 + ``` +- **Device ID**: 基于网卡 MAC 地址生成的设备唯一标识符,用于设备认证、防止多设备共享账户等场景 + +### Why +- HTTP 请求时准确标识客户端环境,便于服务端做兼容性处理 +- 设备绑定和认证,防止账户在多设备上滥用 +- 统一各平台的系统信息获取方式,提供更详细的版本信息(如 Windows 11 26200.7623) diff --git a/src/Plugins/Qt/qt_sys_utils.cpp b/src/Plugins/Qt/qt_sys_utils.cpp index 3c4c7f316b..e3c9f8c0ab 100644 --- a/src/Plugins/Qt/qt_sys_utils.cpp +++ b/src/Plugins/Qt/qt_sys_utils.cpp @@ -1,4 +1,3 @@ - /****************************************************************************** * MODULE : qt_sys_utils.cpp * DESCRIPTION: external command launcher @@ -14,14 +13,23 @@ #include "file.hpp" #include "qt_utilities.hpp" #include "string.hpp" +#include "tm_configure.hpp" #include "tm_debug.hpp" +#include #include +#include +#include #include #include #include #include +#ifdef Q_OS_WINDOWS +#include +#include +#endif + string qt_get_current_cpu_arch () { return from_qstring (QSysInfo::currentCpuArchitecture ()); @@ -32,6 +40,129 @@ qt_get_pretty_os_name () { return from_qstring (QSysInfo::prettyProductName ()); } +#ifdef Q_OS_WINDOWS +QString +get_windows_detailed_version () { + RTL_OSVERSIONINFOW osvi; + osvi.dwOSVersionInfoSize= sizeof (osvi); + if (RtlGetVersion (&osvi) != 0) { + return QSysInfo::prettyProductName (); + } + + QString productName; + if (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0) { + if (osvi.dwBuildNumber >= 22000) productName= "Windows 11"; + else productName= "Windows 10"; + } + else if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 3) { + productName= "Windows 8.1"; + } + else if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 2) { + productName= "Windows 8"; + } + else if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1) { + productName= "Windows 7"; + } + else { + productName= QString ("Windows %1.%2") + .arg (osvi.dwMajorVersion) + .arg (osvi.dwMinorVersion); + } + + return QString ("%1 %2.%3.%4") + .arg (productName) + .arg (osvi.dwMajorVersion) + .arg (osvi.dwMinorVersion) + .arg (osvi.dwBuildNumber) + .replace (" ", "_"); +} +#endif + +#ifdef Q_OS_MACOS +QString +get_macos_detailed_version () { + QProcess p; + QStringList env= QProcess::systemEnvironment (); + p.setEnvironment (env); + p.start ("sh", + QStringList () + << "-c" + << "sw_vers -productVersion; sw_vers -productName; uname -m"); + if (!p.waitForFinished (1000)) return QSysInfo::prettyProductName (); + + QString output= p.readAllStandardOutput ().trimmed (); + QStringList lines = output.split ("\n"); + if (lines.size () < 3) return QSysInfo::prettyProductName (); + + return QString ("%1 %2 (%3)") + .arg (lines[1]) + .arg (lines[0]) + .arg (lines[2]) + .replace (" ", "_"); +} +#endif + +#ifdef Q_OS_LINUX +QString +get_linux_detailed_version () { + QFile file ("/etc/os-release"); + if (!file.open (QIODevice::ReadOnly)) return QSysInfo::prettyProductName (); + + QString prettyName; + while (!file.atEnd ()) { + QString line= file.readLine ().trimmed (); + if (line.startsWith ("PRETTY_NAME=")) { + prettyName= line.section ('=', 1).remove ('"'); + break; + } + } + file.close (); + + if (prettyName.isEmpty ()) return QSysInfo::prettyProductName (); + return prettyName.replace (" ", "_"); +} +#endif + +// User-Agent 格式: +// LiiiSTEM-v2026.2.1 Windows_11_10.0.26100 x86_64 +// LiiiSTEM-v2026.2.1 macOS_15.3_(arm64) arm64 +// LiiiSTEM-v2026.2.1 Debian_GNU/Linux_13_(trixie) x86_64 + +string +qt_stem_user_agent () { + QString appVersion= QString ("LiiiSTEM-v") + XMACS_VERSION; +#ifdef Q_OS_WINDOWS + QString osName= get_windows_detailed_version (); +#elif defined(Q_OS_MACOS) + QString osName= get_macos_detailed_version (); +#elif defined(Q_OS_LINUX) + QString osName= get_linux_detailed_version (); +#else + QString osName= QSysInfo::prettyProductName (); +#endif + QString arch= QSysInfo::currentCpuArchitecture (); + + return from_qstring ( + QString ("%1 %2 %3").arg (appVersion).arg (osName).arg (arch)); +} + +string +qt_stem_device_id () { + QByteArray combinedData; + + QList interfaces= QNetworkInterface::allInterfaces (); + for (const QNetworkInterface& interface : interfaces) { + if (!(interface.flags () & QNetworkInterface::IsLoopBack) && + (interface.flags () & QNetworkInterface::IsUp)) { + combinedData.append (interface.hardwareAddress ().toUtf8 ()); + } + } + + QByteArray hashed= + QCryptographicHash::hash (combinedData, QCryptographicHash::Sha256); + return from_qstring (QString (hashed.toHex ())); +} + void qt_open_url (url u) { debug_io << "open-url\t" << u << LF; diff --git a/src/Plugins/Qt/qt_sys_utils.hpp b/src/Plugins/Qt/qt_sys_utils.hpp index aeeae39e53..1bf43519ff 100644 --- a/src/Plugins/Qt/qt_sys_utils.hpp +++ b/src/Plugins/Qt/qt_sys_utils.hpp @@ -17,6 +17,8 @@ string qt_get_current_cpu_arch (); string qt_get_pretty_os_name (); +string qt_stem_user_agent (); +string qt_stem_device_id (); void qt_open_url (url u); #endif // defined QT_SYS_UTILS_H diff --git a/src/Scheme/Glue/glue_basic.lua b/src/Scheme/Glue/glue_basic.lua index aa5e3c0e8a..35e17d92cd 100644 --- a/src/Scheme/Glue/glue_basic.lua +++ b/src/Scheme/Glue/glue_basic.lua @@ -1972,6 +1972,16 @@ function main() "url" } }, + { + scm_name = "stem-user-agent", + cpp_name = "stem_user_agent", + ret_type = "string" + }, + { + scm_name = "stem-device-id", + cpp_name = "stem_device_id", + ret_type = "string" + }, } } end \ No newline at end of file diff --git a/src/System/Misc/tm_sys_utils.cpp b/src/System/Misc/tm_sys_utils.cpp index d1c0c513e2..0e1b9d0ff9 100644 --- a/src/System/Misc/tm_sys_utils.cpp +++ b/src/System/Misc/tm_sys_utils.cpp @@ -250,3 +250,25 @@ is_community_stem () { return false; #endif } + +/****************************************************************************** + * STEM User-Agent and Device ID + ******************************************************************************/ + +string +stem_user_agent () { +#ifdef QTTEXMACS + return qt_stem_user_agent (); +#else + return "unknown"; +#endif +} + +string +stem_device_id () { +#ifdef QTTEXMACS + return qt_stem_device_id (); +#else + return "unknown"; +#endif +} diff --git a/src/System/Misc/tm_sys_utils.hpp b/src/System/Misc/tm_sys_utils.hpp index 38d32c7c89..fbef2ad535 100644 --- a/src/System/Misc/tm_sys_utils.hpp +++ b/src/System/Misc/tm_sys_utils.hpp @@ -44,4 +44,7 @@ void system_wait (string message, string argument= "", int level= 0); bool is_community_stem (); +string stem_user_agent (); +string stem_device_id (); + #endif