mirror of
https://github.com/BeamMP/BeamMP-Server.git
synced 2025-07-01 15:26:59 +00:00
Add mod hash caching and mod protection
This commit is contained in:
parent
6c3174ac08
commit
7a439bb5b9
@ -30,6 +30,7 @@ public:
|
|||||||
[[nodiscard]] std::string TrimmedList() const { return mTrimmedList; }
|
[[nodiscard]] std::string TrimmedList() const { return mTrimmedList; }
|
||||||
[[nodiscard]] std::string FileSizes() const { return mFileSizes; }
|
[[nodiscard]] std::string FileSizes() const { return mFileSizes; }
|
||||||
[[nodiscard]] int ModsLoaded() const { return mModsLoaded; }
|
[[nodiscard]] int ModsLoaded() const { return mModsLoaded; }
|
||||||
|
[[nodiscard]] nlohmann::json GetMods() const { return mMods; }
|
||||||
|
|
||||||
[[nodiscard]] std::string NewFileList() const;
|
[[nodiscard]] std::string NewFileList() const;
|
||||||
|
|
||||||
|
@ -810,6 +810,11 @@ void TNetwork::SendFile(TClient& c, const std::string& UnsafeName) {
|
|||||||
auto FileName = fs::path(UnsafeName).filename().string();
|
auto FileName = fs::path(UnsafeName).filename().string();
|
||||||
FileName = Application::Settings.getAsString(Settings::Key::General_ResourceFolder) + "/Client/" + FileName;
|
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 (!std::filesystem::exists(FileName)) {
|
||||||
if (!TCPSend(c, StringToVector("CO"))) {
|
if (!TCPSend(c, StringToVector("CO"))) {
|
||||||
// TODO: handle
|
// TODO: handle
|
||||||
|
@ -66,14 +66,52 @@ void TResourceManager::RefreshFiles() {
|
|||||||
std::unique_lock Lock(mModsMutex);
|
std::unique_lock Lock(mModsMutex);
|
||||||
|
|
||||||
std::string Path = Application::Settings.getAsString(Settings::Key::General_ResourceFolder) + "/Client";
|
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)) {
|
for (const auto& entry : fs::directory_iterator(Path)) {
|
||||||
std::string File(entry.path().string());
|
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())) {
|
if (entry.path().extension() != ".zip" || std::filesystem::is_directory(entry.path())) {
|
||||||
beammp_warnf("'{}' is not a ZIP file and will be ignored", File);
|
beammp_warnf("'{}' is not a ZIP file and will be ignored", File);
|
||||||
continue;
|
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 {
|
try {
|
||||||
EVP_MD_CTX* mdctx;
|
EVP_MD_CTX* mdctx;
|
||||||
const EVP_MD* md;
|
const EVP_MD* md;
|
||||||
@ -133,9 +171,28 @@ void TResourceManager::RefreshFiles() {
|
|||||||
{ "file_size", std::filesystem::file_size(File) },
|
{ "file_size", std::filesystem::file_size(File) },
|
||||||
{ "hash_algorithm", "sha256" },
|
{ "hash_algorithm", "sha256" },
|
||||||
{ "hash", result },
|
{ "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) {
|
} catch (const std::exception& e) {
|
||||||
beammp_errorf("Sha256 hashing of '{}' failed: {}", File, e.what());
|
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()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user