mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2026-01-01 13:11:40 +09:00
Better sandboxing for /interface
This commit is contained in:
@@ -31,67 +31,75 @@ Global.register(interface_env, function(tbl)
|
|||||||
interface_env = tbl
|
interface_env = tbl
|
||||||
end)
|
end)
|
||||||
|
|
||||||
--- Adds a callback function when the interface command is used
|
--- Adds a static module that can be accessed with the interface
|
||||||
-- nb: returned value is saved in the env that the interface uses
|
-- @tparam string name The name that the value is assigned to
|
||||||
-- @tparam string name the name that the value is loaded under, cant use upvalues
|
-- @tparam any value The value that will be accessible in the interface env
|
||||||
-- @tparam function callback the function that will run whent he command is used
|
|
||||||
-- callback param - player: LuaPlayer - the player who used the command
|
-- callback param - player: LuaPlayer - the player who used the command
|
||||||
|
local function add_interface_module(name, value)
|
||||||
|
interface_modules[name] = value
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Adds a dynamic value that is calculated when the interface is used
|
||||||
|
-- @tparam string name The name that the value is assigned to
|
||||||
|
-- @tparam function callback The function that will be called to get the value
|
||||||
local function add_interface_callback(name, callback)
|
local function add_interface_callback(name, callback)
|
||||||
if type(callback) == 'function' then
|
if type(callback) == 'function' then
|
||||||
interface_callbacks[name] = callback
|
interface_callbacks[name] = callback
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- this is a meta function for __index when self[key] is nil
|
--- Internal, this is a meta function for __index when self[key] is nil
|
||||||
local function get_index(_, key)
|
local function get_index(_, key)
|
||||||
if interface_env[key] then
|
if interface_env[key] then
|
||||||
return interface_env[key]
|
return interface_env[key]
|
||||||
elseif interface_modules[key] then
|
elseif interface_modules[key] then
|
||||||
return interface_modules[key]
|
return interface_modules[key]
|
||||||
|
elseif _G[key] then
|
||||||
|
return _G[key]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Sends an innovation to be ran and returns the result.
|
--- Sends an invocation to be ran and returns the result.
|
||||||
-- @command interface
|
-- @command interface
|
||||||
-- @tparam string innovation the command that will be run
|
-- @tparam string invocation the command that will be run
|
||||||
Commands.new_command('interface', 'Sends an innovation to be ran and returns the result.')
|
Commands.new_command('interface', 'Sends an invocation to be ran and returns the result.')
|
||||||
:add_param('innovation', false)
|
:add_param('invocation', false)
|
||||||
:enable_auto_concat()
|
:enable_auto_concat()
|
||||||
:set_flag('admin_only')
|
:set_flag('admin_only')
|
||||||
:register(function(player, innovation)
|
:register(function(player, invocation)
|
||||||
if not innovation:find('%s') and not innovation:find('return') then
|
-- If the invocation has no white space then prepend return to it
|
||||||
-- if there are no spaces and return is not present then return is appended to the start
|
if not invocation:find('%s') and not invocation:find('return') then
|
||||||
innovation='return '..innovation
|
invocation = 'return '..invocation
|
||||||
end
|
end
|
||||||
-- temp_env will index to interface_env and interface_modules if value not found
|
|
||||||
local temp_env = setmetatable({}, {__index=get_index})
|
-- _env will be the new _ENV that the invocation will run inside of
|
||||||
if player then -- player can be nil when it is the server
|
local _env = setmetatable({}, {
|
||||||
|
__index = get_index,
|
||||||
|
__newindex = interface_env
|
||||||
|
})
|
||||||
|
|
||||||
|
-- If the command is ran by a player then load the dynamic values
|
||||||
|
if player then
|
||||||
for name, callback in pairs(interface_callbacks) do
|
for name, callback in pairs(interface_callbacks) do
|
||||||
-- loops over callbacks and loads the values returned
|
|
||||||
local _, rtn = pcall(callback, player)
|
local _, rtn = pcall(callback, player)
|
||||||
temp_env[name]=rtn
|
rawset(_env, name, rtn)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- sets the global metatable to prevent new values being made
|
|
||||||
-- global will index to temp_env and new indexes saved to interface_sandbox
|
-- Compile the invocation with the custom _env value
|
||||||
local old_mt = getmetatable(_G)
|
local invocation_func, compile_error = load(invocation, 'interface', nil, _env)
|
||||||
setmetatable(_G, {__index=temp_env, __newindex=interface_env})
|
if compile_error then return Commands.error(compile_error) end
|
||||||
-- runs the innovation and returns values to the player
|
|
||||||
innovation = loadstring(innovation)
|
-- Run the invocation
|
||||||
local success, rtn = pcall(innovation)
|
local success, rtn = pcall(invocation_func)
|
||||||
setmetatable(_G, old_mt)
|
|
||||||
if not success then
|
if not success then
|
||||||
if type(rtn) == 'string' then
|
local err = rtn:gsub('%.%.%..-/temp/currently%-playing', '')
|
||||||
-- there may be stack trace that must be removed to avoid desyncs
|
return Commands.error(err)
|
||||||
rtn = rtn:gsub('%.%.%..-/temp/currently%-playing', '')
|
|
||||||
end
|
|
||||||
return Commands.error(rtn)
|
|
||||||
else
|
|
||||||
return Commands.success(rtn)
|
|
||||||
end
|
end
|
||||||
|
return Commands.success(rtn)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- adds some basic callbacks for the interface
|
-- Adds some basic callbacks for the interface
|
||||||
add_interface_callback('player', function(player) return player end)
|
add_interface_callback('player', function(player) return player end)
|
||||||
add_interface_callback('surface', function(player) return player.surface end)
|
add_interface_callback('surface', function(player) return player.surface end)
|
||||||
add_interface_callback('force', function(player) return player.force end)
|
add_interface_callback('force', function(player) return player.force end)
|
||||||
@@ -99,9 +107,10 @@ add_interface_callback('position', function(player) return player.position end)
|
|||||||
add_interface_callback('entity', function(player) return player.selected end)
|
add_interface_callback('entity', function(player) return player.selected end)
|
||||||
add_interface_callback('tile', function(player) return player.surface.get_tile(player.position) end)
|
add_interface_callback('tile', function(player) return player.surface.get_tile(player.position) end)
|
||||||
|
|
||||||
|
-- Module Return
|
||||||
return {
|
return {
|
||||||
add_interface_callback=add_interface_callback,
|
add_interface_module = add_interface_module,
|
||||||
interface_env=interface_env,
|
add_interface_callback = add_interface_callback,
|
||||||
interface_callbacks=interface_callbacks,
|
interface_env = interface_env,
|
||||||
clean_stack_trace=function(str) return str:gsub('%.%.%..-/temp/currently%-playing', '') end
|
clean_stack_trace = function(str) return str:gsub('%.%.%..-/temp/currently%-playing', '') end
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user