summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTest_User <hax@andrewyu.org>2024-06-17 19:17:55 -0400
committerTest_User <hax@andrewyu.org>2024-06-17 19:17:55 -0400
commitb1627de0341fde3f8e736cdc809d3297f9ff0cbe (patch)
tree895e572414be7c4c77c669e570507767d69461af
parentc3c84a3c6aa633d0833f74d6ce1c99397a7fa8e2 (diff)
downloadpy_coupserv-b1627de0341fde3f8e736cdc809d3297f9ff0cbe.tar.gz
py_coupserv-b1627de0341fde3f8e736cdc809d3297f9ff0cbe.zip
Python Coupserv improvements/lua seperation
-rwxr-xr-xCoupServ.lua200
-rwxr-xr-xCoupServ.py67
-rw-r--r--commands.lua359
-rw-r--r--network.lua310
-rwxr-xr-xrerun.sh11
-rw-r--r--stdin.lua132
6 files changed, 50 insertions, 1029 deletions
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 <hax@andrewyu.org>
-
-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 <hax@andrewyu.org>
-
-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 = "<target> <new nick>",
- },
-
- ["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 = "[<section>]",
- },
-
- ["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 = "<raw IRC message>",
- },
-
- ["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 = "<target> <count> <message>",
- },
-
- ["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 = "[<target>]",
- },
-
- ["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 = "[<nick>]",
- },
-
- ["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 = "<list>",
- },
-
- ["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 = "[<UID>]",
- },
-
- ["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 = "[<UID>]",
- },
-
- ["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 = "<server>",
- },
-
- ["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 = "<user>",
- },
-
- ["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 = "<user>",
- },
-
- ["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 = "<command>",
- },
-
- ["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 <hax@andrewyu.org>
-
-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 <hax@andrewyu.org>
-
-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,
-}