GrabBag/Module/AuthModule/Src/AuthManager.cpp

156 lines
5.3 KiB
C++
Raw Normal View History

2026-01-25 01:27:01 +08:00
#include "AuthManager.h"
#include "AuthConfig.h"
#include "VrLog.h"
#include <QCryptographicHash>
#include <QString>
#include <QFile>
#include <QDir>
#include <QDateTime>
#include <QProcess>
static QString md5(const QString& s) {
return QCryptographicHash::hash(s.toUtf8(), QCryptographicHash::Md5).toHex();
}
static QString encrypt(const QString& text, const QString& key) {
QByteArray t = text.toUtf8(), k = key.toUtf8(), r;
for (int i = 0; i < t.size(); ++i) r.append(t[i] ^ k[i % k.size()]);
return r.toBase64();
}
static QString decrypt(const QString& text, const QString& key) {
QByteArray t = QByteArray::fromBase64(text.toUtf8()), k = key.toUtf8(), r;
for (int i = 0; i < t.size(); ++i) r.append(t[i] ^ k[i % k.size()]);
return QString::fromUtf8(r);
}
static QString exec(const QString& cmd) {
QProcess p;
#ifdef _WIN32
p.start("cmd", {"/c", cmd});
#else
p.start("sh", {"-c", cmd});
#endif
p.waitForFinished();
return QString(p.readAllStandardOutput()).remove('\r').remove('\n').remove(' ');
}
static QString cpuSerial() {
#ifdef _WIN32
QString r = exec(WMIC_CMD_CPU_SERIAL);
r.remove("ProcessorId");
#else
QString r = exec("cat /proc/cpuinfo | grep Serial | awk '{print $3}'");
#endif
return r;
2026-01-25 01:27:01 +08:00
}
static QString diskSerial() {
#ifdef _WIN32
QString r = exec(WMIC_CMD_DISK_SERIAL);
r.remove("SerialNumber");
#else
// ARM: 优先读取 eMMC/SD 卡 CID其次读取 SATA 硬盘序列号
QString r = exec("cat /sys/block/mmcblk0/device/cid 2>/dev/null || "
"cat /sys/block/sda/device/serial 2>/dev/null || "
"cat /sys/class/dmi/id/product_serial 2>/dev/null || echo 'unknown'");
#endif
return r.remove("0000").remove('_').remove('.');
}
static QString getFilePath() {
return QDir::homePath() + "/" + AUTH_FILE_PATH;
}
std::string AuthManager::GetMachineCode() {
QString cpu = cpuSerial(), disk = diskSerial();
LOG_INFO("cpu: %s, disk: %s\n", qPrintable(cpu), qPrintable(disk));
// 使用 CPU + DISK 的 MD5 哈希32位
QString hash = md5(cpu + disk);
// 前16位和后16位异或生成16位机器码
QString front = hash.left(16);
QString back = hash.right(16);
QString xorResult;
for (int i = 0; i < 16; ++i) {
int f = front[i].toLatin1();
int b = back[i].toLatin1();
int x = f ^ b;
// 将异或结果映射到 0-F 范围
xorResult += QString::number(x % 16, 16);
}
xorResult = xorResult.toUpper();
// 格式化为 xxxx-xxxx-xxxx-xxxx
2026-01-25 01:27:01 +08:00
QString result;
for (int i = 0; i < 16; i += 4) {
2026-01-25 01:27:01 +08:00
if (!result.isEmpty()) result += "-";
result += xorResult.mid(i, 4);
2026-01-25 01:27:01 +08:00
}
return result.toStdString();
}
std::string AuthManager::GenerateLicenseKey(const std::string& machineCode, const std::string& expireDate) {
QString mc = QString::fromStdString(machineCode), ed = QString::fromStdString(expireDate);
QString key = md5(mc + "|" + ed);
QString hash = md5(AUTH_KEY_SEED + key + ed).toUpper();
return encrypt(ed + "|" + hash, AUTH_KEY_SEED).toStdString();
}
bool AuthManager::SaveLicenseInfo(const std::string& licenseKey, const std::string& /*expireDate*/) {
#ifndef _WIN32
QDir().mkpath(QDir::homePath() + "/.config");
#endif
QString filePath = getFilePath();
QFile f(filePath);
if (!f.open(QIODevice::WriteOnly)) {
LOG_WARN("Failed to open file %s for writing", qPrintable(filePath));
return false;
}
f.write(QString::fromStdString(licenseKey).toUtf8());
return true;
}
bool AuthManager::LoadLicenseInfo(std::string& licenseKey, std::string& expireDate) {
QString filePath = getFilePath();
QFile f(filePath);
if (!f.open(QIODevice::ReadOnly)) {
LOG_WARN("Failed to open file %s for reading\n", qPrintable(filePath));
return false;
}
licenseKey = QString(f.readAll()).trimmed().toStdString();
// 从授权码中解析过期日期
QString decoded = decrypt(QString::fromStdString(licenseKey), AUTH_KEY_SEED);
int pos = decoded.indexOf('|');
if (pos == -1) return false;
expireDate = decoded.left(pos).toStdString();
return true;
}
bool AuthManager::CheckLicenseValid() {
std::string lk, ed;
if (!LoadLicenseInfo(lk, ed)) return false;
return ValidateLicenseKey(lk, ed);
}
bool AuthManager::ValidateLicenseKey(const std::string& licenseKey, std::string& expireDate) {
QString decoded = decrypt(QString::fromStdString(licenseKey), AUTH_KEY_SEED);
int pos = decoded.indexOf('|');
if (pos == -1) return false;
QString expDate = decoded.left(pos);
// 验证过期日期格式
if (expDate != PERMANENT_LICENSE_DATE && expDate.length() != 8) return false;
// 验证授权码是否匹配当前机器
std::string expectedKey = GenerateLicenseKey(GetMachineCode(), expDate.toStdString());
if (QString::fromStdString(expectedKey).toUpper() != QString::fromStdString(licenseKey).toUpper()) return false;
// 验证是否过期
if (expDate != PERMANENT_LICENSE_DATE && QDate::currentDate().toString("yyyyMMdd") > expDate) return false;
expireDate = expDate.toStdString();
return true;
}