diff --git a/core/runner/sandbox.lua b/core/runner/sandbox.lua index 158901f..368b857 100644 --- a/core/runner/sandbox.lua +++ b/core/runner/sandbox.lua @@ -10,11 +10,16 @@ __http_response = {} __module_paths = {} __module_bytecode = {} __ready_modules = {} +__EXIT_SENTINEL = {} -- Unique object for exit identification -- ====================================================================== -- CORE SANDBOX FUNCTIONALITY -- ====================================================================== +function exit() + error(__EXIT_SENTINEL) +end + -- Create environment inheriting from _G function __create_env(ctx) local env = setmetatable({}, {__index = _G}) @@ -35,10 +40,15 @@ function __execute_script(fn, ctx) __http_response = nil local env = __create_env(ctx) + env.exit = exit setfenv(fn, env) local ok, result = pcall(fn) if not ok then + if result == __EXIT_SENTINEL then + return + end + error(result, 0) end @@ -314,6 +324,58 @@ local session = { end } +-- ====================================================================== +-- CSRF MODULE +-- ====================================================================== + +local csrf = { + generate = function() + local token = util.generate_token(32) + session.set("_csrf_token", token) + return token + end, + + field = function() + local token = session.get("_csrf_token") + if not token then + token = csrf.generate() + end + return string.format('', token) + end, + + validate = function() + local env = getfenv(2) + local token = false + if env.ctx and env.ctx.session and env.ctx.session.data then + token = env.ctx.session.data["_csrf_token"] + end + + if not token then + http.set_status(403) + __http_response.body = "CSRF validation failed" + exit() + end + + local request_token = nil + if env.ctx and env.ctx.form then + request_token = env.ctx.form._csrf_token + end + + if not request_token and env.ctx and env.ctx._request_headers then + request_token = env.ctx._request_headers["x-csrf-token"] or + env.ctx._request_headers["csrf-token"] + end + + if not request_token or request_token ~= token then + http.set_status(403) + __http_response.body = "CSRF validation failed" + exit() + end + + return true + end +} + -- ====================================================================== -- UTIL MODULE -- ====================================================================== @@ -404,5 +466,6 @@ local util = { _G.http = http _G.session = session +_G.csrf = csrf _G.cookie = cookie _G.util = util