bunkerweb 1.4.0
This commit is contained in:
@@ -0,0 +1,375 @@
|
||||
local _M = {}
|
||||
_M.__index = _M
|
||||
|
||||
local utils = require "utils"
|
||||
local datastore = require "datastore"
|
||||
local logger = require "logger"
|
||||
local cjson = require "cjson"
|
||||
local session = require "resty.session"
|
||||
local captcha = require "antibot.captcha"
|
||||
local base64 = require "base64"
|
||||
local sha256 = require "resty.sha256"
|
||||
local str = require "resty.string"
|
||||
local http = require "resty.http"
|
||||
|
||||
function _M.new()
|
||||
local self = setmetatable({}, _M)
|
||||
return self, nil
|
||||
end
|
||||
|
||||
function _M:init()
|
||||
-- Check if init is needed
|
||||
local init_needed, err = utils.has_not_variable("USE_ANTIBOT", "no")
|
||||
if init_needed == nil then
|
||||
return false, err
|
||||
end
|
||||
if not init_needed then
|
||||
return true, "no service uses Antibot, skipping init"
|
||||
end
|
||||
-- Load templates
|
||||
local templates = {}
|
||||
for i, template in ipairs({"javascript", "captcha", "recaptcha", "hcaptcha"}) do
|
||||
local f, err = io.open("/opt/bunkerweb/core/antibot/files/" .. template .. ".html")
|
||||
if not f then
|
||||
return false, "error while loading " .. template .. ".html : " .. err
|
||||
end
|
||||
templates[template] = f:read("*all")
|
||||
f:close()
|
||||
end
|
||||
local ok, err = datastore:set("plugin_antibot_templates", cjson.encode(templates))
|
||||
if not ok then
|
||||
return false, "can't save templates to datastore : " .. err
|
||||
end
|
||||
return true, "success"
|
||||
end
|
||||
|
||||
function _M:access()
|
||||
-- Check if access is needed
|
||||
local antibot, err = utils.get_variable("USE_ANTIBOT")
|
||||
if antibot == nil then
|
||||
return false, err, nil, nil
|
||||
end
|
||||
if antibot == "no" then
|
||||
return true, "Antibot not activated", nil, nil
|
||||
end
|
||||
|
||||
-- Get challenge URI
|
||||
local challenge_uri, err = utils.get_variable("ANTIBOT_URI")
|
||||
if not challenge_uri then
|
||||
return false, "can't get Antibot URI from datastore : " .. err, nil, nil
|
||||
end
|
||||
|
||||
-- Don't go further if client resolved the challenge
|
||||
local resolved, err, original_uri = self:challenge_resolved(antibot)
|
||||
if resolved == nil then
|
||||
return false, "can't check if challenge is resolved : " .. err, nil, nil
|
||||
end
|
||||
if resolved then
|
||||
if ngx.var.uri == challenge_uri then
|
||||
return true, "client already resolved the challenge", true, ngx.redirect(original_uri)
|
||||
end
|
||||
return true, "client already resolved the challenge", nil, nil
|
||||
end
|
||||
|
||||
-- Redirect to challenge page
|
||||
if ngx.var.uri ~= challenge_uri then
|
||||
local ok, err = self:prepare_challenge(antibot, challenge_uri)
|
||||
if not ok then
|
||||
return false, "can't prepare challenge : " .. err, true, ngx.HTTP_INTERNAL_SERVER_ERROR
|
||||
end
|
||||
return true, "redirecting client to the challenge uri", true, ngx.redirect(challenge_uri)
|
||||
end
|
||||
|
||||
-- Display challenge
|
||||
if ngx.var.request_method == "GET" then
|
||||
local ok, err = self:display_challenge(antibot, challenge_uri)
|
||||
if not ok then
|
||||
if err == "can't open session" then
|
||||
local ok, err = self:prepare_challenge(antibot, challenge_uri)
|
||||
if not ok then
|
||||
return false, "can't prepare challenge : " .. err, true, ngx.HTTP_INTERNAL_SERVER_ERROR
|
||||
end
|
||||
return true, "redirecting client to the challenge uri", true, ngx.redirect(challenge_uri)
|
||||
end
|
||||
return false, "display challenge error : " .. err, true, ngx.HTTP_INTERNAL_SERVER_ERROR
|
||||
end
|
||||
return true, "displaying challenge to client", true, ngx.HTTP_OK
|
||||
end
|
||||
|
||||
-- Check challenge
|
||||
if ngx.var.request_method == "POST" then
|
||||
local ok, err, redirect = self:check_challenge(antibot)
|
||||
if ok == nil then
|
||||
if err == "can't open session" then
|
||||
local ok, err = self:prepare_challenge(antibot, challenge_uri)
|
||||
if not ok then
|
||||
return false, "can't prepare challenge : " .. err, true, ngx.HTTP_INTERNAL_SERVER_ERROR
|
||||
end
|
||||
return true, "redirecting client to the challenge uri", true, ngx.redirect(challenge_uri)
|
||||
end
|
||||
return false, "check challenge error : " .. err, true, ngx.HTTP_INTERNAL_SERVER_ERROR
|
||||
end
|
||||
if redirect then
|
||||
return true, "check challenge redirect : " .. redirect, true, ngx.redirect(redirect)
|
||||
end
|
||||
local ok, err = self:display_challenge(antibot)
|
||||
if not ok then
|
||||
if err == "can't open session" then
|
||||
local ok, err = self:prepare_challenge(antibot, challenge_uri)
|
||||
if not ok then
|
||||
return false, "can't prepare challenge : " .. err, true, ngx.HTTP_INTERNAL_SERVER_ERROR
|
||||
end
|
||||
return true, "redirecting client to the challenge uri", true, ngx.redirect(challenge_uri)
|
||||
end
|
||||
return false, "display challenge error : " .. err, true, ngx.HTTP_INTERNAL_SERVER_ERROR
|
||||
end
|
||||
return true, "displaying challenge to client", true, ngx.HTTP_OK
|
||||
end
|
||||
|
||||
-- Method is suspicious, let's deny the request
|
||||
return true, "unsupported HTTP method for Antibot", true, ngx.HTTP_FORBIDDEN
|
||||
|
||||
end
|
||||
|
||||
function _M:challenge_resolved(antibot)
|
||||
local chall_session, present, reason = session.open()
|
||||
if present and chall_session.data.resolved and chall_session.data.type == antibot then
|
||||
return true, "challenge " .. antibot .. " resolved", chall_session.data.original_uri
|
||||
end
|
||||
return false, "challenge " .. antibot .. " not resolved", nil
|
||||
end
|
||||
|
||||
function _M:prepare_challenge(antibot, challenge_uri)
|
||||
local chall_session, present, reason = session.open()
|
||||
if not present then
|
||||
local chall_session, present, reason = chall_session:start()
|
||||
if not chall_session then
|
||||
return false, "can't start session", nil
|
||||
end
|
||||
chall_session.data.type = antibot
|
||||
chall_session.data.resolved = false
|
||||
if ngx.var.request_uri == challenge_uri then
|
||||
chall_session.data.original_uri = "/"
|
||||
else
|
||||
chall_session.data.original_uri = ngx.var.request_uri
|
||||
end
|
||||
if antibot == "cookie" then
|
||||
chall_session.data.resolved = true
|
||||
end
|
||||
local saved, err = chall_session:save()
|
||||
if not saved then
|
||||
return false, "error while saving session : " .. err
|
||||
end
|
||||
end
|
||||
return true, antibot .. " challenge prepared"
|
||||
end
|
||||
|
||||
function _M:display_challenge(antibot, challenge_uri)
|
||||
-- Open session
|
||||
local chall_session, present, reason = session.open()
|
||||
if not present then
|
||||
return false, "can't open session"
|
||||
end
|
||||
|
||||
-- Check if session type is equal to antibot type
|
||||
if antibot ~= chall_session.data.type then
|
||||
return false, "session type is different from antibot type"
|
||||
end
|
||||
|
||||
-- Compute challenges
|
||||
if antibot == "javascript" then
|
||||
chall_session:start()
|
||||
chall_session.data.random = utils.rand(20)
|
||||
chall_session:save()
|
||||
elseif antibot == "captcha" then
|
||||
chall_session:start()
|
||||
local chall_captcha = captcha.new()
|
||||
chall_captcha:font("/opt/bunkerweb/core/antibot/files/font.ttf")
|
||||
chall_captcha:generate()
|
||||
chall_session.data.image = base64.encode(chall_captcha:jpegStr(70))
|
||||
chall_session.data.text = chall_captcha:getStr()
|
||||
chall_session:save()
|
||||
end
|
||||
|
||||
-- Load HTML templates
|
||||
local str_templates, err = datastore:get("plugin_antibot_templates")
|
||||
if not str_templates then
|
||||
return false, "can't get templates from datastore : " .. err
|
||||
end
|
||||
local templates = cjson.decode(str_templates)
|
||||
|
||||
local html = ""
|
||||
|
||||
-- Javascript case
|
||||
if antibot == "javascript" then
|
||||
html = templates.javascript:format(challenge_uri, chall_session.data.random)
|
||||
end
|
||||
|
||||
-- Captcha case
|
||||
if antibot == "captcha" then
|
||||
html = templates.captcha:format(challenge_uri, chall_session.data.image)
|
||||
end
|
||||
|
||||
-- reCAPTCHA case
|
||||
if antibot == "recaptcha" then
|
||||
local recaptcha_sitekey, err = utils.get_variable("ANTIBOT_RECAPTCHA_SITEKEY")
|
||||
if not recaptcha_sitekey then
|
||||
return false, "can't get reCAPTCHA sitekey variable : " .. err
|
||||
end
|
||||
html = templates.recaptcha:format(recaptcha_sitekey, challenge_uri, recaptcha_sitekey)
|
||||
end
|
||||
|
||||
-- hCaptcha case
|
||||
if antibot == "hcaptcha" then
|
||||
local hcaptcha_sitekey, err = utils.get_variable("ANTIBOT_HCAPTCHA_SITEKEY")
|
||||
if not hcaptcha_sitekey then
|
||||
return false, "can't get hCaptcha sitekey variable : " .. err
|
||||
end
|
||||
html = templates.hcaptcha:format(challenge_uri, hcaptcha_sitekey)
|
||||
end
|
||||
|
||||
ngx.header["Content-Type"] = "text/html"
|
||||
ngx.say(html)
|
||||
|
||||
return true, "displayed challenge"
|
||||
|
||||
end
|
||||
|
||||
function _M:check_challenge(antibot)
|
||||
-- Open session
|
||||
local chall_session, present, reason = session.open()
|
||||
if not present then
|
||||
return nil, "can't open session", nil
|
||||
end
|
||||
|
||||
-- Check if session type is equal to antibot type
|
||||
if antibot ~= chall_session.data.type then
|
||||
return nil, "session type is different from antibot type", nil
|
||||
end
|
||||
|
||||
local resolved = false
|
||||
local err = ""
|
||||
local redirect = nil
|
||||
|
||||
-- Javascript case
|
||||
if antibot == "javascript" then
|
||||
ngx.req.read_body()
|
||||
local args, err = ngx.req.get_post_args(1)
|
||||
if err == "truncated" or not args or not args["challenge"] then
|
||||
return false, "missing challenge arg", nil
|
||||
end
|
||||
local hash = sha256:new()
|
||||
hash:update(chall_session.data.random .. args["challenge"])
|
||||
local digest = hash:final()
|
||||
resolved = str.to_hex(digest):find("^0000") ~= nil
|
||||
if not resolved then
|
||||
return false, "wrong value", nil
|
||||
end
|
||||
chall_session:start()
|
||||
chall_session.data.resolved = true
|
||||
chall_session:save()
|
||||
return true, "resolved", chall_session.data.original_uri
|
||||
end
|
||||
|
||||
-- Captcha case
|
||||
if antibot == "captcha" then
|
||||
ngx.req.read_body()
|
||||
local args, err = ngx.req.get_post_args(1)
|
||||
if err == "truncated" or not args or not args["captcha"] then
|
||||
return false, "missing challenge arg", nil
|
||||
end
|
||||
if chall_session.data.text ~= args["captcha"] then
|
||||
return false, "wrong value", nil
|
||||
end
|
||||
chall_session:start()
|
||||
chall_session.data.resolved = true
|
||||
chall_session:save()
|
||||
return true, "resolved", chall_session.data.original_uri
|
||||
end
|
||||
|
||||
-- reCAPTCHA case
|
||||
if antibot == "recaptcha" then
|
||||
ngx.req.read_body()
|
||||
local args, err = ngx.req.get_post_args(1)
|
||||
if err == "truncated" or not args or not args["token"] then
|
||||
return false, "missing challenge arg", nil
|
||||
end
|
||||
local recaptcha_secret, err = utils.get_variable("ANTIBOT_RECAPTCHA_SECRET")
|
||||
if not recaptcha_secret then
|
||||
return nil, "can't get reCAPTCHA secret variable : " .. err, nil
|
||||
end
|
||||
local httpc, err = http.new()
|
||||
if not httpc then
|
||||
return false, "can't instantiate http object : " .. err, nil, nil
|
||||
end
|
||||
local res, err = httpc:request_uri("https://www.google.com/recaptcha/api/siteverify", {
|
||||
method = "POST",
|
||||
body = "secret=" .. recaptcha_secret .. "&response=" .. args["token"] .. "&remoteip=" .. ngx.var.remote_addr,
|
||||
headers = {
|
||||
["Content-Type"] = "application/x-www-form-urlencoded"
|
||||
}
|
||||
})
|
||||
httpc:close()
|
||||
if not res then
|
||||
return nil, "can't send request to reCAPTCHA API : " .. err, nil
|
||||
end
|
||||
local ok, data = pcall(cjson.decode, res.body)
|
||||
if not ok then
|
||||
return nil, "error while decoding JSON from reCAPTCHA API : " .. data, nil
|
||||
end
|
||||
local recaptcha_score, err = utils.get_variable("ANTIBOT_RECAPTCHA_SCORE")
|
||||
if not recaptcha_score then
|
||||
return nil, "can't get reCAPTCHA score variable : " .. err, nil
|
||||
end
|
||||
if not data.success or data.score < tonumber(recaptcha_score) then
|
||||
return false, "client failed challenge with score " .. tostring(data.score), nil
|
||||
end
|
||||
chall_session:start()
|
||||
chall_session.data.resolved = true
|
||||
chall_session:save()
|
||||
return true, "resolved", chall_session.data.original_uri
|
||||
end
|
||||
|
||||
-- hCaptcha case
|
||||
if antibot == "hcaptcha" then
|
||||
ngx.req.read_body()
|
||||
local args, err = ngx.req.get_post_args(1)
|
||||
if err == "truncated" or not args or not args["token"] then
|
||||
return false, "missing challenge arg", nil
|
||||
end
|
||||
local hcaptcha_secret, err = utils.get_variable("ANTIBOT_HCAPTCHA_SECRET")
|
||||
if not hcaptcha_secret then
|
||||
return nil, "can't get hCaptcha secret variable : " .. err, nil
|
||||
end
|
||||
local httpc, err = http.new()
|
||||
if not httpc then
|
||||
return false, "can't instantiate http object : " .. err, nil, nil
|
||||
end
|
||||
local res, err = httpc:request_uri("https://hcaptcha.com/siteverify", {
|
||||
method = "POST",
|
||||
body = "secret=" .. hcaptcha_secret .. "&response=" .. args["token"] .. "&remoteip=" .. ngx.var.remote_addr,
|
||||
headers = {
|
||||
["Content-Type"] = "application/x-www-form-urlencoded"
|
||||
}
|
||||
})
|
||||
httpc:close()
|
||||
if not res then
|
||||
return nil, "can't send request to hCaptcha API : " .. err, nil
|
||||
end
|
||||
local ok, data = pcall(cjson.decode, res.body)
|
||||
if not ok then
|
||||
return nil, "error while decoding JSON from hCaptcha API : " .. data, nil
|
||||
end
|
||||
if not data.success then
|
||||
return false, "client failed challenge", nil
|
||||
end
|
||||
chall_session:start()
|
||||
chall_session.data.resolved = true
|
||||
chall_session:save()
|
||||
return true, "resolved", chall_session.data.original_uri
|
||||
end
|
||||
|
||||
return nil, "unknown", nil
|
||||
end
|
||||
|
||||
return _M
|
||||
@@ -0,0 +1,193 @@
|
||||
-- Copyright startx <startx@plentyfact.org>
|
||||
-- Modifications copyright mrDoctorWho <mrdoctorwho@gmail.com>
|
||||
-- Published under the MIT license
|
||||
|
||||
local _M = {}
|
||||
|
||||
local gd = require 'gd'
|
||||
local logger = require "logger"
|
||||
|
||||
local mt = { __index = {} }
|
||||
|
||||
|
||||
function _M.new()
|
||||
local cap = {}
|
||||
local f = setmetatable({ cap = cap}, mt)
|
||||
return f
|
||||
end
|
||||
|
||||
|
||||
local function urandom()
|
||||
local seed = 1
|
||||
local devurandom = io.open("/dev/urandom", "r")
|
||||
local urandom = devurandom:read(32)
|
||||
devurandom:close()
|
||||
|
||||
for i=1,string.len(urandom) do
|
||||
local s = string.byte(urandom,i)
|
||||
seed = seed + s
|
||||
end
|
||||
return seed
|
||||
end
|
||||
|
||||
|
||||
local function random_char(length)
|
||||
local set, char, uid
|
||||
-- local set = [[1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]]
|
||||
local set = [[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]]
|
||||
local captcha_t = {}
|
||||
|
||||
math.randomseed(urandom())
|
||||
|
||||
for c=1,length do
|
||||
local i = math.random(1, string.len(set))
|
||||
table.insert(captcha_t, string.sub(set,i,i))
|
||||
end
|
||||
|
||||
return captcha_t
|
||||
end
|
||||
|
||||
|
||||
local function random_angle()
|
||||
math.randomseed(urandom())
|
||||
return math.random(-20, 40)
|
||||
end
|
||||
|
||||
|
||||
local function scribble(w,h)
|
||||
math.randomseed(urandom())
|
||||
local x1 = math.random(5, w - 5)
|
||||
local x2 = math.random(5, w - 5)
|
||||
return x1, x2
|
||||
end
|
||||
|
||||
|
||||
function mt.__index:string(s)
|
||||
self.cap.string = s
|
||||
end
|
||||
|
||||
function mt.__index:scribble(n)
|
||||
self.cap.scribble = n or 20
|
||||
end
|
||||
|
||||
function mt.__index:length(l)
|
||||
self.cap.length = l
|
||||
end
|
||||
|
||||
|
||||
function mt.__index:bgcolor(r,g,b)
|
||||
self.cap.bgcolor = { r = r , g = g , b = b}
|
||||
end
|
||||
|
||||
function mt.__index:fgcolor(r,g,b)
|
||||
self.cap.fgcolor = { r = r , g = g , b = b}
|
||||
end
|
||||
|
||||
function mt.__index:line(line)
|
||||
self.cap.line = line
|
||||
end
|
||||
|
||||
|
||||
function mt.__index:font(font)
|
||||
self.cap.font = font
|
||||
end
|
||||
|
||||
|
||||
function mt.__index:generate()
|
||||
--local self.captcha = {}
|
||||
local captcha_t = {}
|
||||
|
||||
if not self.cap.string then
|
||||
if not self.cap.length then
|
||||
self.cap.length = 6
|
||||
end
|
||||
captcha_t = random_char(self.cap.length)
|
||||
self:string(table.concat(captcha_t))
|
||||
else
|
||||
for i=1, #self.cap.string do
|
||||
table.insert(captcha_t, string.sub(self.cap.string, i, i))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
self.im = gd.createTrueColor(#captcha_t * 40, 45)
|
||||
local black = self.im:colorAllocate(0, 0, 0)
|
||||
local white = self.im:colorAllocate(255, 255, 255)
|
||||
local bgcolor
|
||||
if not self.cap.bgcolor then
|
||||
bgcolor = white
|
||||
else
|
||||
bgcolor = self.im:colorAllocate(self.cap.bgcolor.r , self.cap.bgcolor.g, self.cap.bgcolor.b )
|
||||
end
|
||||
|
||||
local fgcolor
|
||||
if not self.cap.fgcolor then
|
||||
fgcolor = black
|
||||
else
|
||||
fgcolor = self.im:colorAllocate(self.cap.fgcolor.r , self.cap.fgcolor.g, self.cap.fgcolor.b )
|
||||
end
|
||||
|
||||
self.im:filledRectangle(0, 0, #captcha_t * 40, 45, bgcolor)
|
||||
|
||||
local offset_left = 10
|
||||
|
||||
for i=1, #captcha_t do
|
||||
local angle = random_angle()
|
||||
local llx, lly, lrx, lry, urx, ury, ulx, uly = self.im:stringFT(fgcolor, self.cap.font, 25, math.rad(angle), offset_left, 35, captcha_t[i])
|
||||
self.im:polygon({ {llx, lly}, {lrx, lry}, {urx, ury}, {ulx, uly} }, bgcolor)
|
||||
offset_left = offset_left + 40
|
||||
end
|
||||
|
||||
if self.cap.line then
|
||||
self.im:line(10, 10, ( #captcha_t * 40 ) - 10 , 40, fgcolor)
|
||||
self.im:line(11, 11, ( #captcha_t * 40 ) - 11 , 41, fgcolor)
|
||||
self.im:line(12, 12, ( #captcha_t * 40 ) - 12 , 42, fgcolor)
|
||||
end
|
||||
|
||||
|
||||
if self.cap.scribble then
|
||||
for i=1,self.cap.scribble do
|
||||
local x1,x2 = scribble( #captcha_t * 40 , 45 )
|
||||
self.im:line(x1, 5, x2, 40, fgcolor)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Perhaps it's not the best solution
|
||||
-- Writes the generated image to a jpeg file
|
||||
function mt.__index:jpeg(outfile, quality)
|
||||
self.im:jpeg(outfile, quality)
|
||||
end
|
||||
|
||||
-- Writes the generated image to a png file
|
||||
function mt.__index:png(outfile)
|
||||
self.im:png(outfile)
|
||||
end
|
||||
|
||||
-- Allows to get the image data in PNG format
|
||||
function mt.__index:pngStr()
|
||||
return self.im:pngStr()
|
||||
end
|
||||
|
||||
-- Allows to get the image data in JPEG format
|
||||
function mt.__index:jpegStr(quality)
|
||||
return self.im:jpegStr(quality)
|
||||
end
|
||||
|
||||
-- Allows to get the image text
|
||||
function mt.__index:getStr()
|
||||
return self.cap.string
|
||||
end
|
||||
|
||||
-- Writes the image to a file
|
||||
function mt.__index:write(outfile, quality)
|
||||
if self.cap.string == nil then
|
||||
self:generate()
|
||||
end
|
||||
self:jpeg(outfile, quality)
|
||||
-- Compatibility
|
||||
return self:getStr()
|
||||
end
|
||||
|
||||
return _M
|
||||
@@ -0,0 +1,9 @@
|
||||
map "{{ ANTIBOT_SESSION_SECRET }}" $session_secret {
|
||||
default "{{ ANTIBOT_SESSION_SECRET }}";
|
||||
"random" "{{ random(32) }}";
|
||||
}
|
||||
|
||||
map "{{ ANTIBOT_SESSION_NAME }}" $session_name {
|
||||
default "{{ ANTIBOT_SESSION_NAME }}";
|
||||
"random" "{{ random(16) }}";
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,98 @@
|
||||
{
|
||||
"id": "antibot",
|
||||
"order": 4,
|
||||
"name": "Antibot",
|
||||
"description": "Bot detection by using a challenge.",
|
||||
"version": "0.1",
|
||||
"settings": {
|
||||
"USE_ANTIBOT": {
|
||||
"context": "multisite",
|
||||
"default": "no",
|
||||
"help": "Activate antibot feature.",
|
||||
"id": "use-antibot",
|
||||
"label": "Antibot challenge",
|
||||
"regex": "^(no|cookie|javascript|captcha|recaptcha|hcaptcha)$",
|
||||
"type": "select",
|
||||
"select": [
|
||||
"no",
|
||||
"cookie",
|
||||
"javascript",
|
||||
"captcha",
|
||||
"recaptcha",
|
||||
"hcaptcha"
|
||||
]
|
||||
},
|
||||
"ANTIBOT_URI": {
|
||||
"context": "multisite",
|
||||
"default": "/challenge",
|
||||
"help": "Unused URI that clients will be redirected to solve the challenge.",
|
||||
"id": "antibot-uri",
|
||||
"label": "Antibot URL",
|
||||
"regex": "^.*$",
|
||||
"type": "text"
|
||||
},
|
||||
"ANTIBOT_SESSION_SECRET": {
|
||||
"context": "global",
|
||||
"default": "random",
|
||||
"help": "Secret used to encrypt sessions variables for storing data related to challenges.",
|
||||
"id": "antibot-session-secret",
|
||||
"label": "Session secret",
|
||||
"regex": "^.*$",
|
||||
"type": "text"
|
||||
},
|
||||
"ANTIBOT_SESSION_NAME": {
|
||||
"context": "global",
|
||||
"default": "random",
|
||||
"help": "Name of the cookie used by the antibot feature.",
|
||||
"id": "antibot-session-name",
|
||||
"label": "Session name",
|
||||
"regex": "^.*$",
|
||||
"type": "text"
|
||||
},
|
||||
"ANTIBOT_RECAPTCHA_SCORE": {
|
||||
"context": "multisite",
|
||||
"default": "0.7",
|
||||
"help": "Minimum score required for reCAPTCHA challenge.",
|
||||
"id": "antibot-recaptcha-score",
|
||||
"label": "reCAPTCHA score",
|
||||
"regex": "^.*$",
|
||||
"type": "text"
|
||||
},
|
||||
"ANTIBOT_RECAPTCHA_SITEKEY": {
|
||||
"context": "multisite",
|
||||
"default": "",
|
||||
"help": "Sitekey for reCAPTCHA challenge.",
|
||||
"id": "antibot-recaptcha-sitekey",
|
||||
"label": "reCAPTCHA sitekey",
|
||||
"regex": "^.*$",
|
||||
"type": "text"
|
||||
},
|
||||
"ANTIBOT_RECAPTCHA_SECRET": {
|
||||
"context": "multisite",
|
||||
"default": "",
|
||||
"help": "Secret for reCAPTCHA challenge.",
|
||||
"id": "antibot-recaptcha-secret",
|
||||
"label": "reCAPTCHA secret",
|
||||
"regex": "^.*$",
|
||||
"type": "text"
|
||||
},
|
||||
"ANTIBOT_HCAPTCHA_SITEKEY": {
|
||||
"context": "multisite",
|
||||
"default": "",
|
||||
"help": "Sitekey for hCaptcha challenge.",
|
||||
"id": "antibot-hcaptcha-sitekey",
|
||||
"label": "hCaptcha sitekey",
|
||||
"regex": "^.*$",
|
||||
"type": "text"
|
||||
},
|
||||
"ANTIBOT_HCAPTCHA_SECRET": {
|
||||
"context": "multisite",
|
||||
"default": "",
|
||||
"help": "Secret for hCaptcha challenge.",
|
||||
"id": "antibot-hcaptcha-secret",
|
||||
"label": "hCaptcha secret",
|
||||
"regex": "^.*$",
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user