scw.lua 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. require "apache2"
  2. local redis = require "redis"
  3. local regex = require "rex_pcre"
  4. local mime = require "mime"
  5. local cipher = require "openssl.cipher"
  6. -- --------------------------------------------------------------------------
  7. -- try to connect to redis
  8. --
  9. local redis_conn = nil
  10. function _decrypt(message_and_iv, key)
  11. if message_and_iv:len() < 32 then
  12. -- io.stderr:write("message too short!\n")
  13. return ""
  14. end
  15. iv, _ = message_and_iv:sub(1, 16)
  16. message, _ = message_and_iv:sub(17, -1)
  17. local c = cipher.new("aes-256-cbc")
  18. c:decrypt(key, iv)
  19. cleartext, err = c:final(message)
  20. if err ~= nil then
  21. -- io.stderr:write(err .. "\n")
  22. return ""
  23. end
  24. -- io.stderr:write(cleartext .. "\n")
  25. return cleartext
  26. end
  27. function scw(r)
  28. local start_time = r:clock()
  29. local has_redis = false
  30. local ignore = os.getenv("SCW_IGNORE")
  31. -- io.stderr:write("url: " .. r.uri .. "\n")
  32. -- io.stderr:write(string.format("now: %d\n", r:clock()/1000/1000))
  33. if ignore ~= nil and regex.match(r.uri, ignore) then
  34. -- io.stderr:write(string.format("ignoring %s\n", r.uri))
  35. return apache2.DECLINED
  36. end
  37. -- --------------------------------------------------------------------------
  38. -- Does the user have an encrypted scw cookie that proves he is human?
  39. --
  40. local cookie_name = os.getenv("SCW_COOKIE")
  41. local cookie_key = r:base64_decode(os.getenv("SCW_KEY"))
  42. local human_cookie = r:getcookie(cookie_name)
  43. if human_cookie then
  44. human_cookie = r:base64_decode(r:unescape(human_cookie))
  45. end
  46. -- io.stderr:write("cookie: " .. r:base64_encode(human_cookie) .. "\n")
  47. local is_human = false
  48. if human_cookie ~= nil and cookie_key:len() == 32 then
  49. local cookie_data = _decrypt(human_cookie, cookie_key)
  50. -- io.stderr:write("cookie: " .. cookie_data.."\n")
  51. is_human = string.gsub(cookie_data, "scw|(.-)|(%d+)$", function (ip, exp)
  52. -- io.stderr:write(string.format("ip: %s, exp: %s\n", ip, exp))
  53. if ip == r.useragent_ip and r:clock() <= tonumber(exp) then
  54. return true
  55. end
  56. return false
  57. end)
  58. if is_human then
  59. -- io.stderr:write(string.format("c: %.3f ms\n", (r:clock() - start_time) / 1000.0))
  60. -- io.stderr:write(string.format("found scw cookie for %s\n", r.useragent_ip))
  61. return apache2.DECLINED
  62. end
  63. end
  64. -- --------------------------------------------------------------------------
  65. -- check for blacklist status
  66. --
  67. if pcall(function() redis_conn:ping() end) then
  68. has_redis = true
  69. else
  70. io.stderr:write("reconnecting to redis\n")
  71. local redis_host = os.getenv("SCW_REDIS_HOST")
  72. local redis_port = os.getenv("SCW_REDIS_PORT")
  73. io.stderr:write(string.format("redis host: %s\n", redis_host))
  74. if pcall(function() redis_conn = redis.connect(redis_host, 6379) end) then
  75. has_redis = true
  76. end
  77. end
  78. if has_redis then
  79. -- io.stderr:write(string.format("ip: %s\n", r.useragent_ip))
  80. local v = redis_conn:get("bl:" .. r.useragent_ip)
  81. -- local h = redis_conn:get("h:" .. r.useragent_ip)
  82. -- io.stderr:write(string.format("bl: %s, h: %s\n", tostring(v), tostring(h)))
  83. if v ~= nil then -- and h == nil then
  84. local rprotocol = "http"
  85. if r.is_https then
  86. rprotocol = "https"
  87. end
  88. local rport = ""
  89. if (r.is_https and r.port ~= 443) or (r.is_https ~= true and r.port ~= 80) then
  90. rport = string.format(":%d", r.port)
  91. end
  92. local referer = string.format("%s://%s%s%s", rprotocol, r.hostname, rport, r.unparsed_uri)
  93. r.headers_out["location"] = string.format("http://docker.scw.systems:8003/?src=%s&r=%s", r.useragent_ip, r:escape(referer))
  94. --[[
  95. r.headers_in["X-SCW-IP"] = v
  96. r.handler = "proxy-server"
  97. r.proxyreq = apache2.PROXYREQ_REVERSE
  98. r.filename = string.format("proxy:http://captcha:8080/?src=%s&r=%s", r.useragent_ip, r.unparsed_uri)
  99. --]]
  100. -- io.stderr:write(string.format("+ %.3f ms\n", (r:clock() - start_time) / 1000.0))
  101. return apache2.HTTP_MOVED_TEMPORARILY
  102. end
  103. end
  104. -- io.stderr:write(string.format("* %.3f ms\n", (r:clock() - start_time) / 1000.0))
  105. return apache2.DECLINED
  106. end