Mini Shell
local cookie = require('resty.cookie')
local digest = require('openssl').digest
local pbi = require "ws_message_pb"
local splashscreen_sessions = ngx.shared.splashscreen_sessions
local cookie_name = ngx.var.ws_cookie_name
local i360_socket = "unix:/var/run/defence360agent/protobuf.sock"
local function write_format(little_endian, format, ...)
local res = ''
local values = {...}
for i=1,#format do
local size = tonumber(format:sub(i,i))
local value = values[i]
local str = ""
for j=1,size do
str = str .. string.char(value % 256)
value = math.floor(value / 256)
end
if not little_endian then
str = string.reverse(str)
end
res = res .. str
end
return res
end
local function composeMessage(uid, ip, success)
local msg = pbi.SendInfo()
msg.ip = ip
msg.method = msg.WEBSHIELD
msg.timestamp = os.time(os.date("!*t"))
if uid then -- yes, UID might be absent
msg.websh.user_id = uid
end
if success then
msg.websh.captcha = msg.websh.PASSED
else
msg.websh.captcha = msg.websh.FAILED
end
local serialized = msg:SerializeToString()
return write_format(false, "2", string.len(serialized)) .. serialized
end
local function notify_peer (uid, ip, success)
local sock = ngx.socket.tcp()
sock:settimeout(1000)
local ok, err = sock:connect(i360_socket)
if not ok then
ngx.log(ngx.ERR, "Could not connect to i360 socket: ", err)
return
end
local sent, err = sock:send(composeMessage(uid, ip, success))
if not sent then
ngx.log(ngx.ERR, "Could not send to i360 socket: ", err)
end
sock:close()
end
local function set_uid_cookie()
local cookie_obj, err = cookie:new()
if not cookie_obj then
ngx.log(ngx.ERR, "Failed to init cookie: ", err)
return
end
local user_agent = ngx.var.http_user_agent
if user_agent == nil then
user_agent = ''
end
local user_data = ngx.var.wsuserip .. user_agent
local secret_key = ngx.var.ws_trusted_secret_key
local ttl = tostring(ngx.time() + tonumber(ngx.var.ws_cookie_ttl))
local hashsum = digest.digest('sha1', user_data .. secret_key .. ttl, false)
local val = hashsum .. "." .. ttl .. ".1"
local current_timestamp = os.time()
local offset = 30 * 24 * 3600 -- 30 days
local expiration_date = os.date(
"!%a, %d-%b-%y %H:%M:%S GMT", current_timestamp + offset)
local ok, err = cookie_obj:set({
key = cookie_name,
domain = ngx.var.host,
samesite = "Lax",
httponly = true,
value = val,
path = "/",
expires = expiration_date
})
if not ok then
ngx.log(ngx.ERR, "Could not set cookie: ", err)
end
return hashsum
end
local function route()
local chkval = ngx.var.arg_wsidchk
if not chkval then -- no query arg with check sum
ngx.exit(ngx.HTTP_BAD_REQUEST) -- return 400
end
local chknum = tonumber(chkval)
if not chknum then -- query arg is not number
ngx.exit(ngx.HTTP_BAD_REQUEST) -- return 400
end
local xsum = string.format("%X", chknum) -- convert query arg to hex
local redirect_uri = splashscreen_sessions:get(xsum) -- and use it as key for dict lookup
if redirect_uri then -- key found, so we have location for redirection
local userid = set_uid_cookie() -- set cookie
local userip = ngx.var.wsuserip
-- splashscreen had been shown instead of captcha
if ip_status == "GRAY" then
notify_peer(userid, userip, true)
end
return ngx.redirect(redirect_uri) -- and redirect
end
ngx.exit(ngx.HTTP_NOT_FOUND) -- key not found. So return 404
end
route()
Zerion Mini Shell 1.0