fix: 优化客户端错误提示和校验诊断信息
This commit is contained in:
+79
-26
@@ -1,6 +1,7 @@
|
||||
#include "PolicyHelper.h"
|
||||
#include "ConfigHelper.h"
|
||||
#include <QApplication>
|
||||
#include <QCoreApplication>
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
@@ -29,15 +30,26 @@ static QString resolvePolicyPath(const QString& baseDir, const QString& relative
|
||||
|
||||
bool PolicyHelper::loadPolicy(const QString& relativePath)
|
||||
{
|
||||
QFile file(resolvePolicyPath(m_baseDir, relativePath, false));
|
||||
if (!file.open(QIODevice::ReadOnly)) { m_error = "Cannot open policy file"; return false; }
|
||||
QJsonParseError error;
|
||||
const QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &error);
|
||||
if (error.error != QJsonParseError::NoError || !doc.isObject()) {
|
||||
m_error = "Invalid policy JSON: " + error.errorString(); return false;
|
||||
}
|
||||
return loadPolicyObject(doc.object());
|
||||
}
|
||||
const QString path = resolvePolicyPath(m_baseDir, relativePath, false);
|
||||
QFile file(path);
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
m_error = QCoreApplication::translate(
|
||||
"PolicyHelper",
|
||||
"Cannot open signed version policy file: %1. Error: %2.")
|
||||
.arg(path, file.errorString());
|
||||
return false;
|
||||
}
|
||||
QJsonParseError error;
|
||||
const QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &error);
|
||||
if (error.error != QJsonParseError::NoError || !doc.isObject()) {
|
||||
m_error = QCoreApplication::translate(
|
||||
"PolicyHelper",
|
||||
"Signed version policy is not valid JSON. File: %1. JSON error: %2.")
|
||||
.arg(path, error.errorString());
|
||||
return false;
|
||||
}
|
||||
return loadPolicyObject(doc.object());
|
||||
}
|
||||
|
||||
bool PolicyHelper::loadPolicyObject(const QJsonObject& policy, const QString& signedText)
|
||||
{
|
||||
@@ -51,7 +63,10 @@ bool PolicyHelper::savePolicy(const QString& relativePath) const
|
||||
QString writeError;
|
||||
const QString path = resolvePolicyPath(m_baseDir, relativePath, true);
|
||||
if (!ConfigHelper::writeFileWithElevationIfNeeded(path, bytes, &writeError)) {
|
||||
m_error = "Cannot save policy file: " + writeError;
|
||||
m_error = QCoreApplication::translate(
|
||||
"PolicyHelper",
|
||||
"Cannot save signed version policy file: %1. Error: %2.")
|
||||
.arg(path, writeError);
|
||||
return false;
|
||||
}
|
||||
m_error.clear();
|
||||
@@ -84,35 +99,73 @@ QByteArray PolicyHelper::canonicalPolicyBytes(const QJsonObject& policy) const
|
||||
|
||||
bool PolicyHelper::verifySignature(const QByteArray& payload, const QString& signatureBase64) const
|
||||
{
|
||||
#ifndef HAVE_OPENSSL
|
||||
Q_UNUSED(payload); Q_UNUSED(signatureBase64); m_error = "OpenSSL unavailable"; return false;
|
||||
#else
|
||||
QString keyPath = m_baseDir + "/config/manifest_public_key.pem";
|
||||
QFile keyFile(keyPath);
|
||||
if (!keyFile.open(QIODevice::ReadOnly)) { m_error = "Cannot open policy public key"; return false; }
|
||||
#ifndef HAVE_OPENSSL
|
||||
Q_UNUSED(payload);
|
||||
Q_UNUSED(signatureBase64);
|
||||
m_error = QCoreApplication::translate(
|
||||
"PolicyHelper",
|
||||
"OpenSSL is unavailable, so the signed version policy cannot be verified.");
|
||||
return false;
|
||||
#else
|
||||
QString keyPath = m_baseDir + "/config/manifest_public_key.pem";
|
||||
QFile keyFile(keyPath);
|
||||
if (!keyFile.open(QIODevice::ReadOnly)) {
|
||||
m_error = QCoreApplication::translate(
|
||||
"PolicyHelper",
|
||||
"Cannot open version policy public key: %1. Error: %2.")
|
||||
.arg(keyPath, keyFile.errorString());
|
||||
return false;
|
||||
}
|
||||
const QByteArray keyData = keyFile.readAll();
|
||||
BIO* bio = BIO_new_mem_buf(keyData.constData(), keyData.size());
|
||||
EVP_PKEY* key = bio ? PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr) : nullptr;
|
||||
if (bio) BIO_free(bio);
|
||||
if (!key) { m_error = "Invalid policy public key"; return false; }
|
||||
if (!key) {
|
||||
m_error = QCoreApplication::translate(
|
||||
"PolicyHelper",
|
||||
"Version policy public key is invalid: %1.")
|
||||
.arg(keyPath);
|
||||
return false;
|
||||
}
|
||||
EVP_MD_CTX* ctx = EVP_MD_CTX_new();
|
||||
const QByteArray signature = QByteArray::fromBase64(signatureBase64.toUtf8());
|
||||
bool ok = ctx && EVP_DigestVerifyInit(ctx, nullptr, EVP_sha256(), nullptr, key) == 1
|
||||
&& EVP_DigestVerifyUpdate(ctx, payload.constData(), payload.size()) == 1
|
||||
&& EVP_DigestVerifyFinal(ctx, reinterpret_cast<const unsigned char*>(signature.constData()), signature.size()) == 1;
|
||||
if (ctx) EVP_MD_CTX_free(ctx); EVP_PKEY_free(key);
|
||||
if (!ok) m_error = "Invalid RSA policy signature";
|
||||
return ok;
|
||||
#endif
|
||||
}
|
||||
if (!ok) {
|
||||
m_error = QCoreApplication::translate(
|
||||
"PolicyHelper",
|
||||
"Version policy RSA signature is invalid. The policy file may have been changed, or the public key does not match the server private key.");
|
||||
}
|
||||
return ok;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool PolicyHelper::isValid() const
|
||||
{
|
||||
if (!m_loaded) return false;
|
||||
const QStringList required{"app_id","channel","current_version","policy_seq","allow_run",
|
||||
"force_update","allow_rollback","offline_allowed","valid_until","signature_alg","key_id","signature"};
|
||||
for (const QString& key : required) if (!m_policy.contains(key)) { m_error = "Missing policy field: " + key; return false; }
|
||||
if (m_policy.value("signature_alg").toString() != "RSA-2048-SHA256") return false;
|
||||
if (!m_loaded) {
|
||||
m_error = QCoreApplication::translate("PolicyHelper", "Version policy has not been loaded.");
|
||||
return false;
|
||||
}
|
||||
const QStringList required{"app_id","channel","current_version","policy_seq","allow_run",
|
||||
"force_update","allow_rollback","offline_allowed","valid_until","signature_alg","key_id","signature"};
|
||||
for (const QString& key : required) {
|
||||
if (!m_policy.contains(key)) {
|
||||
m_error = QCoreApplication::translate(
|
||||
"PolicyHelper",
|
||||
"Version policy is missing required field: %1.")
|
||||
.arg(key);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (m_policy.value("signature_alg").toString() != "RSA-2048-SHA256") {
|
||||
m_error = QCoreApplication::translate(
|
||||
"PolicyHelper",
|
||||
"Version policy signature algorithm is unsupported: %1.")
|
||||
.arg(m_policy.value("signature_alg").toString());
|
||||
return false;
|
||||
}
|
||||
const QByteArray payload = m_signedText.isEmpty() ? canonicalPolicyBytes(m_policy) : m_signedText.toUtf8();
|
||||
return verifySignature(payload, m_policy.value("signature").toString());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user