mirror of
https://github.com/ammaraskar/pyCraft.git
synced 2024-11-24 19:25:33 +01:00
357 lines
16 KiB
Python
357 lines
16 KiB
Python
import socket
|
|
import PacketListenerManager
|
|
import urllib2
|
|
import traceback
|
|
import threading
|
|
import hashlib
|
|
import string
|
|
import unicodedata
|
|
import Utils
|
|
import sys
|
|
from networking import PacketSenderManager
|
|
from Crypto.Random import _UserFriendlyRNG
|
|
from Crypto.Util import asn1
|
|
from Crypto.PublicKey import RSA
|
|
from Crypto.Cipher import AES
|
|
from Crypto.Cipher import PKCS1_v1_5
|
|
|
|
EntityID = 0
|
|
|
|
|
|
class ServerConnection(threading.Thread):
|
|
def __init__(self, pluginLoader, username, sessionID, server, port, options=None):
|
|
threading.Thread.__init__(self)
|
|
self.pluginLoader = pluginLoader
|
|
self.options = options
|
|
self.isConnected = False
|
|
self.username = username
|
|
self.sessionID = sessionID
|
|
self.server = server
|
|
self.port = port
|
|
|
|
def disconnect(self, reason="Disconnected by user"):
|
|
PacketSenderManager.sendFF(self.socket, reason)
|
|
self.listener.kill = True
|
|
self.socket.close()
|
|
|
|
def setWindow(self, window):
|
|
self.window = window
|
|
|
|
def grabSocket(self):
|
|
return self.socket
|
|
|
|
def run(self):
|
|
try:
|
|
#Create the socket and fileobject
|
|
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
self.socket.connect(( self.server, self.port ))
|
|
self.FileObject = self.socket.makefile()
|
|
|
|
#Send out the handshake packet
|
|
PacketSenderManager.sendHandshake(self.socket, self.username, self.server, self.port)
|
|
|
|
#Receive the encryption packet id
|
|
packetid = self.socket.recv(1)
|
|
|
|
if (packetid == "\xFF"):
|
|
print PacketListenerManager.handleFF(self.FileObject)
|
|
#Sanity check the packet id
|
|
assert packetid == "\xFD", "Server didn't respond back to handshake with proper packet!"
|
|
|
|
#Parse the packet
|
|
packetFD = PacketListenerManager.handleFD(self.FileObject)
|
|
|
|
#Import the server's public key
|
|
self.pubkey = RSA.importKey(packetFD['Public Key'])
|
|
|
|
#Generate a 16 byte (128 bit) shared secret
|
|
self.sharedSecret = _UserFriendlyRNG.get_random_bytes(16)
|
|
|
|
#Authenticate the server from sessions.minecraft.net
|
|
if (packetFD['ServerID'] != '-'):
|
|
try:
|
|
#Grab the server id
|
|
sha1 = hashlib.sha1()
|
|
sha1.update(packetFD['ServerID'])
|
|
sha1.update(self.sharedSecret)
|
|
sha1.update(packetFD['Public Key'])
|
|
#lovely java style hex digest by barneygale
|
|
serverid = Utils.javaHexDigest(sha1)
|
|
#Open up the url with the appropriate get parameters
|
|
url = "http://session.minecraft.net/game/joinserver.jsp?user=" + self.username + "&sessionId=" + self.sessionID + "&serverId=" + serverid
|
|
response = urllib2.urlopen(url).read()
|
|
|
|
if (response != "OK"):
|
|
print "Response from sessions.minecraft.net wasn't OK, it was " + response
|
|
return False
|
|
|
|
#Success \o/ We can now begin sending our serverAddress to the server
|
|
|
|
#Instantiate our main packet listener
|
|
self.listener = PacketListener(self, self.socket, self.FileObject)
|
|
self.listener.setDaemon(True)
|
|
self.listener.start()
|
|
|
|
#Encrypt the verification token from earlier along with our shared secret with the server's rsa key
|
|
self.RSACipher = PKCS1_v1_5.new(self.pubkey)
|
|
encryptedSanityToken = self.RSACipher.encrypt(str(packetFD['Token']))
|
|
encryptedSharedSecret = self.RSACipher.encrypt(str(self.sharedSecret))
|
|
|
|
#Send out a a packet FC to the server
|
|
PacketSenderManager.sendFC(self.socket, encryptedSharedSecret, encryptedSanityToken)
|
|
self.pluginLoader.notify("onConnect")
|
|
|
|
except Exception, e:
|
|
traceback.print_exc()
|
|
else:
|
|
print "Server is in offline mode"
|
|
#Instantiate our main packet listener
|
|
self.listener = PacketListener(self, self.socket, self.FileObject)
|
|
self.listener.setDaemon(True)
|
|
self.listener.start()
|
|
|
|
#Encrypt the verification token from earlier along with our shared secret with the server's rsa key
|
|
self.RSACipher = PKCS1_v1_5.new(self.pubkey)
|
|
encryptedSanityToken = self.RSACipher.encrypt(str(packetFD['Token']))
|
|
encryptedSharedSecret = self.RSACipher.encrypt(str(self.sharedSecret))
|
|
|
|
#Send out a a packet FC to the server
|
|
PacketSenderManager.sendFC(self.socket, encryptedSharedSecret, encryptedSanityToken)
|
|
self.pluginLoader.notify("onConnect")
|
|
except Exception, e:
|
|
print "Connection to server failed"
|
|
traceback.print_exc()
|
|
sys.exit(1)
|
|
|
|
|
|
class EncryptedFileObjectHandler():
|
|
def __init__(self, fileobject, cipher):
|
|
self.fileobject = fileobject
|
|
self.cipher = cipher
|
|
self.length = 0
|
|
|
|
def read(self, length):
|
|
rawData = self.fileobject.read(length)
|
|
self.length += length
|
|
unencryptedData = self.cipher.decrypt(rawData)
|
|
return unencryptedData
|
|
|
|
def tell(self):
|
|
return self.length
|
|
|
|
|
|
class EncryptedSocketObjectHandler():
|
|
def __init__(self, socket, cipher):
|
|
self.socket = socket
|
|
self.cipher = cipher
|
|
|
|
def send(self, serverAddress):
|
|
self.socket.send(self.cipher.encrypt(serverAddress))
|
|
|
|
def close(self):
|
|
self.socket.close()
|
|
|
|
|
|
class PacketListener(threading.Thread):
|
|
def __init__(self, connection, socket, FileObject):
|
|
threading.Thread.__init__(self)
|
|
self.connection = connection
|
|
self.socket = socket
|
|
self.FileObject = FileObject
|
|
self.encryptedConnection = False
|
|
self.kill = False
|
|
|
|
def enableEncryption(self):
|
|
#Create an AES cipher from the previously obtained public key
|
|
self.cipher = AES.new(self.connection.sharedSecret, AES.MODE_CFB, IV=self.connection.sharedSecret)
|
|
self.decipher = AES.new(self.connection.sharedSecret, AES.MODE_CFB, IV=self.connection.sharedSecret)
|
|
|
|
self.rawsocket = self.socket
|
|
self.connection.rawsocket = self.connection.socket
|
|
self.socket = EncryptedSocketObjectHandler(self.rawsocket, self.cipher)
|
|
self.connection.socket = self.socket
|
|
|
|
self.rawFileObject = self.FileObject
|
|
self.connection.rawFileObject = self.connection.FileObject
|
|
self.FileObject = EncryptedFileObjectHandler(self.rawFileObject, self.decipher)
|
|
self.connection.FileObject = self.FileObject
|
|
|
|
self.encryptedConnection = True
|
|
|
|
def run(self):
|
|
while True:
|
|
if (self.kill):
|
|
break
|
|
try:
|
|
response = self.FileObject.read(1)
|
|
if (response == ""):
|
|
continue
|
|
except Exception, e:
|
|
print "Ping timeout"
|
|
sys.exit()
|
|
break
|
|
if (response == "\x00"):
|
|
packet = PacketListenerManager.handle00(self.FileObject, self.socket)
|
|
elif (response == "\x01"):
|
|
packet = PacketListenerManager.handle01(self.FileObject)
|
|
print "Logged in \o/ Received an entity id of " + str(packet['EntityID'])
|
|
elif (response == "\x03"):
|
|
packet = PacketListenerManager.handle03(self.FileObject)
|
|
if not self.connection.options.disableAnsiColours:
|
|
filtered_string = Utils.translate_escapes(packet['Message'])
|
|
else:
|
|
filtered_string = packet['Message']
|
|
print filtered_string
|
|
|
|
elif (response == "\x04"):
|
|
packet = PacketListenerManager.handle04(self.FileObject)
|
|
elif (response == "\x05"):
|
|
packet = PacketListenerManager.handle05(self.FileObject)
|
|
elif (response == "\x06"):
|
|
packet = PacketListenerManager.handle06(self.FileObject)
|
|
elif (response == "\x07"):
|
|
packet = PacketListenerManager.handle07(self.FileObject)
|
|
elif (response == "\x08"):
|
|
packet = PacketListenerManager.handle08(self.FileObject)
|
|
elif (response == "\x09"):
|
|
packet = PacketListenerManager.handle09(self.FileObject)
|
|
elif (response == "\x0D"):
|
|
packet = PacketListenerManager.handle0D(self.FileObject)
|
|
elif (response == "\x10"):
|
|
packet = PacketListenerManager.handle10(self.FileObject)
|
|
elif (response == "\x11"):
|
|
packet = PacketListenerManager.handle11(self.FileObject)
|
|
elif (response == "\x12"):
|
|
packet = PacketListenerManager.handle12(self.FileObject)
|
|
elif (response == "\x14"):
|
|
packet = PacketListenerManager.handle14(self.FileObject)
|
|
elif (response == "\x15"):
|
|
packet = PacketListenerManager.handle15(self.FileObject)
|
|
elif (response == "\x16"):
|
|
packet = PacketListenerManager.handle16(self.FileObject)
|
|
elif (response == "\x17"):
|
|
packet = PacketListenerManager.handle17(self.FileObject)
|
|
elif (response == "\x18"):
|
|
packet = PacketListenerManager.handle18(self.FileObject)
|
|
elif (response == "\x19"):
|
|
packet = PacketListenerManager.handle19(self.FileObject)
|
|
elif (response == "\x1A"):
|
|
packet = PacketListenerManager.handle1A(self.FileObject)
|
|
elif (response == "\x1C"):
|
|
packet = PacketListenerManager.handle1C(self.FileObject)
|
|
elif (response == "\x1D"):
|
|
packet = PacketListenerManager.handle1D(self.FileObject)
|
|
elif (response == "\x1E"):
|
|
packet = PacketListenerManager.handle1E(self.FileObject)
|
|
elif (response == "\x1F"):
|
|
packet = PacketListenerManager.handle1F(self.FileObject)
|
|
elif (response == "\x20"):
|
|
packet = PacketListenerManager.handle20(self.FileObject)
|
|
elif (response == "\x21"):
|
|
packet = PacketListenerManager.handle21(self.FileObject)
|
|
elif (response == "\x22"):
|
|
packet = PacketListenerManager.handle22(self.FileObject)
|
|
elif (response == "\x23"):
|
|
packet = PacketListenerManager.handle23(self.FileObject)
|
|
elif (response == "\x26"):
|
|
packet = PacketListenerManager.handle26(self.FileObject)
|
|
elif (response == "\x27"):
|
|
packet = PacketListenerManager.handle27(self.FileObject)
|
|
elif (response == "\x28"):
|
|
packet = PacketListenerManager.handle28(self.FileObject)
|
|
elif (response == "\x29"):
|
|
packet = PacketListenerManager.handle29(self.FileObject)
|
|
elif (response == "\x2A"):
|
|
packet = PacketListenerManager.handle2A(self.FileObject)
|
|
elif (response == "\x2B"):
|
|
packet = PacketListenerManager.handle2B(self.FileObject)
|
|
elif (response == "\x2C"):
|
|
packet = PacketListenerManager.handle2C(self.FileObject)
|
|
elif (response == "\x33"):
|
|
packet = PacketListenerManager.handle33(self.FileObject)
|
|
elif (response == "\x34"):
|
|
packet = PacketListenerManager.handle34(self.FileObject)
|
|
elif (response == "\x35"):
|
|
packet = PacketListenerManager.handle35(self.FileObject)
|
|
elif (response == "\x36"):
|
|
packet = PacketListenerManager.handle36(self.FileObject)
|
|
elif (response == "\x37"):
|
|
packet = PacketListenerManager.handle37(self.FileObject)
|
|
elif (response == "\x38"):
|
|
packet = PacketListenerManager.handle38(self.FileObject)
|
|
elif (response == "\x3C"):
|
|
packet = PacketListenerManager.handle3C(self.FileObject)
|
|
elif (response == "\x3D"):
|
|
packet = PacketListenerManager.handle3D(self.FileObject)
|
|
elif (response == "\x3E"):
|
|
packet = PacketListenerManager.handle3E(self.FileObject)
|
|
elif (response == "\x3F"):
|
|
packet = PacketListenerManager.handle3F(self.FileObject)
|
|
elif (response == "\x46"):
|
|
packet = PacketListenerManager.handle46(self.FileObject)
|
|
elif (response == "\x47"):
|
|
packet = PacketListenerManager.handle47(self.FileObject)
|
|
elif (response == "\x64"):
|
|
packet = PacketListenerManager.handle64(self.FileObject)
|
|
elif (response == "\x65"):
|
|
packet = PacketListenerManager.handle65(self.FileObject)
|
|
elif (response == "\x67"):
|
|
packet = PacketListenerManager.handle67(self.FileObject)
|
|
elif (response == "\x68"):
|
|
packet = PacketListenerManager.handle68(self.FileObject)
|
|
elif (response == "\x69"):
|
|
packet = PacketListenerManager.handle69(self.FileObject)
|
|
elif (response == "\x6A"):
|
|
packet = PacketListenerManager.handle6A(self.FileObject)
|
|
elif (response == "\x6B"):
|
|
packet = PacketListenerManager.handle6B(self.FileObject)
|
|
elif (response == "\x82"):
|
|
packet = PacketListenerManager.handle82(self.FileObject)
|
|
elif (response == "\x83"):
|
|
packet = PacketListenerManager.handle83(self.FileObject)
|
|
elif (response == "\x84"):
|
|
packet = PacketListenerManager.handle84(self.FileObject)
|
|
elif (response == "\x85"):
|
|
packet = PacketListenerManager.handle85(self.FileObject)
|
|
elif (response == "\xC8"):
|
|
packet = PacketListenerManager.handleC8(self.FileObject)
|
|
elif (response == "\xC9"):
|
|
packet = PacketListenerManager.handleC9(self.FileObject)
|
|
elif (response == "\xCA"):
|
|
packet = PacketListenerManager.handleCA(self.FileObject)
|
|
elif (response == "\xCB"):
|
|
packet = PacketListenerManager.handleCB(self.FileObject)
|
|
elif (response == "\xCE"):
|
|
packet = PacketListenerManager.handleCE(self.FileObject)
|
|
elif (response == "\xCF"):
|
|
packet = PacketListenerManager.handleCF(self.FileObject)
|
|
elif (response == "\xD0"):
|
|
packet = PacketListenerManager.handleD0(self.FileObject)
|
|
elif (response == "\xD1"):
|
|
packet = PacketListenerManager.handleD1(self.FileObject)
|
|
elif (response == "\xFA"):
|
|
packet = PacketListenerManager.handleFA(self.FileObject)
|
|
elif (response == "\xFC"):
|
|
packet = PacketListenerManager.handleFC(self.FileObject)
|
|
if (not self.encryptedConnection):
|
|
self.enableEncryption()
|
|
self.connection.isConnected = True
|
|
PacketSenderManager.sendCD(self.socket, 0)
|
|
elif (response == "\xFF"):
|
|
packet = PacketListenerManager.handleFF(self.FileObject)
|
|
print "Disconnected: " + packet['Reason']
|
|
self.connection.disconnect()
|
|
self.connection.pluginLoader.disablePlugins()
|
|
sys.exit(1)
|
|
break
|
|
else:
|
|
print "Protocol error: " + hex(ord(response))
|
|
self.connection.disconnect("Protocol error, invalid packet: " + hex(ord(response)))
|
|
self.connection.pluginLoader.disablePlugins()
|
|
sys.exit(1)
|
|
break
|
|
|
|
# Invoke plugin listeners
|
|
for listener in self.connection.pluginLoader.getPacketListeners():
|
|
listener(response, packet)
|