· 5 years ago · Oct 12, 2020, 11:30 AM
1--Title: Dark Server
2Version = 6.37
3--Author: Darkrising (minecraft name djhannz)
4--Platform: ComputerCraft Lua Virtual Machine
5term.clear()
6term.setCursorPos(1,1)
7if fs.exists("dark") == false then
8 print("Missing DarkAPI")
9 print("Attempting to download...")
10 status, getGit = pcall(http.get, "https://raw.github.com/darkrising/darkprograms/darkprograms/api/dark.lua")
11 if not status then
12 print("\nFailed to get Dark API")
13 print("Error: ".. getGit)
14 return exit
15 end
16 getGit = getGit.readAll()
17 file = fs.open("dark", "w")
18 file.write(getGit)
19 file.close()
20 print("Done!")
21 sleep(0.5)
22end
23os.loadAPI("dark")
24--Search for a modem
25S = dark.findPeripheral("modem")
26if S == false then
27 print("Please attach Modem")
28 return exit
29else
30 rednet.open(S)
31end
32--Some Vars
33x, y = term.getSize()
34AutoUpdate = true
35globalWait = 1
36slevel = 1
37cliVent = {}
38co = "blue"
39mLog = {}
40--Fixes
41
42--Communication
43function logDat(Message)
44 table.insert(mLog, Message)
45end
46function sendE(ID, Message)
47 if debugMode and (debugMode == true) then
48 logDat("Sending to ID: "..ID)
49 logDat("Message: "..Message)
50 logDat("--------------------")
51 end
52 if masterdb.pc[tostring(S)] and masterdb.pc[tostring(S)].enCode then
53 Message = dark.repCrypt(Message, masterdb.pc[tostring(ID)].enCode)
54 else
55 Message = dark.repCrypt(Message, 1)
56 end
57 rednet.send(ID, Message)
58end
59function recDec(S,M,D)
60 if masterdb.pc[tostring(S)] and masterdb.pc[tostring(S)].enCode then
61 M = dark.repdeCrypt(M, masterdb.pc[tostring(S)].enCode)
62 else
63 M = dark.repdeCrypt(M, 1, true)
64 end
65 if debugMode and (debugMode == true) then
66 logDat("Sender: "..S)
67 logDat("Message: "..M)
68 logDat("Distance: "..D)
69 logDat("--------------------")
70 end
71 return S,M,D
72end
73--User Management
74function decUser(user)
75 local encText, pash, out
76 encText = masterdb.user[user].password
77 pash = masterdb.user[user].pash
78 out = dark.decrypt(encText, pash)
79 return out
80end
81function newUser(slevel, Username, Password, isadmin)
82 local encText, Hash = dark.encrypt(Password)
83 masterdb.user[Username] = {}
84 masterdb.user[Username].password = encText
85 masterdb.user[Username].pash = Hash
86 masterdb.user[Username].admin = isadmin
87 masterdb.user[Username].area = slevel
88 databaseSave()
89end
90function delUser(Username)
91 masterdb.user[Username] = nil
92 databaseSave()
93end
94--Database Control
95function databaseNew()
96 local db = {}
97 db.ids = {}
98 db.user = {}
99 db.pc = {}
100 return db
101end
102function databaseSave()
103 dark.db.save(".DarkDB", masterdb)
104 dark.db.save(".DarkS_conf", config)
105end
106function databaseLoad()
107 masterdb = dark.db.load(".DarkDB")
108 config = dark.db.load(".DarkS_conf")
109end
110--Gui Elements
111function header(text, lText, rText)
112 if debugMode and (debugMode == true) then
113 co = "red"
114 else
115 co = "blue"
116 end
117 dark.printL("-", 1, nil, co, co)
118 dark.printA("|", x, 2, nil, co, co)
119 dark.printA("|", 1, 2, nil, co, co)
120 dark.printC(string.rep(" ", x), 2, nil, "white", co)
121 if lText then dark.printA(lText, 1, 2, nil, "white", co) end
122 if rText then dark.printA(rText, x - #rText, 2, nil, "white", co) end
123 dark.printC(text, 2, nil, "yellow", co)
124 dark.printL("-", 3, 5, co, co)
125end
126function footer()
127 if debugMode and (debugMode == true) then
128 co = "red"
129 else
130 co = "blue"
131 end
132 dark.printL("-", y, nil, co, co)
133 dark.printA("Demeter Systems", x-14, y, nil, "yellow", co)
134end
135function displayTNameColumn(TName, Page, Extrater, Admin)
136 if Extrater then
137 local TName2 = {}
138 for i,v in pairs(TName) do
139 if Admin then
140 if v.admin == true then
141 table.insert(TName2, i)
142 end
143 else
144 table.insert(TName2, i)
145 end
146 end
147 TName = TName2
148 end
149 Mod = 42 * Page
150 gPage = math.floor(#TName / 42)
151 for i = 1, 14 do
152 dark.printA(TName[i+Mod], 1, i + 3)
153 end
154 for i = 1, 14 do
155 dark.printA(TName[(i+14)+Mod], 17, i + 3)
156 end
157 for i = 1, 14 do
158 dark.printA(TName[(i+28)+Mod], 34, i + 3)
159 end
160end
161function prevPage()
162 if Page ~= 0 then
163 Page = Page - 1
164 end
165end
166function nextPage()
167 if Page < gPage then
168 Page = Page + 1
169 end
170end
171function resetCli()
172 cliVent = {}
173end
174function printR(text, option, bx, line, bgCol)
175 if not bx then
176 bx, line = term.getCursorPos()
177 end
178 local clindex = #cliVent + 1
179 cliVent[clindex] = {}
180 cliVent[clindex].startx = bx
181 cliVent[clindex].endx = bx + #text
182 cliVent[clindex].starty = line
183 cliVent[clindex].endy = line
184 cliVent[clindex].option = option
185 cliVent[clindex].draw = function()
186 term.setCursorPos(bx, line)
187 if term.isColor() == true then
188 if bgCol then term.setBackgroundColor(colors[bgCol]) end
189 term.setTextColor(colors.yellow)
190 term.write(text)
191 dark.resetCol("white", "black")
192 end
193 end
194 write(text)
195 term.setCursorPos(1, line + 1)
196end
197function regBut(text, startx, line, option, bgCol)
198 local clindex = #cliVent + 1
199 cliVent[clindex] = {}
200 cliVent[clindex].startx = startx
201 cliVent[clindex].endx = startx + #text
202 cliVent[clindex].starty = line
203 cliVent[clindex].endy = line
204 cliVent[clindex].option = option
205 cliVent[clindex].draw = function()
206 term.setCursorPos(startx, line)
207 if term.isColor() == true then
208 if bgCol then term.setBackgroundColor(colors[bgCol]) end
209 term.setTextColor(colors.yellow)
210 term.write(text)
211 dark.resetCol("white", "black")
212 end
213 end
214end
215function checkArea(tx,ty)
216 for _, data in pairs(cliVent) do
217 if ty >= data.starty and ty <= data.endy then
218 if tx >= data.startx and tx <= data.endx then
219 state = Co[state].options[data.option]
220 data.draw()
221 sleep(0.1)
222 end
223 end
224 end
225end
226--Server Loops
227function listen()
228 local cou = 1
229 while true do
230 os.pullEvent("D")
231 cou = cou + 1
232 if cou == 5 then
233 debugMode = not debugMode
234 cou = 1
235 end
236 end
237end
238function runServerGui()
239 term.clear()
240 term.setCursorPos(1,1)
241 dark.splash(1.5, "Powered by Artemis")
242 state = "main"
243 Page = 0
244 while true do
245 term.clear()
246 term.setCursorPos(1,1)
247 resetCli()
248 if Co[state].draw then
249 Co[state].draw()
250 Event, key, mx, my = os.pullEvent()
251 if Event == "char" then
252 if tonumber(key) then
253 key = tonumber(key)
254 end
255 if Co[Co[state].options[key]] then
256 state = Co[state].options[key]
257 end
258 if key == "d" then
259 os.queueEvent("D")
260 end
261 if key == "l" then
262 Co["secLev_select"].run()
263 end
264 elseif Event == "mouse_click" then
265 checkArea(mx,my)
266 end
267 else
268 Co[state].run()
269 state = Co[state].parent
270 end
271 end
272end
273function runServerBackend()
274 while true do
275 serverstatus = "running"
276 T,S,M,D = os.pullEvent()
277 if T == "rednet_message" then
278 S,M,D = recDec(S,M,D)
279 com = textutils.unserialize(M)
280 if (type(com) == "table") and com.area and com.computerid and tonumber(com.area) and tonumber(com.computerid) then
281 if (not com.super) and masterdb.pc[tostring(com.computerid)] and (masterdb.pc[tostring(com.computerid)].area == com.area) then
282 if com.diskQuery and tonumber(com.diskQuery) and masterdb.ids[tostring(com.diskQuery)] and (masterdb.ids[tostring(com.diskQuery)].area <= tonumber(com.area)) then
283 sendE(S, "#granted")
284 end
285 if com.userQuery and com.passQuery and masterdb.user[com.userQuery] and (decUser(com.userQuery) == com.passQuery) then
286 if masterdb.user[com.userQuery].area <= tonumber(com.area) then
287 sendE(S, "#granted")
288 elseif (masterdb.user[com.userQuery].admin == true) then
289 sendE(S, "#granted")
290 end
291 end
292 else
293 if com.super and com.userQuery and com.passQuery and masterdb.user[com.userQuery] and (decUser(com.userQuery) == com.passQuery) and (masterdb.user[com.userQuery].admin == true) then
294 if com.addMe then
295 local genCode = dark.serialGen(18)
296 sendE(S, tostring(genCode))
297 masterdb.pc[tostring(com.computerid)] = {}
298 masterdb.pc[tostring(com.computerid)].enCode = genCode
299 masterdb.pc[tostring(com.computerid)].area = tonumber(com.area)
300 databaseSave()
301 end
302 end
303 end
304 elseif (type(com) == "table") and com.ping then
305 sendE(S, "#pong")
306 end
307 end
308 end
309end
310function stealthUpdate()
311 if AutoUpdate == true then
312 if ((dark.gitUpdate("server", shell.getRunningProgram(), Version) == true) or (dark.gitUpdate("dark", "dark", dark.DARKversion) == true)) then
313 os.reboot()
314 end
315 end
316 return
317end
318--Gui Table
319Co = {
320 ["help"] = {
321 draw = function()
322 term.clear()
323 term.setCursorPos(1,1)
324 header("Help")
325 dark.printA("Press [1] to return to the main menu", 1, y)
326 print("\nHelp comming soon!")
327 os.pullEvent("key")
328 end,
329 options = {"main"}
330 },
331 ["main"] = {
332 draw = function()
333 Page = 0
334 if debugMode and debugMode == true then
335 header("Debug mode enabled!", "V"..Version, "ID:".. os.getComputerID())
336 Co.main.options = {"ids", "user_main", "pc_general", "secLev", "help", "log", "lua", "shell"}
337 else
338 header("Minerva Security Control Panel")
339 Co.main.options = {"ids", "user_main", "pc_general", "secLev", "help"}
340 end
341 printR("[1] Disk ID managment", 1)
342 printR("[2] User managment", 2)
343 printR("[3] Pc managment", 3)
344 printR("[4] Security Level Manager", 4)
345 printR("[5] Help", 5)
346 print("")
347 if debugMode and debugMode == true then
348 printR("[6] Log", 6)
349 printR("[7] Lua Command Prompt", 7)
350 printR("[8] Shell", 8)
351 end
352 dark.printL("-", y, nil, co, co)
353 dark.printA("Demeter Systems", x-14, y, nil, "yellow", co)
354 dark.printA(" ", 1, y, nil, co, co)
355 dark.printA("Security Level: "..slevel, 1, y, nil, "white", co)
356 end,
357 },
358 ["log"] = {
359 draw = function()
360 term.setCursorPos(1,4)
361 for name, stuff in pairs(mLog) do
362 print(stuff)
363 end
364 header("Communications Log - [1]Go Back, [2]Dump Log")
365 end,
366 options = {"main", "dump"}
367 },
368 ["dump"] = {
369 run = function()
370 header("Log Dump")
371 write("log filename: ")
372 local filename = "/"..read()
373 local file = fs.open(filename, "w")
374 for name, stuff in pairs(mLog) do
375 file.writeLine(stuff)
376 end
377 file.close()
378 print("\nDone!")
379 sleep(2)
380 end,
381 parent = "log"
382 },
383 ["lua"] = {
384 run = function()
385 print("Opened direct Lua input, the program is still running.")
386 print("")
387 shell.run("lua")
388 end,
389 parent = "main"
390 },
391 ["shell"] = {
392 run = function()
393 print("Dropped to shell, type 'exit' to exit.")
394 print("")
395 shell.run("shell")
396 end,
397 parent = "main"
398 },
399
400 -- disk ids menu
401 ["ids"] = {
402 draw = function()
403 databaseLoad()
404 header("ID managment","[4]prevPage","[5]nextPage")
405 regBut("[4]prevPage",1,2,4, co)
406 regBut("[5]nextPage",x - 7,2,5, co)
407 dark.printL("-", y-1, nil, co, co)
408 local tempList = {}
409 for name, data in pairs(masterdb.ids) do
410 if data.area == slevel then
411 table.insert(tempList, name)
412 end
413 end
414 displayTNameColumn(tempList, Page)
415 dark.printL("-", y, nil, co, co)
416 dark.printA("[1]ADD, [2]Delete, [3]Back, P:"..Page + 1 .."/"..gPage + 1 .." Level:"..slevel, 1, y, nil, "white", co)
417 regBut("[1]ADD,",1,y,1,co)
418 regBut("[2]Delete,",9,y,2,co)
419 regBut("[3]Back,",20,y,3,co)
420 end,
421 options = {"ids_add", "ids_delete", "main", "ids_prevPage", "ids_nextPage"}
422 },
423 ["ids_add"] = {
424 run = function()
425 dark.cs()
426 header("Disk IDs - add")
427
428 print("Do you want to add the id manually?")
429 repeat
430 write("y / n : ")
431 answer1 = read()
432 until ((answer1 == "y") or (answer1 == "n"))
433
434 if answer1 == "y" then
435 repeat
436 write("Disk ID to add: ")
437 answer = read()
438 until tonumber(answer)
439 else
440 repeat
441 print("\nPlease insert a disk into the drive.")
442 _,DSide = os.pullEvent("disk")
443 if disk.hasData(DSide) == true then
444 answer = disk.getID(DSide)
445 else
446 print("\nNot a disk!")
447 end
448 until disk.hasData(DSide) == true
449 disk.eject(DSide)
450 answer = tostring(answer)
451 end
452
453 if not masterdb.ids[answer] then
454 masterdb.ids[answer] = {}
455 masterdb.ids[answer].area = slevel
456 print("\nAdded!")
457 databaseSave()
458 else
459 print("\nDisk id already exists.")
460 end
461 write("\nPress enter to continue.")
462 read()
463 end,
464 parent = "ids"
465 },
466 ["ids_delete"] = {
467 run = function()
468 dark.cs()
469 header("Disk IDs - remove")
470 write("Disk ID to remove: ")
471 repeat
472 answer = read()
473 until tonumber(answer)
474 if masterdb.ids[answer] then
475 masterdb.ids[answer] = nil
476 databaseSave()
477 print("\nRemoved!")
478 else
479 print("\nID not found!")
480 end
481 sleep(globalWait)
482 end,
483 parent = "ids"
484 },
485 ["ids_prevPage"] = {
486 run = prevPage,
487 parent = "ids"
488 },
489 ["ids_nextPage"] = {
490 run = nextPage,
491 parent = "ids"
492 },
493
494 -- user menus
495 ["user_main"] = {
496 draw = function()
497 Page = 0
498 header("User Management")
499 printR("[1] Main Menu", 1)
500 print("")
501 printR("[2] User Manager", 2)
502 printR("[3] Admin Manager", 3)
503 footer()
504 end,
505 options = {"main", "user_general", "user_admin"}
506 },
507
508 ["user_general"] = {
509 draw = function()
510 Page = 0
511 databaseLoad()
512 header("General User Managment","[4]prevPage","[5]nextPage")
513 regBut("[4]prevPage",1,2,4, co)
514 regBut("[5]nextPage",x - 7,2,5, co)
515 dark.printL("-", y-1, nil, co, co)
516 tempList = {}
517 for name, data in pairs(masterdb.user) do
518 if (data.area == slevel) and (data.admin == false) then
519 table.insert(tempList, name)
520 end
521 end
522 displayTNameColumn(tempList, Page)
523 dark.printL("-", y, nil, co, co)
524 dark.printA("[1]ADD, [2]Delete, [3]Back, P:"..Page + 1 .."/"..gPage + 1 .." Level:"..slevel, 1, y, nil, "white", co)
525 regBut("[1]ADD,",1,y,1,co)
526 regBut("[2]Delete,",9,y,2,co)
527 regBut("[3]Back,",20,y,3,co)
528 end,
529 options = {"user_general_add","user_general_remove","user_main","user_general_prevPage","user_general_nextPage"}
530 },
531 ["user_general_add"] = {
532 run = function()
533 dark.cs()
534 header("Add User")
535 write("Username: ")
536 local username = read()
537 repeat
538 write("Password: ")
539 pass1 = read("*")
540 write("Confirm Password: ")
541 pass2 = read("*")
542 until pass1 == pass2
543 pass1 = tostring(pass1)
544 username = string.lower(username)
545 newUser(tonumber(slevel), username, pass1, false)
546 print("\nUser Added!")
547 sleep(globalWait)
548 end,
549 parent = "user_general"
550 },
551 ["user_general_remove"] = {
552 run = function()
553 dark.cs()
554 header("Remove User")
555 write("User to remove: ")
556 local username = read()
557 if masterdb.user[username] then
558 delUser(username)
559 print("\nUser deleted!")
560 else
561 print("\nUser doesn't exist.")
562 end
563 sleep(globalWait)
564 end,
565 parent = "user_general"
566 },
567 ["user_general_prevPage"] = {
568 run = prevPage,
569 parent = "user_general"
570 },
571 ["user_general_nextPage"] = {
572 run = nextPage,
573 parent = "user_general"
574 },
575
576 ["user_admin"] = {
577 draw = function()
578 Page = 0
579 databaseLoad()
580 header("Admin Managment","[4]prevPage","[5]nextPage")
581 regBut("[4]prevPage",1,2,4, co)
582 regBut("[5]nextPage",x - 7,2,5, co)
583 dark.printL("-", y-1, nil, co, co)
584 displayTNameColumn(masterdb.user, Page, true, true)
585 dark.printL("-", y, nil, co, co)
586 dark.printA("[1]Promote, [2]Demote, [3]Back, P:"..Page + 1 .."/"..gPage + 1, 1, y, nil, "white", co)
587 regBut("[1]Promote,",1,y,1,co)
588 regBut("[2]Demote,",13,y,2,co)
589 regBut("[3]Back,",24,y,3,co)
590 end,
591 options = {"user_admin_promote","user_admin_demote","user_main","user_admin_prevPage","user_admin_nextPage"}
592 },
593 ["user_admin_promote"] = {
594 run = function()
595 dark.cs()
596 header("Promote User")
597 write("User to promote to admin: ")
598 username = read()
599 if masterdb.user[username] then
600 masterdb.user[username].admin = true
601 databaseSave()
602 print("\nUser promoted")
603 else
604 print("\nUser doesn't exist")
605 end
606 sleep(globalWait)
607 end,
608 parent = "user_admin"
609 },
610 ["user_admin_demote"] = {
611 run = function()
612 dark.cs()
613 header("Demote User")
614 write("User to demote from admin: ")
615 username = read()
616 if masterdb.user[username] then
617 masterdb.user[username].admin = false
618 databaseSave()
619 print("\nUser demoted")
620 else
621 print("\nUser doesn't exist")
622 end
623 sleep(globalWait)
624 end,
625 parent = "user_admin"
626 },
627 ["user_admin_prevPage"] = {
628 run = prevPage,
629 parent = "user_admin"
630 },
631 ["user_admin_nextPage"] = {
632 run = nextPage,
633 parent = "user_admin"
634 },
635
636 -- pc menus
637 ["pc_general"] = {
638 draw = function()
639 Page = 0
640 databaseLoad()
641 header("Pc Whitelist","[4]prevPage","[5]nextPage")
642 regBut("[4]prevPage",1,2,4, co)
643 regBut("[5]nextPage",x - 7,2,5, co)
644 dark.printL("-", y-1, nil, co, co)
645 tempList = {}
646 for name, data in pairs(masterdb.pc) do
647 if data.area == slevel then
648 table.insert(tempList, name)
649 end
650 end
651 displayTNameColumn(tempList, Page)
652 dark.printL("-", y, nil, co, co)
653 dark.printA("[1]ADD, [2]Delete, [3]Back, P:"..Page + 1 .."/"..gPage + 1 .." Level:"..slevel, 1, y, nil, "white", co)
654 regBut("[1]ADD,",1,y,1,co)
655 regBut("[2]Delete,",9,y,2,co)
656 regBut("[3]Back,",20,y,3,co)
657 end,
658 options = {"pc_general_add","pc_general_remove","main","pc_general_prevPage","pc_general_nextPage"}
659 },
660 ["pc_general_add"] = {
661 run = function()
662 dark.cs()
663 header("Pc whitelist - add")
664 write("PC ID to add to the whitelist: ")
665 repeat
666 answer = read()
667 until tonumber(answer)
668 if not masterdb.pc[answer] then
669 masterdb.pc[answer] = {}
670 masterdb.pc[answer].enCode = dark.serialGen(5)
671 masterdb.pc[answer].area = slevel
672 databaseSave()
673 print("\nAdded!")
674 dark.setCol("yellow", "black")
675 print("\nEncryption Code for the new Client is: ".. masterdb.pc[answer].enCode)
676 dark.resetCol(true, true)
677 print("\nMake sure to take a note of this number!")
678 write("\nPress enter to continue.")
679 read()
680 else
681 print("\nPc id exists.")
682 sleep(globalWait)
683 end
684 end,
685 parent = "pc_general"
686 },
687 ["pc_general_remove"] = {
688 run = function()
689 dark.cs()
690 header("Pc whitelist - remove")
691 write("ID to remove from whitelist: ")
692 repeat
693 answer = read()
694 until tonumber(answer)
695 if masterdb.pc[answer] then
696 masterdb.pc[answer] = nil
697 databaseSave()
698 print("\nRemoved!")
699 else
700 print("\nID not found!")
701 end
702 sleep(globalWait)
703 end,
704 parent = "pc_general"
705 },
706 ["pc_general_prevPage"] = {
707 run = prevPage,
708 parent = "pc_general"
709 },
710 ["pc_general_nextPage"] = {
711 run = nextPage,
712 parent = "pc_general"
713 },
714
715 -- security level menu
716 ["secLev"] = {
717 draw = function()
718 databaseLoad()
719 header("Security Level Manager")
720 printR("[1] Main Menu", 1)
721 print("")
722 print("Security Levels: ".. config.secLevels)
723 print("")
724 printR("[2] Select Level", 2)
725 printR("[3] Modify Level Amount", 3)
726 footer()
727 dark.printA("Current Security Level: "..slevel, 1, y, nil, "white", co)
728 end,
729 options = {"main","secLev_select","secLev_modify"}
730 },
731 ["secLev_select"] = {
732 run = function()
733 dark.cs()
734 header("Security Level - Select")
735 print("Currently Selected Security Level: "..slevel)
736 print("Security Levels: ".. config.secLevels)
737 repeat
738 write("\nSecurity Level to switch too: ")
739 answer = read()
740 until tonumber(answer)
741 answer = tonumber(answer)
742 if ((answer < 0) or (answer > config.secLevels)) then
743 print("\nInvalid number entered.")
744 else
745 slevel = answer
746 print("Switched to level: "..slevel)
747 end
748 sleep(globalWait)
749 end,
750 parent = "secLev"
751 },
752 ["secLev_modify"] = {
753 run = function()
754 dark.cs()
755 header("Security Level - Modify")
756 print("\nSecurity Level Amount: ".. config.secLevels)
757 write("New security level amount: ")
758 repeat
759 answer = read()
760 until tonumber(answer)
761 config.secLevels = tonumber(answer)
762 databaseSave()
763 print("Changed!")
764 sleep(globalWait)
765 end,
766 parent = "secLev"
767 },
768}
769--Config file
770if fs.exists(".DarkS_conf") == false then
771 dark.cs()
772 config = {}
773 masterdb = databaseNew()
774 header("Server Setup")
775 print("Computer's id is ".. os.getComputerID())
776 repeat
777 write("security level amount (must be a number): ")
778 securityLevelNumber = io.read()
779 until tonumber(securityLevelNumber)
780 config.secLevels = tonumber(securityLevelNumber)
781
782 dark.db.save(".DarkDB", masterdb)
783 dark.db.save(".DarkS_conf", config)
784end
785--Finale Stuff
786databaseLoad()
787parallel.waitForAll(runServerBackend, runServerGui, stealthUpdate, listen)