{% if ANTIBOT_SESSION_SECRET == "random" %}
set $session_secret {{ random(32) }} ;
{% else %}
set $session_secret {{ ANTIBOT_SESSION_SECRET }};
{% endif %}
set $session_check_addr on;

access_by_lua_block {

-- disable checks for internal requests
if ngx.req.is_internal() then
	return
end

-- let's encrypt
local use_lets_encrypt		= {% if AUTO_LETS_ENCRYPT == "yes" %}true{% else %}false{% endif %}

-- external blacklists
local use_user_agents		= {% if BLOCK_USER_AGENT == "yes" %}true{% else %}false{% endif %}
local use_proxies		= {% if BLOCK_PROXIES == "yes" %}true{% else %}false{% endif %}
local use_abusers		= {% if BLOCK_ABUSERS == "yes" %}true{% else %}false{% endif %}
local use_tor_exit_nodes	= {% if BLOCK_TOR_EXIT_NODE == "yes" %}true{% else %}false{% endif %}
local use_referrers		= {% if BLOCK_REFERRER == "yes" %}true{% else %}false{% endif %}

-- countries
local use_country		= {% if WHITELIST_COUNTRY != "" or BLACKLIST_COUNTRY != "" %}true{% else %}false{% endif %}

-- crowdsec
local use_crowdsec		= {% if USE_CROWDSEC == "yes" %}true{% else %}false{% endif %}

-- antibot
local use_antibot_cookie	= {% if USE_ANTIBOT == "cookie" %}true{% else %}false{% endif %}
local use_antibot_javascript	= {% if USE_ANTIBOT == "javascript" %}true{% else %}false{% endif %}
local use_antibot_captcha	= {% if USE_ANTIBOT == "captcha" %}true{% else %}false{% endif %}
local use_antibot_recaptcha	= {% if USE_ANTIBOT == "recaptcha" %}true{% else %}false{% endif %}

-- resolvers
local dns_resolvers		= {% raw %}{{% endraw %}{% if DNS_RESOLVERS != "" %}{% set elements = DNS_RESOLVERS.split(" ") %}{% for i in range(0, elements|length) %}"{{ elements[i] }}"{% if i < elements|length-1 %},{% endif %}{% endfor %}{% endif %}{% raw %}}{% endraw %}

-- whitelist
local use_whitelist_ip		= {% if USE_WHITELIST_IP == "yes" %}true{% else %}false{% endif %}
local use_whitelist_reverse	= {% if USE_WHITELIST_REVERSE == "yes" %}true{% else %}false{% endif %}
local whitelist_ip_list		= {% raw %}{{% endraw %}{% if WHITELIST_IP_LIST != "" %}{% set elements = WHITELIST_IP_LIST.split(" ") %}{% for i in range(0, elements|length) %}"{{ elements[i] }}"{% if i < elements|length-1 %},{% endif %}{% endfor %}{% endif %}{% raw %}}{% endraw %}
local whitelist_reverse_list	= {% raw %}{{% endraw %}{% if WHITELIST_REVERSE_LIST != "" %}{% set elements = WHITELIST_REVERSE_LIST.split(" ") %}{% for i in range(0, elements|length) %}"{{ elements[i] }}"{% if i < elements|length-1 %},{% endif %}{% endfor %}{% endif %}{% raw %}}{% endraw %}

-- blacklist
local use_blacklist_ip		= {% if USE_BLACKLIST_IP == "yes" %}true{% else %}false{% endif %}
local use_blacklist_reverse	= {% if USE_BLACKLIST_REVERSE == "yes" %}true{% else %}false{% endif %}
local blacklist_ip_list		= {% raw %}{{% endraw %}{% if BLACKLIST_IP_LIST != "" %}{% set elements = BLACKLIST_IP_LIST.split(" ") %}{% for i in range(0, elements|length) %}"{{ elements[i] }}"{% if i < elements|length-1 %},{% endif %}{% endfor %}{% endif %}{% raw %}}{% endraw %}
local blacklist_reverse_list	= {% raw %}{{% endraw %}{% if BLACKLIST_REVERSE_LIST != "" %}{% set elements = BLACKLIST_REVERSE_LIST.split(" ") %}{% for i in range(0, elements|length) %}"{{ elements[i] }}"{% if i < elements|length-1 %},{% endif %}{% endfor %}{% endif %}{% raw %}}{% endraw %}

-- dnsbl
local use_dnsbl			= {% if USE_DNSBL == "yes" %}true{% else %}false{% endif %}
local dnsbl_list		= {% raw %}{{% endraw %}{% if DNSBL_LIST != "" %}{% set elements = DNSBL_LIST.split(" ") %}{% for i in range(0, elements|length) %}"{{ elements[i] }}"{% if i < elements|length-1 %},{% endif %}{% endfor %}{% endif %}{% raw %}}{% endraw %}

-- bad behavior
local use_bad_behavior		= {% if USE_BAD_BEHAVIOR == "yes" %}true{% else %}false{% endif %}

-- include LUA code
local whitelist			= require "whitelist"
local blacklist			= require "blacklist"
local dnsbl			= require "dnsbl"
local cookie			= require "cookie"
local javascript		= require "javascript"
local captcha			= require "captcha"
local recaptcha			= require "recaptcha"
local iputils			= require "resty.iputils"
local behavior			= require "behavior"
local logger			= require "logger"

-- user variables
local antibot_uri		= "{{ ANTIBOT_URI }}"
local whitelist_user_agent	= {% raw %}{{% endraw %}{% if WHITELIST_USER_AGENT != "" %}{% set elements = WHITELIST_USER_AGENT.split(" ") %}{% for i in range(0, elements|length) %}"{{ elements[i] }}"{% if i < elements|length-1 %},{% endif %}{% endfor %}{% endif %}{% raw %}}{% endraw %}
local whitelist_uri		= {% raw %}{{% endraw %}{% if WHITELIST_URI != "" %}{% set elements = WHITELIST_URI.split(" ") %}{% for i in range(0, elements|length) %}"{{ elements[i] }}"{% if i < elements|length-1 %},{% endif %}{% endfor %}{% endif %}{% raw %}}{% endraw %}

-- check if already in whitelist cache
if use_whitelist_ip and whitelist.ip_cached_ok() then
	ngx.exit(ngx.OK)
end
if use_whitelist_reverse and whitelist.reverse_cached_ok() then
	ngx.exit(ngx.OK)
end

-- check if already in blacklist cache
if use_blacklist_ip and blacklist.ip_cached_ko() then
	ngx.exit(ngx.HTTP_FORBIDDEN)
end
if use_blacklist_reverse and blacklist.reverse_cached_ko() then
	ngx.exit(ngx.HTTP_FORBIDDEN)
end

-- check if already in dnsbl cache
if use_dnsbl and dnsbl.cached_ko() then
	ngx.exit(ngx.HTTP_FORBIDDEN)
end

-- check if IP is whitelisted (only if not in cache)
if use_whitelist_ip and not whitelist.ip_cached() then
	if whitelist.check_ip(whitelist_ip_list) then
		ngx.exit(ngx.OK)
	end
end

-- check if reverse is whitelisted (only if not in cache)
if use_whitelist_reverse and not whitelist.reverse_cached() then
	if whitelist.check_reverse(whitelist_reverse_list) then
		ngx.exit(ngx.OK)
	end
end

-- check if URI is whitelisted
for k, v in pairs(whitelist_uri) do
	if ngx.var.request_uri == v then
		logger.log(ngx.NOTICE, "WHITELIST", "URI " .. v .. " is whitelisted")
		ngx.exit(ngx.OK)
	end
end

-- check if it's certbot
if use_lets_encrypt and string.match(ngx.var.request_uri, "^/.well-known/acme-challenge/") then
	logger.log(ngx.INFO, "LETSENCRYPT", "got a visit from Let's Encrypt")
	ngx.exit(ngx.OK)
end

-- check if IP is blacklisted (only if not in cache)
if use_blacklist_ip and not blacklist.ip_cached() then
	if blacklist.check_ip(blacklist_ip_list) then
		ngx.exit(ngx.HTTP_FORBIDDEN)
	end
end

-- check if reverse is blacklisted (only if not in cache)
if use_blacklist_reverse and not blacklist.reverse_cached() then
	if blacklist.check_reverse(blacklist_reverse_list, dns_resolvers) then
		ngx.exit(ngx.HTTP_FORBIDDEN)
	end
end

-- check if IP is banned because of "bad behavior"
if use_bad_behavior and behavior.is_banned() then
	logger.log(ngx.WARN, "BEHAVIOR", "IP " .. ngx.var.remote_addr .. " is banned because of bad behavior")
	ngx.exit(ngx.HTTP_FORBIDDEN)
end

-- check if IP is in proxies list
if use_proxies then
	local value, flags = ngx.shared.proxies_data:get(iputils.ip2bin(ngx.var.remote_addr))
	if value ~= nil then
		logger.log(ngx.WARN, "PROXIES", "IP " .. ngx.var.remote_addr .. " is in proxies list")
		ngx.exit(ngx.HTTP_FORBIDDEN)
	end
end

-- check if IP is in abusers list
if use_abusers then
	local value, flags = ngx.shared.abusers_data:get(iputils.ip2bin(ngx.var.remote_addr))
	if value ~= nil then
		logger.log(ngx.WARN, "ABUSERS", "IP " .. ngx.var.remote_addr .. " is in abusers list")
		ngx.exit(ngx.HTTP_FORBIDDEN)
	end
end

-- check if IP is in TOR exit nodes list
if use_tor_exit_nodes then
	local value, flags = ngx.shared.tor_exit_nodes_data:get(iputils.ip2bin(ngx.var.remote_addr))
	if value ~= nil then
		logger.log(ngx.WARN, "TOR", "IP " .. ngx.var.remote_addr .. " is in TOR exit nodes list")
		ngx.exit(ngx.HTTP_FORBIDDEN)
	end
end

-- check if user-agent is allowed
if use_user_agents and ngx.var.http_user_agent ~= nil then
	local whitelisted = false
	for k, v in pairs(whitelist_user_agent) do
		if string.match(ngx.var.http_user_agent, v) then
			logger.log(ngx.NOTICE, "WHITELIST", "User-Agent " .. ngx.var.http_user_agent .. " is whitelisted")
			whitelisted = true
			break
		end
	end
	if not whitelisted then
		local value, flags = ngx.shared.user_agents_cache:get(ngx.var.http_user_agent)
		if value == nil then
			local patterns = ngx.shared.user_agents_data:get_keys(0)
			for i, pattern in ipairs(patterns) do
				if string.match(ngx.var.http_user_agent, pattern) then
					value = "ko"
					ngx.shared.user_agents_cache:set(ngx.var.http_user_agent, "ko", 86400)
					break
				end
			end
			if value == nil then
				value = "ok"
				ngx.shared.user_agents_cache:set(ngx.var.http_user_agent, "ok", 86400)
			end
		end
		if value == "ko" then
			logger.log(ngx.WARN, "USER-AGENT", "User-Agent " .. ngx.var.http_user_agent .. " is blacklisted")
			ngx.exit(ngx.HTTP_FORBIDDEN)
		end
	end
end

-- check if referrer is allowed
if use_referrer and ngx.var.http_referer ~= nil then
	local value, flags = ngx.shared.referrers_cache:get(ngx.var.http_referer)
	if value == nil then
		local patterns = ngx.shared.referrers_data:get_keys(0)
		for i, pattern in ipairs(patterns) do
			if string.match(ngx.var.http_referer, pattern) then
				value = "ko"
				ngx.shared.referrers_cache:set(ngx.var.http_referer, "ko", 86400)
				break
			end
		end
		if value == nil then
			value = "ok"
			ngx.shared.referrers_cache:set(ngx.var.http_referer, "ok", 86400)
		end
	end
	if value == "ko" then
		logger.log(ngx.WARN, "REFERRER", "Referrer " .. ngx.var.http_referer .. " is blacklisted")
		ngx.exit(ngx.HTTP_FORBIDDEN)
	end
end

-- check if country is allowed
if use_country and ngx.var.allowed_country == "no" then
	logger.log(ngx.WARN, "COUNTRY", "Country of " .. ngx.var.remote_addr .. " is blacklisted")
	ngx.exit(ngx.HTTP_FORBIDDEN)
end

-- check if IP is in DNSBLs (only if not in cache)
if use_dnsbl and not dnsbl.cached() then
	if dnsbl.check(dnsbl_list, dns_resolvers) then
		ngx.exit(ngx.HTTP_FORBIDDEN)
	end
end

-- check if IP is in CrowdSec DB
if use_crowdsec then
	local ok, err = require "crowdsec.CrowdSec".allowIp(ngx.var.remote_addr)
	if ok == nil then
		logger.log(ngx.ERR, "CROWDSEC", err)
	end
	if not ok then
		logger.log(ngx.WARN, "CROWDSEC", "denied " .. ngx.var.remote_addr)
		ngx.exit(ngx.HTTP_FORBIDDEN)
	end
end

-- cookie check
if use_antibot_cookie and ngx.var.uri ~= "/favicon.ico" then
	if not cookie.is_set("uri") then
		if ngx.var.request_uri ~= antibot_uri then
			cookie.set({uri = ngx.var.request_uri})
			return ngx.redirect(antibot_uri)
		end
		logger.log(ngx.WARN, "ANTIBOT", "cookie fail for " .. ngx.var.remote_addr)
		return ngx.exit(ngx.HTTP_FORBIDDEN)
	else
		if ngx.var.request_uri == antibot_uri then
			return ngx.redirect(cookie.get("uri"))
		end
	end
end

-- javascript check
if use_antibot_javascript and ngx.var.uri ~= "/favicon.ico" then
	if not cookie.is_set("javascript") then
		if ngx.var.request_uri ~= antibot_uri then
			cookie.set({uri = ngx.var.request_uri, challenge = javascript.get_challenge()})
			return ngx.redirect(antibot_uri)
		end
	end
end

-- captcha check
if use_antibot_captcha and ngx.var.uri ~= "/favicon.ico" then
	if not cookie.is_set("captcha") then
		if ngx.var.request_uri ~= antibot_uri then
			cookie.set({uri = ngx.var.request_uri})
			return ngx.redirect(antibot_uri)
		end
	end
end

-- recaptcha check
if use_antibot_recaptcha and ngx.var.uri ~= "/favicon.ico" then
	if not cookie.is_set("recaptcha") then
		if ngx.var.request_uri ~= antibot_uri then
			cookie.set({uri = ngx.var.request_uri})
			return ngx.redirect(antibot_uri)
		end
	end
end

-- plugins check
local plugins, flags = ngx.shared.plugins_data:get("plugins")
if plugins ~= nil then
	for plugin_id in string.gmatch(plugins, "%w+") do
		local plugin = require(plugin_id .. "/" .. plugin_id)
		plugin.check()
	end
end

ngx.exit(ngx.OK)

}

{% if USE_ANTIBOT == "javascript" %}
include {{ NGINX_PREFIX }}antibot-javascript.conf;
{% elif USE_ANTIBOT == "captcha" %}
include {{ NGINX_PREFIX }}antibot-captcha.conf;
{% elif USE_ANTIBOT == "recaptcha" %}
include {{ NGINX_PREFIX }}antibot-recaptcha.conf;
{% endif %}
