_M = {} local url = require("url") local http = require("http") local utils = require("utils") local cookie = require("cookie") local json = require("json") local sha = require("sha") local captcha_secret = os.getenv("HCAPTCHA_SECRET") local captcha_sitekey = os.getenv("HCAPTCHA_SITEKEY") local hcaptcha_cookie_secret = os.getenv("CAPTCHA_COOKIE_SECRET") local pow_cookie_secret = os.getenv("POW_COOKIE_SECRET") local captcha_provider_domain = "hcaptcha.com" local captcha_map = Map.new("/etc/haproxy/no_captcha.map", Map._dom); -- main page template local body_template = [[ Hold on...

Checking your browser for robots...

%s %s ]] -- 3 dots animation for proof of work local pow_section_template = [[
]] -- message, hcaptcha form and submit button local captcha_section_template = [[

Please solve the captcha to continue.

]] function _M.view(applet) local response_body local response_status_code if applet.method == "GET" then generated_work = utils.generate_secret(applet, pow_cookie_secret, true, "") local captcha_body = "" local pow_body = "" local captcha_enabled = false local host = applet.headers['host'][0] loc = captcha_map:lookup(host); if loc == nil then captcha_enabled = true end if captcha_enabled then captcha_body = string.format(captcha_section_template, captcha_sitekey) else pow_body = pow_section_template end response_body = string.format(body_template, generated_work, pow_body, captcha_body) response_status_code = 403 applet:set_status(response_status_code) applet:add_header("content-type", "text/html") applet:add_header("content-length", string.len(response_body)) applet:start_response() applet:send(response_body) elseif applet.method == "POST" then local parsed_body = url.parseQuery(applet.receive(applet)) if parsed_body["h-captcha-response"] then local url = string.format( "https://%s/siteverify?secret=%s&response=%s", core.backends["hcaptcha"].servers["hcaptcha"]:get_addr(), captcha_secret, parsed_body["h-captcha-response"] ) local res, err = http.get{url=url, headers={host=captcha_provider_domain} } local status, api_response = pcall(res.json, res) if not status then local original_error = api_response api_response = {} end if api_response.success == true then local floating_hash = utils.generate_secret(applet, hcaptcha_cookie_secret, true, nil) applet:add_header( "set-cookie", string.format("z_ddos_captcha=%s; expires=Thu, 31-Dec-37 23:55:55 GMT; Path=/", floating_hash) ) -- else -- core.Debug("HCAPTCHA FAILED: " .. json.encode(api_response)) end end response_body = "" response_status_code = 302 applet:add_header("location", applet.qs) applet:set_status(response_status_code) applet:add_header("content-type", "text/html") applet:add_header("content-length", string.len(response_body)) applet:start_response() applet:send(response_body) end end function _M.check_captcha_status(txn) local parsed_request_cookies = cookie.get_cookie_table(txn.sf:hdr("Cookie")) local expected_cookie = utils.generate_secret(txn, hcaptcha_cookie_secret, false, nil) if parsed_request_cookies["z_ddos_captcha"] == expected_cookie then --core.Debug("CAPTCHA STATUS CHECK SUCCESS") return txn:set_var("txn.captcha_passed", true) end end function _M.check_pow_status(txn) local parsed_request_cookies = cookie.get_cookie_table(txn.sf:hdr("Cookie")) if parsed_request_cookies["z_ddos_pow"] then local generated_work = utils.generate_secret(txn, pow_cookie_secret, false, "") local iterations = parsed_request_cookies["z_ddos_pow"] local completed_work = sha.sha1(generated_work .. iterations) local challenge_offset = tonumber(generated_work:sub(1,1),16) * 2 --core.Debug(completed_work:sub(challenge_offset+1, challenge_offset+4)) if completed_work:sub(challenge_offset+1, challenge_offset+4) == 'b00b' then -- i dont know lua properly :^) return txn:set_var("txn.pow_passed", true) end end end return _M