require "apache2"
-- local redis = require "redis"
local hiredis = require "hiredis"
local regex = require "rex_pcre"
local mime = require "mime"
local cipher = require "openssl".cipher
local pretty = require 'pl.pretty'


-- --------------------------------------------------------------------------
-- try to connect to redis
-- 
local redis_conn = nil


function _decrypt(message_and_iv, key)
  if message_and_iv:len() < 32 then
    return ""
  end

  iv, _ = message_and_iv:sub(1, 16)
  message, _ = message_and_iv:sub(17, -1)

  local c = cipher.new("aes-256-cbc")

  c:decrypt(key, iv)
  cleartext, err = c:final(message)
  if err ~= nil then
    return ""
  end

  return cleartext
end

function scw(r)
  local start_time = r:clock()
  local has_redis = false
  local ignore = os.getenv("SCW_IGNORE")
  if ignore == nil or ignore == "" then
    r:err("SCW_IGNORE is not set!")
  end

	local uri = string.match(r.the_request, "^%w+%s+(.+)%s+HTTP")
  if ignore ~= nil and regex.match(uri, ignore) then
    return apache2.DECLINED
  end

  -- --------------------------------------------------------------------------
  -- Does the user have an encrypted scw cookie that proves he is human?
  --
  local cookie_name = os.getenv("SCW_COOKIE")
  if cookie_name == nil or cookie_name == "" then
    r:err("SCW_COOKIE is not set!")
  end


  local cookie_key = r:base64_decode(os.getenv("SCW_KEY"))
  if cookie_key == nil or cookie_key == "" then
    r:err("SCW_KEY is not set!")
  end
  local human_cookie = r:getcookie(cookie_name)
  local xff = tostring(r.headers_in["X-Forwarded-For"])
  local rip = tostring(r.headers_in["X-Real-IP"])

  if human_cookie then
    human_cookie = r:base64_decode(r:unescape(human_cookie))
  end
  local is_human = false


  if human_cookie ~= nil and cookie_key:len() == 32 then
    local cookie_data = _decrypt(human_cookie, cookie_key)

    is_human = string.gsub(cookie_data, "scw|(.-)|(%d+)$", function (ip, exp)
      if (ip == r.useragent_ip or ip == xff or ip == rip) and r:clock() <= tonumber(exp) then
        return true
      end
      return false
    end)

    if is_human then
      return apache2.DECLINED
    end
  end

  -- --------------------------------------------------------------------------
  -- check for blacklist status
  --
  
	
  local sucess = false
	local err = ""
  
  if redis_conn ~= nil then
    success, err = pcall(function() redis_conn:command("PING") end)
    if redis_conn == nil then
      r:info("redis_conn turned nil after ping")
    end
  end

  if success then
    r:info("redis ping was successful")
    has_redis = true
  else
    -- io.stderr:write("reconnecting to redis\n")
    local redis_host = os.getenv("SCW_REDIS_HOST")
    if redis_host == nil or redis_host == "" then
      r:err("SCW_REDIS_HOST is not set!")
    end
    local redis_port = os.getenv("SCW_REDIS_PORT")
    if redis_port == nil or redis_port == "" then
      r:err("SCW_REDIS_PORT is not set!")
    end
    r:info(string.format("connecting to redis %s:%s", redis_host, redis_port))
    success, err = pcall(function() redis_conn = hiredis.connect(redis_host, redis_port) end)
    if success then
      r:info("created redis connection to " .. redis_host .. ":" .. redis_port)
      has_redis = true
    end
  end

  local captcha_url = os.getenv("SCW_CAPTCHA_URL")
  if captcha_url == nil or captcha_url == "" then
    r:err("SCW_CAPTCHA_URL is not set!")
  end

  if has_redis and captcha_url ~= "" then
    -- the client ip
    if redis_conn == nil then
      r:info("redis is suddenly nil!")
    end
    local v = redis_conn:command("GET", "bl:" .. r.useragent_ip)

    -- if v == nil then
    --   r:info("v is nil!")
    -- end
    -- the X-Forwarded-For IP
    if v == nil and xff ~= "" then
      v = redis_conn:command("GET", "bl:" .. xff)
    end

    -- the X-Real-IP IP
    if v == nil and rip ~= "" then
      v = redis_conn:command("GET", "bl:" .. rip)
    end

    if tostring(v) ~= "" and tostring(v) ~= "NIL" then -- and h == nil then
      local rprotocol = "http"
      if r.is_https then
        rprotocol = "https"
      end

      local rport = ""
      if (r.is_https and r.port ~= 443) or (r.is_https ~= true and r.port ~= 80) then
        rport = string.format(":%d", r.port)
      end

      local referer = string.format("%s://%s%s%s", rprotocol, r.hostname, rport, r.unparsed_uri)
      r.headers_out["location"] = string.format(captcha_url, r.useragent_ip, r:escape(referer))
--[[
      r.headers_in["X-SCW-IP"] = v
      r.handler = "proxy-server"
      r.proxyreq = apache2.PROXYREQ_REVERSE
      r.filename = string.format("proxy:http://captcha:8080/?src=%s&r=%s", r.useragent_ip, r.unparsed_uri)
--]]
      return apache2.HTTP_MOVED_TEMPORARILY
    end
  end

  return apache2.DECLINED
end