145 lines
3.4 KiB
Go
145 lines
3.4 KiB
Go
package workers
|
|
|
|
// setupSandbox initializes the sandbox environment creation function
|
|
func (w *worker) setupSandbox() error {
|
|
// This is the Lua script that creates our sandbox function
|
|
setupScript := `
|
|
-- Create a function to run code in a sandbox environment
|
|
function __create_sandbox()
|
|
-- Create new environment table
|
|
local env = {}
|
|
|
|
-- Add standard library modules (can be restricted as needed)
|
|
env.string = string
|
|
env.table = table
|
|
env.math = math
|
|
env.os = {
|
|
time = os.time,
|
|
date = os.date,
|
|
difftime = os.difftime,
|
|
clock = os.clock
|
|
}
|
|
env.tonumber = tonumber
|
|
env.tostring = tostring
|
|
env.type = type
|
|
env.pairs = pairs
|
|
env.ipairs = ipairs
|
|
env.next = next
|
|
env.select = select
|
|
env.unpack = unpack
|
|
env.pcall = pcall
|
|
env.xpcall = xpcall
|
|
env.error = error
|
|
env.assert = assert
|
|
|
|
-- Allow access to package.loaded for modules
|
|
env.require = function(name)
|
|
return package.loaded[name]
|
|
end
|
|
|
|
-- Create metatable to restrict access to _G
|
|
local mt = {
|
|
__index = function(t, k)
|
|
-- First check in env table
|
|
local v = rawget(env, k)
|
|
if v ~= nil then return v end
|
|
|
|
-- If not found, check for registered modules/functions
|
|
local moduleValue = _G[k]
|
|
if type(moduleValue) == "table" or
|
|
type(moduleValue) == "function" then
|
|
return moduleValue
|
|
end
|
|
|
|
return nil
|
|
end,
|
|
__newindex = function(t, k, v)
|
|
rawset(env, k, v)
|
|
end
|
|
}
|
|
|
|
setmetatable(env, mt)
|
|
return env
|
|
end
|
|
|
|
-- Create function to execute code with a sandbox
|
|
function __run_sandboxed(f, ctx)
|
|
local env = __create_sandbox()
|
|
|
|
-- Add context to the environment if provided
|
|
if ctx then
|
|
env.ctx = ctx
|
|
end
|
|
|
|
-- Set the environment and run the function
|
|
setfenv(f, env)
|
|
return f()
|
|
end
|
|
`
|
|
|
|
return w.state.DoString(setupScript)
|
|
}
|
|
|
|
// executeJobSandboxed runs a script in a sandbox environment
|
|
func (w *worker) executeJobSandboxed(j job) JobResult {
|
|
// No need to reset the state for each execution, since we're using a sandbox
|
|
|
|
// Re-run init function to register functions and modules if needed
|
|
if w.pool.stateInit != nil {
|
|
if err := w.pool.stateInit(w.state); err != nil {
|
|
return JobResult{nil, err}
|
|
}
|
|
}
|
|
|
|
// Set up context if provided
|
|
if j.Context != nil {
|
|
// Push context table
|
|
w.state.NewTable()
|
|
|
|
// Add values to context table
|
|
for key, value := range j.Context.Values {
|
|
// Push key
|
|
w.state.PushString(key)
|
|
|
|
// Push value
|
|
if err := w.state.PushValue(value); err != nil {
|
|
return JobResult{nil, err}
|
|
}
|
|
|
|
// Set table[key] = value
|
|
w.state.SetTable(-3)
|
|
}
|
|
} else {
|
|
// Push nil if no context
|
|
w.state.PushNil()
|
|
}
|
|
|
|
// Load bytecode
|
|
if err := w.state.LoadBytecode(j.Bytecode, "script"); err != nil {
|
|
w.state.Pop(1) // Pop context
|
|
return JobResult{nil, err}
|
|
}
|
|
|
|
// Get the sandbox runner function
|
|
w.state.GetGlobal("__run_sandboxed")
|
|
|
|
// Push loaded function and context as arguments
|
|
w.state.PushCopy(-2) // Copy the loaded function
|
|
w.state.PushCopy(-4) // Copy the context table or nil
|
|
|
|
// Remove the original function and context
|
|
w.state.Remove(-5) // Remove original context
|
|
w.state.Remove(-4) // Remove original function
|
|
|
|
// Call the sandbox runner with 2 args (function and context), expecting 1 result
|
|
if err := w.state.Call(2, 1); err != nil {
|
|
return JobResult{nil, err}
|
|
}
|
|
|
|
// Get result
|
|
value, err := w.state.ToValue(-1)
|
|
w.state.Pop(1) // Pop result
|
|
|
|
return JobResult{value, err}
|
|
}
|