From 47b5b1a6f252bdc407e7fa8d37b5bf43786bd972 Mon Sep 17 00:00:00 2001 From: Fierelier Date: Thu, 28 Oct 2021 08:17:07 +0200 Subject: [PATCH] Oop --- .gitignore | 2 +- modules/account.py | 69 ++++++++++++++++++++++++++++ modules/db.py | 97 +++++++++++++++++++++++++++++++++++++++ modules/filelock.py | 2 + modules/history.py | 59 ++++++++++++++++++++++++ modules/messageid.py | 7 +++ modules/nop.py | 3 ++ modules/req.py | 6 +++ modules/send.py | 28 +++++++++++ modules/servercaps.py | 8 ++++ modules/spamprotection.py | 29 ++++++++++++ 11 files changed, 309 insertions(+), 1 deletion(-) create mode 100644 modules/account.py create mode 100644 modules/db.py create mode 100644 modules/filelock.py create mode 100644 modules/history.py create mode 100644 modules/messageid.py create mode 100644 modules/nop.py create mode 100644 modules/req.py create mode 100644 modules/send.py create mode 100644 modules/servercaps.py create mode 100644 modules/spamprotection.py diff --git a/.gitignore b/.gitignore index fc4289b..9382144 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -/modules/ +/accounts/ server.db \ No newline at end of file diff --git a/modules/account.py b/modules/account.py new file mode 100644 index 0000000..c32abcc --- /dev/null +++ b/modules/account.py @@ -0,0 +1,69 @@ +global configparser +import configparser +global accountPath +accountPath = p(sp,"accounts") +global accountUserChars +accountUserChars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_" +global accountUsernameLengthMin +accountUsernameLengthMin = 2 +global accountUsernameLengthMax +accountUsernameLengthMax = 32 +global accountPasswordLengthMin +accountPasswordLengthMin = 0 +global accountPasswordLengthMax +accountPasswordLengthMax = 128 + +global accountExists +def accountExists(acc): + if os.path.isdir(p(accountPath,acc)): return True + return False + +global accountNameValid +def accountNameValid(name): + for char in name: + if not char in accountUserChars: + return False + return True + +def f(self,cmd,*args): + with fileLock: + if len(args) != 2: + return ["error","nonfatal","syntax","Correct syntax: " +cmd+ ",,"] + + if len(args[0]) < accountUsernameLengthMin or len(args[0]) > accountUsernameLengthMax: + return ["error","nonfatal","invalid_name","Your username has to be between " +str(accountUsernameLengthMin)+ " and " +str(accountUsernameLengthMax)+ " characters long"] + + if len(args[1]) < accountPasswordLengthMin or len(args[1]) > accountPasswordLengthMax: + return ["error","nonfatal","invalid_password","Your password has to be between " +str(accountPasswordLengthMin)+ " and " +str(accountPasswordLengthMax)+ " characters long"] + + if not accountNameValid(args[0]): + return ["error","nonfatal","invalid_name","Your username can only contain the following characters: '" +accountUserChars+ "'"] + + if accountExists(args[0]): + return ["error","nonfatal","user_exists","This user already exists"] + + dbSet(p(accountPath,args[0],"user.db"),"DEFAULT","password",args[1]) +commands["register"] = f + +def f(self,cmd,*args): + with fileLock: + if len(args) != 2: + return ["error","nonfatal","syntax","Correct syntax: " +cmd+ ",,"] + + if not accountNameValid(args[0]): + return ["error","nonfatal","invalid_name","Your username can only contain the following characters: '" +accountUserChars+ "'"] + + passw = dbGet(p(accountPath,args[0],"user.db"),"DEFAULT","password") + + if passw == False: + return ["error","nonfatal","wrong_user_or_password"] + + if passw != args[1]: + return ["error","nonfatal","wrong_user_or_password"] + + with connectionsLock: + if "user" in connections[self.cid]: + return ["error","nonfatal","logged_in","You are already logged in"] + connections[self.cid]["user"] = args[0] + connections[self.cid]["lastMessage"] = "0" +commands["login"] = f \ No newline at end of file diff --git a/modules/db.py b/modules/db.py new file mode 100644 index 0000000..d576a32 --- /dev/null +++ b/modules/db.py @@ -0,0 +1,97 @@ +global json +import json + +global dbGet +def dbGet(dbPath,table,key): + if not os.path.isfile(dbPath): return False + config = [[],[]] + with open(dbPath,"r",encoding="utf-8") as dbFile: + config = json.loads(dbFile.read()) + + tableIndex = -1 + try: + tableIndex = config[0].index(table) + except: + return False + + keyIndex = -1 + try: + keyIndex = config[1][tableIndex][0].index(key) + except: + return False + + return config[1][tableIndex][1][keyIndex] + +global dbGetTable +def dbGetTable(dbPath,table): + if not os.path.isfile(dbPath): return False + config = [[],[]] + with open(dbPath,"r",encoding="utf-8") as dbFile: + config = json.loads(dbFile.read()) + + tableIndex = -1 + try: + tableIndex = config[0].index(table) + except: + return False + + return config[1][tableIndex] + +global dbSet +def dbSet(dbPath,table,key,value): + config = [[],[]] + if os.path.isfile(dbPath): + with open(dbPath,"r",encoding="utf-8") as dbFile: + config = json.loads(dbFile.read()) + elif not os.path.isdir(pUp(dbPath)): os.makedirs(pUp(dbPath)) + + tableIndex = -1 + try: + tableIndex = config[0].index(table) + except: + pass + + if tableIndex == -1: + config[0].append(table) + config[1].append([[],[]]) + tableIndex = len(config[0]) - 1 + + keyIndex = -1 + try: + keyIndex = config[1][tableIndex][0].index(key) + except: + pass + + if keyIndex == -1: + config[1][tableIndex][0].append(key) + config[1][tableIndex][1].append("") + keyIndex = len(config[1][tableIndex][0]) - 1 + + config[1][tableIndex][1][keyIndex] = value + + with open(dbPath,"w+",encoding="utf-8") as dbFile: + dbFile.write(json.dumps(config)) + +global dbSetTable +def dbSetTable(dbPath,table,value): + config = [[],[]] + if os.path.isfile(dbPath): + with open(dbPath,"r",encoding="utf-8") as dbFile: + config = json.loads(dbFile.read()) + elif not os.path.isdir(pUp(dbPath)): os.makedirs(pUp(dbPath)) + + tableIndex = -1 + try: + tableIndex = config[0].index(table) + except: + pass + + if tableIndex == -1: + config[0].append(table) + config[1].append([[],[]]) + tableIndex = len(config[0]) - 1 + + config[1][tableIndex] = value + + with open(dbPath,"w+",encoding="utf-8") as dbFile: + dbFile.write(json.dumps(config)) \ No newline at end of file diff --git a/modules/filelock.py b/modules/filelock.py new file mode 100644 index 0000000..1c8000d --- /dev/null +++ b/modules/filelock.py @@ -0,0 +1,2 @@ +global fileLock +fileLock = threading.Lock() \ No newline at end of file diff --git a/modules/history.py b/modules/history.py new file mode 100644 index 0000000..fe26da0 --- /dev/null +++ b/modules/history.py @@ -0,0 +1,59 @@ +global historyMaxMessages +historyMaxMessages = 10000 + +global addToHistory +def addToHistory(user,id,cmd): + if historyMaxMessages == 0: return + messageHistory = dbGetTable(p(accountPath,user,"history.db"),"HISTORY") + if messageHistory == False: messageHistory = [[],[]] + hlength = len(messageHistory[0]) + while hlength >= historyMaxMessages: + del messageHistory[0][0] + del messageHistory[1][0] + hlength -= 1 + break + + messageHistory[0].append(id) + messageHistory[1].append(cmd) + dbSetTable(p(accountPath,user,"history.db"),"HISTORY",messageHistory) + +global getHistoryUntil +def getHistoryUntil(user,id): + messageHistory = dbGetTable(p(accountPath,user,"history.db"),"HISTORY") + if messageHistory == False: messageHistory = [[],[]] + id = int(id) + hlength = len(messageHistory[0]) + index = hlength - 1 + while index > 0: + mId = int(messageHistory[0][index]) + if mId < id: break + yield messageHistory[1][index] + index -= 1 + +def f(self,cmd,*args): + if len(args) != 1: + return ["error","nonfatal","syntax","Correct syntax: " +cmd+ ","] + + fetchTill = 0 + try: + fetchTill = int(args[0]) + except: + return ["error","nonfatal","syntax","The message ID has to be an integer"] + + with connectionsLock: + with fileLock: + user = connections[self.cid]["user"] + lastMessage = 0 + if "lastMessage" in connections[self.cid]: + lastMessage = int(connections[self.cid]["lastMessage"]) + if lastMessage < fetchTill: + connections[self.cid]["lastMessage"] = str(fetchTill) + + msgList = [] + for msg in getHistoryUntil(user,fetchTill): + msgList.append(commandlineToList(msg)) + + msgList.reverse() + for msg in msgList: + connections[self.cid]["threadOut"].queue.put(listToCommandline("history" + msg)) +commands["getHistory"] = f \ No newline at end of file diff --git a/modules/messageid.py b/modules/messageid.py new file mode 100644 index 0000000..5883698 --- /dev/null +++ b/modules/messageid.py @@ -0,0 +1,7 @@ +global getMessageId +def getMessageId(): + messageId = dbGet(p(sp,"server.db"),"MESSAGES","messageId") + if messageId == False: messageId = "-1" + messageId = str(int(messageId) + 1) + dbSet(p(sp,"server.db"),"MESSAGES","messageId",messageId) + return messageId \ No newline at end of file diff --git a/modules/nop.py b/modules/nop.py new file mode 100644 index 0000000..9022715 --- /dev/null +++ b/modules/nop.py @@ -0,0 +1,3 @@ +def f(self,cmd,*args): + return [""] +commands["nop"] = f \ No newline at end of file diff --git a/modules/req.py b/modules/req.py new file mode 100644 index 0000000..948fc0a --- /dev/null +++ b/modules/req.py @@ -0,0 +1,6 @@ +def f(self,cmd,*args): + if len(args) < 2: + return ["error","nonfatal","syntax","Correct syntax: " +cmd+ ",,,[arg 1],[arg 2],[...]"] + + return ["req",args[0]] + runCommand(self,*args[1:]) +commands["req"] = f \ No newline at end of file diff --git a/modules/send.py b/modules/send.py new file mode 100644 index 0000000..216bf3d --- /dev/null +++ b/modules/send.py @@ -0,0 +1,28 @@ +def f(self,cmd,*args): + if len(args) < 2: + return ["error","nonfatal","syntax","Correct syntax: " +cmd+ ",,,[arg 1],[arg 2],[...]"] + + with connectionsLock: + with fileLock: + if not accountExists(args[0]): + return ["error","nonfatal","wrong_user_or_password"] + + user = connections[self.cid]["user"] + + if dbGet(p(accountPath,args[0],"user.db"),"SETTINGS","friendsOnly") == "1": + if not areMutualFriends(args[0],user): + return ["error","nonfatal","permission_denied","This user only accepts messages from friends"] + + messageId = getMessageId() + msg = ["send",user,args[0],messageId] + list(args[1:]) + msgCommandline = listToCommandline(msg) + addToHistory(user,messageId,msgCommandline) + addToHistory(args[0],messageId,msgCommandline) + + for cid in connections: + if not "user" in connections[cid]: continue + if connections[cid]["user"] != args[0]: continue + if not "acceptingMessages" in connections[cid]: continue + connections[cid]["threadOut"].queue.put(msgCommandline) + +commands["send"] = f \ No newline at end of file diff --git a/modules/servercaps.py b/modules/servercaps.py new file mode 100644 index 0000000..62cab41 --- /dev/null +++ b/modules/servercaps.py @@ -0,0 +1,8 @@ +global serverCaps +serverCaps = [] +serverCaps.append("maxRequestSize:" +str(maxRequestSize)) +serverCaps.append("heartbeatTime:" +str(heartbeatTime)) + +def f(self,cmd,*args): + return ["serverCaps"] + serverCaps +commands["serverCaps"] = f \ No newline at end of file diff --git a/modules/spamprotection.py b/modules/spamprotection.py new file mode 100644 index 0000000..931fbc4 --- /dev/null +++ b/modules/spamprotection.py @@ -0,0 +1,29 @@ +global time +import time +global spMult +spMult = 10 +global spMinSleep +spMinSleep = 0.1 +global spMaxSleep +spMaxSleep = 5 + +def f(env): + with connectionsLock: + connections[env["self"].cid]["spCmdStart"] = time.perf_counter() +handlers["preCommand"].append(f) + +def f(env): + passedTime = 0 + with connectionsLock: + if "spCmdStart" in connections[env["self"].cid]: + passedTime = time.perf_counter() - connections[env["self"].cid]["spCmdStart"] + if passedTime < 0: passedTime = 0 + else: + return + + sleepTime = passedTime*spMult + if sleepTime > spMaxSleep: sleepTime = spMaxSleep + if sleepTime < spMinSleep: sleepTime = spMinSleep + print("sleeping for: " +str(sleepTime)) + time.sleep(sleepTime) +handlers["command"].append(f) \ No newline at end of file