mirror of
https://github.com/HarbourMasters/Shipwright
synced 2026-06-10 05:03:29 -04:00
Fix Malformed Preset Filenames (#6712)
Sanitize preset names for filesystem safety, log errors without crashing Co-authored-by: Unreference <87878910+unreference@users.noreply.github.com>
This commit is contained in:
@@ -14,11 +14,37 @@
|
||||
#include "soh/Enhancements/randomizer/randomizer_check_tracker.h"
|
||||
#include "soh/Enhancements/randomizer/randomizer_entrance_tracker.h"
|
||||
#include "soh/Enhancements/randomizer/randomizer_item_tracker.h"
|
||||
#include "soh/Enhancements/randomizer/SeedContext.h"
|
||||
#include "soh/Enhancements/randomizer/settings.h"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
/**
|
||||
* Replace characters to prevent crashes from invalid paths (e.g, "test :)" creating an NTFS Alternate Data Stream
|
||||
* instead of a regular file).
|
||||
*/
|
||||
static std::string SanitizeFilename(const std::string& name) {
|
||||
std::string result;
|
||||
result.reserve(name.size());
|
||||
for (const char c : name) {
|
||||
if (c == '<' || c == '>' || c == ':' || c == '"' || c == '/' || c == '\\' || c == '|' || c == '?' || c == '*' ||
|
||||
c < 32) {
|
||||
result += '_';
|
||||
} else {
|
||||
result += c;
|
||||
}
|
||||
}
|
||||
|
||||
while (!result.empty() && (result.back() == '.' || result.back() == ' ')) {
|
||||
result.pop_back();
|
||||
}
|
||||
|
||||
if (result.empty()) {
|
||||
result = "Unnamed";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace SohGui {
|
||||
extern std::shared_ptr<SohMenu> mSohMenu;
|
||||
} // namespace SohGui
|
||||
@@ -75,7 +101,7 @@ static BlockInfo blockInfo[PRESET_SECTION_MAX] = {
|
||||
};
|
||||
|
||||
std::string FormatPresetPath(std::string name) {
|
||||
return fmt::format("{}/{}.json", presetFolder, name);
|
||||
return fmt::format("{}/{}.json", presetFolder, SanitizeFilename(name));
|
||||
}
|
||||
|
||||
void applyPreset(std::string presetName, std::vector<PresetSection> includeSections) {
|
||||
@@ -220,16 +246,19 @@ void LoadPresets() {
|
||||
}
|
||||
if (fs::exists(presetFolder)) {
|
||||
for (auto const& preset : fs::directory_iterator(presetFolder)) {
|
||||
std::ifstream ifs(preset.path());
|
||||
try {
|
||||
std::ifstream ifs(preset.path());
|
||||
if (auto json = nlohmann::json::parse(ifs); !json.contains("presetName")) {
|
||||
spdlog::error(fmt::format("Attempted to load file {} as a preset, but was not a preset file.",
|
||||
preset.path().filename().string()));
|
||||
} else {
|
||||
ParsePreset(json, preset.path().filename().stem().string());
|
||||
}
|
||||
|
||||
auto json = nlohmann::json::parse(ifs);
|
||||
if (!json.contains("presetName")) {
|
||||
spdlog::error(fmt::format("Attempted to load file {} as a preset, but was not a preset file.",
|
||||
preset.path().filename().string()));
|
||||
} else {
|
||||
ParsePreset(json, preset.path().filename().stem().string());
|
||||
ifs.close();
|
||||
} catch (const std::exception& e) {
|
||||
spdlog::error("Failed to load preset {}: {}", preset.path().filename().string(), e.what());
|
||||
}
|
||||
ifs.close();
|
||||
}
|
||||
}
|
||||
auto initData = std::make_shared<Ship::ResourceInitData>();
|
||||
@@ -255,8 +284,16 @@ void SavePreset(std::string& presetName) {
|
||||
}
|
||||
presets[presetName].presetValues["presetName"] = presetName;
|
||||
presets[presetName].presetValues["fileType"] = FILE_TYPE_PRESET;
|
||||
|
||||
std::string safeFilename = SanitizeFilename(presetName);
|
||||
std::ofstream file(
|
||||
fmt::format("{}/{}.json", Ship::Context::GetRawInstance()->LocateFileAcrossAppDirs("presets"), presetName));
|
||||
fmt::format("{}/{}.json", Ship::Context::GetRawInstance()->LocateFileAcrossAppDirs("presets"), safeFilename));
|
||||
|
||||
if (!file.is_open()) {
|
||||
spdlog::error("Failed to save preset '{}': Could not create file", presetName);
|
||||
return;
|
||||
}
|
||||
|
||||
file << presets[presetName].presetValues.dump(4);
|
||||
file.close();
|
||||
LoadPresets();
|
||||
|
||||
Reference in New Issue
Block a user