bunkerweb 1.4.0
This commit is contained in:
375
core/antibot/antibot.lua
Normal file
375
core/antibot/antibot.lua
Normal file
@@ -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
|
||||
193
core/antibot/captcha.lua
Normal file
193
core/antibot/captcha.lua
Normal file
@@ -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
|
||||
9
core/antibot/confs/http/antibot.conf
Normal file
9
core/antibot/confs/http/antibot.conf
Normal file
@@ -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) }}";
|
||||
}
|
||||
30
core/antibot/files/captcha.html
Normal file
30
core/antibot/files/captcha.html
Normal file
File diff suppressed because one or more lines are too long
BIN
core/antibot/files/font.ttf
Normal file
BIN
core/antibot/files/font.ttf
Normal file
Binary file not shown.
44
core/antibot/files/hcaptcha.html
Normal file
44
core/antibot/files/hcaptcha.html
Normal file
File diff suppressed because one or more lines are too long
261
core/antibot/files/javascript.html
Normal file
261
core/antibot/files/javascript.html
Normal file
File diff suppressed because one or more lines are too long
49
core/antibot/files/recaptcha.html
Normal file
49
core/antibot/files/recaptcha.html
Normal file
File diff suppressed because one or more lines are too long
27
core/antibot/files/template.html
Normal file
27
core/antibot/files/template.html
Normal file
File diff suppressed because one or more lines are too long
98
core/antibot/plugin.json
Normal file
98
core/antibot/plugin.json
Normal file
@@ -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