diff --git a/README.md b/README.md index db13342..92b8d54 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ Originally inspired by a proof of concept from https://github.com/mora9715/hapro - Maintenance mode page for selected domains. - Geoip mapping support for alt-svc headers. - Support simple load balancing to multiple backends per domain dynamically. +- Multiple language support with locales files (currently en-US and pt-PT). - Fix multiple security issues. - Many bugfixes. diff --git a/docker-compose.yml b/docker-compose.yml index 36f426f..2c94009 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,6 +17,7 @@ services: - ./src/lua/scripts/:/etc/haproxy/scripts/ - ./src/lua/libs/:/etc/haproxy/libs/ - ./src/js/:/etc/haproxy/js/ + - ./src/locales/:/etc/haproxy/locales/ environment: # These are the hcaptcha and recaptcha test keys, not leaking any dont worry :^) - HCAPTCHA_SITEKEY=20000000-ffff-ffff-ffff-000000000002 diff --git a/src/locales/en-US.json b/src/locales/en-US.json new file mode 100644 index 0000000..d00ec4a --- /dev/null +++ b/src/locales/en-US.json @@ -0,0 +1,23 @@ +{ + "Maintenance Mode": "Maintenance Mode", + "Under maintenance. Please try again soon!": "Under maintenance. Please try again soon!", + "Hold on...": "Hold on...", + "Browser does not support Web Workers.": "Browser does not support Web Workers.", + "Browser does not support WebAssembly.": "Browser does not support WebAssembly.", + "Server rejected your submission.": "Server rejected your submission.", + "Server encountered an error.": "Server encountered an error.", + "Failed to send request to server.": "Failed to send request to server.", + "Working, ≈%ss remaining": "Working, ≈%ss remaining", + "Waiting for captcha.": "Waiting for captcha.", + "Submitting...": "Submitting...", + "Performance & security by BasedFlare": "Performance & security by BasedFlare", + "Verifying your connection to %s": "Verifying your connection to %s", + "This process is automatic, please wait a moment...": "This process is automatic, please wait a moment...", + "Please solve the captcha to continue.": "Please solve the captcha to continue.", + "JavaScript is required on this page.": "JavaScript is required on this page.", + "No JavaScript?": "No JavaScript?", + "Run this in a linux terminal (requires argon2 package installed):": "Run this in a linux terminal (requires argon2 package installed):", + "Run this in a linux terminal (requires perl):": "Run this in a linux terminal (requires perl):", + "Paste the script output into the box and submit:": "Paste the script output into the box and submit:", + "submit": "submit" +} diff --git a/src/locales/pt-PT.json b/src/locales/pt-PT.json new file mode 100644 index 0000000..9ece498 --- /dev/null +++ b/src/locales/pt-PT.json @@ -0,0 +1,23 @@ +{ + "Maintenance Mode": "Modo Manutenção", + "Under maintenance. Please try again soon!": "Em manutenção. Tenta outra vez em breve!", + "Hold on...": "Aguarda...", + "Browser does not support Web Workers.": "Navegador não suporta Web Workers.", + "Browser does not support WebAssembly.": "Navegador não suporta WebAssembly.", + "Server rejected your submission.": "Servidor rejeitou o teu pedido.", + "Server encountered an error.": "Servidor encontrou um erro.", + "Failed to send request to server.": "Envio de pedido ao servidor falhou.", + "Working, ≈%ss remaining": "A trabalhar, ≈%ss para terminar", + "Waiting for captcha.": "À espera do captcha.", + "Submitting...": "A enviar...", + "Performance & security by BasedFlare": "Performance & segurança por BasedFlare", + "Verifying your connection to %s": "A verificar a tua ligação a %s", + "This process is automatic, please wait a moment...": "Este processo é automático, por favor espera um momento...", + "Please solve the captcha to continue.": "Por favor resolve a captcha para continuar.", + "JavaScript is required on this page.": "Javascript é necessário nesta página.", + "No JavaScript?": "Sem Javascript?", + "Run this in a linux terminal (requires argon2 package installed):": "Corre isto num terminal linux (requer package argon2 instalada):", + "Run this in a linux terminal (requires perl):": "Corre isto num terminal linux (requer perl):", + "Paste the script output into the box and submit:": "Cola o output do script na caixa e envia:", + "submit": "enviar" +} diff --git a/src/lua/scripts/bot-check.lua b/src/lua/scripts/bot-check.lua index d6690af..3b23cd8 100644 --- a/src/lua/scripts/bot-check.lua +++ b/src/lua/scripts/bot-check.lua @@ -11,6 +11,19 @@ local cookie = require("cookie") local json = require("json") local randbytes = require("randbytes") local templates = require("templates") +local locales_path = "/etc/haproxy/locales/" +local locales_table = {} +-- local locales_strings = {} +for file_name in io.popen('ls "'..locales_path..'"*.json'):lines() do + local file_name_with_path = utils.split(file_name, "/") + local file_name_without_ext = utils.split(file_name_with_path[#file_name_with_path], ".")[1] + local file = io.open(file_name, "r") + local json_contents = file:read("*all") + local json_object = json.decode(json_contents) + file:close() + locales_table[file_name_without_ext] = json_object + -- locales_strings[file_name_without_ext] = json_contents +end -- POW local pow_type = os.getenv("POW_TYPE") or "argon2" @@ -74,8 +87,31 @@ function _M.kill_tor_circuit(txn) utils.send_tor_control_port(circuit_identifier) end +-- read first language from accept-language in applet +local default_lang = "en-US" +function _M.get_first_language(applet) + local accept_language = applet.headers["accept-language"] or {} + accept_language = accept_language[0] or "" + if #accept_language > 0 and #accept_language < 100 then -- length limit preventing abuse + for lang in accept_language:gmatch("[^,%s]+") do + if not lang:find(";") then + return lang + end + end + end +end + + function _M.view(applet) + -- set the ll language var based off header or default to en-US + local lang = _M.get_first_language(applet) + local ll = locales_table[lang] + if ll == nil then + ll = locales_table[default_lang] + lang = default_lang + end + -- set response body and declare status code local response_body = "" local response_status_code @@ -120,27 +156,62 @@ function _M.view(applet) end -- pow at least is always enabled when reaching bot-check page - site_name_body = string.format(templates.site_name_section, host) + site_name_body = string.format( + templates.site_name_section, + string.format(ll["Verifying your connection to %s"], host) + ) if captcha_enabled then - captcha_body = string.format(templates.captcha_section, captcha_classname, - captcha_sitekey, captcha_script_src) + captcha_body = string.format( + templates.captcha_section, + ll["Please solve the captcha to continue."], + captcha_classname, + captcha_sitekey, + captcha_script_src + ) else - pow_body = templates.pow_section + pow_body = string.format( + templates.pow_section, + ll["This process is automatic, please wait a moment..."] + ) local noscript_extra if pow_type == "argon2" then noscript_extra = templates.noscript_extra_argon2 else noscript_extra = templates.noscript_extra_sha256 end - noscript_extra_body = string.format(noscript_extra, user_key, - challenge_hash, expiry, signature, math.ceil(pow_difficulty/8), - argon_time, argon_kb) + noscript_extra_body = string.format( + noscript_extra, + ll["No JavaScript?"], + ll["Run this in a linux terminal (requires perl):"], + user_key, + challenge_hash, + expiry, + signature, + math.ceil(pow_difficulty/8), + argon_time, + argon_kb, + ll["Paste the script output into the box and submit:"] + ) end -- sub in the body sections - response_body = string.format(templates.body, combined_challenge, - pow_difficulty, argon_time, argon_kb, pow_type, - site_name_body, pow_body, captcha_body, noscript_extra_body, ray_id) + response_body = string.format( + templates.body, + lang, + ll["Hold on..."], + combined_challenge, + pow_difficulty, + argon_time, + argon_kb, + pow_type, + site_name_body, + pow_body, + captcha_body, + ll["JavaScript is required on this page."], + noscript_extra_body, + ray_id, + ll["Performance & security by BasedFlare"] + ) response_status_code = 403 -- if request is POST, check the answer to the pow/cookie diff --git a/src/lua/scripts/templates.lua b/src/lua/scripts/templates.lua index 7b623e1..41efba0 100644 --- a/src/lua/scripts/templates.lua +++ b/src/lua/scripts/templates.lua @@ -4,9 +4,9 @@ local _M = {} _M.body = [[ - + - Hold on... + %s