Add mod hash caching and mod protection

This commit is contained in:
Tixx 2025-03-31 08:04:15 +02:00
parent 6c3174ac08
commit 7a439bb5b9
No known key found for this signature in database
GPG Key ID: EC6E7A2BAABF0B8C
3 changed files with 63 additions and 0 deletions

View File

@ -30,6 +30,7 @@ public:
[[nodiscard]] std::string TrimmedList() const { return mTrimmedList; }
[[nodiscard]] std::string FileSizes() const { return mFileSizes; }
[[nodiscard]] int ModsLoaded() const { return mModsLoaded; }
[[nodiscard]] nlohmann::json GetMods() const { return mMods; }
[[nodiscard]] std::string NewFileList() const;

View File

@ -810,6 +810,11 @@ void TNetwork::SendFile(TClient& c, const std::string& UnsafeName) {
auto FileName = fs::path(UnsafeName).filename().string();
FileName = Application::Settings.getAsString(Settings::Key::General_ResourceFolder) + "/Client/" + FileName;
for (auto mod : mResourceManager.GetMods()) {
if (mod["filename"] == FileName && mod["protected"] == true)
return;
}
if (!std::filesystem::exists(FileName)) {
if (!TCPSend(c, StringToVector("CO"))) {
// TODO: handle

View File

@ -66,14 +66,52 @@ void TResourceManager::RefreshFiles() {
std::unique_lock Lock(mModsMutex);
std::string Path = Application::Settings.getAsString(Settings::Key::General_ResourceFolder) + "/Client";
nlohmann::json modsDB;
if (std::filesystem::exists(Path + "/mods.json")) {
try {
std::ifstream stream(Path + "/mods.json");
stream >> modsDB;
stream.close();
} catch (const std::exception& e) {
beammp_errorf("Failed to load mods.json: {}", e.what());
}
}
for (const auto& entry : fs::directory_iterator(Path)) {
std::string File(entry.path().string());
if (entry.path().filename().string() == "mods.json") {
continue;
}
if (entry.path().extension() != ".zip" || std::filesystem::is_directory(entry.path())) {
beammp_warnf("'{}' is not a ZIP file and will be ignored", File);
continue;
}
if (modsDB.contains(entry.path().filename().string())) {
auto dbEntry = modsDB[entry.path().filename().string()];
if (entry.last_write_time().time_since_epoch().count() > dbEntry["lastwrite"] || std::filesystem::file_size(File) != dbEntry["filesize"].get<size_t>()) {
beammp_infof("File '{}' has been modified, rehashing", File);
} else {
mMods.push_back(nlohmann::json {
{ "file_name", std::filesystem::path(File).filename() },
{ "file_size", std::filesystem::file_size(File) },
{ "hash_algorithm", "sha256" },
{ "hash", dbEntry["hash"] },
{ "protected", dbEntry["protected"] }
});
beammp_debugf("Mod '{}' loaded from cache", File);
continue;
}
}
try {
EVP_MD_CTX* mdctx;
const EVP_MD* md;
@ -133,9 +171,28 @@ void TResourceManager::RefreshFiles() {
{ "file_size", std::filesystem::file_size(File) },
{ "hash_algorithm", "sha256" },
{ "hash", result },
{ "protected", false }
});
modsDB[std::filesystem::path(File).filename().string()] = {
{ "lastwrite", entry.last_write_time().time_since_epoch().count() },
{ "hash", result },
{ "filesize", std::filesystem::file_size(File) },
{ "protected", false }
};
} catch (const std::exception& e) {
beammp_errorf("Sha256 hashing of '{}' failed: {}", File, e.what());
}
}
try {
std::ofstream stream(Path + "/mods.json");
stream << modsDB.dump(4);
stream.close();
} catch (std::exception& e) {
beammp_error("Failed to update mod DB: " + std::string(e.what()));
}
}