improved, now handles domain OR path protection with 0, 1, 2 setting for none, pow, captcha

global override does POW only (for now --or can be easily changed for captcha+pow) until i make that customisable level too
no more confusing inverted map
use maps correctly as k:v
cleaned up some stuff
added comments
This commit is contained in:
Thomas Lynch
2021-12-04 21:42:27 +11:00
parent e6ed817746
commit 6f52ee8977
9 changed files with 70 additions and 87 deletions

View File

@@ -15,7 +15,7 @@ local ray_id = os.getenv("RAY_ID")
local captcha_provider_domain = "hcaptcha.com"
local captcha_map = Map.new("/etc/haproxy/no_captcha.map", Map._dom);
local captcha_map = Map.new("/etc/haproxy/ddos.map", Map._str);
-- main page template
local body_template = [[
@@ -83,20 +83,35 @@ function _M.view(applet)
local response_body = ""
local response_status_code
if applet.method == "GET" then
-- get challenge string for proof of work
generated_work = utils.generate_secret(applet, pow_cookie_secret, true, "")
-- define body sections
local captcha_body = ""
local pow_body = ""
-- pretty much same as decice_checks but path is different. todo: refactor and pass the applet, with some ifs for applet vs txn
local captcha_enabled = false
local host = applet.headers['host'][0]
loc = captcha_map:lookup(host);
if loc == nil then
local domain_lookup = captcha_map:lookup(host) or 0
domain_lookup = tonumber(domain_lookup)
local path = applet.qs; --because on /bot-check?/whatever, .qs (query string) holds the "path"
local path_lookup = captcha_map:lookup(host..path) or 0
path_lookup = tonumber(path_lookup)
if (path_lookup == 2 and path_lookup >= domain_lookup) or domain_lookup == 2 then
captcha_enabled = true
end
--
-- pow at least is always enabled when reaching bot-check page
if captcha_enabled then
captcha_body = string.format(captcha_section_template, captcha_sitekey)
else
pow_body = pow_section_template
end
-- sub in the body sections
response_body = string.format(body_template, generated_work, pow_body, captcha_body, ray_id)
response_status_code = 403
elseif applet.method == "POST" then
@@ -120,14 +135,13 @@ function _M.view(applet)
"set-cookie",
string.format("z_ddos_captcha=%s; expires=Thu, 31-Dec-37 23:55:55 GMT; Path=/; SameSite=Strict; Secure=true;", floating_hash)
)
-- else
-- core.Debug("HCAPTCHA FAILED: " .. json.encode(api_response))
end
end
-- if failed captcha, will just get sent back here so 302 is fine
response_status_code = 302
applet:add_header("location", applet.qs)
else
--other methods
-- other methods
response_status_code = 403
end
applet:set_status(response_status_code)
@@ -137,15 +151,35 @@ function _M.view(applet)
applet:send(response_body)
end
-- decide which checks to do based on domain and path and domain acls
function _M.decide_checks_necessary(txn)
local host = txn.sf:hdr("Host")
local domain_lookup = captcha_map:lookup(host) or 0
domain_lookup = tonumber(domain_lookup)
local path = txn.sf:path();
local path_lookup = captcha_map:lookup(host..path) or 0
path_lookup = tonumber(path_lookup)
-- probably should make this check less shit
if (path_lookup == 2 and path_lookup >= domain_lookup) or domain_lookup == 2 then
-- check both if captcha mode enabled
txn:set_var("txn.validate_captcha", true)
txn:set_var("txn.validate_pow", true)
elseif (path_lookup == 1 and path_lookup >= domain_lookup) or domain_lookup == 1 then
-- only check pow if mode=1
txn:set_var("txn.validate_pow", true)
end
end
-- check if captcha token is valid, separate secret from POW
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
-- check if pow token is valid
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

View File

@@ -5,3 +5,4 @@ local hcaptcha = require("hcaptcha")
core.register_service("hcaptcha-view", "http", hcaptcha.view)
core.register_action("hcaptcha-check", { 'http-req', }, hcaptcha.check_captcha_status)
core.register_action("pow-check", { 'http-req', }, hcaptcha.check_pow_status)
core.register_action("decide-checks-necessary", { 'http-req', }, hcaptcha.decide_checks_necessary)