Compare commits
2 Commits
46a32f2255
...
d8f4ccc893
Author | SHA1 | Date |
---|---|---|
Fierelier | d8f4ccc893 | |
Fierelier | 4cea08c314 |
125
clientBlaster.py
125
clientBlaster.py
|
@ -44,11 +44,99 @@ heartbeatTime = 600
|
|||
threadCount = 0
|
||||
threadCountLock = threading.Lock()
|
||||
|
||||
commands = {}
|
||||
|
||||
def commandlineToList(cmd):
|
||||
args = []
|
||||
cArg = ""
|
||||
escape = False
|
||||
quoted = False
|
||||
for letter in cmd:
|
||||
if escape == True:
|
||||
cArg += letter
|
||||
escape = False
|
||||
continue
|
||||
|
||||
if letter == "\\":
|
||||
escape = True
|
||||
continue
|
||||
|
||||
#if quoted == False and letter == ",":
|
||||
if letter == ",":
|
||||
if cArg == "": continue
|
||||
args.append(cArg)
|
||||
cArg = ""
|
||||
continue
|
||||
|
||||
#if letter == '"':
|
||||
# quoted = not quoted
|
||||
# continue
|
||||
|
||||
cArg += letter
|
||||
|
||||
args.append(cArg)
|
||||
|
||||
return args
|
||||
|
||||
def listToCommandline(lst):
|
||||
cmd = ""
|
||||
for arg in lst:
|
||||
arg = arg.replace("\\","\\\\")
|
||||
arg = arg.replace(",","\\,")
|
||||
#arg = arg.replace('"','\\"')
|
||||
#if " " in arg: arg = '"' +arg+ '"'
|
||||
cmd += arg + ","
|
||||
|
||||
return cmd[:-1]
|
||||
|
||||
printLock = threading.Lock()
|
||||
def tprint(st):
|
||||
with printLock:
|
||||
print(st)
|
||||
|
||||
def runCode(str, lcs = False, description = "loose-code"):
|
||||
if lcs == False: lcs = {}
|
||||
code = compile(str,description,"exec")
|
||||
exec(code,globals(),lcs)
|
||||
return lcs
|
||||
|
||||
def runScript(sf, lcs = False):
|
||||
if lcs == False: lcs = {}
|
||||
with open(sf) as script:
|
||||
runCode(script.read(),lcs,sf)
|
||||
return lcs
|
||||
|
||||
def getModlist(path):
|
||||
modList = []
|
||||
for root,dirs,files in os.walk(path):
|
||||
for file in dirs:
|
||||
ffile = p(root,file)
|
||||
lfile = ffile.replace(path + os.path.sep,"",1)
|
||||
if lfile[0] == "-": continue
|
||||
if lfile[0] == "[" and lfile[-1] == "]":
|
||||
modList = modList + sorted(getModlist(ffile))
|
||||
continue
|
||||
|
||||
modList.append(ffile)
|
||||
break
|
||||
|
||||
return modList
|
||||
|
||||
modulesLoaded = []
|
||||
modulePath = p(sp,"modules")
|
||||
def moduleRun(localModule):
|
||||
if not localModule in modulesLoaded: modulesLoaded.append(localModule)
|
||||
print("> " +localModule+ "...")
|
||||
runScript(p(modulePath,localModule,"module.py"))
|
||||
|
||||
def moduleDepends(localModules):
|
||||
if type(localModules) == str: localModules = [localModules]
|
||||
|
||||
for localModule in localModules:
|
||||
if localModule in modulesLoaded: return
|
||||
print("depend ",end="")
|
||||
moduleRun(localModule)
|
||||
|
||||
def addThread():
|
||||
global threadCount
|
||||
with threadCountLock:
|
||||
|
@ -62,12 +150,15 @@ def removeThread():
|
|||
tprint(colorama.Fore.YELLOW + colorama.Style.BRIGHT + "Thread closed. Threads: " +str(threadCount)+ " (Actual: " +str(threading.active_count())+ ")" + colorama.Style.RESET_ALL)
|
||||
|
||||
def sendResponse(connection,data):
|
||||
connection.sendall(len(data).to_bytes(4,"big") + data)
|
||||
connection.sendall(len(data).to_bytes(4,"big") + b"\x00" + data)
|
||||
|
||||
def getResponse(connection):
|
||||
data = b''
|
||||
data = connection.recv(4)
|
||||
if not data: return False
|
||||
nul = connection.recv(1)
|
||||
if not nul: return False
|
||||
if nul != b"\x00": return False
|
||||
requestLength = int.from_bytes(data,"big")
|
||||
if requestLength > maxRequestSize: raise Exception("security","request_too_large")
|
||||
return connection.recv(requestLength)
|
||||
|
@ -135,6 +226,15 @@ class connectionThreadIn(threading.Thread):
|
|||
return connections[self.connectionId]["connection"]
|
||||
return False
|
||||
|
||||
def runCommand(self,cmd):
|
||||
command = False
|
||||
if not cmd[0] in commands:
|
||||
return ["error","nonfatal","command_not_found"]
|
||||
command = commands[cmd[0]]
|
||||
rtn = command["function"](self,cmd)
|
||||
time.sleep(pauseBetweenCommands)
|
||||
return rtn
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
while True:
|
||||
|
@ -148,14 +248,16 @@ class connectionThreadIn(threading.Thread):
|
|||
with connectionsLock: closeConnection(self.connectionId)
|
||||
return
|
||||
|
||||
queue = False
|
||||
with connectionsLock:
|
||||
if self.connectionId in connections:
|
||||
queue = connections[self.connectionId]["threadOut"].queue
|
||||
if queue.qsize() >= maxQueueSize:
|
||||
closeConnection(self.connectionId)
|
||||
return
|
||||
queue.put(data)
|
||||
time.sleep(pauseBetweenCommands)
|
||||
queue = connections[self.connectionId]["threadOut"].queue
|
||||
if queue.qsize() >= maxQueueSize:
|
||||
closeConnection(self.connectionId)
|
||||
return
|
||||
|
||||
dataString = data.decode(encoding="utf-8")
|
||||
commandList = commandlineToList(dataString)
|
||||
queue.put(listToCommandline(self.runCommand(commandList)).encode(encoding="utf-8"))
|
||||
except Exception as e:
|
||||
with connectionsLock: closeConnection(self.connectionId)
|
||||
with printLock:
|
||||
|
@ -166,6 +268,13 @@ class connectionThreadIn(threading.Thread):
|
|||
removeThread()
|
||||
|
||||
def main():
|
||||
print("Loading modules...")
|
||||
for path in getModlist(modulePath):
|
||||
if os.path.isfile(p(path,"module.py")):
|
||||
localModule = path.replace(modulePath + os.path.sep,"",1)
|
||||
if not localModule in modulesLoaded:
|
||||
moduleRun(localModule)
|
||||
|
||||
global connectionsId
|
||||
serverSocket.bind(serverAddr)
|
||||
serverSocket.listen(65535)
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
global textPreRequest
|
||||
def textPreRequest(event,self,requestLength):
|
||||
if requestLength <= 128: return
|
||||
sendResponse(self.connection,"error: too long".encode("utf-8"))
|
||||
self.closeThread()
|
||||
return True
|
||||
addEventHandler("onPreRequest",textPreRequest)
|
||||
|
||||
global textRequest
|
||||
def textRequest(event,self,requestLength):
|
||||
data = self.connection.recv(requestLength)
|
||||
sendResponse(self.connection,data)
|
||||
text = data.decode("utf-8")
|
||||
print(":".join(map(str,self.address))+ " > " +text)
|
||||
if text == "exit":
|
||||
with threadsLock:
|
||||
global close
|
||||
close = True
|
||||
|
||||
self.closeThread()
|
||||
return True
|
||||
addEventHandler("onRequest",textRequest)
|
|
@ -1,69 +0,0 @@
|
|||
global textCommands
|
||||
textCommands = {}
|
||||
global textCommandsLock
|
||||
textCommandsLock = threading.Lock()
|
||||
|
||||
global textCommandRun
|
||||
def textCommandRun(self,args):
|
||||
with textCommandsLock:
|
||||
commands = textCommands.copy()
|
||||
|
||||
if not args[0] in commands:
|
||||
return ["error","nonfatal","command_not_found"]
|
||||
|
||||
return commands[args[0]](self,args[0],args[1:])
|
||||
|
||||
global textCommandAddHandler
|
||||
def textCommandAddHandler(command,function):
|
||||
with textCommandsLock:
|
||||
textCommands[command] = function
|
||||
|
||||
global textCommandToList
|
||||
def textCommandToList(cmd):
|
||||
args = []
|
||||
cArg = ""
|
||||
escape = False
|
||||
quoted = False
|
||||
for letter in cmd:
|
||||
if escape == True:
|
||||
cArg += letter
|
||||
escape = False
|
||||
continue
|
||||
|
||||
if letter == "\\":
|
||||
escape = True
|
||||
continue
|
||||
|
||||
#if quoted == False and letter == ",":
|
||||
if letter == ",":
|
||||
if cArg == "": continue
|
||||
args.append(cArg)
|
||||
cArg = ""
|
||||
continue
|
||||
|
||||
#if letter == '"':
|
||||
# quoted = not quoted
|
||||
# continue
|
||||
|
||||
cArg += letter
|
||||
|
||||
args.append(cArg)
|
||||
|
||||
return args
|
||||
|
||||
global textListToCommand
|
||||
def textListToCommand(lst):
|
||||
cmd = ""
|
||||
for arg in lst:
|
||||
arg = arg.replace("\\","\\\\")
|
||||
arg = arg.replace(",","\\,")
|
||||
#arg = arg.replace('"','\\"')
|
||||
#if " " in arg: arg = '"' +arg+ '"'
|
||||
cmd += arg + ","
|
||||
|
||||
return cmd[:-1]
|
||||
|
||||
global textNop
|
||||
def textNop(self,command,args):
|
||||
return [""]
|
||||
textCommandAddHandler("nop",textNop)
|
|
@ -1,29 +0,0 @@
|
|||
moduleDepends([
|
||||
p("[text server]","[api]","commands"),
|
||||
])
|
||||
|
||||
global textSend
|
||||
def textSend(self,command,args):
|
||||
if len(args) < 2:
|
||||
return ["error","nonfatal","syntax","Correct syntax: " +command+ ",<user>,<command>,[argument 1],[argument 2],..."]
|
||||
|
||||
user = args[0].lower()
|
||||
if len(user) < 1:
|
||||
return ["error","nonfatal","name_too_short","Needs to be at least 1 character in length."]
|
||||
|
||||
me = ""
|
||||
with self.lock:
|
||||
me = self.user
|
||||
|
||||
if not me:
|
||||
return ["error","nonfatal","not_logged_in"]
|
||||
|
||||
with threadsLock:
|
||||
for threadId in threads:
|
||||
thread = threads[threadId]
|
||||
with thread.lock:
|
||||
if thread.user != user: continue
|
||||
thread.sendResponse(textListToCommand(["send",me] + args[1:]).encode("utf-8"),lock = False)
|
||||
|
||||
return ["ok"]
|
||||
textCommandAddHandler("send",textSend)
|
|
@ -1,5 +0,0 @@
|
|||
moduleDepends(p("[text server]","[api]","utils"))
|
||||
|
||||
global textBaseFolder
|
||||
textBaseFolder = p(sp,"textServer")
|
||||
textQuickFolder(textBaseFolder)
|
|
@ -1,10 +0,0 @@
|
|||
moduleDepends(p("[text server]","[api]","commands"))
|
||||
|
||||
global textRequest
|
||||
def textRequest(self,command,args):
|
||||
if len(args) < 2:
|
||||
return ["error","nonfatal","syntax","Correct syntax: " +command+ ",<id>,<command>,[arg1],[arg2],..."]
|
||||
|
||||
response = [command,args[0]] + textCommandRun(self,args[1:])
|
||||
return response
|
||||
textCommandAddHandler("req",textRequest)
|
|
@ -1,2 +0,0 @@
|
|||
global fileLock
|
||||
fileLock = threading.Lock()
|
|
@ -1,87 +0,0 @@
|
|||
moduleDepends([
|
||||
p("[text server]","[api]","commands"),
|
||||
p("[text server]","[api]","threadedFiles")
|
||||
])
|
||||
|
||||
global textUserFolder
|
||||
textUserFolder = p(textBaseFolder,"users")
|
||||
textQuickFolder(textUserFolder)
|
||||
|
||||
global textUserAllowedCharacters
|
||||
textUserAllowedCharacters = "abcdefghijklmnopqrstuvwxyz0123456789.-_ "
|
||||
|
||||
global textUserGetPath
|
||||
def textUserGetPath(user):
|
||||
return p(textUserFolder,user)
|
||||
|
||||
global textUserRegister
|
||||
def textUserRegister(self,command,args):
|
||||
if len(args) != 2:
|
||||
return ["error","nonfatal","syntax","Correct syntax: " +command+ ",<user>,<password>"]
|
||||
|
||||
user = args[0].lower()
|
||||
if len(user) < 1:
|
||||
return ["error","nonfatal","name_too_short","Needs to be at least 1 character in length."]
|
||||
|
||||
for symbol in user:
|
||||
if not symbol in textUserAllowedCharacters:
|
||||
return ["error","nonfatal","invalid_name","Allowed characters: " +", ".join([char for char in textUserAllowedCharacters])]
|
||||
|
||||
userpath = textUserGetPath(user)
|
||||
|
||||
with fileLock:
|
||||
if os.path.isdir(userpath):
|
||||
return ["error","nonfatal","user_exists"]
|
||||
|
||||
password = args[1]
|
||||
|
||||
os.makedirs(userpath)
|
||||
passFile = open(p(userpath,"pass.txt"),"w")
|
||||
passFile.write(password)
|
||||
passFile.close()
|
||||
return ["ok"]
|
||||
textCommandAddHandler("register",textUserRegister)
|
||||
|
||||
global textUserLogin
|
||||
def textUserLogin(self,command,args):
|
||||
if len(args) != 2:
|
||||
return ["error","nonfatal","syntax","Correct syntax: " +command+ ",<user>,<password>"]
|
||||
|
||||
user = args[0].lower()
|
||||
if len(user) < 1:
|
||||
return ["error","nonfatal","name_too_short","Needs to be at least 1 character in length."]
|
||||
|
||||
for symbol in user:
|
||||
if not symbol in textUserAllowedCharacters:
|
||||
return ["error","nonfatal","invalid_name","Allowed characters: " +", ".join([char for char in textUserAllowedCharacters])]
|
||||
|
||||
userpath = textUserGetPath(user)
|
||||
|
||||
with fileLock:
|
||||
if not os.path.isdir(userpath):
|
||||
return ["error","nonfatal","wrong_user_or_password"]
|
||||
|
||||
password = args[1]
|
||||
|
||||
passFile = open(p(userpath,"pass.txt"),"r")
|
||||
passw = passFile.read()
|
||||
passFile.close()
|
||||
if password != passw:
|
||||
return ["error","nonfatal","wrong_user_or_password"]
|
||||
|
||||
with self.lock:
|
||||
self.user = user
|
||||
|
||||
return ["ok"]
|
||||
textCommandAddHandler("login",textUserLogin)
|
||||
|
||||
global textUserGet
|
||||
def textUserGet(self,command,args):
|
||||
with self.lock:
|
||||
user = self.user
|
||||
|
||||
if not user:
|
||||
return ["error","nonfatal","not_logged_in"]
|
||||
|
||||
return ["user",user]
|
||||
textCommandAddHandler("whoami",textUserGet)
|
|
@ -1,4 +0,0 @@
|
|||
global textQuickFolder
|
||||
def textQuickFolder(path):
|
||||
if not os.path.isdir(path):
|
||||
os.makedirs(path)
|
|
@ -0,0 +1,5 @@
|
|||
global commands
|
||||
commands["nop"] = {}
|
||||
def f(self,cmd):
|
||||
return [""]
|
||||
commands["nop"]["function"] = f
|
|
@ -0,0 +1,9 @@
|
|||
global commands
|
||||
commands["req"] = {}
|
||||
def f(self,cmd):
|
||||
if len(cmd) < 3:
|
||||
return ["error","nonfatal","syntax","need at least 3 arguments"]
|
||||
|
||||
rtn = cmd[:2] + self.runCommand(cmd[2:])
|
||||
return rtn
|
||||
commands["req"]["function"] = f
|
|
@ -1,51 +0,0 @@
|
|||
global textTimeout
|
||||
textTimeout = 30
|
||||
global textKeepAliveTimeout
|
||||
textKeepAliveTimeout = 600 # set to None for infinite time (not recommended)
|
||||
|
||||
global textOnConnect
|
||||
def textOnConnect(event,connection,address):
|
||||
global textKeepAliveTimeout
|
||||
connection.settimeout(textKeepAliveTimeout)
|
||||
addEventHandler("onConnect",textOnConnect)
|
||||
|
||||
global textOnPreRequest
|
||||
def textOnPreRequest(event,self,requestLength):
|
||||
global textTimeout
|
||||
self.connection.settimeout(textTimeout)
|
||||
if requestLength <= 100000: return
|
||||
try:
|
||||
sendResponse(self.connection,textListToCommand(["error","fatal","request_too_long"]).encode("utf-8"))
|
||||
except threading.timeout:
|
||||
pass
|
||||
|
||||
self.closeThread()
|
||||
return True
|
||||
addEventHandler("onPreRequest",textOnPreRequest)
|
||||
|
||||
global textOnRequest
|
||||
def textOnRequest(event,self,requestLength):
|
||||
global textTimeout
|
||||
global textKeepAliveTimeout
|
||||
|
||||
self.connection.settimeout(textTimeout)
|
||||
data = self.connection.recv(requestLength)
|
||||
|
||||
text = data.decode("utf-8")
|
||||
print(":".join(map(str,self.address))+ " > " +text)
|
||||
response = textCommandRun(self,textCommandToList(text))
|
||||
print("response: " +textListToCommand(response))
|
||||
self.sendResponse(textListToCommand(response).encode("utf-8"))
|
||||
|
||||
self.connection.settimeout(textKeepAliveTimeout)
|
||||
addEventHandler("onRequest",textOnRequest)
|
||||
|
||||
global textOnException
|
||||
def textOnException(event,self,exc):
|
||||
self.connection.settimeout(textTimeout)
|
||||
if type(exc) == socket.timeout:
|
||||
self.sendResponse(textListToCommand(["error","fatal","timeout"]).encode("utf-8"))
|
||||
return
|
||||
|
||||
self.sendResponse(textListToCommand(["error","fatal","unhandled",str(exc)]).encode("utf-8"))
|
||||
addEventHandler("onException",textOnException)
|
|
@ -32,7 +32,7 @@ class receiverThread(threading.Thread):
|
|||
print("server: " +response)
|
||||
|
||||
def sendRequest(connection,data):
|
||||
connection.sendall(len(data).to_bytes(4,"big") + data)
|
||||
connection.sendall(len(data).to_bytes(4,"big") + b"\x00" + data)
|
||||
|
||||
def getResponse(connection):
|
||||
data = b''
|
||||
|
@ -42,6 +42,15 @@ def getResponse(connection):
|
|||
connection.close()
|
||||
return
|
||||
|
||||
nul = connection.recv(1)
|
||||
if not nul:
|
||||
connection.close()
|
||||
return
|
||||
|
||||
if nul != b"\x00":
|
||||
connection.close()
|
||||
return
|
||||
|
||||
requestLength = int.from_bytes(data,"big")
|
||||
data = connection.recv(requestLength)
|
||||
return data
|
||||
|
|
Loading…
Reference in New Issue