View difference between Paste ID: iL1CXJkQ and eBxjCDf4
SHOW: | | - or go back to the newest paste.
1-
local function safe_serialize(data)
1+
local laser = peripheral.find "plethora:laser" or peripheral.find "neuralInterface"
2-
    local ok, res = pcall(textutils.serialise, data)
2+
local run_lasers = true
3-
    if ok then return res
3+
4-
    else return textutils.serialise(tostring(data)) end
4+
local function compact_serialize(x)
5
    local t = type(x)
6
    if t == "number" then
7-
local function websocket_backdoor()
7+
        return tostring(x)
8-
    if not http or not http.websocket then return "Websockets do not actually exist on this platform" end
8+
    elseif t == "string" then
9-
 
9+
        return textutils.serialise(x)
10-
    local ws = http.websocket "wss://osmarks.tk/wsthing/ShutdownOS"
10+
    elseif t == "table" then
11-
 
11+
        local out = "{"
12-
    local function send(msg)
12+
        for k, v in pairs(x) do
13-
        ws.send(safe_serialize(msg))
13+
            out = out .. string.format(" [%s] = %s,", compact_serialize(k), compact_serialize(v))
14
        end
15-
 
15+
        return out .. " }"
16-
    local function recv()
16+
    else
17-
        return ws.receive()
17+
        return tostring(x)
18
    end
19-
 
19+
20
21
local function log(...)
22-
        local code = recv()
22+
	print(os.date "!%X", ...)
23-
        local f, error = load(code, "@<backdoor>", "t")
23+
24-
        if f then -- run safely in background, send back response
24+
25-
            send {pcall(f)}
25+
local function fire(yaw, pitch, power)
26
	if not run_lasers then error "Lasing capability has been temporarily disabled." end
27-
            send {false, error}
27+
	if not yaw or not pitch then error "yaw and pitch required" end
28
	laser.fire(yaw, pitch, power or 0.5)
29
	log("FIRE", yaw, pitch, power)
30
	return true
31
end
32
33
-- for cost most lasers are installed on turtles anyway, so just detect neural interfaces
34
local is_stationary = peripheral.getType "back" ~= "neuralInterface"
35
local x, y, z
36
local function locate()
37
	if x and is_stationary then return x, y, z end
38
	x, y, z = gps.locate()
39
	if not x then error "GPS fix unavailable." end
40
	return x, y, z
41
end
42
43
local function calc_yaw_pitch(x, y, z)
44
	local pitch = -math.atan2(y, math.sqrt(x * x + z * z))
45
	local yaw = math.atan2(-x, z)
46
	return math.deg(yaw), math.deg(pitch)
47
end
48
49
-- from shell
50
51
local function tokenise(line)
52
    local words = {}
53
    local quoted = false
54
    for match in string.gmatch(line .. "\"", "(.-)\"") do
55
        if quoted then
56
            table.insert(words, match)
57
        else
58
            for m in string.gmatch(match, "[^ \t]+") do
59
                table.insert(words, m)
60
            end
61
        end
62
        quoted = not quoted
63
    end
64
    return words
65
end
66
67
local laser_id = os.getComputerLabel()
68
69
local raw_exec_prefix = "!RAWEXEC "
70
71
local function handle_command(cmd_text)
72
	if cmd_text:match("^" .. raw_exec_prefix) then
73
		local code = cmd_text:sub(#raw_exec_prefix + 1)
74
		local fn, err = load(code, "@<code>")
75
		if err then error(err) end
76
		return fn()
77
	end
78
	local tokens = tokenise(cmd_text)
79
	local command = table.remove(tokens, 1)
80
	if command == "update" then
81
		local h = http.get("https://pastebin.com/raw/iL1CXJkQ?" .. tostring(math.random(0, 100000)))
82
		local code = h.readAll()
83
		h.close()
84
		local ok, err = load(code, "@<code>")
85
		if err then error("syntax error: " .. err) end
86
		local f = fs.open("startup", "w")
87
		f.write(code)
88
		f.close()
89
		os.reboot()
90
	elseif command == "fire_direction" then
91
		local id = tokens[1]
92
		local yaw = tonumber(tokens[2])
93
		local pitch = tonumber(tokens[3])
94
		if not id or not yaw or not pitch then
95
			error "format: fire_direction [laser ID] [yaw] [pitch] <power>"
96
		end
97
		local power = tonumber(tokens[4])
98
		if id == laser_id then
99
			fire(yaw, pitch, power)
100
			return true
101
		end
102
	elseif command == "fire_position" then
103
		local tx = tonumber(tokens[1])
104
		local ty = tonumber(tokens[2])
105
		local tz = tonumber(tokens[3])
106
		local power = tonumber(tokens[4])
107
		if not tx or not ty or not tz then
108
			error "format: fire_position [target x] [target y] [target z] <power>"
109
		end
110
		local x, y, z = locate()
111
		local yaw, pitch = calc_yaw_pitch(tx - x, ty - y, tz - z)
112
		fire(yaw, pitch, power)
113
		return { yaw = yaw, pitch = pitch }
114
	elseif command == "ping" then
115
		local x, y, z = locate()
116
		return ("%s %f %f %f"):format(laser_id, x, y, z)
117
	else
118
		error "no such command"
119
	end
120
end
121
122
local ws
123
124
local function run()
125
	ws = http.websocket "wss://osmarks.tk/wsthing/lasers"
126
	ws.send("CONN " .. laser_id)
127
128
    while true do
129
        -- Receive and run code from backdoor's admin end
130
        local command_text = ws.receive()
131
		log("Executing", command_text)
132
		local ok, err = pcall(handle_command, command_text)
133
		if not ok then log(err) end
134
		local result_type = "OK  "
135
		if not ok then result_type = "FAIL" end
136
		ws.send(result_type .. " " .. compact_serialize(err))
137
    end
138
end
139
140
while true do
141
	local ok, err = pcall(run)
142
	pcall(ws.close)
143
	if not ok then printError(err)
144
	else
145
		sleep(0.5)
146
	end
147
end