mirror of
https://gitgud.io/fatchan/haproxy-protection.git
synced 2025-05-09 02:05:37 +00:00
Start on localisation ref #22
This commit is contained in:
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
23
src/locales/en-US.json
Normal file
23
src/locales/en-US.json
Normal file
@ -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 <a href=\"https://basedflare.com\" rel=\"noreferrer noopener\" target=\"_blank\">BasedFlare</a>",
|
||||
"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 <code>argon2</code> package installed):": "Run this in a linux terminal (requires <code>argon2</code> package installed):",
|
||||
"Run this in a linux terminal (requires <code>perl</code>):": "Run this in a linux terminal (requires <code>perl</code>):",
|
||||
"Paste the script output into the box and submit:": "Paste the script output into the box and submit:",
|
||||
"submit": "submit"
|
||||
}
|
23
src/locales/pt-PT.json
Normal file
23
src/locales/pt-PT.json
Normal file
@ -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 <a href=\"https://basedflare.com\" rel=\"noreferrer noopener\" target=\"_blank\">BasedFlare</a>",
|
||||
"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 <code>argon2</code> package installed):": "Corre isto num terminal linux (requer package <code>argon2</code> instalada):",
|
||||
"Run this in a linux terminal (requires <code>perl</code>):": "Corre isto num terminal linux (requer <code>perl</code>):",
|
||||
"Paste the script output into the box and submit:": "Cola o output do script na caixa e envia:",
|
||||
"submit": "enviar"
|
||||
}
|
@ -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 <code>perl</code>):"],
|
||||
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
|
||||
|
@ -4,9 +4,9 @@ local _M = {}
|
||||
_M.body = [[
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<head lang="%s">
|
||||
<meta name='viewport' content='width=device-width initial-scale=1'>
|
||||
<title>Hold on...</title>
|
||||
<title>%s</title>
|
||||
<style>
|
||||
:root{--text-color:#c5c8c6;--bg-color:#1d1f21}
|
||||
@media (prefers-color-scheme:light){:root{--text-color:#333;--bg-color:#fff}}
|
||||
@ -46,13 +46,13 @@ details[open]{border-left-color: #1400ff}
|
||||
%s
|
||||
<noscript>
|
||||
<br>
|
||||
<p class="red left">JavaScript is required on this page.</p>
|
||||
<p class="red left">%s</p>
|
||||
%s
|
||||
</noscript>
|
||||
<div class="powstatus"></div>
|
||||
<footer>
|
||||
<p>Node: <code>%s</code></p>
|
||||
<p>Performance & security by <a href="https://basedflare.com" rel="noreferrer noopener" target="_blank">BasedFlare</a></p>
|
||||
<p>%s</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@ -60,16 +60,16 @@ details[open]{border-left-color: #1400ff}
|
||||
|
||||
_M.noscript_extra_argon2 = [[
|
||||
<details>
|
||||
<summary>No JavaScript?</summary>
|
||||
<summary>%s</summary>
|
||||
<ol>
|
||||
<li>
|
||||
<p>Run this in a linux terminal (requires <code>argon2</code> package installed):</p>
|
||||
<p>%s</p>
|
||||
<code style="word-break: break-all;">
|
||||
echo "Q0g9IiQyIjtCPSQocHJpbnRmIDAlLjBzICQoc2VxIDEgJDUpKTtlY2hvICJXb3JraW5nLi4uIjtJPTA7d2hpbGUgdHJ1ZTsgZG8gSD0kKGVjaG8gLW4gJENIJEkgfCBhcmdvbjIgJDEgLWlkIC10ICQ2IC1rICQ3IC1wIDEgLWwgMzIgLXIpO0U9JHtIOjA6JDV9O1tbICRFID09ICRCIF1dICYmIGVjaG8gIk91dHB1dDoiICYmIGVjaG8gJDEjJDIjJDMjJDQjJEkgJiYgZXhpdCAwOygoSSsrKSk7ZG9uZTsK" | base64 -d | bash -s %s %s %s %s %s %s %s
|
||||
</code>
|
||||
<li>Paste the script output into the box and submit:
|
||||
<li>%s
|
||||
<form method="post">
|
||||
<textarea name="pow_response" placeholder="script output" required></textarea>
|
||||
<textarea name="pow_response" required></textarea>
|
||||
<div><input type="submit" value="submit" /></div>
|
||||
</form>
|
||||
</ol>
|
||||
@ -78,16 +78,16 @@ _M.noscript_extra_argon2 = [[
|
||||
|
||||
_M.noscript_extra_sha256 = [[
|
||||
<details>
|
||||
<summary>No JavaScript?</summary>
|
||||
<summary>%s</summary>
|
||||
<ol>
|
||||
<li>
|
||||
<p>Run this in a linux terminal (requires <code>perl</code>):</p>
|
||||
<p>%s</p>
|
||||
<code style="word-break: break-all;">
|
||||
echo "dXNlIHN0cmljdDt1c2UgRGlnZXN0OjpTSEEgcXcoc2hhMjU2X2hleCk7cHJpbnQgIldvcmtpbmcuLi4iO215JGM9IiRBUkdWWzBdIi4iJEFSR1ZbMV0iO215JGlkPSRBUkdWWzRdKzA7bXkkZD0iMCJ4JGlkO215JGk9MDt3aGlsZSgxKXtsYXN0IGlmICRkIGVxIHN1YnN0ciBzaGEyNTZfaGV4KCRjLCRpKSwwLCRpZDskaSsrfXByaW50IlxuT3V0cHV0OlxuJEFSR1ZbMF0jJEFSR1ZbMV0jJEFSR1ZbMl0jJEFSR1ZbM10jJGlcbiI=" | base64 -d | perl -w - %s %s %s %s %s %s %s
|
||||
</code>
|
||||
<li>Paste the script output into the box and submit:
|
||||
<li>%s
|
||||
<form method="post">
|
||||
<textarea name="pow_response" placeholder="script output" required></textarea>
|
||||
<textarea name="pow_response" required></textarea>
|
||||
<div><input type="submit" value="submit" /></div>
|
||||
</form>
|
||||
</ol>
|
||||
@ -98,14 +98,14 @@ _M.noscript_extra_sha256 = [[
|
||||
_M.site_name_section = [[
|
||||
<h3 class="pt">
|
||||
<img src="/favicon.ico" width="64" height="64" alt=" ">
|
||||
Verifying your connection to %s
|
||||
%s
|
||||
</h3>
|
||||
]]
|
||||
|
||||
-- animation while waiting
|
||||
_M.pow_section = [[
|
||||
<span>
|
||||
This process is automatic, please wait a moment...
|
||||
%s
|
||||
</span>
|
||||
<div class="jsonly">
|
||||
<div id="loader"><div class="b"></div><div class="b"></div><div class="b"></div></div>
|
||||
@ -125,7 +125,7 @@ _M.pow_section = [[
|
||||
-- message, captcha form and submit button
|
||||
_M.captcha_section = [[
|
||||
<p>
|
||||
Please solve the captcha to continue.
|
||||
%s
|
||||
</p>
|
||||
<div id="captcha" class="jsonly">
|
||||
<div class="%s" data-sitekey="%s" data-callback="onCaptchaSubmit"></div>
|
||||
|
Reference in New Issue
Block a user