192 lines
		
	
	
		
			No EOL
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			192 lines
		
	
	
		
			No EOL
		
	
	
		
			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) |