#include "AuthManager.h" #include "AuthConfig.h" #include "VrLog.h" #include #include #include #include #include #include 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 md5(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(); QString combined = (cpu + disk).left(40).toUpper(); LOG_INFO("cpu: %s, disk: %s \n", qPrintable(cpu), qPrintable(disk)); QString result; for (int i = 0; i < combined.length(); i += 8) { if (!result.isEmpty()) result += "-"; result += combined.mid(i, 8); } 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; }