feat(hardening): 内嵌产品配置 + 系统级状态 + 全量 i18n + 依赖治理 + 资料清理
update-client-hardening 四工作流合入(构建/静态检查已过): - 配置:不可变产品策略经 UpdateClientResources.cmake 归一化校验后 内嵌 qrc(URL/相对路径/主程序必须落 install_root/版本/UUID 格式, CMake override 写入前复验);可变机器状态迁系统级原生存储; 运行目录不再落可编辑 app_config.json。 - i18n:生产源全英文(no-Han 检查 41/41),中文进 translations/ zh_CN 目录;翻译加载收敛 Common/TranslationHelper 唯一入口; Bootstrap 补资源文件。 - 依赖:Qt/OpenSSL/架构/Perl 机器路径改 imported targets + UpdateClientDependencies.cmake,3rdparty 由父工程契约供给。 - 清理:旧 README/SDK README/3 个重复 PowerShell 打包脚本/PDF 提取 文本删除,canonical README + 5 份结构化英文文档替代;Launcher requireAdministrator manifest;统一 MSVC /utf-8 删运行时编码设置。
This commit is contained in:
+46
-6
@@ -22,12 +22,35 @@ bool PolicyHelper::loadPolicy(const QString& relativePath)
|
||||
if (error.error != QJsonParseError::NoError || !doc.isObject()) {
|
||||
m_error = "Invalid policy JSON: " + error.errorString(); return false;
|
||||
}
|
||||
return loadPolicyObject(doc.object());
|
||||
const QJsonObject stored = doc.object();
|
||||
if (stored.value("policy").isObject() && stored.value("policy_text").isString())
|
||||
return loadPolicyObject(stored.value("policy").toObject(),
|
||||
stored.value("policy_text").toString());
|
||||
return loadPolicyObject(stored);
|
||||
}
|
||||
|
||||
bool PolicyHelper::loadPolicyObject(const QJsonObject& policy, const QString& signedText)
|
||||
{
|
||||
m_policy = policy; m_signedText = signedText; m_loaded = true; m_error.clear();
|
||||
m_error.clear();
|
||||
m_signedText = signedText;
|
||||
m_policy = policy;
|
||||
if (!signedText.isEmpty())
|
||||
{
|
||||
QJsonParseError parseError;
|
||||
const QJsonDocument signedDocument =
|
||||
QJsonDocument::fromJson(signedText.toUtf8(), &parseError);
|
||||
if (parseError.error != QJsonParseError::NoError || !signedDocument.isObject())
|
||||
{
|
||||
m_error = "Signed policy text is invalid JSON: " + parseError.errorString();
|
||||
m_loaded = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
const QString signature = policy.value("signature").toString();
|
||||
m_policy = signedDocument.object();
|
||||
m_policy.insert("signature", signature);
|
||||
}
|
||||
m_loaded = true;
|
||||
return isValid();
|
||||
}
|
||||
|
||||
@@ -35,7 +58,12 @@ bool PolicyHelper::savePolicy(const QString& relativePath) const
|
||||
{
|
||||
QSaveFile file(m_baseDir + "/" + relativePath);
|
||||
if (!file.open(QIODevice::WriteOnly)) return false;
|
||||
const QByteArray bytes = QJsonDocument(m_policy).toJson(QJsonDocument::Indented);
|
||||
QJsonObject stored = m_policy;
|
||||
if (!m_signedText.isEmpty())
|
||||
{
|
||||
stored = QJsonObject{{"policy", m_policy}, {"policy_text", m_signedText}};
|
||||
}
|
||||
const QByteArray bytes = QJsonDocument(stored).toJson(QJsonDocument::Indented);
|
||||
return file.write(bytes) == bytes.size() && file.commit();
|
||||
}
|
||||
|
||||
@@ -68,9 +96,8 @@ bool PolicyHelper::verifySignature(const QByteArray& payload, const QString& sig
|
||||
#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; }
|
||||
QFile keyFile(QStringLiteral(":/simcae/update-client/manifest-public-key.pem"));
|
||||
if (!keyFile.open(QIODevice::ReadOnly)) { m_error = "Cannot open embedded policy public key"; 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;
|
||||
@@ -97,6 +124,19 @@ bool PolicyHelper::isValid() const
|
||||
const QByteArray payload = m_signedText.isEmpty() ? canonicalPolicyBytes(m_policy) : m_signedText.toUtf8();
|
||||
return verifySignature(payload, m_policy.value("signature").toString());
|
||||
}
|
||||
bool PolicyHelper::isApplicable(const QString& appId, const QString& channel,
|
||||
const QString& currentVersion) const
|
||||
{
|
||||
if (!isValid()) return false;
|
||||
if (m_policy.value("app_id").toString() != appId
|
||||
|| m_policy.value("channel").toString() != channel
|
||||
|| m_policy.value("current_version").toString() != currentVersion)
|
||||
{
|
||||
m_error = "Policy identity does not match this installation";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
QString PolicyHelper::errorString() const { return m_error; }
|
||||
bool PolicyHelper::isVersionAllowed(const QString& version) const {
|
||||
if (!isValid()) return false;
|
||||
|
||||
Reference in New Issue
Block a user