diff --git a/haproxy/haproxy.cfg b/haproxy/haproxy.cfg index 09051e5..47ce854 100644 --- a/haproxy/haproxy.cfg +++ b/haproxy/haproxy.cfg @@ -13,9 +13,15 @@ defaults frontend http-in bind *:80 default_backend servers - # http-request lua.test-payload - http-request use-service lua.hello-world if { path /hello_world } - http-request use-service lua.hcaptcha-view if { path /captcha } + + http-request lua.hcaptcha-redirect if !{ path -m beg /captcha } + http-request use-service lua.hello-world if { path /hello_world } + http-request use-service lua.hcaptcha-view if { path /captcha/ } http-request use-service lua.ratelimit if { path /test } + + acl captcha_passed var(txn.captcha_passed) -m bool + acl on_captcha_url path -m beg /captcha + redirect prefix /captcha code 301 if !captcha_passed !on_captcha_url + backend servers server server1 nginx:80 maxconn 32 diff --git a/scripts/cookie.lua b/scripts/cookie.lua new file mode 100644 index 0000000..9da861e --- /dev/null +++ b/scripts/cookie.lua @@ -0,0 +1,82 @@ +-- Copyright (C) 2013-2016 Jiale Zhi (calio), CloudFlare Inc. +-- See RFC6265 http://tools.ietf.org/search/rfc6265 +-- require "luacov" + +local type = type +local byte = string.byte +local sub = string.sub + +local EQUAL = byte("=") +local SEMICOLON = byte(";") +local SPACE = byte(" ") +local HTAB = byte("\t") + + +local _M = {} +_M._VERSION = '0.01' + + +function _M.get_cookie_table(text_cookie) + if type(text_cookie) ~= "string" then + return {} + end + + local EXPECT_KEY = 1 + local EXPECT_VALUE = 2 + local EXPECT_SP = 3 + + local n = 0 + local len = #text_cookie + + for i=1, len do + if byte(text_cookie, i) == SEMICOLON then + n = n + 1 + end + end + + local cookie_table = {} + + local state = EXPECT_SP + local i = 1 + local j = 1 + local key, value + + while j <= len do + if state == EXPECT_KEY then + if byte(text_cookie, j) == EQUAL then + key = sub(text_cookie, i, j - 1) + state = EXPECT_VALUE + i = j + 1 + end + elseif state == EXPECT_VALUE then + if byte(text_cookie, j) == SEMICOLON + or byte(text_cookie, j) == SPACE + or byte(text_cookie, j) == HTAB + then + value = sub(text_cookie, i, j - 1) + cookie_table[key] = value + + key, value = nil, nil + state = EXPECT_SP + i = j + 1 + end + elseif state == EXPECT_SP then + if byte(text_cookie, j) ~= SPACE + and byte(text_cookie, j) ~= HTAB + then + state = EXPECT_KEY + i = j + j = j - 1 + end + end + j = j + 1 + end + + if key ~= nil and value == nil then + cookie_table[key] = sub(text_cookie, i) + end + + return cookie_table +end + +return _M diff --git a/scripts/counter.lua b/scripts/counter.lua index 80dd036..99a8091 100644 --- a/scripts/counter.lua +++ b/scripts/counter.lua @@ -1,8 +1,2 @@ --- --- Created by IntelliJ IDEA. --- User: dinoz --- Date: 08.06.2021 --- Time: 15:28 --- To change this template use File | Settings | File Templates. --- - + + diff --git a/scripts/hcaptcha.lua b/scripts/hcaptcha.lua index 7dcb501..bcb3376 100644 --- a/scripts/hcaptcha.lua +++ b/scripts/hcaptcha.lua @@ -4,13 +4,12 @@ local url = require("net.url") local https = require("ssl.https") local json = require("json") local utils = require("utils") - +local cookie = require("cookie") local floating_hash = utils.get_floating_hash() function hcaptcha.view(applet) local hcaptcha_secret = os.getenv("HCAPTCHA_SECRET") local hcaptcha_sitekey = os.getenv("HCAPTCHA_SITEKEY") - local response if applet.method == "GET" then response = @@ -37,7 +36,7 @@ function hcaptcha.view(applet) if api_response.success == true then print("HCAPTCHA SUCCESSFULLY PASSED") - applet:add_header("set-cookie", string.format("z_ddos_protection=%s; Max-Age=14400", floating_hash)) + applet:add_header("set-cookie", string.format("z_ddos_protection=%s; Max-Age=14400; Path=/", floating_hash)) else print("HCAPTCHA FAILED", body) end @@ -52,3 +51,19 @@ function hcaptcha.view(applet) applet:start_response() applet:send(response) end + +function hcaptcha.check_captcha_status(txn) + print("CAPTCHA STATUS CHECK START") + local raw_request_cookies = txn.sf:hdr("Cookie") + local parsed_request_cookies = cookie.get_cookie_table(raw_request_cookies) + + print("RECEIVED SECRET COOKIE: ", parsed_request_cookies["z_ddos_protection"]) + print("OUR SECRET COOKIE: ", floating_hash) + + if parsed_request_cookies["z_ddos_protection"] == floating_hash then + print("CAPTCHA STATUS CHECK SUCCESS") + return txn:set_var("txn.captcha_passed", true); + end + + print("CAPTCHA STATUS CHECK FINISH") +end \ No newline at end of file diff --git a/scripts/register.lua b/scripts/register.lua index 16983c9..c5894d4 100644 --- a/scripts/register.lua +++ b/scripts/register.lua @@ -4,7 +4,8 @@ require("guard") require("hcaptcha") require("test") ---core.register_service("hello-world", "http", guard.hello_world) ---core.register_service("hcaptcha-view", "http", hcaptcha.view) ---core.register_service("test", "http", test.hello_world2) + +core.register_service("hello-world", "http", guard.hello_world) +core.register_service("hcaptcha-view", "http", hcaptcha.view) +core.register_action("hcaptcha-redirect", { 'http-req', }, hcaptcha.check_captcha_status) core.register_service("ratelimit", "http", test.ratelimit) diff --git a/scripts/test.lua b/scripts/test.lua index ae98def..25df7e0 100644 --- a/scripts/test.lua +++ b/scripts/test.lua @@ -1,6 +1,27 @@ package.path = package.path .. "./?.lua;/usr/local/etc/haproxy/scripts/?.lua" - +test = {} local redis = require 'redis' -client = redis.connect('127.0.0.1', 6379) -response = client:ping() - +client = redis.connect('redis', 6379) +-- response = client:ping() +-- print(response) +function test.ratelimit(applet) + host = applet.headers.host[0] + current = client:llen(host) + if current > 3 then + applet:set_status(200) + local response = string.format([[powel naxyi %s, current - %s\n]], host, current, message); + applet:add_header("content-type", "text/html"); + applet:add_header("content-length", string.len(response)) + applet:start_response() + applet:send(response) + else + client:rpush(host,host) + client:expire(host, 10) + applet:set_status(200) + local response = string.format([[lox %s, current - %s\n]], host, current, message); + applet:add_header("content-type", "text/html"); + applet:add_header("content-length", string.len(response)) + applet:start_response() + applet:send(response) + end +end \ No newline at end of file