mirror of
https://github.com/edubart/otclient.git
synced 2025-10-14 11:34:54 +02:00
Improve modules and sandbox system
This commit is contained in:
@@ -30,8 +30,7 @@
|
||||
Module::Module(const std::string& name)
|
||||
{
|
||||
m_name = name;
|
||||
g_lua.newEnvironment();
|
||||
m_sandboxEnv = g_lua.ref();
|
||||
m_sandboxEnv = g_lua.newSandboxEnv();
|
||||
}
|
||||
|
||||
bool Module::load()
|
||||
@@ -49,12 +48,11 @@ bool Module::load()
|
||||
stdext::throw_exception(stdext::format("dependency '%s' has failed to load", m_name, depName));
|
||||
}
|
||||
|
||||
if(m_sandboxed)
|
||||
g_lua.setGlobalEnvironment(m_sandboxEnv);
|
||||
|
||||
for(const std::string& script : m_scripts) {
|
||||
g_lua.loadScript(script);
|
||||
if(m_sandboxed) {
|
||||
g_lua.getRef(m_sandboxEnv);
|
||||
g_lua.setEnv();
|
||||
}
|
||||
g_lua.safeCall(0, 0);
|
||||
}
|
||||
|
||||
@@ -69,8 +67,13 @@ bool Module::load()
|
||||
g_lua.safeCall(0, 0);
|
||||
}
|
||||
|
||||
if(m_sandboxed)
|
||||
g_lua.resetGlobalEnvironment();
|
||||
|
||||
g_logger.debug(stdext::format("Loaded module '%s'", m_name));
|
||||
} catch(stdext::exception& e) {
|
||||
if(m_sandboxed)
|
||||
g_lua.resetGlobalEnvironment();
|
||||
g_logger.error(stdext::format("Unable to load module '%s': %s", m_name, e.what()));
|
||||
return false;
|
||||
}
|
||||
@@ -93,20 +96,29 @@ void Module::unload()
|
||||
{
|
||||
if(m_loaded) {
|
||||
try {
|
||||
if(m_sandboxed)
|
||||
g_lua.setGlobalEnvironment(m_sandboxEnv);
|
||||
|
||||
const std::string& onUnloadBuffer = std::get<0>(m_onUnloadFunc);
|
||||
const std::string& onUnloadSource = std::get<1>(m_onUnloadFunc);
|
||||
if(!onUnloadBuffer.empty()) {
|
||||
g_lua.loadBuffer(onUnloadBuffer, onUnloadSource);
|
||||
if(m_sandboxed) {
|
||||
g_lua.getRef(m_sandboxEnv);
|
||||
g_lua.setEnv();
|
||||
}
|
||||
g_lua.safeCall(0, 0);
|
||||
}
|
||||
|
||||
if(m_sandboxed)
|
||||
g_lua.resetGlobalEnvironment();
|
||||
} catch(stdext::exception& e) {
|
||||
if(m_sandboxed)
|
||||
g_lua.resetGlobalEnvironment();
|
||||
g_logger.error(stdext::format("Unable to unload module '%s': %s", m_name, e.what()));
|
||||
}
|
||||
|
||||
// clear all env references
|
||||
g_lua.getRef(m_sandboxEnv);
|
||||
g_lua.clearTable();
|
||||
g_lua.pop();
|
||||
|
||||
m_loaded = false;
|
||||
//g_logger.info(stdext::format("Unloaded module '%s'", m_name));
|
||||
g_modules.updateModuleLoadOrder(asModule());
|
||||
@@ -135,6 +147,12 @@ bool Module::hasDependency(const std::string& name)
|
||||
return false;
|
||||
}
|
||||
|
||||
int Module::getSandbox(LuaInterface* lua)
|
||||
{
|
||||
lua->getRef(m_sandboxEnv);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Module::discover(const OTMLNodePtr& moduleNode)
|
||||
{
|
||||
const static std::string none = "none";
|
||||
|
@@ -43,7 +43,9 @@ public:
|
||||
bool isLoaded() { return m_loaded; }
|
||||
bool isReloadable() { return m_reloadable; }
|
||||
bool isDependent();
|
||||
bool isSandboxed() { return m_sandboxed; }
|
||||
bool hasDependency(const std::string& name);
|
||||
int getSandbox(LuaInterface *lua);
|
||||
|
||||
std::string getDescription() { return m_description; }
|
||||
std::string getName() { return m_name; }
|
||||
|
@@ -151,7 +151,7 @@ void ResourceManager::loadFile(const std::string& fileName, std::iostream& out)
|
||||
PHYSFS_file* file = PHYSFS_openRead(fullPath.c_str());
|
||||
if(!file) {
|
||||
out.clear(std::ios::failbit);
|
||||
stdext::throw_exception(stdext::format("failed to load file '%s': %s", fullPath.c_str(), PHYSFS_getLastError()));
|
||||
stdext::throw_exception(stdext::format("unable to load file '%s': %s", fullPath.c_str(), PHYSFS_getLastError()));
|
||||
} else {
|
||||
int fileSize = PHYSFS_fileLength(file);
|
||||
if(fileSize > 0) {
|
||||
@@ -167,7 +167,7 @@ void ResourceManager::loadFile(const std::string& fileName, std::iostream& out)
|
||||
std::ifstream fin(fileName);
|
||||
if(!fin) {
|
||||
out.clear(std::ios::failbit);
|
||||
stdext::throw_exception(stdext::format("failed to load file '%s': %s", fileName.c_str(), PHYSFS_getLastError()));
|
||||
stdext::throw_exception(stdext::format("unable to file '%s': %s", fileName.c_str(), PHYSFS_getLastError()));
|
||||
} else {
|
||||
out << fin.rdbuf();
|
||||
}
|
||||
|
@@ -47,6 +47,12 @@ void LuaInterface::init()
|
||||
{
|
||||
createLuaState();
|
||||
|
||||
// store global environment reference
|
||||
pushThread();
|
||||
getEnv();
|
||||
m_globalEnv = ref();
|
||||
pop();
|
||||
|
||||
// check if demangle_type is working as expected
|
||||
assert(stdext::demangle_type<LuaObject>() == "LuaObject");
|
||||
|
||||
@@ -297,7 +303,7 @@ bool LuaInterface::safeRunScript(const std::string& fileName)
|
||||
try {
|
||||
runScript(fileName);
|
||||
return true;
|
||||
} catch(LuaException& e) {
|
||||
} catch(stdext::exception& e) {
|
||||
g_logger.error(stdext::format("Failed to load script '%s': %s", fileName, e.what()));
|
||||
return false;
|
||||
}
|
||||
@@ -322,13 +328,9 @@ void LuaInterface::loadScript(const std::string& fileName)
|
||||
if(!boost::starts_with(fileName, "/"))
|
||||
filePath = getCurrentSourcePath() + "/" + filePath;
|
||||
|
||||
try {
|
||||
std::string buffer = g_resources.loadFile(fileName);
|
||||
std::string source = "@" + filePath;
|
||||
loadBuffer(buffer, source);
|
||||
} catch(stdext::exception& e) {
|
||||
throw LuaException(e.what());
|
||||
}
|
||||
std::string buffer = g_resources.loadFile(fileName);
|
||||
std::string source = "@" + filePath;
|
||||
loadBuffer(buffer, source);
|
||||
}
|
||||
|
||||
void LuaInterface::loadFunction(const std::string& buffer, const std::string& source)
|
||||
@@ -515,7 +517,7 @@ int LuaInterface::signalCall(int numArgs, int numRets)
|
||||
else {
|
||||
throw LuaException("attempt to call a non function value", 0);
|
||||
}
|
||||
} catch(LuaException &e) {
|
||||
} catch(stdext::exception& e) {
|
||||
g_logger.error(stdext::format("protected lua call failed: %s", e.what()));
|
||||
}
|
||||
|
||||
@@ -529,16 +531,16 @@ int LuaInterface::signalCall(int numArgs, int numRets)
|
||||
return rets;
|
||||
}
|
||||
|
||||
void LuaInterface::newEnvironment()
|
||||
int LuaInterface::newSandboxEnv()
|
||||
{
|
||||
newTable(); // pushes the new environment table
|
||||
newTable(); // pushes the new environment metatable
|
||||
getGlobalEnvironment(); // pushes the global environment
|
||||
getRef(getGlobalEnvironment()); // pushes the global environment
|
||||
setField("__index"); // sets metatable __index to the global environment
|
||||
setMetatable(); // assigns environment metatable
|
||||
return ref(); // return a reference to the environment table
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// lua C functions
|
||||
|
||||
@@ -550,13 +552,13 @@ int LuaInterface::luaScriptLoader(lua_State* L)
|
||||
try {
|
||||
g_lua.loadScript(fileName);
|
||||
return 1;
|
||||
} catch(LuaException& e) {
|
||||
g_logger.error(stdext::format("failed to load script file '%s': %s", fileName, e.what()));
|
||||
return 0;
|
||||
} catch(stdext::exception& e) {
|
||||
g_lua.pushString(stdext::mkstr("\n\t", e.what()));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int LuaInterface::luaScriptRunner(lua_State* L)
|
||||
int LuaInterface::lua_dofile(lua_State* L)
|
||||
{
|
||||
std::string fileName = g_lua.popString();
|
||||
if(!boost::ends_with(fileName, ".lua"))
|
||||
@@ -566,13 +568,14 @@ int LuaInterface::luaScriptRunner(lua_State* L)
|
||||
g_lua.loadScript(fileName);
|
||||
g_lua.call(0, LUA_MULTRET);
|
||||
return g_lua.stackSize();
|
||||
} catch(LuaException& e) {
|
||||
g_logger.error(stdext::format("failed to load script file '%s': %s", fileName, e.what()));
|
||||
} catch(stdext::exception& e) {
|
||||
g_lua.pushString(e.what());
|
||||
g_lua.error();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int LuaInterface::luaScriptsRunner(lua_State* L)
|
||||
int LuaInterface::lua_dofiles(lua_State* L)
|
||||
{
|
||||
std::string directory = g_lua.popString();
|
||||
|
||||
@@ -583,13 +586,31 @@ int LuaInterface::luaScriptsRunner(lua_State* L)
|
||||
try {
|
||||
g_lua.loadScript(directory + "/" + fileName);
|
||||
g_lua.call(0, 0);
|
||||
} catch(LuaException& e) {
|
||||
g_logger.error(stdext::format("failed to load script file '%s': %s", fileName, e.what()));
|
||||
} catch(stdext::exception& e) {
|
||||
g_lua.pushString(e.what());
|
||||
g_lua.error();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LuaInterface::lua_loadfile(lua_State* L)
|
||||
{
|
||||
std::string fileName = g_lua.popString();
|
||||
if(!boost::ends_with(fileName, ".lua"))
|
||||
fileName += ".lua";
|
||||
|
||||
try {
|
||||
g_lua.loadScript(fileName);
|
||||
return 1;
|
||||
} catch(stdext::exception& e) {
|
||||
g_lua.pushNil();
|
||||
g_lua.pushString(e.what());
|
||||
g_lua.error();
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
int LuaInterface::luaErrorHandler(lua_State* L)
|
||||
{
|
||||
// pops the error message
|
||||
@@ -618,12 +639,13 @@ int LuaInterface::luaCppFunctionCallback(lua_State* L)
|
||||
numRets = (*(funcPtr->get()))(&g_lua);
|
||||
g_lua.m_cppCallbackDepth--;
|
||||
assert(numRets == g_lua.stackSize());
|
||||
} catch(stdext::exception &e) {
|
||||
} catch(stdext::exception& e) {
|
||||
// cleanup stack
|
||||
while(g_lua.stackSize() > 0)
|
||||
g_lua.pop();
|
||||
numRets = 0;
|
||||
g_logger.error(stdext::format("C++ call failed: %s", g_lua.traceback(e.what())));
|
||||
g_lua.pushString(stdext::format("C++ call failed: %s", g_lua.traceback(e.what())));
|
||||
g_lua.error();
|
||||
}
|
||||
|
||||
return numRets;
|
||||
@@ -670,13 +692,24 @@ void LuaInterface::createLuaState()
|
||||
rawSeti(5);
|
||||
pop(2);
|
||||
|
||||
// replace loadfile
|
||||
getGlobal("package");
|
||||
getField("loaders");
|
||||
pushCFunction(&LuaInterface::luaScriptLoader);
|
||||
rawSeti(5);
|
||||
pop(2);
|
||||
|
||||
// replace dofile
|
||||
pushCFunction(&LuaInterface::luaScriptRunner);
|
||||
pushCFunction(&LuaInterface::lua_dofile);
|
||||
setGlobal("dofile");
|
||||
|
||||
// dofiles
|
||||
pushCFunction(&LuaInterface::luaScriptsRunner);
|
||||
pushCFunction(&LuaInterface::lua_dofiles);
|
||||
setGlobal("dofiles");
|
||||
|
||||
// replace loadfile
|
||||
pushCFunction(&LuaInterface::lua_loadfile);
|
||||
setGlobal("loadfile");
|
||||
}
|
||||
|
||||
void LuaInterface::closeLuaState()
|
||||
@@ -833,18 +866,13 @@ void LuaInterface::getWeakRef(int weakRef)
|
||||
remove(-2);
|
||||
}
|
||||
|
||||
void LuaInterface::getGlobalEnvironment()
|
||||
void LuaInterface::setGlobalEnvironment(int env)
|
||||
{
|
||||
pushThread();
|
||||
getEnv();
|
||||
remove(-2);
|
||||
}
|
||||
|
||||
void LuaInterface::setGlobalEnvironment()
|
||||
{
|
||||
pushThread();
|
||||
insert(-2);
|
||||
getRef(env);
|
||||
assert(isTable());
|
||||
setEnv();
|
||||
pop();
|
||||
}
|
||||
|
||||
void LuaInterface::setMetatable(int index)
|
||||
@@ -899,6 +927,24 @@ void LuaInterface::setTable(int index)
|
||||
lua_settable(L, index);
|
||||
}
|
||||
|
||||
void LuaInterface::clearTable(int index)
|
||||
{
|
||||
assert(hasIndex(index) && isTable(index));
|
||||
pushNil();
|
||||
bool stop = false;
|
||||
while(!stop && next(index-1)) {
|
||||
pop();
|
||||
pushValue();
|
||||
if(next(index-2))
|
||||
pop();
|
||||
else
|
||||
stop = true;
|
||||
insert(-2);
|
||||
pushNil();
|
||||
rawSet(index-3);
|
||||
}
|
||||
}
|
||||
|
||||
void LuaInterface::getGlobal(const std::string& key)
|
||||
{
|
||||
lua_getglobal(L, key.c_str());
|
||||
|
@@ -186,7 +186,7 @@ public:
|
||||
/// The new environment table is redirected to the global environment (aka _G),
|
||||
/// this allows to access global variables from _G in the new environment and
|
||||
/// prevents new variables in this new environment to be set on the global environment
|
||||
void newEnvironment();
|
||||
int newSandboxEnv();
|
||||
|
||||
template<typename... T>
|
||||
int callGlobalField(const std::string& global, const std::string& field, const T&... args);
|
||||
@@ -200,9 +200,11 @@ private:
|
||||
/// Load scripts requested by lua 'require'
|
||||
static int luaScriptLoader(lua_State* L);
|
||||
/// Run scripts requested by lua 'dofile'
|
||||
static int luaScriptRunner(lua_State* L);
|
||||
static int lua_dofile(lua_State* L);
|
||||
/// Run scripts requested by lua 'dofiles'
|
||||
static int luaScriptsRunner(lua_State* L);
|
||||
static int lua_dofiles(lua_State* L);
|
||||
/// Run scripts requested by lua 'dofiles'
|
||||
static int lua_loadfile(lua_State* L);
|
||||
/// Handle lua errors from safeCall
|
||||
static int luaErrorHandler(lua_State* L);
|
||||
/// Handle bound cpp functions callbacks
|
||||
@@ -240,8 +242,9 @@ public:
|
||||
void getRef(int ref);
|
||||
void getWeakRef(int weakRef);
|
||||
|
||||
void getGlobalEnvironment();
|
||||
void setGlobalEnvironment();
|
||||
int getGlobalEnvironment() { return m_globalEnv; }
|
||||
void setGlobalEnvironment(int env);
|
||||
void resetGlobalEnvironment() { setGlobalEnvironment(m_globalEnv); }
|
||||
|
||||
void setMetatable(int index = -2);
|
||||
void getMetatable(int index = -1);
|
||||
@@ -253,6 +256,7 @@ public:
|
||||
|
||||
void getTable(int index = -2);
|
||||
void setTable(int index = -3);
|
||||
void clearTable(int index = -1);
|
||||
|
||||
void getEnv(int index = -1);
|
||||
void setEnv(int index = -2);
|
||||
@@ -334,6 +338,7 @@ private:
|
||||
int m_cppCallbackDepth;
|
||||
int m_totalObjRefs;
|
||||
int m_totalFuncRefs;
|
||||
int m_globalEnv;
|
||||
};
|
||||
|
||||
extern LuaInterface g_lua;
|
||||
|
@@ -148,11 +148,13 @@ void Application::registerLuaFunctions()
|
||||
g_lua.bindClassMemberFunction<Module>("canUnload", &Module::canUnload);
|
||||
g_lua.bindClassMemberFunction<Module>("isLoaded", &Module::isLoaded);
|
||||
g_lua.bindClassMemberFunction<Module>("isReloadble", &Module::isReloadable);
|
||||
g_lua.bindClassMemberFunction<Module>("isSandboxed", &Module::isSandboxed);
|
||||
g_lua.bindClassMemberFunction<Module>("getDescription", &Module::getDescription);
|
||||
g_lua.bindClassMemberFunction<Module>("getName", &Module::getName);
|
||||
g_lua.bindClassMemberFunction<Module>("getAuthor", &Module::getAuthor);
|
||||
g_lua.bindClassMemberFunction<Module>("getWebsite", &Module::getWebsite);
|
||||
g_lua.bindClassMemberFunction<Module>("getVersion", &Module::getVersion);
|
||||
g_lua.bindClassMemberFunction<Module>("getSandbox", &Module::getSandbox);
|
||||
g_lua.bindClassMemberFunction<Module>("isAutoLoad", &Module::isAutoLoad);
|
||||
g_lua.bindClassMemberFunction<Module>("getAutoLoadPriority", &Module::getAutoLoadPriority);
|
||||
|
||||
|
@@ -312,6 +312,7 @@ void UIWidget::parseBaseStyle(const OTMLNodePtr& styleNode)
|
||||
} else if(boost::starts_with(node->tag(), "&")) {
|
||||
std::string fieldName = node->tag().substr(1);
|
||||
std::string fieldOrigin = "@" + node->source() + "[" + node->tag() + "]";
|
||||
|
||||
g_lua.evaluateExpression(node->value(), fieldOrigin);
|
||||
luaSetField(fieldName);
|
||||
}
|
||||
|
Reference in New Issue
Block a user