From b1627de0341fde3f8e736cdc809d3297f9ff0cbe Mon Sep 17 00:00:00 2001 From: Test_User Date: Mon, 17 Jun 2024 19:17:55 -0400 Subject: Python Coupserv improvements/lua seperation --- CoupServ.lua | 200 --------------------------------- CoupServ.py | 67 ++++++----- commands.lua | 359 ----------------------------------------------------------- network.lua | 310 --------------------------------------------------- rerun.sh | 11 ++ stdin.lua | 132 ---------------------- 6 files changed, 50 insertions(+), 1029 deletions(-) delete mode 100755 CoupServ.lua delete mode 100644 commands.lua delete mode 100644 network.lua create mode 100755 rerun.sh delete mode 100644 stdin.lua diff --git a/CoupServ.lua b/CoupServ.lua deleted file mode 100755 index 20ee42e..0000000 --- a/CoupServ.lua +++ /dev/null @@ -1,200 +0,0 @@ -#!/usr/bin/env lua ---[[ - -Main program for HaxServ, a pseudoserver for inspircd3. - -Written by: Test_User - -This is free and unencumbered software released into the public -domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. -]] - -path = arg[0]:sub(1, -arg[0]:reverse():find('/')) - -socket = require("socket") -json = require("json") -ssl = require("ssl") - -servlist = {} -userlist = {} -chanlist = {} - -function has_permission(user, privs) - if not user or type(user) ~= "table" then - return false - end - - privs = privs or {} - for _, v in pairs(privs) do - if v == "Admin" then - if user.opertype ~= "Admin" then - return false - end - elseif v == "Owner" then -- not dealing with this yet, so just always return false for now - return false - else -- unknown priv, naturally no one has it - return false - end - end - return true -end - -config_file = io.open(path.."CoupServConfig.json", "r+") -config = json.decode(config_file:read("*a")) - -for file, _ in pairs(config.files) do - dofile(path..file) -end - -stdin = socket.tcp() -stdin:close() -stdin:setfd(0) --clearly a hack but it works - -while true do - servlist = {} - userlist = {} - chanlist = {} - - ::continue:: - - local s = socket.tcp4() - s:connect("irc.andrewyu.org", 7005) - local con = ssl.wrap(s, {mode = "client", protocol = "tlsv1_3"}) - - if not con:dohandshake() then - socket.select(nil, nil, 5) - con:close() - goto continue - end - - local time = tostring(os.time()) - - con:send("SERVER hax.irc.andrewyu.org "..config.send_password.." 0 1HC :HaxServ\n") - con:send("BURST "..time.."\n") - con:send("UID 1HC000000 "..time.." "..config.nick.." "..config.hostmask.." "..config.hostmask.." HaxServ 192.168.1.1 "..time.." +k :HaxServ\n") - con:send(":1HC000000 OPERTYPE Admin\n") - - userlist["1HC000000"] = { - server = "1HC", - nick_ts = time, - nick = config.nick, - hostname = config.hostmask, - vhost = config.hostmask, - ident = "HaxServ", - ip = "192.168.1.1", - user_ts = time, - modes = { - ["k"] = true, - }, - realname = "HaxServ", - - metadata = {}, - } - - for channel, _ in pairs(config.channels) do - con:send("FJOIN "..channel.." "..time.." + :,1HC000000\n") - con:send("MODE "..channel.." +o 1HC000000\n") - end - con:send("ENDBURST\n") - - local proceed = true - while proceed do - ready, _, err = socket.select({con, stdin}, {}, 120) - if err then - con:send("") -- hack to make it properly timeout due to annoying bugs - end - - for _, sock in ipairs(ready) do - if sock == con then - local msg, err = con:receive() - - local original = msg - - if err then - proceed = false - break - end - - local source = nil - if msg:sub(1, 1) == ":" then - source = msg:sub(2):match("^[^ ]*") - msg = msg:sub(string.len(source) + 3) -- 1 for the leading ':', 1 for the trailing ' ', and 1 for the offset - end - - local lastarg = msg:match(" :.*") - if lastarg ~= nil then - msg = msg:sub(1, -string.len(lastarg) - 1) -- only offset - lastarg = lastarg:sub(3) - end - - local args = {} - for arg in msg:gmatch("[^ ]*") do - table.insert(args, arg) - end - - local command = args[1] - table.remove(args, 1) - - if lastarg ~= nil then - table.insert(args, lastarg) - end - - if message_handler[command] then - local success, stop = pcall(message_handler[command], con, source, args, original) - if success and stop then - proceed = false - break - elseif not success then - print(stop) - end - else - print("Unhandled command:", ("%q"):format(original)) - end - elseif sock == stdin then - msg = io.stdin:read() - local args = {} - for arg in msg:gmatch("[^ ]*") do - table.insert(args, arg) - end - local command = args[1]:upper() - table.remove(args, 1) - - if stdin_commands[command] then - local success, err = pcall(stdin_commands[command], con, msg, args) - if not success then - print(err) - elseif err then - proceed = false - break - end - else - print("Unknown command.") - end - end - end - if err then break end - end - - con:close() -end diff --git a/CoupServ.py b/CoupServ.py index c4576a0..2357e86 100755 --- a/CoupServ.py +++ b/CoupServ.py @@ -124,9 +124,9 @@ never gonna tell a lie, and hurt you""" s=ssl.wrap_socket(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) -s.connect(("irc.andrewyu.org", 7005)) +s.connect(("localhost", 7021)) -send("SERVER hax.irc.andrewyu.org "+config["send_password"]+" 0 1HC :HaxServ") +send("SERVER py.hax.irc.andrewyu.org "+config["send_password"]+" 0 "+config["sid"]+" :HaxServ") msg = "" @@ -136,12 +136,14 @@ servlist = {} userlist = {} chanlist = {} +jupe_list = {} + usercount = 0 def read_and_send(): for line in sys.stdin: try: - send(line) + send(line.rstrip("\n")) except Exception: pass @@ -149,7 +151,10 @@ threading.Thread(target=read_and_send, daemon=True).start() def detect_broken(): while True: - send("") + for key in servlist: + if servlist[key].distance == 0: + send(":"+config["sid"]+" PING "+config["sid"]+" :"+key) + break time.sleep(15) threading.Thread(target=detect_broken, daemon=True).start() @@ -182,18 +187,22 @@ try: send(":"+args[1]+" PONG "+args[1]+" "+source) elif command == "SERVER": if source != "": - continue + servlist[args[3]] = {"attached_to": source, "address": args[0], "distance": servlist[source]["distance"] + 1, "name": args[4]} else: if config["recv_password"] != args[1]: print("Received invalid password from the server!") os._exit() send("BURST "+str(math.floor(time.time()))) - send("UID 1HC000000 "+str(math.floor(time.time()))+" "+config["nick"]+" hax.irc.andrewyu.org LibreIRC/services/HaxServ™ HaxServ 192.168.1.1 "+str(math.floor(time.time()))+" +Bk :HaxServ") - send(":1HC000000 OPERTYPE Admin") + send("UID "+config["sid"]+"000000 "+str(math.floor(time.time()))+" "+config["nick"]+" hax.irc.andrewyu.org LibreIRC/services/HaxServ™ HaxServ 192.168.1.1 "+str(math.floor(time.time()))+" +Bk :HaxServ") + send(":"+config["sid"]+"000000 OPERTYPE Admin") for channel in config["channels"]: - send("FJOIN "+channel+" "+str(math.floor(time.time()))+" + :,1HC000000") - send("MODE "+channel+" +o 1HC000000") + send("FJOIN "+channel+" "+str(math.floor(time.time()))+" + :,"+config["sid"]+"000000") + send("MODE "+channel+" +o "+config["sid"]+"000000") send("ENDBURST") + servlist[args[3]] = {"attached_to": config["sid"], "address": args[0], "distance": 1, "name": args[4]} + elif command == "SQUIT": + if args[0] in jupe_list: + send(":"+config["sid"]+" SERVER "+jupe_list[args[0]]+" * 0 "+args[0]+" :No") elif command == "UID": userlist[args[0]] = { "server": source, @@ -222,8 +231,8 @@ try: print("Unable to find nick!\r\n") elif command == "PRIVMSG": try: - if userlist[source]["opertype"] == "Admin": - if args[0] == "1HC000000" or (args[0][0] == "#" and args[1][0] == "-"): + if userlist[source]["opertype"] == "NetAdmin": + if args[0] == config["sid"]+"000000" or (args[0][0] == "#" and args[1][0] == "-"): if args[0][0] == "#": chan = args[0] resp = chan @@ -235,7 +244,7 @@ try: cmd = args[1].split(" ")[0].lower() argv = args[1].split(" ")[1:] - send(":1HC000000 PRIVMSG "+config["log_chan"]+" :"+userlist[source]["nick"]+" executed command: "+args[1]) + send(":"+config["sid"]+"000000 PRIVMSG "+config["log_chan"]+" :"+userlist[source]["nick"]+" executed command: "+args[1]) if len(cmd) == 0: continue @@ -244,41 +253,43 @@ try: elif cmd == "get": if argv[0] == "uid": try: - send(":1HC000000 PRIVMSG "+resp+" :"+[key for key in userlist if userlist[key]["nick"] == argv[1]][0]) + send(":"+config["sid"]+"000000 PRIVMSG "+resp+" :"+[key for key in userlist if userlist[key]["nick"] == argv[1]][0]) except IndexError: - send(":1HC000000 PRIVMSG "+resp+" :Nick not found!") + send(":"+config["sid"]+"000000 PRIVMSG "+resp+" :Nick not found!") elif argv[0] == "ts": try: - send(":1HC000000 PRIVMSG "+resp+" :"+userlist[argv[1]]["nick_ts"]) + send(":"+config["sid"]+"000000 PRIVMSG "+resp+" :"+userlist[argv[1]]["nick_ts"]) except KeyError: - send(":1HC000000 PRIVMSG "+resp+" :UID not found!") + send(":"+config["sid"]+"000000 PRIVMSG "+resp+" :UID not found!") elif cmd == "jupe": - send("RSQUIT :"+argv[0]) - send(":1HC SERVER "+argv[0]+" * 0 010 :No") + found = 0 + for key in servlist: + if servlist[key]["address"] == argv[0]: + send("RSQUIT "+argv[0]+" :") + jupe_list[key] = argv[0] + break elif cmd == "sanick": - send(":1HC000000 SANICK "+argv[0]+" :"+" ".join(argv[1:])) + send(":"+config["sid"]+"000000 SANICK "+argv[0]+" :"+" ".join(argv[1:])) elif cmd == "nggyu": for line in rickroll.split("\n"): - send(":1HC000000 PRIVMSG "+argv[0]+" :"+line) - elif cmd == "rdos": - send(':1HC PRIVMSG lurk :.sh while true; do printf "nggyu" | nc -q 0 -u '+argv[0]+' $RANDOM; done &') + send(":"+config["sid"]+"000000 PRIVMSG "+argv[0]+" :"+line) elif cmd == "spam": for _ in range(0, int(argv[1])): - send(":1HC PRIVMSG "+argv[0]+" :"+" ".join(argv[2:])) + send(":"+config["sid"]+" PRIVMSG "+argv[0]+" :"+" ".join(argv[2:])) elif cmd == "join": - send(":1HC000000 FJOIN "+argv[0]+" "+str(math.floor(time.time()))+" + :,1HC000000") + send(":"+config["sid"]+"000000 FJOIN "+argv[0]+" "+str(math.floor(time.time()))+" + :,"+config["sid"]+"000000") config["channels"][argv[0]] = True # actual value doesn't matter save() elif cmd == "part": - send(":1HC000000 PART "+resp) + send(":"+config["sid"]+"000000 PART "+resp) del config["channels"][resp] save() elif cmd == "op": if chan: try: - send(":1HC000000 MODE "+chan+" +o "+argv[0]) + send(":"+config["sid"]+"000000 MODE "+chan+" +o "+argv[0]) except IndexError: - send(":1HC000000 MODE "+chan+" +o "+source) + send(":"+config["sid"]+"000000 MODE "+chan+" +o "+source) if args[1] == "nggyu": if args[0][0] == "#": @@ -287,7 +298,7 @@ try: resp = source for line in rickroll.split("\n"): - send(":1HC000000 PRIVMSG "+resp+" :"+line) + send(":"+config["sid"]+"000000 PRIVMSG "+resp+" :"+line) except KeyError: pass diff --git a/commands.lua b/commands.lua deleted file mode 100644 index bf38ff1..0000000 --- a/commands.lua +++ /dev/null @@ -1,359 +0,0 @@ ---[[ - -Commands file for HaxServ. - -Written by: Test_User - -This is free and unencumbered software released into the public -domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. -]] - -commands = { - ["SANICK"] = { - func = function(con, user, cmd, args, resp) - if #args < 2 then - con:send(":1HC000000 NOTICE "..resp.." :Not enough args.\n") - else - con:send("SANICK "..args[1].." :"..table.concat(args, " ", 2).."\n") - end - end, - privs = {"Admin"}, - args = " ", - }, - - ["RELOAD"] = { - func = function(con, user, cmd, args, resp) - if #args == 0 then - config_file:seek("set", 0) - local success, value_or_err = pcall(json.decode, config_file:read("*a")) - if success then - config = value_or_err - con:send(":1HC000000 NOTICE "..resp.." :Successfully reloaded config.json\n") - else - con:send(":1HC000000 NOTICE "..resp.." :Unable to reload config.json, check /dev/stdout for details.\n") - print("config.json") - print(value_or_err) - end - - for file, _ in pairs(config.files) do - local success, err = pcall(dofile, path..file) - if success then - con:send(":1HC000000 NOTICE "..resp.." :Successfully reloaded "..file.."\n") - else - con:send(":1HC000000 NOTICE "..resp.." :Unable to reload "..file..", check /dev/stdout for details.\n") - print(file) - print(err) - end - end - else - local file = args[1]..".lua" - if config.files[file] then - local success, err = pcall(dofile, path..file) - if success then - con:send(":1HC000000 NOTICE "..resp.." :Successfully reloaded "..file.."\n") - else - con:send(":1HC000000 NOTICE "..resp.." :Unable to reload "..file..", check /dev/stdout for details.\n") - print(file) - print(err) - end - elseif args[1] == "config" then - config_file:seek("set", 0) - local success, value_or_err = pcall(json.decode, config_file:read("*a")) - if success then - config = value_or_err - con:send(":1HC000000 NOTICE "..resp.." :Successfully reloaded config.json\n") - else - con:send(":1HC000000 NOTICE "..resp.." :Unable to reload config.json, check /dev/stdout for details.\n") - print("CoupServConfig.json") - print(value_or_err) - end - else - con:send(":1HC000000 NOTICE "..resp.." :Invalid section.\n") - end - end - end, - privs = {"Admin"}, - args = "[
]", - }, - - ["RECONNECT"] = { - func = function(con, user, cmd, args, resp) - return true - end, - privs = {"Admin"}, - }, - - [":"] = { - func = function(con, user, cmd, args, resp) - con:send(table.concat(args, " ").."\n") - end, - privs = {"Admin"}, - args = "", - }, - - ["HELP"] = { - func = function(con, user, cmd, args, resp) - for command, tbl in pairs(commands) do - if has_permission(userlist[user], tbl.privs) then - if tbl.args then - con:send(":1HC000000 NOTICE "..resp.." :"..command.." "..tbl.args.."\n") - else - con:send(":1HC000000 NOTICE "..resp.." :"..command.."\n") - end - end - end - end, - }, - - ["SHUTDOWN"] = { - func = function(con, user, cmd, args, resp) - local crash_me = nil - crash_me() - end, - privs = {"Owner"}, - }, - - ["SPAM"] = { - func = function(con, user, cmd, args, resp) - if #args < 3 then - con:send(":1HC000000 NOTICE "..resp.." :Not enough args.\n") - elseif tonumber(args[2]) == nil then - con:send(":1HC000000 NOTICE "..resp.." :"..args[2]..": Not a valid positive integer.\n") - elseif tonumber(args[2]) < 1 then - con:send(":1HC000000 NOTICE "..resp.." :"..args[2]..": Not a valid positive integer.\n") - elseif tonumber(args[2]) > 65535 then - con:send(":1HC000000 NOTICE "..resp.." :"..args[2]..": Too large of a number, max is 65535.\n") - else - local msg = ":1HC000000 PRIVMSG "..args[1].." :"..table.concat(args, " ", 3).."\n" - for i=1, tonumber(args[2]), 1 do - con:send(msg) - end - end - end, - privs = {"Admin"}, - args = " ", - }, - - ["OP"] = { - func = function(con, user, cmd, args, resp) - if resp:sub(1, 1) ~= "#" then - con:send(":1HC000000 NOTICE "..resp.." :This command must be executed within a channel.\n") - return - end - - if #args == 0 then - con:send(":1HC000000 MODE "..resp.." +o "..user.."\n") - else - con:send(":1HC000000 MODE "..resp.." +o "..args[1].."\n") - end - end, - privs = {"Admin"}, - args = "[]", - }, - - ["GETUID"] = { - func = function(con, user, cmd, args, resp) - if #args == 0 then - con:send(":1HC000000 NOTICE "..resp.." :"..user.."\n") - else - local nick = table.concat(args, " ") - for uid, tbl in pairs(userlist) do - if tbl.nick == nick then - con:send(":1HC000000 NOTICE "..resp.." :"..uid.."\n") - return - end - end - con:send(":1HC000000 NOTICE "..resp.." :Nick not found.\n") - end - end, - args = "[]", - }, - - ["PRINT"] = { - func = function(con, user, cmd, args, resp) - if #args == 0 then - con:send(":1HC000000 NOTICE "..resp.." :Not enough args.\n") - else - local list - if args[1] == "userlist" then - list = userlist - elseif args[1] == "chanlist" then - list = chanlist - elseif args[1] == "servlist" then - list = servlist - else - con:send(":1HC000000 NOTICE "..resp.." :Unknown list.\n") - return - end - - for k, v in pairs(list) do - local msg = {} - for key, val in pairs(v) do - table.insert(msg, "["..(type(key) == "string" and ("%q"):format(key) or tostring(key)).."] = "..(type(val) == "string" and ("%q"):format(val) or tostring(val))) - end - print("["..(type(k) == "string" and ("%q"):format(k) or tostring(k)).."] = {"..table.concat(msg, ", ").."}") - end - end - end, - privs = {"Admin"}, - args = "", - }, - - ["GETUSERINFO"] = { - func = function(con, user, cmd, args, resp) - if #args == 0 then - args[1] = source - end - - if userlist[args[1]] then - local msg = {} - for key, val in pairs(userlist[args[1]]) do - table.insert(msg, "["..(type(key) == "string" and ("%q"):format(key) or tostring(key)).."] = "..(type(val) == "string" and ("%q"):format(val) or tostring(val))) - end - con:send(":1HC000000 PRIVMSG "..resp.." :{"..table.concat(msg, ", ").."}\n") - else - con:send(":1HC000000 PRIVMSG "..resp.." :Nonexistent UID\n") - end - end, - privs = {"Admin"}, - args = "[]", - }, - - ["GETNICK"] = { - func = function(con, user, cmd, args, resp) - if userlist[args[1]] then - con:send(":1HC000000 NOTICE "..resp.." :"..userlist[args[1]].nick.."\n") - else - con:send(":1HC000000 NOTICE "..resp.." :Nonexistent UID\n") - end - end, - args = "[]", - }, - - ["JUPE"] = { - func = function(con, user, cmd, args, resp) - if #args == 0 then - con:send(":1HC000000 NOTICE "..resp.." :Not enough args.\n") - else - for id, tbl in pairs(servlist) do - if tbl.address == args[1] then - con:send("RSQUIT "..args[1].." :"..table.concat(args, " ", 2).."\n") - con:send(":1HC SERVER "..args[1].." * 0 "..id.." :Juped.\n") - return - end - end - con:send(":1HC000000 NOTICE "..resp.." :Server not found.\n") - end - end, - privs = {"Admin"}, - args = "", - }, - - ["ALLOW"] = { - func = function(con, user, cmd, args, resp) - if #args == 0 then - con:send(":1HC000000 NOTICE "..resp.." :Not enough args.\n") - else - for id, tbl in pairs(userlist) do - if tbl.nick == args[1] then - userlist[id].opertype = "Admin" - con:send(":1HC000000 NOTICE "..resp.." :"..args[1].." is now considered an oper.\n") - return - end - end - con:send(":1HC000000 NOTICE "..resp.." :Nick not found.\n") - end - end, - privs = {"Admin"}, - args = "", - }, - - ["DENY"] = { - func = function(con, user, cmd, args, resp) - if #args == 0 then - con:send(":1HC000000 NOTICE "..resp.." :Not enough args.\n") - else - for id, tbl in pairs(userlist) do - if tbl.nick == args[1] then - userlist[id].opertype = nil - con:send(":1HC000000 MODE "..id.." -o\n") - con:send(":1HC000000 NOTICE "..resp.." :"..args[1].." is no longer an oper.\n") - return - end - end - con:send(":1HC000000 NOTICE "..resp.." :Nick not found.\n") - end - end, - privs = {"Admin"}, - args = "", - }, - - ["SH"] = { - func = function(con, user, cmd, args, resp) - local command = table.concat(args, " ") - if bash_command ~= nil and command == bash_command then - local fd = io.popen(command) - local message = fd:read("*a") - for line in message:gmatch("[^\n]*") do - con:send(":1HC000000 PRIVMSG "..resp.." :"..line.."\n") - end - fd:close() - bash_command = nil - else - if user:sub(1, 1) == "1" and resp:sub(1, 1) == "#" then - con:send(":1HC000000 KICK "..resp.." "..user.." :Thought they could execute arbitrary code on hax's computer.)\n") - else - con:send(":1HC000000 KILL "..user.." :Killed (Thought they could execute arbitrary code on hax's computer.)\n") - end - end - end, - args = "", - }, - - ["SUS"] = { - func = function(con, user, cmd, args, resp) - local lines = { - ":1HC000000 PRIVMSG "..resp.." :Andrew is very sus.\n", - ":1HC000000 PRIVMSG "..resp.." :I was the impostor, but you only know because I killed you.\n", - ":1HC000000 PRIVMSG "..resp.." :\x1b(0\n", - ":1HC000000 KILL "..user.." :Ejected (1 Impostor remains)\n", - ":1HC000000 KILL "..user.." :Ejected, and the crewmates have won.\n", - } - con:send(lines[math.random(#lines)]) - end, - }, - - ["CR"] = { - func = function(con, user, cmd, args, resp) - local lines = { - ":1HC000000 PRIVMSG "..resp.." :You are now a cruxian toxicpod, kill the sharded crewmates.\n", - ":1HC000000 PRIVMSG "..resp.." :You are now a cruxian omura, kill the sharded crewmates.\n", - ":1HC000000 PRIVMSG "..resp.." :You are now a cruxian oct, but you ran out of reactors.\n", - ":1HC000000 KILL "..user.." :Eliminated (You became a cruxian eclipse, but were drawn to my bait reactor)\n", - ":1HC000000 PRIVMSG "..resp.." :You attempted to change into a cruxian navanax, but were caught in the act.\n", - } - con:send(lines[math.random(#lines)]) - end, - }, -} diff --git a/network.lua b/network.lua deleted file mode 100644 index 84cb712..0000000 --- a/network.lua +++ /dev/null @@ -1,310 +0,0 @@ ---[[ - -Network protocol file for HaxServ. - -Written by: Test_User - -This is free and unencumbered software released into the public -domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. -]] - -local function mode_snomask(current, mode, dir, arg) - if dir == "+" then - current[mode] = current[mode] or {} - parse_modes(arg, {}, {}, current[mode]) - if not next(current[mode]) then - current[mode] = nil - end - return true - else - current[mode] = nil - end -end - -local function mode_replace(current, mode, dir, arg) - if dir == "+" then - current[mode] = arg - return true - else - current[mode] = nil - end -end - -local function mode_multi(current, mode, dir, arg) - if dir == "+" then - current[mode] = current[mode] or {} - current[mode][arg] = true - else - if current[mode] == nil then - print("Invalid mode change attempt!\n") - current[mode] = {} - end - current[mode][arg] = nil - if next(current[mode]) == nil then - current[mode] = nil - end - end - return true -end - -local usermodes = { - ["s"] = mode_snomask, -} - -local chanmodes = { - ["l"] = mode_replace, - ["L"] = mode_replace, - ["v"] = mode_multi, - ["o"] = mode_multi, - ["h"] = mode_multi, - ["a"] = mode_multi, - ["q"] = mode_multi, - ["Y"] = mode_multi, - ["d"] = mode_replace, - ["f"] = mode_replace, - ["g"] = mode_multi, - ["b"] = mode_multi, - ["e"] = mode_multi, - ["I"] = mode_multi, - ["k"] = mode_replace, - ["w"] = mode_multi, - ["E"] = mode_replace, - ["F"] = mode_replace, - ["H"] = mode_replace, - ["J"] = mode_replace, - ["X"] = mode_multi, -} - -local function parse_modes(modes, args, has_args, current) - local dir = "-" - for i = 1, #modes do - local mode = modes:sub(i, i) - - if mode == "+" or mode == "-" then - dir = mode - elseif has_args[mode] and has_args[mode][dir] then - if not args[1] then return false end - - if dir == "+" then - current[mode] = (type(current[mode]) == "table" and current[mode] or {}) - current[mode][args[1]] = true - else - if current[mode] then - current[mode][args[1]] = nil - end - end - table.remove(args, 1) - else - current[mode] = (dir == "+" and true or nil) - end - end - return true -end - -local function mode_to_string(modes) - local res = "+" - local args = {} - for mode, arg in pairs(modes) do - if arg == true then - res = res..mode - elseif type(arg) == "string" then - res = res..mode - table.insert(args, arg) - elseif type(arg) == "table" then - for _, a in pairs(arg) do - res = res..mode - table.insert(args, a) - end - end - end - - res = res.." "..table.concat(args, " ") - - return res -end - -message_handler = { - ["PING"] = function(con, source, args, original) - con:send(":"..args[2].." PONG "..args[2].." "..source.."\n") - end, - - ["SERVER"] = function(con, source, args, original) - if source then - servlist[args[4]] = {address = args[1], distance = args[3] + 1 + servlist[source].distance, name = args[5], metadata = {}} - else - servlist[args[4]] = {address = args[1], distance = args[3], name = args[5], metadata = {}} - end - end, - - ["METADATA"] = function(con, source, args, original) - if args[1] == "*" then - if servlist[source] then - servlist[source].metadata[args[2]] = args[3] - else - print("Got metadata command from an unknown server!\n") - end - elseif args[1]:sub(1, 1) == "#" then - print(string.format("%q", original)) - print("Channels not yet handled!\n") - else - if userlist[args[1]] then - userlist[args[1]].metadata[args[2]] = args[3] - else - print(("%q"):format(original)) - print("Got metadata for an unknown user!\n") - end - end - end, - - ["UID"] = function(con, source, args, original) - userlist[args[1]] = { - server = source, - nick_ts = args[2], - nick = args[3], - hostname = args[4], - vhost = args[5], - ident = args[6], - ip = args[7], - user_ts = args[8], - modes = {}, - realname = args[-1], -- last one is safer as any extra are arguments to umodes (or protocol violations, but at that point nothing is a safe option) - - metadata = {}, -- controlled by METADATA network commands - } - - if not parse_modes(args[9], {table.unpack(args, 10, #args-1)}, {["s"] = {["+"] = true, ["-"] = false}}, userlist[args[1]].modes) then return true end - end, - - ["OPERTYPE"] = function(con, source, args, original) - if userlist[source] then - userlist[source].opertype = args[1] - else - print("Server "..source.." attempted to set OPERTYPE on a nonexistent user!\n") - end - end, - - ["NICK"] = function(con, source, args, original) - if userlist[source] then - userlist[source].nick = args[1] - userlist[source].nick_ts = args[2] - end - end, - - ["PRIVMSG"] = function(con, source, args, original) - if args[1] == cur_channel then - print(("%q"):format("<"..userlist[source].nick.."> "..args[2])) - end - - local cmd_args = {} - for part in args[2]:gmatch("[^ ]*") do - table.insert(cmd_args, part) - end - cmd = cmd_args[1]:upper() - table.remove(cmd_args, 1) - - local resp - if args[1]:sub(1, 1) == "#" then - resp = args[1] - - if cmd:sub(1, 3) ~= "\x0304" then return end - - cmd = cmd:sub(4) -- remove leading '-' - else - resp = source - end - - if commands[cmd] then - if has_permission(userlist[source], commands[cmd].privs) then - print(("%q"):format(userlist[source].nick.." executed command: "..cmd)) - return commands[cmd].func(con, source, cmd, cmd_args, resp) - else - con:send(":1HC000000 NOTICE "..resp.." :You are not authorized to execute that command.\n") - end - else - con:send(":1HC000000 NOTICE "..resp.." :Unknown command: "..cmd.."\n") - end - end, - - ["MODE"] = function(con, source, args, original) - if args[1]:sub(1, 1) == "#" then - print("Channels not handled yet!\n") - else - if not userlist[args[1]] then - print("Attempted to set mode on an unknown user!\n") - elseif not parse_modes(args[2], {table.unpack(args, 3)}, usermodes, userlist[args[1]].modes) then - return true - elseif not userlist[args[1]].modes.o then - userlist[args[1]].opertype = nil - end - end - end, - - ["QUIT"] = function(con, source, args, original) - userlist[source] = nil - for name, chan in pairs(chanlist) do - chan["users"][source] = nil - if next(chan["users"]) == nil and not chan["modes"]["P"] then - chanlist[name] = nil - end - end - end, - - ["KILL"] = function(con, source, args, original) - if args[1]:sub(1,3) ~= "1HC" then - print("Kill remote", original) - userlist[source] = nil - for name, chan in pairs(chanlist) do - chan["users"][source] = nil - if next(chan["users"]) == nil and not chan["modes"]["P"] then - chanlist[name] = nil - end - end - else - print("Kill local", original) - local user = userlist[args[1]] - if type(user) == "table" then - con:send("UID "..args[1].." "..user.nick_ts.." "..user.nick.." "..user.hostname.." "..user.vhost.." "..user.ident.." "..user.ip.." "..user.user_ts.." "..mode_to_string(user.modes).." :"..user.realname.."\n") - - -- temporary before I handle channels - for channel, _ in pairs(config.channels) do - con:send(":"..args[1].." JOIN "..channel.."\n") - con:send("MODE "..channel.." +o "..args[1].."\n") - end - end - end - end, - - ["KICK"] = function(con, soure, args, original) - if args[2]:sub(1,3) == "1HC" then - con:send(":"..args[2].." JOIN "..args[1].."\n") - con:send("MODE "..args[1].." +o "..args[2].."\n") - else - print("Channels not yet handled: "..("%q"):format(original)) - end - end, - ---[[ ["FJOIN"] = function(con, source, args, original) - - end]] -} diff --git a/rerun.sh b/rerun.sh new file mode 100755 index 0000000..ebbad1d --- /dev/null +++ b/rerun.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +{ + start=`date -u +%s` + ./CoupServ.py + uptime=$((`date -u +%s` - $start)) + if (($uptime < 10)); then + sleep $((10 - $uptime)) + fi + + exec "$0" "$@" +} diff --git a/stdin.lua b/stdin.lua deleted file mode 100644 index 4b69590..0000000 --- a/stdin.lua +++ /dev/null @@ -1,132 +0,0 @@ ---[[ - -Network protocol file for HaxServ. - -Written by: Test_User - -This is free and unencumbered software released into the public -domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. -]] - -stdin_commands = { - [":"] = function(con, msg, args) - con:send(msg:sub(3).."\n") - end, - - ["RELOAD"] = function(con, msg, args) - if #args == 0 then - config_file:seek("set", 0) - local success, value_or_err = pcall(json.decode, config_file:read("*a")) - if success then - config = value_or_err - print("Successfully reloaded config.json") - else - print("Unable to reload config.json") - print(value_or_err) - end - - for file, _ in pairs(config.files) do - local success, err = pcall(dofile, path..file) - if success then - print("Successfully reloaded "..file) - else - print("Unable to reload "..file) - print(err) - end - end - else - local file = args[1]..".lua" - if config.files[file] then - local success, err = pcall(dofile, path..file) - if success then - print("Successfully reloaded "..file) - else - print("Unable to reload "..file) - print(err) - end - elseif args[1] == "config" then - config_file:seek("set", 0) - local success, value_or_err = pcall(json.decode, config_file:read("*a")) - if success then - config = value_or_err - print("Successfully reloaded config.json") - else - print("Unable to reload config.json") - print(value_or_err) - end - else - print("Invalid section.") - end - end - end, - - ["ALLOW"] = function(con, msg, args) - if #args == 0 then - print("Not enough args.") - else - for id, tbl in pairs(userlist) do - if tbl.nick == args[1] then - userlist[id].opertype = "Admin" - print(args[1].." is now considered an oper.") - return - end - end - print("Nick not found.") - end - end, - - ["DENY"] = function(con, msg, args) - if #args == 0 then - print("Not enough args.") - else - for id, tbl in pairs(userlist) do - if tbl.nick == args[1] then - userlist[id].opertype = nil - con:send(":1HC000000 MODE "..id.." -o\n") - print(args[1].." is no longer an oper.") - return - end - end - print("Nick not found.") - end - end, - - ["ADDSH"] = function(con, msg, args) - if msg:find(" ") == nil then - print("Not enough args.") - else - local i = msg:find(" ") - bash_command = msg:sub(i + 1) -- yes, global - print(bash_command) - end - end, - - ["SET_CHANNEL"] = function(con, msg, args) - cur_channel = args[1] - end, - - ["M"] = function(con, msg, args) - con:send(":1HC000000 PRIVMSG "..cur_channel.." :"..table.concat(args, " ").."\n") - end, -} -- cgit v1.2.3