Moonshark/core/workers/sandbox.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}
}