summaryrefslogtreecommitdiff
path: root/script/sandbox.lua
diff options
context:
space:
mode:
Diffstat (limited to 'script/sandbox.lua')
-rw-r--r--script/sandbox.lua167
1 files changed, 167 insertions, 0 deletions
diff --git a/script/sandbox.lua b/script/sandbox.lua
new file mode 100644
index 00000000..6b2f2a32
--- /dev/null
+++ b/script/sandbox.lua
@@ -0,0 +1,167 @@
+local function standard(loaded, env)
+ local r = env or {}
+ for _, s in ipairs {
+ --'package',
+ 'coroutine',
+ 'table',
+ --'io',
+ 'os',
+ 'string',
+ 'math',
+ 'utf8',
+ 'debug',
+ } do
+ r[s] = _G[s]
+ loaded[s] = _G[s]
+ end
+ for _, s in ipairs {
+ 'assert',
+ 'collectgarbage',
+ --'dofile',
+ 'error',
+ 'getmetatable',
+ 'ipairs',
+ --'loadfile',
+ 'load',
+ 'next',
+ 'pairs',
+ 'pcall',
+ 'print',
+ 'rawequal',
+ 'rawlen',
+ 'rawget',
+ 'rawset',
+ 'select',
+ 'setmetatable',
+ 'tonumber',
+ 'tostring',
+ 'type',
+ 'xpcall',
+ '_VERSION',
+ --'require',
+ } do
+ r[s] = _G[s]
+ end
+ return r
+end
+
+local function sandbox_env(loadlua, openfile, loaded, env)
+ local _LOADED = loaded or {}
+ local _E = standard(_LOADED, env)
+ local _PRELOAD = {}
+
+ _E.io = {
+ open = openfile,
+ }
+
+ local function searchpath(name, path)
+ local err = ''
+ name = string.gsub(name, '%.', '/')
+ for c in string.gmatch(path, '[^;]+') do
+ local filename = string.gsub(c, '%?', name)
+ local f = openfile(filename)
+ if f then
+ f:close()
+ return filename
+ end
+ err = err .. ("\n\tno file '%s'"):format(filename)
+ end
+ return nil, err
+ end
+
+ local function searcher_preload(name)
+ assert(type(_PRELOAD) == "table", "'package.preload' must be a table")
+ if _PRELOAD[name] == nil then
+ return ("\n\tno field package.preload['%s']"):format(name)
+ end
+ return _PRELOAD[name]
+ end
+
+ local function searcher_lua(name)
+ assert(type(_E.package.path) == "string", "'package.path' must be a string")
+ local filename, err = searchpath(name, _E.package.path)
+ if not filename then
+ return err
+ end
+ local f, err = loadlua(filename)
+ if not f then
+ error(("error loading module '%s' from file '%s':\n\t%s"):format(name, filename, err))
+ end
+ return f, filename
+ end
+
+ local function require_load(name)
+ local msg = ''
+ local _SEARCHERS = _E.package.searchers
+ assert(type(_SEARCHERS) == "table", "'package.searchers' must be a table")
+ for _, searcher in ipairs(_SEARCHERS) do
+ local f, extra = searcher(name)
+ if type(f) == 'function' then
+ return f, extra
+ elseif type(f) == 'string' then
+ msg = msg .. f
+ end
+ end
+ error(("module '%s' not found:%s"):format(name, msg))
+ end
+
+ _E.require = function(name)
+ assert(type(name) == "string", ("bad argument #1 to 'require' (string expected, got %s)"):format(type(name)))
+ local p = _LOADED[name]
+ if p ~= nil then
+ return p
+ end
+ local init, extra = require_load(name)
+ if debug.getupvalue(init, 1) == '_ENV' then
+ debug.setupvalue(init, 1, _E)
+ end
+ local res = init(name, extra)
+ if res ~= nil then
+ _LOADED[name] = res
+ end
+ if _LOADED[name] == nil then
+ _LOADED[name] = true
+ end
+ return _LOADED[name]
+ end
+ _E.package = {
+ config = [[
+ \
+ ;
+ ?
+ !
+ -
+ ]],
+ loaded = _LOADED,
+ path = '?.lua',
+ preload = _PRELOAD,
+ searchers = { searcher_preload, searcher_lua },
+ searchpath = searchpath
+ }
+ return _E
+end
+
+return function(name, root, io_open, loaded, env)
+ if not root:sub(-1):find '[/\\]' then
+ root = root .. '/'
+ end
+ local function openfile(name, mode)
+ return io_open(root .. name, mode)
+ end
+ local function loadlua(name)
+ local f = openfile(name, 'r')
+ if f then
+ local str = f:read 'a'
+ f:close()
+ return load(str, '@' .. root .. name)
+ end
+ end
+ local init = loadlua(name)
+ if not init then
+ return
+ end
+ if debug.getupvalue(init, 1) == '_ENV' then
+ debug.setupvalue(init, 1, sandbox_env(loadlua, openfile, loaded, env))
+ end
+ return init()
+end