#include "UpdatePathPolicy.h" #include #include #include #include namespace { bool exactOrRuntimeMatch(const QString& folded, const QString& runtimePrefix, const QSet& exactPaths) { if (exactPaths.contains(folded)) return true; if (runtimePrefix.isEmpty() || !folded.startsWith(runtimePrefix + QStringLiteral("/"))) return false; return exactPaths.contains(folded.mid(runtimePrefix.size() + 1)); } bool prefixOrRuntimePrefixMatch(const QString& folded, const QString& runtimePrefix, const QString& prefix) { if (folded.startsWith(prefix)) return true; if (runtimePrefix.isEmpty()) return false; return folded.startsWith(runtimePrefix + QStringLiteral("/") + prefix); } } // namespace namespace UpdatePathPolicy { QString normalizeRelativePath(const QString& path) { QString normalized = QDir::cleanPath(QDir::fromNativeSeparators(path.trimmed())); if (normalized == QStringLiteral(".")) return QString(); while (normalized.startsWith(QStringLiteral("./"))) normalized = normalized.mid(2); return normalized; } bool isSafeRelativePath(const QString& path) { const QString clean = normalizeRelativePath(path); return !clean.isEmpty() && !QDir::isAbsolutePath(clean) && clean != QStringLiteral("..") && !clean.startsWith(QStringLiteral("../")) && !clean.contains(QLatin1Char(':')); } bool isUpdaterRuntimeProtectedPath(const QString& path, const QString& runtimeRelativePath) { const QString folded = normalizeRelativePath(path).toCaseFolded(); const QString runtimePrefix = normalizeRelativePath(runtimeRelativePath).toCaseFolded(); const QSet exactPaths{ QStringLiteral("bootstrap"), QStringLiteral("bootstrap.exe"), QStringLiteral("launcher"), QStringLiteral("launcher.exe"), QStringLiteral("updater"), QStringLiteral("updater.exe"), QStringLiteral("client.ini"), QStringLiteral("config/app_config.json"), QStringLiteral("config/local_state.json"), QStringLiteral("config/client_identity.dat"), QStringLiteral("config/version_policy.dat") }; if (exactOrRuntimeMatch(folded, runtimePrefix, exactPaths)) return true; return prefixOrRuntimePrefixMatch(folded, runtimePrefix, QStringLiteral("update/")) || prefixOrRuntimePrefixMatch(folded, runtimePrefix, QStringLiteral("update_temp/")); } bool isIFWInstallerManagedPath(const QString& path) { const QString folded = normalizeRelativePath(path).toCaseFolded(); if (folded.isEmpty()) return false; const bool rootFile = !folded.contains(QLatin1Char('/')); if (rootFile && (folded == QStringLiteral("maintenancetool") || folded == QStringLiteral("maintenancetool.exe") || folded.startsWith(QStringLiteral("maintenancetool.")))) { return true; } const QSet exactPaths{ QStringLiteral("components.xml"), QStringLiteral("components.xml.new"), QStringLiteral("components.xml.old"), QStringLiteral("installation.xml"), QStringLiteral("installation.dat"), QStringLiteral("installer.dat"), QStringLiteral("installer.ini"), QStringLiteral("network.xml"), QStringLiteral("repositories.xml"), QStringLiteral("repositories.cfg"), QStringLiteral("repository.xml") }; if (exactPaths.contains(folded)) return true; const QStringList prefixes{ QStringLiteral("installerresources/"), QStringLiteral("installationinformation/"), QStringLiteral("licenses/") }; for (const QString& prefix : prefixes) { if (folded.startsWith(prefix)) return true; } return false; } bool isFullUpdateProtectedPath(const QString& path, const QString& runtimeRelativePath) { return isUpdaterRuntimeProtectedPath(path, runtimeRelativePath) || isIFWInstallerManagedPath(path); } bool isExecutableOrLibrary(const QString& path) { const QString suffix = QFileInfo(path).suffix().toCaseFolded(); return suffix == QStringLiteral("exe") || suffix == QStringLiteral("dll"); } } // namespace UpdatePathPolicy