GrabBag/Module/AuthModule/Src/AuthManager.cpp

156 lines
5.3 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
}
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
QString result;
for (int i = 0; i < 16; i += 4) {
if (!result.isEmpty()) result += "-";
result += xorResult.mid(i, 4);
}
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;
}