local runtime_path = assert(SW_RUNTIME_PATH, "SW_RUNTIME_PATH is required") local challenge_path = assert(SW_CHALLENGE_PATH, "SW_CHALLENGE_PATH is required") local function assert_equal(actual, expected, message) if actual ~= expected then error((message or "values differ") .. ": expected " .. tostring(expected) .. ", got " .. tostring(actual), 2) end end -- Stable tables: never rebind `exec_calls` / `redir_args` (closures capture -- the upvalue slot; rebinding can leave stale values visible under -- gopher-lua across long test sequences). Clear them in place instead. local output = {} local exec_calls = {} local redir_args = {} local function clear_state() for i = 1, #exec_calls do exec_calls[i] = nil end redir_args.redir = nil end ngx = { var = {}, header = {}, exec = function(uri) exec_calls[#exec_calls + 1] = uri return true end, say = function(body) output.body = body end, req = { get_uri_args = function() return redir_args end, set_uri_args = function(args) redir_args.redir = args.redir end, }, } local function load_runtime() local chunk = assert(loadfile(runtime_path)) return chunk() end local function reset_request(user_agent, uri, cookie, args, method) clear_state() ngx.var = { http_user_agent = user_agent, uri = uri or "/", scheme = "https", host = "example.com", args = args, ["cookie___openflare_sw"] = cookie, } ngx.req.get_method = function() return method or "GET" end end local function test_module_contract() local runtime = load_runtime() assert_equal(type(runtime), "table", "sw.runtime must return a module table, not true/nil") assert_equal(type(runtime.check), "function", "sw.runtime must export check()") end local function test_non_browser_ua_passes_through() local runtime = load_runtime() reset_request("curl/8.0.1") assert_equal(runtime.check(), true, "non-browser UA passes through") assert_equal(#exec_calls, 0, "non-browser UA must not intercept") reset_request("") assert_equal(runtime.check(), true, "empty UA passes through") reset_request(nil) assert_equal(runtime.check(), true, "missing UA passes through") end local function test_browser_ua_non_get_passes_through() local runtime = load_runtime() reset_request( "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", "/", nil, nil, "POST" ) assert_equal(runtime.check(), true, "non-GET request passes through") assert_equal(#exec_calls, 0, "non-GET request must not be intercepted") end local function test_browser_ua_with_cookie_passes_through() local runtime = load_runtime() reset_request( "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", "/", "1" ) assert_equal(runtime.check(), true, "browser UA with cookie passes through") assert_equal(#exec_calls, 0, "cookie holder must not be intercepted") end local function test_browser_ua_root_without_cookie_intercepts() local runtime = load_runtime() local chrome = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" reset_request(chrome, "/") runtime.check() assert_equal(#exec_calls, 1, "browser without cookie on / must be intercepted once") assert_equal(exec_calls[1], "/__openflare_sw_challenge", "intercept targets the challenge page") assert_equal(redir_args.redir, "https://example.com/", "redir arg preserves scheme+host+uri") reset_request(chrome, "/", nil, "a=1&b=2") runtime.check() assert_equal(#exec_calls, 1, "second request also intercepted") assert_equal(redir_args.redir, "https://example.com/?a=1&b=2", "redir arg keeps the query string") reset_request("Mozilla/5.0 (X11; Linux x86_64; rv:121.0) Gecko/20100101 Firefox/121.0", "/") runtime.check() assert_equal(exec_calls[1], "/__openflare_sw_challenge", "Firefox intercepted") reset_request( "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1", "/" ) runtime.check() assert_equal(exec_calls[1], "/__openflare_sw_challenge", "Safari intercepted") end local function test_browser_ua_non_root_passes_through() local runtime = load_runtime() reset_request( "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", "/about" ) assert_equal(runtime.check(), true, "non-root uri passes through") assert_equal(#exec_calls, 0, "non-root uri must not be intercepted") end local function run_challenge(redir_value) output.body = nil ngx.header = {} redir_args.redir = redir_value local chunk = assert(loadfile(challenge_path)) chunk() return output.body end local function test_challenge_embeds_plain_redir() local body = run_challenge("https://example.com/page?a=1&b=2") assert_equal( string.find(body, 'location.replace("https://example.com/page?a=1&b=2")', 1, true) ~= nil, true, "plain redir embedded verbatim" ) end local function test_challenge_escapes_script_breakout() local payload = '"/>' local body = run_challenge(payload) assert_equal(string.find(body, '">