2026-07-09 09:17:30 +00:00
|
|
|
#include <QApplication>
|
|
|
|
|
#include <QDebug>
|
|
|
|
|
#include <QMessageBox>
|
|
|
|
|
#include <QDir>
|
|
|
|
|
#include <QFileInfo>
|
|
|
|
|
#include <QSaveFile>
|
|
|
|
|
#include "MainWindow.h"
|
|
|
|
|
#include "../Common/ConfigHelper.h"
|
|
|
|
|
#include "../Common/PolicyHelper.h"
|
|
|
|
|
#include "../Common/LocalStateHelper.h"
|
|
|
|
|
#include "../Common/TicketHelper.h"
|
|
|
|
|
#include "../Common/IntegrityHelper.h"
|
|
|
|
|
#include "../Common/DeviceIdentityHelper.h"
|
2026-07-10 00:38:23 -07:00
|
|
|
#include "../Common/TranslationHelper.h"
|
2026-07-09 09:17:30 +00:00
|
|
|
|
|
|
|
|
int main(int argc, char* argv[])
|
|
|
|
|
{
|
|
|
|
|
QApplication a(argc, argv);
|
2026-07-10 00:38:23 -07:00
|
|
|
QApplication::setApplicationName("Marsco MainApp");
|
|
|
|
|
TranslationHelper translation;
|
|
|
|
|
translation.installForSystemLocale();
|
2026-07-09 09:17:30 +00:00
|
|
|
|
|
|
|
|
qDebug() << Qt::endl << "entered main app" << Qt::endl;
|
|
|
|
|
|
|
|
|
|
ConfigHelper& config = ConfigHelper::instance();
|
|
|
|
|
QString launcherExecutable = config.getValue("Runtime", "launcher_executable").trimmed();
|
|
|
|
|
if (launcherExecutable.isEmpty()) launcherExecutable = "Launcher.exe";
|
|
|
|
|
QString ticketFilePath;
|
|
|
|
|
QString healthFilePath;
|
|
|
|
|
for (int i = 1; i < argc; ++i)
|
|
|
|
|
{
|
|
|
|
|
const QString arg(argv[i]);
|
|
|
|
|
if (arg.startsWith("--ticket-file="))
|
|
|
|
|
ticketFilePath = arg.mid(QString("--ticket-file=").size());
|
|
|
|
|
else if (arg.startsWith("--health-file="))
|
|
|
|
|
healthFilePath = arg.mid(QString("--health-file=").size());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString ticketError;
|
|
|
|
|
if (ticketFilePath.isEmpty()
|
|
|
|
|
|| !TicketHelper::consumeAndVerify(ticketFilePath,
|
|
|
|
|
config.getValue("App", "app_id"), config.getValue("Update", "device_id"),
|
|
|
|
|
config.getValue("App", "current_version"), config.getValue("App", "launch_token"),
|
|
|
|
|
&ticketError))
|
|
|
|
|
{
|
2026-07-10 00:38:23 -07:00
|
|
|
QMessageBox::critical(nullptr,
|
|
|
|
|
QCoreApplication::translate("MainApp", "Startup Restriction"),
|
|
|
|
|
QCoreApplication::translate("MainApp", "Invalid or missing one-time launch ticket: %1\nPlease use %2.")
|
2026-07-09 09:17:30 +00:00
|
|
|
.arg(ticketError, launcherExecutable));
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString appDir = QApplication::applicationDirPath();
|
|
|
|
|
const QString installRoot = config.installRoot();
|
|
|
|
|
DeviceIdentityHelper identity(appDir);
|
|
|
|
|
if (!identity.verifyLocal(config.getValue("App", "app_id"), config.getValue("App", "channel")))
|
|
|
|
|
{
|
2026-07-10 00:38:23 -07:00
|
|
|
QMessageBox::critical(nullptr,
|
|
|
|
|
QCoreApplication::translate("MainApp", "License Error"),
|
|
|
|
|
QCoreApplication::translate("MainApp", "Local license invalid: %1").arg(identity.errorString()));
|
2026-07-09 09:17:30 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
PolicyHelper policy(appDir);
|
|
|
|
|
if (!policy.loadPolicy("config/version_policy.dat") || !policy.isValid())
|
|
|
|
|
{
|
2026-07-10 00:38:23 -07:00
|
|
|
QMessageBox::critical(nullptr,
|
|
|
|
|
QCoreApplication::translate("MainApp", "Policy Error"),
|
|
|
|
|
QCoreApplication::translate("MainApp", "Local policy invalid: %1").arg(policy.errorString()));
|
2026-07-09 09:17:30 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (policy.isExpired())
|
|
|
|
|
{
|
2026-07-10 00:38:23 -07:00
|
|
|
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."));
|
2026-07-09 09:17:30 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LocalStateHelper state(appDir);
|
|
|
|
|
if (!state.loadState())
|
|
|
|
|
{
|
2026-07-10 00:38:23 -07:00
|
|
|
QMessageBox::critical(nullptr,
|
|
|
|
|
QCoreApplication::translate("MainApp", "State Error"),
|
|
|
|
|
QCoreApplication::translate("MainApp", "Cannot load local state: %1").arg(state.errorString()));
|
2026-07-09 09:17:30 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (state.isPolicySeqRolledBack(policy.policySeq()))
|
|
|
|
|
{
|
2026-07-10 00:38:23 -07:00
|
|
|
QMessageBox::critical(nullptr,
|
|
|
|
|
QCoreApplication::translate("MainApp", "Policy Error"),
|
|
|
|
|
QCoreApplication::translate("MainApp", "A policy sequence rollback was detected, so startup was blocked."));
|
2026-07-09 09:17:30 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (state.isSystemTimeRewound())
|
|
|
|
|
{
|
2026-07-10 00:38:23 -07:00
|
|
|
QMessageBox::critical(nullptr,
|
|
|
|
|
QCoreApplication::translate("MainApp", "Policy Error"),
|
|
|
|
|
QCoreApplication::translate("MainApp", "The system clock appears to have moved backward, so startup was blocked."));
|
2026-07-09 09:17:30 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IntegrityHelper integrity(installRoot);
|
|
|
|
|
if (!integrity.verifyInstalledVersion(
|
|
|
|
|
config.getValue("App", "app_id"), config.getValue("App", "channel"),
|
2026-07-10 00:38:23 -07:00
|
|
|
currentVersion))
|
2026-07-09 09:17:30 +00:00
|
|
|
{
|
2026-07-10 00:38:23 -07:00
|
|
|
QMessageBox::critical(nullptr,
|
|
|
|
|
QCoreApplication::translate("MainApp", "Integrity Check Failed"),
|
|
|
|
|
QCoreApplication::translate("MainApp", "Application files failed signed manifest verification:\n%1")
|
2026-07-09 09:17:30 +00:00
|
|
|
.arg(integrity.errorString()));
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MainWindow w;
|
|
|
|
|
w.show();
|
|
|
|
|
|
|
|
|
|
state.updateAfterSuccessfulRun(ConfigHelper::instance().getValue("App", "current_version"), policy.policySeq());
|
|
|
|
|
if (!state.saveState())
|
|
|
|
|
{
|
2026-07-10 00:38:23 -07:00
|
|
|
QMessageBox::critical(nullptr,
|
|
|
|
|
QCoreApplication::translate("MainApp", "State Error"),
|
|
|
|
|
QCoreApplication::translate("MainApp", "Cannot save local state: %1").arg(state.errorString()));
|
2026-07-09 09:17:30 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!healthFilePath.isEmpty())
|
|
|
|
|
{
|
|
|
|
|
QDir().mkpath(QFileInfo(healthFilePath).path());
|
|
|
|
|
QSaveFile healthFile(healthFilePath);
|
|
|
|
|
const QByteArray healthy("ok\n");
|
|
|
|
|
if (!healthFile.open(QIODevice::WriteOnly)
|
|
|
|
|
|| healthFile.write(healthy) != healthy.size()
|
|
|
|
|
|| !healthFile.commit())
|
|
|
|
|
{
|
2026-07-10 00:38:23 -07:00
|
|
|
QMessageBox::critical(nullptr,
|
|
|
|
|
QCoreApplication::translate("MainApp", "Startup Error"),
|
|
|
|
|
QCoreApplication::translate("MainApp", "Cannot write the update health confirmation file."));
|
2026-07-09 09:17:30 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
qDebug() << "Main program MainApp is running normally";
|
|
|
|
|
return a.exec();
|
|
|
|
|
}
|