class ClientSocket(asynchat.async_chat): def __init__(self, connection): asynchat.async_chat.__init__(self, connection) # Holds all pending text (awaiting a newline from client). self.buffer = '' self.set_terminator('\n') # Retains the player class tied to this socket. self.parent = Player(self) def collect_incoming_data(self, data): for char in data: if char == '\b' and len(self.buffer) > 0: self.buffer = self.buffer[:-1] elif char == '\b' or char == '\r': pass elif char in string.printable: self.buffer += char if self.parent.state == STATE_PASSWORD: self.parent.send('\b \b') def found_terminator(self): data = self.buffer self.buffer = '' command.accept_command(self.parent, data) def handle_close(self): # Shunt output to parent (avoids recursion in simultaneous logouts) self.parent.send = lambda s: None if self.parent.location: libsigma.report(libsigma.ROOM, "$actor has left the game.", self.parent) self.parent.location.characters.remove(self.parent) w = World() if self.parent in w.players: a = Archive() a.save(self.parent) w.players.remove(self.parent) log("NETWORK", "Client at %s closed connection" % self.addr[0]) self.parent.socket = None self.close() def handle_accept(self): pass
def register_thread(c, addr): session_key = None pub_key = None while True: rec = b'' while True: part = c.recv(1024) rec += part if len(part) < 1024: break try: data = json.loads(rec.decode('ascii')) mac = crypto.encrypt( hashlib.sha256(data['message'].encode('ascii')).digest(), session_key) if session_key is not None else None if (mac.hex() if mac is not None else mac) != data['mac']: print("Ignored message with erroneous MAC") continue data = json.loads(data['message']) if data['type'] == messages.CONNECTION_REQUEST and pub_key is None: pub_key = serialization.load_pem_public_key( bytes.fromhex(data['key']), default_backend()) a = crypto.dh_get_private() A = crypto.dh_get_public(a) c.send( json.dumps({ 'message': json.dumps({ 'type': messages.CONNECTION_REPLY, 'iv': crypto.get_string(shuffle.iv), 'param': A, 'sig': rsa_priv_key.sign( hashlib.sha256( str(A).encode('ascii')).digest(), padding.PSS( mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH), hashes.SHA256()).hex() }), 'mac': None }).encode('ascii')) elif data['type'] == messages.CONNECTION_REPLY: pub_key.verify( bytes.fromhex(data['sig']), hashlib.sha256(str( data['param']).encode('ascii')).digest(), padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH), hashes.SHA256()) B = data['param'] dh_sig = data['sig'] session_key = crypto.dh_get_shared(a, B) elif data[ 'type'] == messages.REGISTER_REQUEST and session_key is not None: p = Player(data['name'], bytes.fromhex(data['sig']), c, session_key, pub_key, B, dh_sig) accepted = p.name not in pseudo_db if accepted: new_player_lock.acquire() if len(players) < players_num: players[c] = p pseudo_players[data['name']] = p print('[socket]', addr[0], ':', addr[1], '-', 'Registered, pseudonym:', data['name']) pseudo_db.append(data['name']) ok.add(p.name) else: c.close() new_player_lock.release() return new_player_lock.release() p.send({'type': messages.REGISTER_REPLY, 'accepted': accepted}) if accepted: return except: c.close() return