summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTest_User <hax@andrewyu.org>2022-03-31 11:19:15 -0400
committerTest_User <hax@andrewyu.org>2022-03-31 11:19:15 -0400
commit530882d32cb328f6a59d891198ae8ee509bc82af (patch)
tree1113b730e9b3686107f503540d7b75e9089e1ac3
downloadcoupserv-530882d32cb328f6a59d891198ae8ee509bc82af.tar.gz
coupserv-530882d32cb328f6a59d891198ae8ee509bc82af.zip
e
-rw-r--r--.gitignore1
-rwxr-xr-xCoupServ.py285
2 files changed, 286 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..43b648d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+CoupServConfig.json
diff --git a/CoupServ.py b/CoupServ.py
new file mode 100755
index 0000000..0bfbb87
--- /dev/null
+++ b/CoupServ.py
@@ -0,0 +1,285 @@
+#!/usr/bin/env python3
+
+import threading
+import socket
+import json
+import math
+import time
+import ssl
+import sys
+import os
+
+def send(msg):
+ return s.sendall(msg.encode("UTF-8", "surrogateescape"))
+
+def recv():
+ return s.recv(1024).decode("UTF-8", "surrogateescape")
+
+def save():
+ with open("CoupServTmp.json", "w") as config_file:
+ json.dump(config, config_file, indent='\t', sort_keys=True)
+ os.replace("CoupServTmp.json", "CoupServConfig.json")
+
+try:
+ with open("CoupServConfig.json") as config_file:
+ config = json.load(config_file)
+except FileNotFoundError:
+ print("No config found! Please make one then try again")
+ exit()
+
+s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+
+s.connect(("irc.andrewyu.org", 6666))
+
+send("PASS "+config['send_password']+" TS 6 1HC\r\nCAPAB BAN CHW CLUSTER ECHO ENCAP EOPMOD EUID EX IE KLN KNOCK MLOCK QS RSFNC SAVE SERVICES TB UNKLN\r\nSERVER coup.irc.andrewyu.org 0 :Coup Server\r\nSVINFO 6 6 0 :"+str(math.floor(time.time()))+"\r\n")
+
+msg = ""
+
+connected_server = ""
+
+servlist = {}
+userlist = {}
+chanlist = {}
+
+def read_and_send():
+ for line in sys.stdin:
+ try:
+ send(line)
+ except Exception:
+ pass
+
+threading.Thread(target=read_and_send, daemon=True).start()
+
+try:
+ while True:
+ newmsg = recv()
+ if newmsg == "":
+ break
+ msg += newmsg
+ split_msg = msg.split("\r\n")
+ if len(split_msg) < 2:
+ continue
+ commands = split_msg[0:-1]
+ msg = split_msg[-1]
+ for command in commands:
+ print(command)
+
+ source = ""
+ if command.startswith(":"):
+ source = command.split(" ")[0][1:]
+ command = " ".join(command.split(" ")[1:])
+
+ lastarg = " :".join(command.split(" :")[1:])
+ args = command.split(" :")[0].split(" ")[1:]
+ args.append(lastarg)
+ command = command.split(" :")[0].split(" ")[0]
+
+ if command.upper() == "PING":
+ try:
+ send(args[1]+" PONG "+args[0]+"\r\n")
+ except IndexError:
+ send(":1HC PONG "+args[0]+"\r\n")
+ elif command.upper() == "PASS":
+ if source != "":
+ print("Received PASS from another source!")
+ continue
+ if connected_server != "":
+ print("Received PASS from the server more than once!")
+ continue
+ if args[0] != config['accept_password']:
+ print("Invalid password given by the server!")
+ exit()
+ connected_server = args[3]
+ elif command.upper() == "SERVER":
+ if source != "":
+ print("Received SERVER from another source!")
+ continue
+ if connected_server == "":
+ print("Server sent SERVER before PASS!")
+ exit()
+ servlist[connected_server] = {"server name": args[0], "hopcount": args[1], "server description": args[2]}
+
+ send("EUID "+config["nick"]+" 0 "+str(math.floor(time.time()))+" +SZio CoupServ hax/CoupServ 127.0.0.1 1HC000001 localhost * :CoupServ\r\n:1HC000001 OPER "+config["nick"]+" admin\r\n")
+ send("EUID SpamServ 0 "+str(math.floor(time.time()))+" +Zi SpamServ hax/SpamServ 0.0.0.0 1HC000002 0.0.0.0 * :SpamServ\r\n")
+ for channel in config["channels"]:
+ send(":1HC000001 JOIN "+str(math.floor(time.time()))+" "+channel+" +\r\n:1HC MODE "+channel+" +ov 1HC000001 1HC000001\r\n")
+ elif command.upper() == "SID":
+ servlist[args[2]] = {"server name": args[0], "hopcount": args[1], "server description": args[3]}
+ elif command.upper() == "EUID":
+ userlist[args[7]] = {"nickname": args[0], "hopcount": args[1], "nickTS": args[2], "umodes": args[3], "username": args[4], "visible hostname": args[5], "IP address": args[6], "real hostname": args[8], "account name": args[9], "gecos": args[10]}
+ elif command.upper() == "SJOIN":
+ chanlist[args[1]] = {"channelTS": args[0], "simple modes": args[2], "mode params": args[3:-1], "nicklist": {}}
+ for uid in args[-1].split(" "):
+ mode = {"@": False, "+": False}
+ if uid.startswith("@"):
+ mode["@"] = True
+ uid = uid[1:]
+ if uid.startswith("+"):
+ mode["+"] = True
+ uid = uid[1:]
+ chanlist[args[1]]["nicklist"][uid] = mode
+ elif command.upper() == "NICK":
+ if len(source) == 9:
+ userlist[source]["nickname"] = args[0]
+ userlist[source]["nickTS"] = args[1]
+ elif command.upper() == "QUIT":
+ try:
+ del userlist[source]
+ except KeyError:
+ continue
+ for channel in chanlist:
+ try:
+ del chanlist[channel]["nicklist"][source]
+ except KeyError:
+ pass
+ elif command.upper() == "KILL":
+ try:
+ del userlist[args[0]]
+ except KeyError:
+ continue
+ for channel in chanlist:
+ try:
+ del chanlist[channel]["nicklist"][args[0]]
+ except KeyError:
+ pass
+ elif command.upper() == "TMODE":
+ if int(args[0]) <= int(chanlist[args[1]]["channelTS"]):
+ modechanges = []
+
+ dir = "-"
+ for i in range(0, len(args[2])):
+ if args[2][i] == "+":
+ dir = "+"
+ elif args[2][i] == "-":
+ dir = "-"
+ elif args[2][i] == 'o':
+ if args[3] == "1HC000001" and dir == "-":
+ modechanges.append(["+", "o", args[3]])
+ try:
+ chanlist[args[1]]["nicklist"][args[3]]['@'] = (dir == "+")
+ except KeyError:
+ pass
+ del args[3]
+ elif args[2][i] == 'v':
+ if args[3] == "1HC000001" and dir == "-":
+ modechanges.append(["+", "v", args[3]])
+ try:
+ chanlist[args[1]]["nicklist"][args[3]]['+'] = (dir == "+")
+ except KeyError:
+ pass
+ del args[3]
+ elif args[2][i] in ['e', 'I', 'b', 'q', 'k', 'f', 'l', 'j']:
+ del args[3]
+
+ while len(modechanges) > 0:
+ modechange = [" "]
+ dir = ""
+ for change in modechanges[:4]:
+ if change[0] != dir:
+ modechange[0]+=change[0]
+ dir = change[0]
+ modechange[0]+=change[1]
+ modechange.append(change[2])
+ send(":1HC000001 MODE "+args[1]+" ".join(modechange)+"\r\n")
+ modechanges = modechanges[4:]
+ elif command.upper() == "JOIN":
+ if len(args) == 1:
+ if args[0] == '0':
+ for channel in chanlist:
+ try:
+ del chanlist[channel]["nicklist"][source]
+ except KeyError:
+ pass
+ else:
+ chanlist[args[1]]["nicklist"][source] = {'@': False, '+': False}
+ elif command.upper() == "PRIVMSG":
+ if [userlist[source]["username"], userlist[source]["IP address"]] in config["trusted_IDs"]:
+ if args[0] == "1HC000001" or (args[0].startswith("#") and args[1].startswith("-")):
+ if args[0] != "1HC000001":
+ args[1] = args[1][1:]
+
+ if args[1] == "print userlist":
+ print(userlist)
+ elif args[1] == "print chanlist":
+ print(chanlist)
+ elif args[1] == "print servlist":
+ print(servlist)
+ elif args[1].startswith("join "):
+ chan = args[1].split(" ")[1]
+ if chan not in config["channels"]:
+ config["channels"].append(chan)
+ print("New channel list", config["channels"])
+ save()
+ send(":1HC000001 JOIN "+str(math.floor(time.time()))+" "+chan+" +\r\n")
+ elif args[1].startswith("part "):
+ chan = args[1].split(" ")[1]
+ if chan in config["channels"]:
+ config["channels"] = [c for c in config["channels"] if c != chan]
+ save()
+ send(":1HC000001 PART "+chan+"\r\n")
+ elif args[1].startswith("sanick "):
+ current = args[1].split(" ")[1]
+ target = args[1].split(" ")[2]
+ for id in userlist:
+ if userlist[id]["nickname"] == current:
+ current = id
+ break
+ try:
+ send(":1HC ENCAP * RSFNC "+current+" "+target+" "+str(math.floor(time.time()))+" :"+userlist[current]["nickTS"]+"\r\n")
+ except KeyError:
+ continue
+ elif args[1].startswith("coup "):
+ chan = args[1].split(" ")[1]
+ modechanges = []
+ for user in chanlist[chan]["nicklist"]:
+ if [userlist[user]["username"], userlist[user]["IP address"]] in config["trusted_IDs"]:
+ if not chanlist[chan]["nicklist"][user]["@"]:
+ chanlist[chan]["nicklist"][user]["@"] = True
+ modechanges.append(["+", "o", user])
+ else:
+ if chanlist[chan]["nicklist"][user]["@"]:
+ chanlist[chan]["nicklist"][user]["@"] = False
+ modechanges.append(["-", "o", user])
+
+ while len(modechanges) > 0:
+ modechange = [" "]
+ dir = ""
+ for change in modechanges[:4]:
+ if change[0] != dir:
+ modechange[0]+=change[0]
+ dir = change[0]
+ modechange[0]+=change[1]
+ modechange.append(change[2])
+ send(":1HC000001 MODE "+chan+" ".join(modechange)+"\r\n")
+ modechanges = modechanges[4:]
+ elif args[1].startswith("spam "):
+ chan = args[1].split(" ")[1]
+ count = int(args[1].split(" ")[2])
+ msg = " ".join(args[1].split(" ")[3:])
+ send(":1HC000002 JOIN "+str(math.floor(time.time()))+" "+chan+" +\r\n")
+ for _ in range(count):
+ send(":1HC000002 PRIVMSG "+chan+" :"+msg+"\r\n")
+ send(":1HC000002 PART "+chan+"\r\n")
+ elif args[1].startswith("userspam "):
+ count = args[1].split(" ")[1]
+ for i in range(3, max(0, min(int(count), 1000))+3):
+ send("EUID 1HC"+str(i).zfill(6)+" 0 "+str(math.floor(time.time()))+" +Zi "+str(i)+" hax/SpamServ 0.0.0.0 1HC"+str(i).zfill(6)+" 0.0.0.0 * :SpamServ\r\n:1HC"+str(i).zfill(6)+" JOIN "+str(math.floor(time.time()))+" #spam +\r\n")
+ elif args[1].startswith("nick "):
+ nick = args[1].split(" ")[1]
+ config["nick"] = nick
+ save()
+ send(":1HC000001 NICK "+nick+" "+str(math.floor(time.time()))+"\r\n")
+ elif args[1].startswith("mode "):
+ send(args[1]+"\r\n")
+ elif args[1].startswith("echo "):
+ if args[0] == "1HC000001":
+ dest = source
+ else:
+ dest = args[0]
+ send(":1HC000001 PRIVMSG "+dest+" :"+" ".join(args[1].split(" ")[1:])+"\r\n")
+
+ elif args[1].startswith(":"):
+ send(args[1]+"\r\n")
+except Exception as e:
+ config_file.close()
+ raise e