Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions devel/200_48.md
Original file line number Diff line number Diff line change
@@ -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)
133 changes: 132 additions & 1 deletion src/Plugins/Qt/qt_sys_utils.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

/******************************************************************************
* MODULE : qt_sys_utils.cpp
* DESCRIPTION: external command launcher
Expand All @@ -14,14 +13,23 @@
#include "file.hpp"
#include "qt_utilities.hpp"
#include "string.hpp"
#include "tm_configure.hpp"
#include "tm_debug.hpp"

#include <QCryptographicHash>
#include <QDesktopServices>
#include <QFile>
#include <QNetworkInterface>
#include <QProcess>
#include <QString>
#include <QSysInfo>
#include <QUrl>

#ifdef Q_OS_WINDOWS
#include <qt_windows.h>
#include <windows.h>
#endif

string
qt_get_current_cpu_arch () {
return from_qstring (QSysInfo::currentCpuArchitecture ());
Expand All @@ -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<QNetworkInterface> 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;
Expand Down
2 changes: 2 additions & 0 deletions src/Plugins/Qt/qt_sys_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
10 changes: 10 additions & 0 deletions src/Scheme/Glue/glue_basic.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
22 changes: 22 additions & 0 deletions src/System/Misc/tm_sys_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
3 changes: 3 additions & 0 deletions src/System/Misc/tm_sys_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading