This commit is contained in:
Fierelier 2021-10-28 08:17:07 +02:00
parent fb26b7ac72
commit 47b5b1a6f2
11 changed files with 309 additions and 1 deletions

2
.gitignore vendored
View File

@ -1,2 +1,2 @@
/modules/
/accounts/
server.db

69
modules/account.py Normal file
View File

@ -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+ ",<username>,<password>"]
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+ ",<username>,<password>"]
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

97
modules/db.py Normal file
View File

@ -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))

2
modules/filelock.py Normal file
View File

@ -0,0 +1,2 @@
global fileLock
fileLock = threading.Lock()

59
modules/history.py Normal file
View File

@ -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+ ",<message id>"]
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

7
modules/messageid.py Normal file
View File

@ -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

3
modules/nop.py Normal file
View File

@ -0,0 +1,3 @@
def f(self,cmd,*args):
return [""]
commands["nop"] = f

6
modules/req.py Normal file
View File

@ -0,0 +1,6 @@
def f(self,cmd,*args):
if len(args) < 2:
return ["error","nonfatal","syntax","Correct syntax: " +cmd+ ",<id>,<command>,[arg 1],[arg 2],[...]"]
return ["req",args[0]] + runCommand(self,*args[1:])
commands["req"] = f

28
modules/send.py Normal file
View File

@ -0,0 +1,28 @@
def f(self,cmd,*args):
if len(args) < 2:
return ["error","nonfatal","syntax","Correct syntax: " +cmd+ ",<username>,<command>,[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

8
modules/servercaps.py Normal file
View File

@ -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

29
modules/spamprotection.py Normal file
View File

@ -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)