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:
+18
-21
@@ -1,21 +1,18 @@
|
||||
project(MainApp)
|
||||
add_executable(MainApp
|
||||
main.cpp
|
||||
MainWindow.h
|
||||
MainWindow.cpp
|
||||
../Common/ConfigHelper.h
|
||||
)
|
||||
target_include_directories(MainApp
|
||||
PUBLIC ${CMAKE_SOURCE_DIR}/Common
|
||||
PRIVATE ${OPENSSL_INC}
|
||||
)
|
||||
target_link_libraries(MainApp PRIVATE Common Qt5::Core Qt5::Gui Qt5::Widgets)
|
||||
|
||||
if(WIN32)
|
||||
get_target_property(QT_WINDEPLOYQT_EXE Qt5::qmake IMPORTED_LOCATION)
|
||||
get_filename_component(QT_BIN_PATH "${QT_WINDEPLOYQT_EXE}" DIRECTORY)
|
||||
set(WINDEPLOYQT "${QT_BIN_PATH}/windeployqt.exe")
|
||||
add_custom_command(TARGET MainApp POST_BUILD
|
||||
COMMAND ${WINDEPLOYQT} $<IF:$<CONFIG:Debug>,--debug,--release> $<TARGET_FILE:MainApp>
|
||||
)
|
||||
endif()
|
||||
set(_main_app_sources
|
||||
main.cpp
|
||||
MainWindow.h
|
||||
MainWindow.cpp
|
||||
)
|
||||
|
||||
add_executable(MainApp ${_main_app_sources})
|
||||
target_compile_features(MainApp PRIVATE cxx_std_17)
|
||||
target_link_libraries(MainApp
|
||||
PRIVATE
|
||||
Common
|
||||
Qt5::Core
|
||||
Qt5::Gui
|
||||
Qt5::Widgets
|
||||
)
|
||||
update_client_link_embedded_resources(MainApp)
|
||||
update_client_deploy_openssl_runtime(MainApp)
|
||||
update_client_enable_qt_deployment(MainApp)
|
||||
|
||||
+11
-11
@@ -12,10 +12,10 @@ static QString readDllVersion(const QString& dllPath)
|
||||
{
|
||||
QFile file(dllPath);
|
||||
if (!file.exists())
|
||||
return "missing";
|
||||
return QCoreApplication::translate("MainWindow", "missing");
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
return "unreadable";
|
||||
return QCoreApplication::translate("MainWindow", "unreadable");
|
||||
|
||||
QByteArray data = file.read(1024);
|
||||
file.close();
|
||||
@@ -25,12 +25,12 @@ static QString readDllVersion(const QString& dllPath)
|
||||
MainWindow::MainWindow(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
this->setWindowTitle("Marsco Demo MainApp");
|
||||
this->setWindowTitle(tr("Marsco Demo MainApp"));
|
||||
this->resize(600, 400);
|
||||
|
||||
QString appVersion = ConfigHelper::instance().getValue("App", "current_version");
|
||||
if (appVersion.isEmpty())
|
||||
appVersion = "unknown";
|
||||
appVersion = tr("unknown");
|
||||
|
||||
QString dllVersion = readDllVersion(QApplication::applicationDirPath() + "/plugins/demo_plugin.dll");
|
||||
|
||||
@@ -38,27 +38,27 @@ MainWindow::MainWindow(QWidget* parent)
|
||||
QString policyResult;
|
||||
if (!policy.loadPolicy("config/version_policy.dat"))
|
||||
{
|
||||
policyResult = "policy missing";
|
||||
policyResult = tr("policy missing");
|
||||
}
|
||||
else if (!policy.isValid())
|
||||
{
|
||||
policyResult = "policy invalid";
|
||||
policyResult = tr("policy invalid");
|
||||
}
|
||||
else if (!policy.isVersionAllowed(appVersion))
|
||||
{
|
||||
policyResult = "version disabled";
|
||||
policyResult = tr("version disabled");
|
||||
}
|
||||
else if (policy.isExpired())
|
||||
{
|
||||
policyResult = "policy expired";
|
||||
policyResult = tr("policy expired");
|
||||
}
|
||||
else
|
||||
{
|
||||
policyResult = "policy ok";
|
||||
policyResult = tr("policy ok");
|
||||
}
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
QLabel* label = new QLabel(QString("Software Running Successfully\nVersion: %1\nDLL Version: %2\nPolicy: %3")
|
||||
QLabel* label = new QLabel(tr("Software Running Successfully\nVersion: %1\nDLL Version: %2\nPolicy: %3")
|
||||
.arg(appVersion)
|
||||
.arg(dllVersion)
|
||||
.arg(policyResult));
|
||||
@@ -69,4 +69,4 @@ MainWindow::MainWindow(QWidget* parent)
|
||||
|
||||
layout->addWidget(label);
|
||||
this->setLayout(layout);
|
||||
}
|
||||
}
|
||||
|
||||
+50
-18
@@ -1,7 +1,5 @@
|
||||
#include <Windows.h>
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include <QTextCodec>
|
||||
#include <QMessageBox>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
@@ -13,13 +11,14 @@
|
||||
#include "../Common/TicketHelper.h"
|
||||
#include "../Common/IntegrityHelper.h"
|
||||
#include "../Common/DeviceIdentityHelper.h"
|
||||
#include "../Common/TranslationHelper.h"
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
SetConsoleOutputCP(936);
|
||||
QTextCodec::setCodecForLocale(QTextCodec::codecForName("GBK"));
|
||||
|
||||
QApplication a(argc, argv);
|
||||
QApplication::setApplicationName("Marsco MainApp");
|
||||
TranslationHelper translation;
|
||||
translation.installForSystemLocale();
|
||||
|
||||
qDebug() << Qt::endl << "entered main app" << Qt::endl;
|
||||
|
||||
@@ -44,8 +43,9 @@ int main(int argc, char* argv[])
|
||||
config.getValue("App", "current_version"), config.getValue("App", "launch_token"),
|
||||
&ticketError))
|
||||
{
|
||||
QMessageBox::critical(nullptr, "Startup Restriction",
|
||||
QString("Invalid or missing one-time launch ticket: %1\nPlease use %2.")
|
||||
QMessageBox::critical(nullptr,
|
||||
QCoreApplication::translate("MainApp", "Startup Restriction"),
|
||||
QCoreApplication::translate("MainApp", "Invalid or missing one-time launch ticket: %1\nPlease use %2.")
|
||||
.arg(ticketError, launcherExecutable));
|
||||
return -1;
|
||||
}
|
||||
@@ -55,48 +55,76 @@ int main(int argc, char* argv[])
|
||||
DeviceIdentityHelper identity(appDir);
|
||||
if (!identity.verifyLocal(config.getValue("App", "app_id"), config.getValue("App", "channel")))
|
||||
{
|
||||
QMessageBox::critical(nullptr, "License Error", QString("Local license invalid: %1").arg(identity.errorString()));
|
||||
QMessageBox::critical(nullptr,
|
||||
QCoreApplication::translate("MainApp", "License Error"),
|
||||
QCoreApplication::translate("MainApp", "Local license invalid: %1").arg(identity.errorString()));
|
||||
return -1;
|
||||
}
|
||||
PolicyHelper policy(appDir);
|
||||
if (!policy.loadPolicy("config/version_policy.dat") || !policy.isValid())
|
||||
{
|
||||
QMessageBox::critical(nullptr, "Policy Error", QString("Local policy invalid: %1").arg(policy.errorString()));
|
||||
QMessageBox::critical(nullptr,
|
||||
QCoreApplication::translate("MainApp", "Policy Error"),
|
||||
QCoreApplication::translate("MainApp", "Local policy invalid: %1").arg(policy.errorString()));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (policy.isExpired())
|
||||
{
|
||||
QMessageBox::critical(nullptr, "Policy Error", "Policy expired, cannot start the application.");
|
||||
QMessageBox::critical(nullptr,
|
||||
QCoreApplication::translate("MainApp", "Policy Error"),
|
||||
QCoreApplication::translate("MainApp", "Policy expired. The application cannot start."));
|
||||
return -1;
|
||||
}
|
||||
|
||||
const QString currentVersion = config.getValue("App", "current_version");
|
||||
if (!policy.isApplicable(config.getValue("App", "app_id"),
|
||||
config.getValue("App", "channel"),
|
||||
currentVersion)
|
||||
|| !policy.allowRun() || !policy.isVersionAllowed(currentVersion))
|
||||
{
|
||||
QMessageBox::critical(
|
||||
nullptr,
|
||||
QCoreApplication::translate("MainApp", "Policy Error"),
|
||||
QCoreApplication::translate(
|
||||
"MainApp",
|
||||
"The signed policy does not allow this installed version to run."));
|
||||
return -1;
|
||||
}
|
||||
|
||||
LocalStateHelper state(appDir);
|
||||
if (!state.loadState())
|
||||
{
|
||||
QMessageBox::critical(nullptr, "State Error", QString("Cannot load local state: %1").arg(state.errorString()));
|
||||
QMessageBox::critical(nullptr,
|
||||
QCoreApplication::translate("MainApp", "State Error"),
|
||||
QCoreApplication::translate("MainApp", "Cannot load local state: %1").arg(state.errorString()));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (state.isPolicySeqRolledBack(policy.policySeq()))
|
||||
{
|
||||
QMessageBox::critical(nullptr, "Policy Error", "Detected policy sequence rollback, startup blocked.");
|
||||
QMessageBox::critical(nullptr,
|
||||
QCoreApplication::translate("MainApp", "Policy Error"),
|
||||
QCoreApplication::translate("MainApp", "A policy sequence rollback was detected, so startup was blocked."));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (state.isSystemTimeRewound())
|
||||
{
|
||||
QMessageBox::critical(nullptr, "Policy Error", "System time appears to be rewound, startup blocked.");
|
||||
QMessageBox::critical(nullptr,
|
||||
QCoreApplication::translate("MainApp", "Policy Error"),
|
||||
QCoreApplication::translate("MainApp", "The system clock appears to have moved backward, so startup was blocked."));
|
||||
return -1;
|
||||
}
|
||||
|
||||
IntegrityHelper integrity(installRoot);
|
||||
if (!integrity.verifyInstalledVersion(
|
||||
config.getValue("App", "app_id"), config.getValue("App", "channel"),
|
||||
config.getValue("App", "current_version")))
|
||||
currentVersion))
|
||||
{
|
||||
QMessageBox::critical(nullptr, "Integrity Check Failed",
|
||||
QString("Application files failed signed Manifest verification:\n%1")
|
||||
QMessageBox::critical(nullptr,
|
||||
QCoreApplication::translate("MainApp", "Integrity Check Failed"),
|
||||
QCoreApplication::translate("MainApp", "Application files failed signed manifest verification:\n%1")
|
||||
.arg(integrity.errorString()));
|
||||
return -1;
|
||||
}
|
||||
@@ -107,7 +135,9 @@ int main(int argc, char* argv[])
|
||||
state.updateAfterSuccessfulRun(ConfigHelper::instance().getValue("App", "current_version"), policy.policySeq());
|
||||
if (!state.saveState())
|
||||
{
|
||||
QMessageBox::critical(nullptr, "State Error", QString("Cannot save local state: %1").arg(state.errorString()));
|
||||
QMessageBox::critical(nullptr,
|
||||
QCoreApplication::translate("MainApp", "State Error"),
|
||||
QCoreApplication::translate("MainApp", "Cannot save local state: %1").arg(state.errorString()));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -120,7 +150,9 @@ int main(int argc, char* argv[])
|
||||
|| healthFile.write(healthy) != healthy.size()
|
||||
|| !healthFile.commit())
|
||||
{
|
||||
QMessageBox::critical(nullptr, "Startup Error", "Cannot write update health confirmation file.");
|
||||
QMessageBox::critical(nullptr,
|
||||
QCoreApplication::translate("MainApp", "Startup Error"),
|
||||
QCoreApplication::translate("MainApp", "Cannot write the update health confirmation file."));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user