summaryrefslogtreecommitdiff
path: root/src/sanitychecks.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/sanitychecks.cpp')
-rw-r--r--src/sanitychecks.cpp174
1 files changed, 174 insertions, 0 deletions
diff --git a/src/sanitychecks.cpp b/src/sanitychecks.cpp
new file mode 100644
index 00000000..5f9705b8
--- /dev/null
+++ b/src/sanitychecks.cpp
@@ -0,0 +1,174 @@
+#include "env.h"
+#include "envmodule.h"
+#include <log.h>
+
+using namespace MOBase;
+
+enum class SecurityZone
+{
+ NoZone = -1,
+ MyComputer = 0,
+ Intranet = 1,
+ Trusted = 2,
+ Internet = 3,
+ Untrusted = 4,
+};
+
+QString toString(SecurityZone z)
+{
+ switch (z)
+ {
+ case SecurityZone::NoZone: return "NoZone";
+ case SecurityZone::MyComputer: return "MyComputer";
+ case SecurityZone::Intranet: return "Intranet";
+ case SecurityZone::Trusted: return "Trusted";
+ case SecurityZone::Internet: return "Internet";
+ case SecurityZone::Untrusted: return "Untrusted";
+ default: return QString("unknown (%1)").arg(static_cast<int>(z));
+ }
+}
+
+bool isZoneBlocked(SecurityZone z)
+{
+ return (z == SecurityZone::Internet || z == SecurityZone::Untrusted);
+}
+
+bool isFileBlocked(const QFileInfo& fi)
+{
+ const QString ads = "Zone.Identifier";
+ const auto key = "ZoneTransfer/ZoneId";
+
+ const auto path = fi.absoluteFilePath();
+ const auto adsPath = path + ":" + ads;
+
+ QFile f(adsPath);
+ if (!f.exists()) {
+ return false;
+ }
+
+ log::debug("file '{}' has an ADS for {}", path, adsPath);
+
+ QSettings qs(adsPath, QSettings::IniFormat);
+
+ if (!qs.contains(key)) {
+ log::debug("but key '{}' is not found", key);
+ return false;
+ }
+
+ const auto v = qs.value(key);
+ if (v.isNull()) {
+ log::debug("but key '{}' is null", key);
+ return false;
+ }
+
+ bool ok = false;
+ const auto z = static_cast<SecurityZone>(v.toInt(&ok));
+
+ if (!ok) {
+ log::debug(
+ "but key '{}' is not an int (value is '{}')",
+ key, v);
+
+ return false;
+ }
+
+ if (!isZoneBlocked(z)) {
+ log::debug(
+ "but zone id is {}, {}, which is fine",
+ static_cast<int>(z), toString(z));
+
+ return false;
+ }
+
+ log::warn(
+ "file '{}' is blocked (zone id is {}, {})",
+ path, static_cast<int>(z), toString(z));
+
+ return true;
+}
+
+void checkBlockedFiles(const QDir& dir)
+{
+ if (!dir.exists()) {
+ log::error(
+ "while checking for blocked files, directory '{}' not found",
+ dir.absolutePath());
+
+ return;
+ }
+
+ const auto files = dir.entryInfoList({"*.dll", "*.exe"}, QDir::Files);
+ if (files.empty()) {
+ log::error(
+ "while checking for blocked files, directory '{}' is empty",
+ dir.absolutePath());
+
+ return;
+ }
+
+ for (auto&& fi : files) {
+ isFileBlocked(fi);
+ }
+}
+
+void checkBlocked()
+{
+ const QString appDir = QCoreApplication::applicationDirPath();
+
+ const QDir dirs[] = {
+ appDir,
+ appDir + "/dlls",
+ appDir + "/loot",
+ appDir + "/NCC",
+ appDir + "/platforms",
+ appDir + "/plugins"
+ };
+
+ for (const auto& d : dirs) {
+ checkBlockedFiles(d);
+ }
+}
+
+void checkMissingFiles()
+{
+ // files that are likely to be eaten
+ static const QStringList files({
+ "helper.exe", "nxmhandler.exe",
+ "usvfs_proxy_x64.exe", "usvfs_proxy_x86.exe",
+ "usvfs_x64.dll", "usvfs_x86.dll"
+ });
+
+ const auto dir = QCoreApplication::applicationDirPath();
+
+ for (const auto& name : files) {
+ const QFileInfo file(dir + QDir::separator() + name);
+ if (!file.exists()) {
+ log::warn(
+ "'{}' seems to be missing, an antivirus may have deleted it",
+ file.absoluteFilePath());
+ }
+ }
+}
+
+void checkNahimic(const env::Environment& e)
+{
+ for (auto&& m : e.loadedModules()) {
+ const QFileInfo file(m.path());
+
+ if (file.fileName().compare("NahimicOSD.dll", Qt::CaseInsensitive) == 0) {
+ log::warn(
+ "NahimicOSD.dll is loaded. Nahimic is known to cause issues with "
+ "Mod Organizer, such as freezing or blank windows. Consider "
+ "uninstalling it.");
+
+ break;
+ }
+ }
+}
+
+void sanityChecks(const env::Environment& e)
+{
+ checkBlocked();
+ checkMissingFiles();
+ checkNahimic(e);
+}