Index: ps/trunk/binaries/data/mods/public/globalscripts/Resources.js =================================================================== --- ps/trunk/binaries/data/mods/public/globalscripts/Resources.js +++ ps/trunk/binaries/data/mods/public/globalscripts/Resources.js @@ -10,7 +10,7 @@ { jsonFiles = Engine.FindJSONFiles("resources", false); for (let file in jsonFiles) - jsonFiles[file] = "resources/" + jsonFiles[file] + ".json"; + jsonFiles[file] = "simulation/data/resources/" + jsonFiles[file] + ".json"; } // GUI context else if (Engine.BuildDirEntList) Index: ps/trunk/binaries/data/mods/public/simulation/components/DataTemplateManager.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/DataTemplateManager.js +++ ps/trunk/binaries/data/mods/public/simulation/components/DataTemplateManager.js @@ -25,7 +25,7 @@ { if (!this.allTechs[template]) { - this.allTechs[template] = Engine.ReadJSONFile("technologies/" + template + ".json"); + this.allTechs[template] = Engine.ReadJSONFile("simulation/data/technologies/" + template + ".json"); if (!this.allTechs[template]) error("Failed to load technology \"" + template + "\""); } @@ -37,7 +37,7 @@ { if (!this.allAuras[template]) { - this.allAuras[template] = Engine.ReadJSONFile("auras/" + template + ".json"); + this.allAuras[template] = Engine.ReadJSONFile("simulation/data/auras/" + template + ".json"); if (!this.allAuras[template]) error("Failed to load aura \"" + template + "\""); } Index: ps/trunk/binaries/data/mods/public/simulation/components/SkirmishReplacer.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/SkirmishReplacer.js +++ ps/trunk/binaries/data/mods/public/simulation/components/SkirmishReplacer.js @@ -15,14 +15,9 @@ SkirmishReplacer.prototype.Serialize = null; // We have no dynamic state to save -//this function gets the replacement entities from the {civ}.json file function getReplacementEntities(civ) { - var rawCivData = Engine.ReadCivJSONFile(civ+".json"); - if (rawCivData && rawCivData.SkirmishReplacements) - return rawCivData.SkirmishReplacements; - warn("SkirmishReplacer.js: no replacements found in '"+civ+".json'"); - return {}; + return Engine.ReadJSONFile("simulation/data/civs/" + civ + ".json").SkirmishReplacements; } SkirmishReplacer.prototype.OnOwnershipChanged = function(msg) Index: ps/trunk/binaries/data/mods/public/simulation/helpers/Player.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/helpers/Player.js +++ ps/trunk/binaries/data/mods/public/simulation/helpers/Player.js @@ -9,20 +9,16 @@ */ function LoadPlayerSettings(settings, newPlayers) { + var playerDefaults = Engine.ReadJSONFile("simulation/data/settings/player_defaults.json").PlayerData; + // Default settings if (!settings) settings = {}; - // Get default player data - var rawData = Engine.ReadJSONFile("settings/player_defaults.json"); - if (!(rawData && rawData.PlayerData)) - throw new Error("Player.js: Error reading player_defaults.json"); - // Add gaia to simplify iteration if (settings.PlayerData && settings.PlayerData[0]) settings.PlayerData.unshift(null); - var playerDefaults = rawData.PlayerData; var playerData = settings.PlayerData; var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); @@ -146,18 +142,9 @@ cmpPlayer.SetTeam(myTeam === undefined ? -1 : myTeam); } - // If formations explicitly defined, use that; otherwise use civ defaults - var formations = getSetting(playerData, playerDefaults, i, "Formations"); - if (formations !== undefined) - cmpPlayer.SetFormations(formations); - else - { - var rawFormations = Engine.ReadCivJSONFile(cmpPlayer.GetCiv()+".json"); - if (!(rawFormations && rawFormations.Formations)) - throw new Error("Player.js: Error reading " + cmpPlayer.GetCiv() + ".json"); - - cmpPlayer.SetFormations(rawFormations.Formations); - } + cmpPlayer.SetFormations( + getSetting(playerData, playerDefaults, i, "Formations") || + Engine.ReadJSONFile("simulation/data/civs/" + cmpPlayer.GetCiv() + ".json").Formations); var startCam = getSetting(playerData, playerDefaults, i, "StartingCamera"); if (startCam !== undefined) Index: ps/trunk/source/graphics/MapGenerator.cpp =================================================================== --- ps/trunk/source/graphics/MapGenerator.cpp +++ ps/trunk/source/graphics/MapGenerator.cpp @@ -100,7 +100,7 @@ m_ScriptInterface->LoadGlobalScripts(); // Functions for RMS - JSI_VFS::RegisterReadOnlyScriptFunctions(*m_ScriptInterface); + JSI_VFS::RegisterScriptFunctions_Maps(*m_ScriptInterface); m_ScriptInterface->RegisterFunction("LoadLibrary"); m_ScriptInterface->RegisterFunction("ExportMap"); m_ScriptInterface->RegisterFunction("SetProgress"); Index: ps/trunk/source/gui/scripting/ScriptFunctions.cpp =================================================================== --- ps/trunk/source/gui/scripting/ScriptFunctions.cpp +++ ps/trunk/source/gui/scripting/ScriptFunctions.cpp @@ -65,7 +65,6 @@ JSI_SavedGame::RegisterScriptFunctions(scriptInterface); JSI_Simulation::RegisterScriptFunctions(scriptInterface); JSI_Sound::RegisterScriptFunctions(scriptInterface); - JSI_VFS::RegisterReadOnlyScriptFunctions(scriptInterface); - JSI_VFS::RegisterWriteScriptFunctions(scriptInterface); + JSI_VFS::RegisterScriptFunctions_GUI(scriptInterface); JSI_VisualReplay::RegisterScriptFunctions(scriptInterface); } Index: ps/trunk/source/ps/scripting/JSInterface_VFS.h =================================================================== --- ps/trunk/source/ps/scripting/JSInterface_VFS.h +++ ps/trunk/source/ps/scripting/JSInterface_VFS.h @@ -56,13 +56,17 @@ JS::Value ReadFileLines(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filename); // Return file contents parsed as a JS Object - JS::Value ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filePath); + JS::Value ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::vector& validPaths, const CStrW& filePath); // Save given JS Object to a JSON file void WriteJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filePath, JS::HandleValue val1); - void RegisterReadOnlyScriptFunctions(const ScriptInterface& scriptInterface); - void RegisterWriteScriptFunctions(const ScriptInterface& scriptInterface); + // Tests whether the current script context is allowed to read from the given directory + bool PathRestrictionMet(ScriptInterface::CxPrivate* pCxPrivate, const std::vector& validPaths, const CStrW& filePath); + + void RegisterScriptFunctions_GUI(const ScriptInterface& scriptInterface); + void RegisterScriptFunctions_Simulation(const ScriptInterface& scriptInterface); + void RegisterScriptFunctions_Maps(const ScriptInterface& scriptInterface); } #endif Index: ps/trunk/source/ps/scripting/JSInterface_VFS.cpp =================================================================== --- ps/trunk/source/ps/scripting/JSInterface_VFS.cpp +++ ps/trunk/source/ps/scripting/JSInterface_VFS.cpp @@ -27,6 +27,11 @@ #include "ps/scripting/JSInterface_VFS.h" #include "lib/file/vfs/vfs_util.h" +// Only allow engine compartments to read files they may be concerned about. +#define PathRestriction_GUI {L""} +#define PathRestriction_Simulation {L"simulation/"} +#define PathRestriction_Maps {L"simulation/", L"maps/"} + // shared error handling code #define JS_CHECK_FILE_ERR(err)\ /* this is liable to happen often, so don't complain */\ @@ -178,8 +183,11 @@ return JS::ObjectValue(*line_array); } -JS::Value JSI_VFS::ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filePath) +JS::Value JSI_VFS::ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::vector& validPaths, const CStrW& filePath) { + if (!PathRestrictionMet(pCxPrivate, validPaths, filePath)) + return JS::NullValue(); + JSContext* cx = pCxPrivate->pScriptInterface->GetContext(); JSAutoRequest rq(cx); JS::RootedValue out(cx); @@ -203,7 +211,42 @@ g_VFS->CreateFile(path, buf.Data(), buf.Size()); } -void JSI_VFS::RegisterReadOnlyScriptFunctions(const ScriptInterface& scriptInterface) +bool JSI_VFS::PathRestrictionMet(ScriptInterface::CxPrivate* pCxPrivate, const std::vector& validPaths, const CStrW& filePath) +{ + for (const CStrW& validPath : validPaths) + if (filePath.find(validPath) == 0) + return true; + + CStrW allowedPaths; + for (std::size_t i = 0; i < validPaths.size(); ++i) + { + if (i != 0) + allowedPaths += L", "; + + allowedPaths += L"\"" + validPaths[i] + L"\""; + } + + JS_ReportError( + pCxPrivate->pScriptInterface->GetContext(), + "This part of the engine may only read from %s!", + utf8_from_wstring(allowedPaths).c_str()); + + return false; +} + +#define VFS_ScriptFunctions(context)\ +JS::Value Script_ReadJSONFile_##context(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filePath)\ +{\ + return JSI_VFS::ReadJSONFile(pCxPrivate, PathRestriction_##context, filePath);\ +} + +VFS_ScriptFunctions(GUI); +VFS_ScriptFunctions(Simulation); +VFS_ScriptFunctions(Maps); + +#undef VFS_ScriptFunctions + +void JSI_VFS::RegisterScriptFunctions_GUI(const ScriptInterface& scriptInterface) { scriptInterface.RegisterFunction("BuildDirEntList"); scriptInterface.RegisterFunction("FileExists"); @@ -211,10 +254,18 @@ scriptInterface.RegisterFunction("GetFileSize"); scriptInterface.RegisterFunction("ReadFile"); scriptInterface.RegisterFunction("ReadFileLines"); - scriptInterface.RegisterFunction("ReadJSONFile"); + scriptInterface.RegisterFunction("ReadJSONFile"); + scriptInterface.RegisterFunction("WriteJSONFile"); } -void JSI_VFS::RegisterWriteScriptFunctions(const ScriptInterface& scriptInterface) +void JSI_VFS::RegisterScriptFunctions_Simulation(const ScriptInterface& scriptInterface) { - scriptInterface.RegisterFunction("WriteJSONFile"); + scriptInterface.RegisterFunction("ReadJSONFile"); +} + +void JSI_VFS::RegisterScriptFunctions_Maps(const ScriptInterface& scriptInterface) +{ + scriptInterface.RegisterFunction("BuildDirEntList"); + scriptInterface.RegisterFunction("FileExists"); + scriptInterface.RegisterFunction("ReadJSONFile"); } Index: ps/trunk/source/simulation2/system/ComponentManager.h =================================================================== --- ps/trunk/source/simulation2/system/ComponentManager.h +++ ps/trunk/source/simulation2/system/ComponentManager.h @@ -333,10 +333,7 @@ static void Script_DestroyEntity(ScriptInterface::CxPrivate* pCxPrivate, int ent); static void Script_FlushDestroyedEntities(ScriptInterface::CxPrivate* pCxPrivate); static bool Script_DataFileExists(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& fileName); - static JS::Value Script_ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& fileName); - static JS::Value Script_ReadCivJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& fileName); static std::vector Script_FindJSONFiles(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& subPath, bool recursive); - static JS::Value ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filePath, const std::wstring& fileName); // callback function to handle recursively finding files in a directory static Status FindJSONFilesCallback(const VfsPath&, const CFileInfo&, const uintptr_t); Index: ps/trunk/source/simulation2/system/ComponentManager.cpp =================================================================== --- ps/trunk/source/simulation2/system/ComponentManager.cpp +++ ps/trunk/source/simulation2/system/ComponentManager.cpp @@ -30,6 +30,7 @@ #include "lib/utf8.h" #include "ps/CLogger.h" #include "ps/Filesystem.h" +#include "ps/scripting/JSInterface_VFS.h" /** * Used for script-only message types. @@ -68,6 +69,7 @@ // these functions, so we skip registering them here in those cases if (!skipScriptFunctions) { + JSI_VFS::RegisterScriptFunctions_Simulation(m_ScriptInterface); m_ScriptInterface.RegisterFunction ("RegisterComponentType"); m_ScriptInterface.RegisterFunction ("RegisterSystemComponentType"); m_ScriptInterface.RegisterFunction ("ReRegisterComponentType"); @@ -84,8 +86,6 @@ m_ScriptInterface.RegisterFunction ("DestroyEntity"); m_ScriptInterface.RegisterFunction ("FlushDestroyedEntities"); m_ScriptInterface.RegisterFunction ("DataFileExists"); - m_ScriptInterface.RegisterFunction ("ReadJSONFile"); - m_ScriptInterface.RegisterFunction ("ReadCivJSONFile"); m_ScriptInterface.RegisterFunction, std::wstring, bool, CComponentManager::Script_FindJSONFiles> ("FindJSONFiles"); } @@ -1192,28 +1192,6 @@ return VfsFileExists(path); } -JS::Value CComponentManager::Script_ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& fileName) -{ - return ReadJSONFile(pCxPrivate, L"simulation/data", fileName); -} - -JS::Value CComponentManager::Script_ReadCivJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& fileName) -{ - return ReadJSONFile(pCxPrivate, L"simulation/data/civs", fileName); -} - -JS::Value CComponentManager::ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filePath, const std::wstring& fileName) -{ - CComponentManager* componentManager = static_cast (pCxPrivate->pCBData); - JSContext* cx = pCxPrivate->pScriptInterface->GetContext(); - JSAutoRequest rq(cx); - - VfsPath path = VfsPath(filePath) / fileName; - JS::RootedValue out(cx); - componentManager->GetScriptInterface().ReadJSONFile(path, &out); - return out; -} - Status CComponentManager::FindJSONFilesCallback(const VfsPath& pathname, const CFileInfo& UNUSED(fileInfo), const uintptr_t cbData) { FindJSONFilesCallbackData* data = (FindJSONFilesCallbackData*)cbData;