Skip to content

Commit

Permalink
Version 2.0
Browse files Browse the repository at this point in the history
A lot of things were changed, and everything is now organized correctly.
  • Loading branch information
xlaming authored Nov 23, 2019
1 parent 66885a7 commit d15799d
Show file tree
Hide file tree
Showing 22 changed files with 309 additions and 143 deletions.
26 changes: 16 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,25 @@
* All settings are located on **classes/config.py**

# Commands:
* !chatid **[CHAT NAME]**
* !id **[XAT USERNAME]**
* !price **[POWER NAME]**
* !reg **[XAT ID]**
* !info
* !reload
* !latest
* -chatid **[CHAT NAME]**
* -id **[XAT USERNAME]**
* -price **[POWER NAME]**
* -reg **[XAT ID]**
* -steal **[XAT ID]**
* -enable **[PLUGIN NAME]**
* -disable **[PLUGIN NAME]**
* -info
* -reload
* -relogin
* -latest

# Plugins:
* **clickmsg.py**
* Tell you ID of who ticked you.
* **commands.py**
* Handler for all commands.
* **connected.py**
* Just show a message when you connect to xat.
* **guestlinks.py**
* Allows you to see guest links.
* **noclicks.py**
* Disable your clicks on other people.
* **nofollow.py**
Expand All @@ -33,7 +39,7 @@
5. This is all, just don't bother me anymore.

# Version:
* 1.4 stable
* 2.0 stable

# Credits:
* xLaming (obvious, im da best)
Expand Down
202 changes: 102 additions & 100 deletions classes/client.py
Original file line number Diff line number Diff line change
@@ -1,120 +1,122 @@
from os import path
from socket import *
from glob import glob
from time import sleep
from select import select
from .config import Config
from threading import Thread
from .webserver import WebServer
from xml.etree.ElementTree import fromstring

class Client:
def __init__(self):
self.Threads = []
self.WebServer = WebServer()
self.RunServer = Thread(target=self.WebServer.start)
self.RunServer.daemon = True
self.RunServer.start()
print("> Webserver started.")
self.Plugins = []
self.loadPlugins()
print("> Plugins started.")
self.RunSocket = Thread(target=self.createSocket)
self.RunSocket.daemon = True
self.RunSocket.start()
print("> Socket started.")

def createSocket(self):
def __init__(self, server, sock):
try:
xSock = socket(AF_INET, SOCK_STREAM)
xSock.bind((Config.CLIENT_SERVERIP, Config.CLIENT_SERVERPORT))
while True:
xSock.listen(1)
(conn, (ip, port)) = xSock.accept()
thread = Thread(target=self.addClient, args=(conn,))
thread.start()
self.Threads.append(thread)
for t in self.Threads:
t.join()
self.isConnected = False
self.server = server
self.socks = [[], []]
self.users = {}
self.userID = 0
self.rank = 0
self.chatID = 0
self.socks[1] = sock
self.connectToXat()
except:
pass

def parsePlugins(self, packet, direction, sock):
for p in self.Plugins:
exec(p, globals())
data = plugin(self, packet, direction, sock)
if data:
packet = data
return packet
def connectToXat(self):
self.socks[0] = socket(AF_INET, SOCK_STREAM, SOL_TCP)
self.socks[0].connect((Config.XAT_IP, Config.XAT_PORT))
self.startHeartBeat()
self.keepRunning()

def xml2Array(self, xml):
try:
returnArray = {}
xml = xml.strip('\0')
xml = fromstring(xml)
returnArray['name'] = xml.tag
for tag, attrib in xml.attrib.items():
returnArray[tag] = attrib
except:
pass
return returnArray

def buildPacket(self, node, packets):
packet = ["<" + node]
for (k, v) in packets.items():
if str(k) != 'name':
packet.append(str(k) + "=\"" + str(v) + "\"")
packet.append("/>")
return (' ' .join(packet) + '\x00').encode()

def fixUserID(self, uid):
uid += "_"
trim = uid.index('_')
return uid[0:trim]

def loadPlugins(self):
self.Plugins = []
for pname in glob('plugins/*.py'):
self.Plugins.append(open(pname).read())

def Logger(self, file, text):
if path.exists('logs/' + file + '.log'):
logs = open('logs/' + file + '.log', 'a+')
logs.write(text + "\n")
logs.close()

def addClient(self, conn):
socks = [[], []]
socks[0] = socket(AF_INET, SOCK_STREAM, SOL_TCP)
socks[0].connect((Config.XAT_IP, Config.XAT_PORT))
socks[0].setblocking(0)
socks[1] = conn
def keepRunning(self):
try:
while True:
allSocks,_,_ = select(socks, [], [])
for sock in allSocks:
socks,_,_ = select(self.socks, [], [])
for sock in socks:
recv = ""
sock.setblocking(0)
while recv[-1:] != chr(0):
recv += sock.recv(1204).decode('utf-8', 'ignore')
if len(recv) <= 1:
recv += sock.recv(2048).decode('utf-8', 'ignore')
if len(recv) < 1:
self.killSockets()
break
if recv:
for packet in recv.split('\x00'):
if '<f ' in packet:
dataInfo = 1 if sock == socks[0] else 0
socks[dataInfo].send((packet + '\x00').encode())
dataInfo = 1 if sock == self.socks[0] else 0
self.socks[dataInfo].send(bytes(packet + '\x00', encoding='utf-8'))
else:
data = self.xml2Array(packet)
if data:
dataInfo = [1, 'fromxat', 'RECV'] if sock == socks[0] else [0, 'toxat', 'SENT']
data = self.parsePlugins(data, dataInfo[1], conn)
toBeSend = self.buildPacket(data['name'], data)
if data['name'] == 'policy-file-request':
socks[1].send(Config.CROSSDOMAIN.encode() + b'\x00')
elif data['name'] != 'HIDDEN':
print('[' + dataInfo[2] + ']: ', toBeSend.decode('utf-8', 'ignore'))
socks[dataInfo[0]].send(toBeSend)

except Exception as e:
error = str(e)
if not 'ConnectionAbortedError' in error and not '10053' in error:
self.Logger('errors', error)
self.parse(sock, packet)
except:
self.killSockets()

def parse(self, sock, packet):
data = self.server.xml2Array(packet)
if not data:
return
dataInfo = [1, 'fromxat', 'RECV'] if sock == self.socks[0] else [0, 'toxat', 'SENT']
data = self.server.parsePlugins(data, dataInfo[1], self)
if data['name'] == 'policy-file-request':
self.sendToUser(Config.CROSSDOMAIN)
elif data['name'] != 'HIDDEN':
if data['name'] == 'j2':
self.userID = int(data['u'])
self.chatID = int(data['c'])
elif data['name'] == 'i' and 'r' in data:
self.rank = int(data['r'])
elif data['name'] == 'l' and 'u' in data:
if int(data['u']) in self.users:
del self.users[int(data['u'])]
elif data['name'] == 'done':
self.isConnected = True
self.announce('xatClient is running...')
elif data['name'] == 'u' and 'u' in data:
self.users[int(data['u'])] = {
'name': data['n'],
'avatar': data['a'],
'home': data['h'],
'rank': int(data['f']) & 7 if 'f' in data else 5,
'reg': data['N'] if 'N' in data else False,
'd0': data['d0'] if 'd0' in data else False,
'd2': data['d2'] if 'd2' in data else False,
'f': data['f'] if 'f' in data else False,
}
toBeSend = self.server.buildPacket(data['name'], data)
print('[' + dataInfo[2] + ' - ' + str(self.chatID) + ']: ', toBeSend)
self.socks[dataInfo[0]].send(bytes(toBeSend, encoding='utf-8'))

def sendToUser(self, packet):
print('[RECV - ' + str(self.chatID) + ']: ', packet)
return self.socks[1].send(bytes(packet + '\x00', encoding='utf-8'))

def sendToXat(self, packet):
print('[SENT - ' + str(self.chatID) + ']: ', packet)
return self.socks[0].send(bytes(packet + '\x00', encoding='utf-8'))

def announce(self, message):
self.sendToUser(self.server.buildPacket('m', {'t': message, 'u': 0}))

def killSockets(self):
for sock in self.socks:
sock.close()

def sendHeartBeat(self):
try:
sleep(10) # first time only
while True:
if self.isConnected:
self.sendToXat(self.server.buildPacket('c', {'u': self.userID, 't': '/KEEPALIVE'}))
sleep(50)
except:
pass


def startHeartBeat(self):
thread = Thread(target=self.sendHeartBeat)
thread.daemon = True
thread.start()

def getById(self, userid):
if not self.users:
return False
for uid, user in self.users.items():
if userid == uid:
return user
return False
2 changes: 1 addition & 1 deletion classes/config.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class Config:
CMD_CHARACTER = '!'
CMD_CHARACTER = '-'

CLIENT_SERVERIP = '0.0.0.0'
CLIENT_SERVERPORT = 10000
Expand Down
111 changes: 111 additions & 0 deletions classes/server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
from os import path
from socket import *
from glob import glob
from select import select
from .config import Config
from .client import Client
from ntpath import basename
from threading import Thread
from .webserver import WebServer
from xml.etree.ElementTree import fromstring

class Server:
def __init__(self):
try:
self.Threads = []
self.Disabled = []
self.WebServer = WebServer()
self.RunServer = Thread(target=self.WebServer.start)
self.RunServer.daemon = True
self.RunServer.start()
print("> Webserver started.")
self.Plugins = []
self.loadPlugins()
print("> Plugins started.")
self.RunSocket = Thread(target=self.createSocket)
self.RunSocket.daemon = True
self.RunSocket.start()
print("> Socket started.")
except:
pass

def createSocket(self):
try:
xSock = socket(AF_INET, SOCK_STREAM)
xSock.settimeout(None)
xSock.bind((Config.CLIENT_SERVERIP, Config.CLIENT_SERVERPORT))
xSock.listen(100)
while True:
(conn, (ip, port)) = xSock.accept()
thread = Thread(target=Client, args=(self, conn))
thread.daemon = True
thread.start()
self.Threads.append(thread)
for t in self.Threads:
t.join()
except:
pass

def parsePlugins(self, packet, direction, user):
for p in self.Plugins:
exec(p, globals())
data = plugin(self, packet, direction, user)
if data:
packet = data
return packet

def xml2Array(self, xml):
try:
returnArray = {}
xml = xml.strip('\0')
xml = fromstring(xml)
returnArray['name'] = xml.tag
for tag, attrib in xml.attrib.items():
returnArray[tag] = attrib
except:
pass
return returnArray

def buildPacket(self, node, packets):
packet = ["<" + node]
for (k, v) in packets.items():
if str(k) != 'name':
packet.append(str(k) + "=\"" + self.sanatize(str(v)) + "\"")
packet.append("/>")
return ' ' .join(packet) + '\x00'

def fixUserID(self, uid):
uid += "_"
trim = uid.index('_')
return uid[0:trim]

def sanatize(self, data):
entities = {
'"': '&quot;',
'<': '&lt;',
'˃': '\xcb\x83'
}
for (i, u) in entities.items():
data = data.replace(i, u)
return data

def loadPlugins(self):
self.Plugins = []
for pname in glob('plugins/*.py'):
name = basename(pname).replace('.py', '')
if not name in self.Disabled:
self.Plugins.append(open(pname).read())

def disablePlugin(self, name):
if path.exists('plugins/' + name + '.py') and not name in self.Disabled:
self.Disabled.append(name)
self.loadPlugins()
return True
return False

def enablePlugin(self, name):
if name in self.Disabled:
self.Disabled.remove(name)
self.loadPlugins()
return True
return False
2 changes: 1 addition & 1 deletion classes/webserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def __init__(self):
def start(self):
self.sock = socket(AF_INET, SOCK_STREAM)
self.sock.bind((Config.WEB_SERVERIP, Config.WEB_SERVERPORT))
self.sock.listen(15)
self.sock.listen(25)
while(True):
usock, address = self.sock.accept()
recv = usock.recv(4096)
Expand Down
Loading

0 comments on commit d15799d

Please sign in to comment.