1
0
mirror of https://github.com/citizenfx/cfx-server-data.git synced 2025-01-09 23:02:56 +08:00
cfx-server-data/resources/runcode/runcode_web.lua
2019-10-21 15:04:55 +02:00

192 lines
3.6 KiB
Lua

local cachedFiles = {}
local function sendFile(res, fileName)
if cachedFiles[fileName] then
res.send(cachedFiles[fileName])
return
end
local fileData = LoadResourceFile(GetCurrentResourceName(), 'web/' .. fileName)
if not fileData then
res.writeHead(404)
res.send('Not found.')
return
end
cachedFiles[fileName] = fileData
res.send(fileData)
end
local codeId = 1
local codes = {}
local attempts = 0
local lastAttempt
local function handleRunCode(data, res)
if not data.lang then
data.lang = 'lua'
end
if not data.client or data.client == '' then
CreateThread(function()
local result, err = RunCode(data.lang, data.code)
res.send(json.encode({
result = result,
error = err
}))
end)
else
codes[codeId] = {
timeout = GetGameTimer() + 1000,
res = res
}
TriggerClientEvent('runcode:gotSnippet', tonumber(data.client), codeId, data.lang, data.code)
codeId = codeId + 1
end
end
RegisterNetEvent('runcode:runInBand')
AddEventHandler('runcode:runInBand', function(id, data)
local s = source
local privs = GetPrivs(s)
local res = {
send = function(str)
TriggerClientEvent('runcode:inBandResult', s, id, str)
end
}
if (not data.client or data.client == '') and not privs.canServer then
res.send(json.encode({ error = 'Insufficient permissions.'}))
return
end
if (data.client and data.client ~= '') and not privs.canClient then
if privs.canSelf then
data.client = s
else
res.send(json.encode({ error = 'Insufficient permissions.'}))
return
end
end
SaveResourceFile(GetCurrentResourceName(), 'data.json', json.encode({
lastSnippet = data.code,
lastLang = data.lang or 'lua'
}), -1)
handleRunCode(data, res)
end)
local function handlePost(req, res)
req.setDataHandler(function(body)
local data = json.decode(body)
if not data or not data.password or not data.code then
res.send(json.encode({ error = 'Bad request.'}))
return
end
if GetConvar('rcon_password', '') == '' then
res.send(json.encode({ error = 'The server has an empty rcon_password.'}))
return
end
if attempts > 5 or data.password ~= GetConvar('rcon_password', '') then
attempts = attempts + 1
lastAttempt = GetGameTimer()
res.send(json.encode({ error = 'Bad password.'}))
return
end
handleRunCode(data, res)
end)
end
CreateThread(function()
while true do
Wait(1000)
if attempts > 0 and (GetGameTimer() - lastAttempt) > 5000 then
attempts = 0
lastAttempt = 0
end
end
end)
local function returnCode(id, res, err)
if not codes[id] then
return
end
local code = codes[id]
codes[id] = nil
local gotFrom
if source then
gotFrom = GetPlayerName(source) .. ' [' .. tostring(source) .. ']'
end
code.res.send(json.encode({
result = res,
error = err,
from = gotFrom
}))
end
CreateThread(function()
while true do
Wait(100)
for k, v in ipairs(codes) do
if GetGameTimer() > v.timeout then
source = nil
returnCode(k, '', 'Timed out waiting on the target client.')
end
end
end
end)
RegisterNetEvent('runcode:gotResult')
AddEventHandler('runcode:gotResult', returnCode)
SetHttpHandler(function(req, res)
local path = req.path
if req.method == 'POST' then
return handlePost(req, res)
end
-- client shortcuts
if req.path == '/clients' then
local clientList = {}
for _, id in ipairs(GetPlayers()) do
table.insert(clientList, { GetPlayerName(id), id })
end
res.send(json.encode({
clients = clientList
}))
return
end
-- should this be the index?
if req.path == '/' then
path = 'index.html'
end
-- remove any '..' from the path
path = path:gsub("%.%.", "")
return sendFile(res, path)
end)