From 875e9e5eddd1726dc125b1ae7cdce976ae1b7a91 Mon Sep 17 00:00:00 2001 From: Thomas Lynch Date: Sun, 12 Feb 2023 13:17:03 +1100 Subject: [PATCH 1/5] Add back dataplaneapi in anticipation of using it to control haproxy rather than haproxy-sdk runtime socket --- docker-compose.yml | 3 +++ haproxy/Dockerfile | 8 +++++++- haproxy/dataplaneapi.hcl | 27 +++++++++++++++++++++++++++ haproxy/haproxy.cfg | 26 +++++++++++++++----------- haproxy/map/ddos.map | 2 +- 5 files changed, 53 insertions(+), 13 deletions(-) create mode 100644 haproxy/dataplaneapi.hcl diff --git a/docker-compose.yml b/docker-compose.yml index 768642d..2b98432 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,11 +5,14 @@ services: network_mode: host ports: - 80:80 + # - 2000:2000 #runtime api + # - 2001:2001 #dataplaneapi build: context: ./ dockerfile: haproxy/Dockerfile volumes: - ./haproxy/haproxy.cfg:/etc/haproxy/haproxy.cfg + - ./haproxy/dataplaneapi.hcl:/etc/haproxy/dataplaneapi.hcl - ./haproxy/map/:/etc/haproxy/map/ - ./haproxy/template/:/etc/haproxy/template/ - ./src/lua/scripts/:/etc/haproxy/scripts/ diff --git a/haproxy/Dockerfile b/haproxy/Dockerfile index 6b56813..be78e05 100644 --- a/haproxy/Dockerfile +++ b/haproxy/Dockerfile @@ -17,7 +17,8 @@ RUN set -eux; \ --uid 99 \ haproxy -ENV HAPROXY_URL http://www.haproxy.org/download/2.6/src/snapshot/haproxy-ss-LATEST.tar.gz +ENV HAPROXY_URL http://www.haproxy.org/download/2.7/src/snapshot/haproxy-ss-LATEST.tar.gz +ENV DATAPLANEAPI_URL https://github.com/haproxytech/dataplaneapi/releases/download/v2.7.2/dataplaneapi_2.7.2_Linux_x86_64.tar.gz # see https://sources.debian.net/src/haproxy/jessie/debian/rules/ for some helpful navigation of the possible "make" arguments RUN set -eux; \ @@ -37,6 +38,11 @@ RUN set -eux; \ ; \ rm -rf /var/lib/apt/lists/*; \ \ + wget -O dataplaneapi_Linux_x86_64.tar.gz "$DATAPLANEAPI_URL"; \ + tar -zxvf dataplaneapi_Linux_x86_64.tar.gz; \ + chmod +x build/dataplaneapi; \ + cp build/dataplaneapi /usr/local/bin/; \ + \ wget -O haproxy.tar.gz "$HAPROXY_URL"; \ # echo "$HAPROXY_SHA256 *haproxy.tar.gz" | sha256sum -c; \ mkdir -p /usr/src/haproxy; \ diff --git a/haproxy/dataplaneapi.hcl b/haproxy/dataplaneapi.hcl new file mode 100644 index 0000000..5ab0f82 --- /dev/null +++ b/haproxy/dataplaneapi.hcl @@ -0,0 +1,27 @@ +config_version = 2 +name = "basedflare" +mode = "single" + +dataplaneapi { + host = "127.0.0.1" + port = 2001 + user "admin" { + insecure = true + password = "admin" + } + transaction { + transaction_dir = "/tmp/haproxy" + } + advertised {} +} + +haproxy { + config_file = "/etc/haproxy/haproxy.cfg" + haproxy_bin = "/usr/local/sbin/haproxy" + reload { + reload_delay = 5 + reload_cmd = "service haproxy reload" + restart_cmd = "service haproxy restart" + reload_strategy = "custom" + } +} diff --git a/haproxy/haproxy.cfg b/haproxy/haproxy.cfg index f302c1b..daeb518 100644 --- a/haproxy/haproxy.cfg +++ b/haproxy/haproxy.cfg @@ -18,17 +18,21 @@ defaults timeout server 50000ms timeout tarpit 5000ms -#frontend stats-frontend -# bind *:2000 -# option tcplog -# mode tcp -# acl white_list src xxx.xxx.xxx.xxx -# tcp-request connection reject unless white_list -# default_backend stats-backend - -#backend stats-backend -# mode tcp -# server stats-localhost 127.0.0.1:1999 +# program api + # command dataplaneapi -f /etc/haproxy/dataplaneapi.hcl --update-map-files + # no option start-on-reload +# +# frontend stats-frontend + # bind *:2000 + # option tcplog + # mode tcp + # acl white_list src 127.0.0.1 + # tcp-request connection reject unless white_list + # default_backend stats-backend +# +# backend stats-backend + # mode tcp + # server stats-localhost 127.0.0.1:1999 frontend http-in diff --git a/haproxy/map/ddos.map b/haproxy/map/ddos.map index 49766ca..4baa168 100644 --- a/haproxy/map/ddos.map +++ b/haproxy/map/ddos.map @@ -1,2 +1,2 @@ localhost 1 -localhost/captcha 2 +localhost/test 2 From 5a15eddc4a5193ffb137f57ce3b62a5d27489acc Mon Sep 17 00:00:00 2001 From: Thomas Lynch Date: Sun, 12 Feb 2023 21:25:01 +1100 Subject: [PATCH 2/5] rename --- LICENSE.md => LICENSE.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename LICENSE.md => LICENSE.txt (100%) diff --git a/LICENSE.md b/LICENSE.txt similarity index 100% rename from LICENSE.md rename to LICENSE.txt From 87f66479d8984d7fedbcf794c920bb62ad3b17f2 Mon Sep 17 00:00:00 2001 From: Thomas Lynch Date: Mon, 13 Feb 2023 21:59:02 +1100 Subject: [PATCH 3/5] - Change to using domain instead of resolving, because cloudflare blocked this even with the host header, and haproxy 2.7 appears to no longer need this 'hack' - Fix issue with matched_expiry being 0 and breaking captcha cookie - Spacing --- src/lua/scripts/bot-check.lua | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/lua/scripts/bot-check.lua b/src/lua/scripts/bot-check.lua index f42b28a..bca23bd 100644 --- a/src/lua/scripts/bot-check.lua +++ b/src/lua/scripts/bot-check.lua @@ -228,6 +228,7 @@ function _M.view(applet) ) ) valid_submission = true + matched_expiry = number_expiry end end @@ -238,18 +239,24 @@ function _M.view(applet) -- handle setting the captcha cookie local user_captcha_response = parsed_body["h-captcha-response"] or parsed_body["g-recaptcha-response"] + if valid_submission and user_captcha_response then -- only check captcha if POW is already correct + -- format the url for verifying the captcha response local captcha_url = string.format( "https://%s%s", - core.backends[captcha_backend_name].servers[captcha_backend_name]:get_addr(), + --Seems this is no longer needed, captcha_provider_domain works since 2.7 + --core.backends[captcha_backend_name].servers[captcha_backend_name]:get_addr(), + captcha_provider_domain, captcha_siteverify_path ) + -- construct the captcha body to send to the captcha url local captcha_body = url.buildQuery({ secret=captcha_secret, response=user_captcha_response }) + -- instantiate an http client and make the request local httpclient = core.httpclient() local res = httpclient:post{ @@ -257,17 +264,19 @@ function _M.view(applet) body=captcha_body, headers={ [ "host" ] = { captcha_provider_domain }, - [ "content-type" ] = { "application/x-www-form-urlencoded" } + [ "content-type" ] = { "application/x-www-form-urlencoded" }, + [ "user-agent" ] = { "haproxy-protection (haproxy-protection/0.1; +https://gitgud.io/fatchan/haproxy-protection)" } } } + -- try parsing the response as json local status, api_response = pcall(json.decode, res.body) if not status then api_response = {} end + -- the response was good i.e the captcha provider says they passed, give them a cookie if api_response.success == true then - local user_key = sha.bin_to_hex(randbytes(16)) local user_hash = utils.generate_challenge(applet, captcha_cookie_secret, user_key, true) local signature = sha.hmac(sha.sha3_256, hmac_cookie_secret, user_key .. user_hash .. matched_expiry) @@ -282,8 +291,8 @@ function _M.view(applet) ) ) valid_submission = valid_submission and true - end + end if not valid_submission then From 80e966b6d43eea4ba4433f8779b9dcdd81982b60 Mon Sep 17 00:00:00 2001 From: Thomas Lynch Date: Tue, 14 Feb 2023 00:07:06 +1100 Subject: [PATCH 4/5] Revert to 3 dots loader and adjust page style slightly --- src/js/challenge.js | 10 ++++---- src/lua/scripts/templates.lua | 43 ++++++++++++++++++++++++----------- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/js/challenge.js b/src/js/challenge.js index 9c7138f..0a1c732 100644 --- a/src/js/challenge.js +++ b/src/js/challenge.js @@ -4,10 +4,11 @@ function updateElem(selector, text) { } function insertError(str) { - const ring = document.querySelector('.lds-ring'); + const loader = document.querySelector('#loader'); const captcha = document.querySelector('#captcha'); - (ring || captcha).insertAdjacentHTML('afterend', `

Error: ${str}

`); - ring && ring.remove(); + console.log(loader, captcha); + (captcha || loader).insertAdjacentHTML('afterend', `

Error: ${str}

`); + loader && loader.remove(); captcha && captcha.remove(); updateElem('.powstatus', ''); } @@ -153,7 +154,8 @@ const powFinished = new Promise(resolve => { function onCaptchaSubmit(captchaResponse) { const captchaElem = document.querySelector('[data-sitekey]'); - captchaElem.insertAdjacentHTML('afterend', `
`); + // captchaElem.insertAdjacentHTML('afterend', `
`); + captchaElem.insertAdjacentHTML('afterend', `
`); captchaElem.remove(); powFinished.then(powResponse => { postResponse(powResponse, captchaResponse); diff --git a/src/lua/scripts/templates.lua b/src/lua/scripts/templates.lua index 93e1b46..03c9b4c 100644 --- a/src/lua/scripts/templates.lua +++ b/src/lua/scripts/templates.lua @@ -12,19 +12,26 @@ _M.body = [[ @media (prefers-color-scheme:light){:root{--text-color:#333;--bg-color:#EEE}} .h-captcha,.g-recaptcha{min-height:85px;display:block} .red{color:red;font-weight:bold} + .left{text-align:left} .powstatus{color:green;font-weight:bold} a,a:visited{color:var(--text-color)} - body,html{height:100%%} - body{display:flex;flex-direction:column;background-color:var(--bg-color);color:var(--text-color);font-family:Helvetica,Arial,sans-serif;max-width:1200px;margin:0 auto;padding: 0 20px} + body,html{height:100%%;text-align:center;} + body{display:flex;flex-direction:column;background-color:var(--bg-color);color:var(--text-color);font-family:Helvetica,Arial,sans-serif;max-width:60em;margin:0 auto;padding: 0 20px} details{transition: border-left-color 0.5s;max-width:1200px;text-align:left;border-left: 2px solid var(--text-color);padding:10px} - code{background-color:#dfdfdf30;border-radius:3px;padding:0 3px;} - img,h3,p{margin:0 0 5px 0} - footer{font-size:x-small;margin-top:auto;margin-bottom:20px;text-align:center} + code{background-color:#dfdfdf30;border-radius:4px;padding:0 3px;color:#ff6590} + img,h3{margin:0 0 5px 0} + li{margin-bottom: 1em} + footer{font-size:x-small;margin-top:auto;padding:10px;text-align:center;border-top:1px solid #80808040;padding:10px} img{display:inline} - .pt{padding-top:15vh;display:flex;align-items:center;word-break:break-all} + textarea,input{background:var(--bg-color);color:var(--text-color);border:1px solid var(--text-color);width:100%%;box-sizing: border-box;resize:none;padding:0.5em;font-family:inherit} + .pt{padding-top:30vh;display:flex;align-items:center;word-break:break-all;justify-content: center;} .pt img{margin-right:10px} - details[open]{border-left-color: #1400ff} - .lds-ring{display:inline-block;position:relative;width:80px;height:80px}.lds-ring div{box-sizing:border-box;display:block;position:absolute;width:32px;height:32px;margin:10px;border:5px solid var(--text-color);border-radius:50%%;animation:lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;border-color:var(--text-color) transparent transparent transparent}.lds-ring div:nth-child(1){animation-delay:-0.45s}.lds-ring div:nth-child(2){animation-delay:-0.3s}.lds-ring div:nth-child(3){animation-delay:-0.15s}@keyframes lds-ring{0%%{transform:rotate(0deg)}100%%{transform:rotate(360deg)}} + details[open]{border-left-color: #1400ff} + .b{display:inline-block;background:#6b93f7;border-radius:50%%;margin:10px;height:16px;width:16px;box-shadow:0 0 0 0 #6b93f720;transform:scale(1)} + .b:nth-of-type(1){animation:p 3s infinite} + .b:nth-of-type(2){animation:p 3s .5s infinite} + .b:nth-of-type(3){animation:p 3s 1s infinite} + @keyframes p{0%%{transform:scale(.95);box-shadow:0 0 0 0 #6b93f790}70%%{transform:scale(1);box-shadow:0 0 0 10px #6b93f700}100%%{transform:scale(.95);box-shadow:0 0 0 0 #6b93f700}}