def perform_authp(self, data_parsed): authtoken_parsed = gs_utils.parse_authtoken(data_parsed['authtoken'], self.db) #print authtoken_parsed if "lid" in data_parsed: self.lid = data_parsed['lid'] userid, profileid, gsbrcd, uniquenick = gs_utils.login_profile_via_parsed_authtoken(authtoken_parsed, self.db) if profileid != None: # Successfully logged in or created account, continue creating # session. sesskey = self.db.create_session(profileid, '') self.sessions[profileid] = self self.profileid = int(profileid) msg = gs_query.create_gamespy_message([('__cmd__', "pauthr"), ('__cmd_val__', profileid), ('lid', self.lid),]) else: # login failed self.log(logging.WARNING, "Invalid password") msg = gs_query.create_gamespy_message([('__cmd__', "pauthr"), ('__cmd_val__', -3), ('lid', self.lid), ('errmsg', 'Invalid Validation'),]) self.log(logging.DEBUG, "SENDING: '%s'..." % msg) msg = self.crypt(msg) self.transport.write(bytes(msg))
def perform_authp(self, data_parsed): authtoken_parsed = gs_utils.parse_authtoken(data_parsed['authtoken'], self.db) #print authtoken_parsed if "lid" in data_parsed: self.lid = data_parsed['lid'] userid, profileid, gsbrcd, uniquenick = gs_utils.login_profile_via_parsed_authtoken(authtoken_parsed, self.db) if profileid != None: # Successfully logged in or created account, continue creating session. sesskey = self.db.create_session(profileid, '') self.sessions[profileid] = self self.profileid = int(profileid) msg = gs_query.create_gamespy_message([ ('__cmd__', "pauthr"), ('__cmd_val__', profileid), ('lid', self.lid), ]) else: # login failed self.log(logging.WARNING, "Invalid password") msg = gs_query.create_gamespy_message([ ('__cmd__', "pauthr"), ('__cmd_val__', -3), ('lid', self.lid), ('errmsg', 'Invalid Validation'), ]) self.log(logging.DEBUG, "SENDING: '%s'..." % msg) msg = self.crypt(msg) self.transport.write(bytes(msg))
def perform_bm(self, data_parsed): if data_parsed['__cmd_val__'] in ("1", "5", "102", "103"): # Message to/from clients? if "t" in data_parsed: # Send message to the profile id in "t" dest_profileid = int(data_parsed['t']) dest_profile_buddies = self.db.get_buddy_list(dest_profileid) dest_msg = data_parsed['msg'] not_buddies = False # Check if the user is buddies with the target user before sending message. if not_buddies: for buddy in self.buddies: if buddy['userProfileId'] == dest_profileid: not_buddies = True break if not_buddies: for buddy in dest_profile_buddies: if buddy['userProfileId'] == self.profile: not_buddies = True break # Send error to user if they tried to send a message to someone who isn't a buddy. if not_buddies: msg = gs_query.create_gamespy_message([ ('__cmd__', "error"), ('__cmd_val__', ""), ('err', 2305), ('errmsg', "The profile the message was to be sent to is not a buddy."), ('id', 1), ]) logger.log(logging.DEBUG, "Trying to send message to someone who isn't a buddy: %s" % msg) self.transport.write(msg) return msg = gs_query.create_gamespy_message([ ('__cmd__', "bm"), ('__cmd_val__', "1"), ('f', self.profileid), ('msg', dest_msg), ]) if dest_profileid in self.sessions: self.log(logging.DEBUG, "SENDING TO %s:%s: %s" % (self.sessions[dest_profileid].address.host, self.sessions[dest_profileid].address.port, msg)) self.sessions[dest_profileid].transport.write(bytes(msg)) else: if data_parsed['__cmd_val__'] == "1": self.log(logging.DEBUG, "Saving message to %d: %s" % (dest_profileid, msg)) self.db.save_pending_message(self.profileid, dest_profileid, msg) else: msg = gs_query.create_gamespy_message([ ('__cmd__', "error"), ('__cmd_val__', ""), ('err', 2307), ('errmsg', "The buddy to send a message to is offline."), ('id', 1), ]) logger.log(logging.DEBUG, "Trying to send message to someone who isn't online: %s" % msg) self.transport.write(msg)
def perform_bm(self, data_parsed): if data_parsed['__cmd_val__'] == "1" or data_parsed['__cmd_val__'] == "5" or data_parsed['__cmd_val__'] == "102" or data_parsed['__cmd_val__'] == "103": # Message to/from clients? if "t" in data_parsed: # Send message to the profile id in "t" dest_profileid = int(data_parsed['t']) dest_profile_buddies = self.db.get_buddy_list(dest_profileid) dest_msg = data_parsed['msg'] not_buddies = False # Check if the user is buddies with the target user before sending message. if not_buddies: for buddy in self.buddies: if buddy['userProfileId'] == dest_profileid: not_buddies = True break if not_buddies: for buddy in dest_profile_buddies: if buddy['userProfileId'] == self.profile: not_buddies = True break # Send error to user if they tried to send a message to someone who isn't a buddy. if not_buddies: msg_d = [] msg_d.append(('__cmd__', "error")) msg_d.append(('__cmd_val__', "")) msg_d.append(('err', 2305)) msg_d.append(('errmsg', "The profile the message was to be sent to is not a buddy.")) msg_d.append(('id', 1)) msg = gs_query.create_gamespy_message(msg_d) logger.log(logging.DEBUG, "Trying to send message to someone who isn't a buddy: %s" % msg) self.transport.write(msg) return msg_d = [] msg_d.append(('__cmd__', "bm")) msg_d.append(('__cmd_val__', "1")) msg_d.append(('f', self.profileid)) msg_d.append(('msg', dest_msg)) msg = gs_query.create_gamespy_message(msg_d) if dest_profileid in self.sessions: self.log(logging.DEBUG, "SENDING TO %s:%s: %s" % (self.sessions[dest_profileid].address.host, self.sessions[dest_profileid].address.port, msg)) self.sessions[dest_profileid].transport.write(bytes(msg)) else: if data_parsed['__cmd_val__'] == "1": self.log(logging.DEBUG, "Saving message to %d: %s" % (dest_profileid, msg)) self.db.save_pending_message(self.profileid, dest_profileid, msg) else: msg_d = [] msg_d.append(('__cmd__', "error")) msg_d.append(('__cmd_val__', "")) msg_d.append(('err', 2307)) msg_d.append(('errmsg', "The buddy to send a message to is offline.")) msg_d.append(('id', 1)) msg = gs_query.create_gamespy_message(msg_d) logger.log(logging.DEBUG, "Trying to send message to someone who isn't online: %s" % msg) self.transport.write(msg)
def send_status_to_friends(self, buddy_profileid=None): # TODO: Cache buddy list so we don't have to query the database every time self.buddies = self.db.get_buddy_list(self.profileid) if self.status == "0" and self.statstring == "Offline": # Going offline, don't need to send the other information. status_msg = "|s|%s|ss|%s" % (self.status, self.statstring) else: status_msg = "|s|%s|ss|%s|ls|%s|ip|%d|p|0|qm|0" % ( self.status, self.statstring, self.locstring, self.get_ip_as_int(self.address.host)) msg = gs_query.create_gamespy_message([ ('__cmd__', "bm"), ('__cmd_val__', "100"), ('f', self.profileid), ('msg', status_msg), ]) buddy_list = self.buddies if buddy_profileid != None: buddy_list = [{"buddyProfileId": buddy_profileid}] for buddy in buddy_list: if buddy['buddyProfileId'] in self.sessions: #self.log(logging.DEBUG, "Sending status to buddy id %s (%s:%d): %s" % (str(buddy['buddyProfileId']), self.sessions[buddy['buddyProfileId']].address.host, self.sessions[buddy['buddyProfileId']].address.port, msg)) self.sessions[buddy['buddyProfileId']].transport.write( bytes(msg))
def send_status_to_friends(self, buddy_profileid = None): # TODO: Cache buddy list so we don't have to query the database every time self.buddies = self.db.get_buddy_list(self.profileid) if self.status == "0" and self.statstring == "Offline": # Going offline, don't need to send the other information. status_msg = "|s|%s|ss|%s" % (self.status, self.statstring) else: status_msg = "|s|%s|ss|%s|ls|%s|ip|%d|p|0|qm|0" % (self.status, self.statstring, self.locstring, self.get_ip_as_int(self.address.host)) msg = gs_query.create_gamespy_message([ ('__cmd__', "bm"), ('__cmd_val__', "100"), ('f', self.profileid), ('msg', status_msg), ]) buddy_list = self.buddies if buddy_profileid != None: buddy_list = [{"buddyProfileId":buddy_profileid}] for buddy in buddy_list: if buddy['buddyProfileId'] in self.sessions: #self.log(logging.DEBUG, "Sending status to buddy id %s (%s:%d): %s" % (str(buddy['buddyProfileId']), self.sessions[buddy['buddyProfileId']].address.host, self.sessions[buddy['buddyProfileId']].address.port, msg)) self.sessions[buddy['buddyProfileId']].transport.write(bytes(msg))
def send_bm4(self, playerid): date = int(time.time()) msg = gs_query.create_gamespy_message( [("__cmd__", "bm"), ("__cmd_val__", "4"), ("f", playerid), ("date", date), ("msg", "")] ) self.transport.write(bytes(msg))
def get_status_from_friends(self, buddy_profileid = None): # This will be called when the player logs in. Grab the player's buddy list and check the current sessions to # see if anyone is online. If they are online, make them send an update to the calling client. self.buddies = self.db.get_buddy_list(self.profileid) buddy_list = self.buddies if buddy_profileid != None: buddy_list = [{"buddyProfileId":buddy_profileid}] for buddy in self.buddies: if buddy['status'] != 1: continue if buddy['buddyProfileId'] in self.sessions and self.sessions[buddy['buddyProfileId']].gameid == self.gameid: status_msg = "|s|%s|ss|%s|ls|%s|ip|%d|p|0|qm|0" % (self.sessions[buddy['buddyProfileId']].status, self.sessions[buddy['buddyProfileId']].statstring, self.sessions[buddy['buddyProfileId']].locstring, self.get_ip_as_int(self.sessions[buddy['buddyProfileId']].address.host)) else: status_msg = "|s|0|ss|Offline" msg = gs_query.create_gamespy_message([ ('__cmd__', "bm"), ('__cmd_val__', "100"), ('f', buddy['buddyProfileId']), ('msg', status_msg), ]) self.transport.write(bytes(msg))
def send_keepalive(self): msg = gs_query.create_gamespy_message([ ('__cmd__', "ka"), ('__cmd_val__', ""), ]) self.log(logging.INFO, "%s" % "Sending keepalive...") self.transport.write(msg)
def perform_setpd(self, data_parsed): data = self.data msg = gs_query.create_gamespy_message([ ('__cmd__', "setpdr"), ('__cmd_val__', 1), ('lid', self.lid), ('pid', self.profileid), ('mod', int(time.time())), ]) self.log(logging.DEBUG, "SENDING: '%s'...", msg) msg = self.crypt(msg) self.transport.write(bytes(msg)) # TODO: Return error message. if int(data_parsed['pid']) != self.profileid: logger.log(logging.WARNING, "ERROR: %d tried to update %d's profile", int(data_parsed['pid']), self.profileid) return data_str = "\\data\\" length = int(data_parsed['length']) if len(data) < length: # The packet isn't complete yet, keep loop until we get the # entire packet. The length entire packet SHOULD always be # greater than the data field, so this check should be fine. return if data_str in data: idx = data.index(data_str) + len(data_str) data = data[idx:idx + length].rstrip("\\") else: logger.log(logging.ERROR, "ERROR: Could not find \data\ in setpd command: %s", data) data = "" current_data = self.db.pd_get(self.profileid, data_parsed['dindex'], data_parsed['ptype']) if current_data and data and 'data' in current_data: current_data = current_data['data'].lstrip('\\').split('\\') new_data = data.lstrip('\\').split('\\') current_data = dict(zip(current_data[0::2], current_data[1::2])) new_data = dict(zip(new_data[0::2], new_data[1::2])) for k in new_data.keys(): current_data[k] = new_data[k] # TODO: use str.join() data = "\\" for k in current_data.keys(): data += k + "\\" + current_data[k] + "\\" data = data.rstrip("\\") # Don't put trailing \ into db self.db.pd_insert(self.profileid, data_parsed['dindex'], data_parsed['ptype'], data)
def perform_getpd(self, data_parsed): profile = self.db.pd_get(self.profileid, data_parsed['dindex'], data_parsed['ptype']) keys = data_parsed['keys'].split('\x01') profile_data = None if profile != None and 'data' in profile: profile_data = gs_query.parse_gamespy_message("\\prof\\" + profile['data'] + "\\final\\") data = "" if profile_data != None: profile_data = profile_data[0][0] for key in (key for key in keys if key not in ("__cmd__", "__cmd_val__", "")): data += "\\" + key + "\\" # this WILL error if profile_data isn't properly set above if key in profile_data: data += profile_data[key] modified = int(time.time()) msg = gs_query.create_gamespy_message([ ('__cmd__', "getpdr"), ('__cmd_val__', 1), ('lid', self.lid), ('pid', self.profileid), ('mod', modified), ('length', len(data)), ('data', data), ]) self.log(logging.DEBUG, "SENDING: '%s'..." % msg)
def perform_setpd(self, data_parsed, data): msg_d = [] msg_d.append(('__cmd__', "setpdr")) msg_d.append(('__cmd_val__', 1)) msg_d.append(('lid', self.lid)) msg_d.append(('pid', self.profileid)) msg_d.append(('mod', int(time.time()))) msg = gs_query.create_gamespy_message(msg_d) self.log(logging.DEBUG, "SENDING: '%s'..." % msg) msg = self.crypt(msg) self.transport.write(bytes(msg)) # TODO: Return error message. if int(data_parsed['pid']) != self.profileid: logger.log(logging.WARNING, "ERROR: %d tried to update %d's profile" % (int(data_parsed['pid']), self.profileid)) return data_str = "\\data\\" length = int(data_parsed['length']) if len(data) < length: # The packet isn't complete yet, keep loop until we get the entire packet. # The length entire packet SHOULD always be greater than the data field, so this check should be fine. return idx = data.index(data_str) + len(data_str) data = data[idx:idx+length] self.db.pd_insert(self.profileid, data_parsed['dindex'], data_parsed['ptype'], data)
def connectionMade(self): try: self.log(logging.INFO, "Received connection from %s:%d", self.address.host, self.address.port) # Generate a random challenge string self.challenge = utils.generate_random_str( 10, "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ) # The first command sent to the client is always a login challenge # containing the server challenge key. msg = gs_query.create_gamespy_message([ ('__cmd__', "lc"), ('__cmd_val__', "1"), ('challenge', self.challenge), ('id', "1"), ]) self.log(logging.DEBUG, "SENDING: '%s'...", msg) msg = self.crypt(msg) self.transport.write(bytes(msg)) except: self.log(logging.ERROR, "Unknown exception: %s", traceback.format_exc())
def perform_getprofile(self, data_parsed): #profile = self.db.get_profile_from_session_key(data_parsed['sesskey']) profile = self.db.get_profile_from_profileid(data_parsed['profileid']) # Wii example: \pi\\profileid\474888031\nick\5pde5vhn1WR9E2g1t533\userid\442778352\email\5pde5vhn1WR9E2g1t533@nds\sig\b126556e5ee62d4da9629dfad0f6b2a8\uniquenick\5pde5vhn1WR9E2g1t533\pid\11\lon\0.000000\lat\0.000000\loc\\id\2\final\ sig = utils.generate_random_hex_str(32) msg_d = [] msg_d.append(('__cmd__', "pi")) msg_d.append(('__cmd_val__', "")) msg_d.append(('profileid', profile['profileid'])) msg_d.append(('nick', profile['uniquenick'])) msg_d.append(('userid', profile['userid'])) msg_d.append(('email', profile['email'])) msg_d.append(('sig', sig)) msg_d.append(('uniquenick', profile['uniquenick'])) msg_d.append(('pid', profile['pid'])) if profile['firstname'] != "": msg_d.append( ('firstname', profile['firstname'])) # Wii gets a firstname if profile['lastname'] != "": msg_d.append(('lastname', profile['lastname'])) msg_d.append(('lon', profile['lon'])) msg_d.append(('lat', profile['lat'])) msg_d.append(('loc', profile['loc'])) msg_d.append(('id', data_parsed['id'])) msg = gs_query.create_gamespy_message(msg_d) self.log(logging.DEBUG, "SENDING: %s" % msg) self.transport.write(bytes(msg))
def perform_otherslist(self, data_parsed): # Reference: http://wiki.tockdom.com/wiki/MKWii_Network_Protocol/Server/gpsp.gs.nintendowifi.net # Example from: filtered-mkw-log-2014-01-01-ct1310.eth # \otherslist\\o\146376154\uniquenick\2m0isbjmvRMCJ2i5321j\o\192817284\uniquenick\1jhggtmghRMCJ2jrsh23\o\302594991\uniquenick\7dkjp51v5RMCJ2nr3vs9\o\368031897\uniquenick\1v7p3qmkpRMCJ1o8f56p\o\447214276\uniquenick\7dkt0p6gtRMCJ2ljh72h\o\449615791\uniquenick\4puvrm1g4RMCJ00ho3v1\o\460250854\uniquenick\4rik5l1u1RMCJ0tc3fii\o\456284963\uniquenick\1unitvi86RMCJ1b10u02\o\453830866\uniquenick\7de3q52dbRMCJ2877ss2\o\450197498\uniquenick\3qtutr1ikRMCJ38gem1n\o\444241868\uniquenick\67tp53bs9RMCJ1abs7ej\o\420030955\uniquenick\5blesqia3RMCJ322bbd6\o\394609454\uniquenick\0hddp7mq2RMCJ30uv7r7\o\369478991\uniquenick\59de9c2bhRMCJ0re0fii\o\362755626\uniquenick\5tte2lif7RMCJ0cscgtg\o\350951571\uniquenick\7aeummjlaRMCJ3li4ls2\o\350740680\uniquenick\484uiqhr4RMCJ18opoj0\o\349855648\uniquenick\5blesqia3RMCJ1c245dn\o\324078642\uniquenick\62go5gpt0RMCJ0v0uhc9\o\304111337\uniquenick\4lcg6ampvRMCJ1gjre51\o\301273266\uniquenick\1dhdpjhn8RMCJ2da6f9h\o\193178453\uniquenick\3pcgu0299RMCJ3nhu50f\o\187210028\uniquenick\3tau15a9lRMCJ2ar247h\o\461622261\uniquenick\59epddrnkRMCJ1t2ge7l\oldone\\final\ msg_d = [ ('__cmd__', "otherslist"), ('__cmd_val__', ""), ] if "numopids" in data_parsed and "opids" in data_parsed: numopids = int(data_parsed['numopids']) opids = data_parsed['opids'].split('|') if (len(opids) != numopids) and (not int(opids[0]) == 0): logger.log(logging.ERROR, "Unexpected number of opids, got %d, expected %d." % (len(opids), numopids)) # Return all uniquenicks despite any unexpected/missing opids for opid in opids: profile = self.db.get_profile_from_profileid(opid) msg_d.append(('o', opid)) if profile != None: msg_d.append(('uniquenick', profile['uniquenick'])) else: msg_d.append(('uniquenick', '')) msg_d.append(('oldone', "")) msg = gs_query.create_gamespy_message(msg_d) logger.log(logging.DEBUG, "SENDING: %s" % msg) self.transport.write(bytes(msg))
def get_status_from_friends(self): # This will be called when the player logs in. Grab the player's buddy list and check the current sessions to # see if anyone is online. If they are online, make them send an update to the calling client. self.buddies = self.db.get_buddy_list(self.profileid) for buddy in self.buddies: if buddy['status'] != 1: continue if buddy['buddyProfileId'] in self.sessions and self.sessions[ buddy['buddyProfileId']].gameid == self.gameid: status_msg = "|s|%s|ss|%s|ls|%s|ip|%d|p|0|qm|0" % ( self.sessions[buddy['buddyProfileId']].status, self.sessions[buddy['buddyProfileId']].statstring, self.sessions[buddy['buddyProfileId']].locstring, self.get_ip_as_int( self.sessions[buddy['buddyProfileId']].address.host)) else: status_msg = "|s|0|ss|Offline" msg_d = [] msg_d.append(('__cmd__', "bm")) msg_d.append(('__cmd_val__', "100")) msg_d.append(('f', buddy['buddyProfileId'])) msg_d.append(('msg', status_msg)) msg = gs_query.create_gamespy_message(msg_d) self.transport.write(bytes(msg))
def connectionMade(self): try: self.transport.setTcpKeepAlive(1) self.log(logging.INFO, "Received connection from %s:%d", self.address.host, self.address.port) # Create new session id self.session = "" # Generate a random challenge string self.challenge = utils.generate_random_str( 10, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") # The first command sent to the client is always a login challenge # containing the server challenge key. msg = gs_query.create_gamespy_message([ ('__cmd__', "lc"), ('__cmd_val__', "1"), ('challenge', self.challenge), ('id', "1"), ]) self.log(logging.DEBUG, "SENDING: '%s'...", msg) self.transport.write(bytes(msg)) except: self.log(logging.ERROR, "Unknown exception: %s", traceback.format_exc())
def perform_getpd(self, data_parsed): profile = self.db.pd_get(self.profileid, data_parsed['dindex'], data_parsed['ptype']) data = "" keys = data_parsed['keys'].split('\x01') profile_data = None if profile != None and 'data' in profile: profile_data = gs_query.parse_gamespy_message("\\prof\\" + profile['data'] + "\\final\\") if profile_data != None: profile_data = profile_data[0][0] for key in keys: if key != "__cmd__" and key != "__cmd_val__" and key != "": data += "\\" data += key data += "\\" if key in profile_data: data += profile_data[key] modified = int(time.time()) msg_d = [] msg_d.append(('__cmd__', "getpdr")) msg_d.append(('__cmd_val__', 1)) msg_d.append(('lid', self.lid)) msg_d.append(('pid', self.profileid)) msg_d.append(('mod', modified)) msg_d.append(('length', len(data))) msg_d.append(('data', data)) msg = gs_query.create_gamespy_message(msg_d) self.log(logging.DEBUG, "SENDING: '%s'..." % msg)
def perform_getprofile(self, data_parsed): #profile = self.db.get_profile_from_session_key(data_parsed['sesskey']) profile = self.db.get_profile_from_profileid(data_parsed['profileid']) # Wii example: \pi\\profileid\474888031\nick\5pde5vhn1WR9E2g1t533\userid\442778352\email\5pde5vhn1WR9E2g1t533@nds\sig\b126556e5ee62d4da9629dfad0f6b2a8\uniquenick\5pde5vhn1WR9E2g1t533\pid\11\lon\0.000000\lat\0.000000\loc\\id\2\final\ sig = utils.generate_random_hex_str(32) msg_d = [ ('__cmd__', "pi"), ('__cmd_val__', ""), ('profileid', profile['profileid']), ('nick', profile['uniquenick']), ('userid', profile['userid']), ('email', profile['email']), ('sig', sig), ('uniquenick', profile['uniquenick']), ('pid', profile['pid']), ] if profile['firstname'] != "": msg_d.append(('firstname', profile['firstname'])) # Wii gets a firstname if profile['lastname'] != "": msg_d.append(('lastname', profile['lastname'])) msg_d.extend([ ('lon', profile['lon']), ('lat', profile['lat']), ('loc', profile['loc']), ('id', data_parsed['id']), ]) msg = gs_query.create_gamespy_message(msg_d) self.log(logging.DEBUG, "SENDING: %s" % msg) self.transport.write(bytes(msg))
def perform_setpd(self, data_parsed, data): msg_d = [] msg_d.append(('__cmd__', "setpdr")) msg_d.append(('__cmd_val__', 1)) msg_d.append(('lid', self.lid)) msg_d.append(('pid', self.profileid)) msg_d.append(('mod', int(time.time()))) msg = gs_query.create_gamespy_message(msg_d) self.log(logging.DEBUG, "SENDING: '%s'..." % msg) msg = self.crypt(msg) self.transport.write(bytes(msg)) # TODO: Return error message. if int(data_parsed['pid']) != self.profileid: logger.log( logging.WARNING, "ERROR: %d tried to update %d's profile" % (int(data_parsed['pid']), self.profileid)) return data_str = "\\data\\" length = int(data_parsed['length']) idx = data.index(data_str) + len(data_str) data = data[idx:idx + length] self.db.pd_insert(self.profileid, data_parsed['dindex'], data_parsed['ptype'], data)
def perform_otherslist(self, data_parsed): # Reference: http://wiki.tockdom.com/wiki/MKWii_Network_Protocol/Server/gpsp.gs.nintendowifi.net # Example from: filtered-mkw-log-2014-01-01-ct1310.eth # \otherslist\\o\146376154\uniquenick\2m0isbjmvRMCJ2i5321j\o\192817284\uniquenick\1jhggtmghRMCJ2jrsh23\o\302594991\uniquenick\7dkjp51v5RMCJ2nr3vs9\o\368031897\uniquenick\1v7p3qmkpRMCJ1o8f56p\o\447214276\uniquenick\7dkt0p6gtRMCJ2ljh72h\o\449615791\uniquenick\4puvrm1g4RMCJ00ho3v1\o\460250854\uniquenick\4rik5l1u1RMCJ0tc3fii\o\456284963\uniquenick\1unitvi86RMCJ1b10u02\o\453830866\uniquenick\7de3q52dbRMCJ2877ss2\o\450197498\uniquenick\3qtutr1ikRMCJ38gem1n\o\444241868\uniquenick\67tp53bs9RMCJ1abs7ej\o\420030955\uniquenick\5blesqia3RMCJ322bbd6\o\394609454\uniquenick\0hddp7mq2RMCJ30uv7r7\o\369478991\uniquenick\59de9c2bhRMCJ0re0fii\o\362755626\uniquenick\5tte2lif7RMCJ0cscgtg\o\350951571\uniquenick\7aeummjlaRMCJ3li4ls2\o\350740680\uniquenick\484uiqhr4RMCJ18opoj0\o\349855648\uniquenick\5blesqia3RMCJ1c245dn\o\324078642\uniquenick\62go5gpt0RMCJ0v0uhc9\o\304111337\uniquenick\4lcg6ampvRMCJ1gjre51\o\301273266\uniquenick\1dhdpjhn8RMCJ2da6f9h\o\193178453\uniquenick\3pcgu0299RMCJ3nhu50f\o\187210028\uniquenick\3tau15a9lRMCJ2ar247h\o\461622261\uniquenick\59epddrnkRMCJ1t2ge7l\oldone\\final\ msg_d = [] msg_d.append(('__cmd__', "otherslist")) msg_d.append(('__cmd_val__', "")) if "numopids" in data_parsed and "opids" in data_parsed: numopids = int(data_parsed['numopids']) opids = data_parsed['opids'].split('|') if (len(opids) != numopids) and (not int(opids[0]) == 0): logger.log( logging.ERROR, "Unexpected number of opids, got %d, expected %d." % (len(opids), numopids)) # Return all uniquenicks despite any unexpected/missing opids for opid in opids: profile = self.db.get_profile_from_profileid(opid) msg_d.append(('o', opid)) if profile != None: msg_d.append(('uniquenick', profile['uniquenick'])) else: msg_d.append(('uniquenick', '')) msg_d.append(('oldone', "")) msg = gs_query.create_gamespy_message(msg_d) self.transport.write(bytes(msg))
def perform_setpd(self, data_parsed, data): msg_d = [] msg_d.append(('__cmd__', "setpdr")) msg_d.append(('__cmd_val__', 1)) msg_d.append(('lid', self.lid)) msg_d.append(('pid', self.profileid)) msg_d.append(('mod', int(time.time()))) msg = gs_query.create_gamespy_message(msg_d) self.log(logging.DEBUG, "SENDING: '%s'..." % msg) msg = self.crypt(msg) self.transport.write(bytes(msg)) # TODO: Return error message. if int(data_parsed['pid']) != self.profileid: logger.log(logging.WARNING, "ERROR: %d tried to update %d's profile" % (int(data_parsed['pid']), self.profileid)) return data_str = "\\data\\" length = int(data_parsed['length']) idx = data.index(data_str) + len(data_str) data = data[idx:idx+length] self.db.pd_insert(self.profileid, data_parsed['dindex'], data_parsed['ptype'], data)
def perform_setpd(self, data_parsed, data): msg_d = [] msg_d.append(('__cmd__', "setpdr")) msg_d.append(('__cmd_val__', 1)) msg_d.append(('lid', self.lid)) msg_d.append(('pid', self.profileid)) msg_d.append(('mod', int(time.time()))) msg = gs_query.create_gamespy_message(msg_d) self.log(logging.DEBUG, "SENDING: '%s'..." % msg) msg = self.crypt(msg) self.transport.write(bytes(msg)) # TODO: Return error message. if int(data_parsed['pid']) != self.profileid: logger.log( logging.WARNING, "ERROR: %d tried to update %d's profile" % (int(data_parsed['pid']), self.profileid)) return data_str = "\\data\\" length = int(data_parsed['length']) if len(data) < length: # The packet isn't complete yet, keep loop until we get the entire packet. # The length entire packet SHOULD always be greater than the data field, so this check should be fine. return idx = data.index(data_str) + len(data_str) data = data[idx:idx + length] self.db.pd_insert(self.profileid, data_parsed['dindex'], data_parsed['ptype'], data)
def perform_ka(self, data_parsed): self.keepalive = int(time.time()) msg = gs_query.create_gamespy_message([ ('__cmd__', "ka"), ('__cmd_val__', ""), ]) self.transport.write(msg)
def perform_ka(self, data_parsed): msg = gs_query.create_gamespy_message([('__cmd__', "ka"), ('__cmd_val__', ""),]) self.log(logging.DEBUG, "SENDING: '%s'..." % msg) msg = self.crypt(msg) self.transport.write(bytes(msg)) return
def send_bm4(self, playerid): date = int(time.time()) msg = gs_query.create_gamespy_message([ ('__cmd__', "bm"), ('__cmd_val__', "4"), ('f', playerid), ('date', date), ('msg', ""), ]) self.transport.write(bytes(msg))
def perform_ka(self, data_parsed): msg = gs_query.create_gamespy_message([ ('__cmd__', "ka"), ('__cmd_val__', ""), ]) self.log(logging.DEBUG, "SENDING: '%s'...", msg) msg = self.crypt(msg) self.transport.write(bytes(msg)) return
def perform_setpd(self, data_parsed): data = self.data msg = gs_query.create_gamespy_message([ ('__cmd__', "setpdr"), ('__cmd_val__', 1), ('lid', self.lid), ('pid', self.profileid), ('mod', int(time.time())), ]) self.log(logging.DEBUG, "SENDING: '%s'..." % msg) msg = self.crypt(msg) self.transport.write(bytes(msg)) # TODO: Return error message. if int(data_parsed['pid']) != self.profileid: logger.log(logging.WARNING, "ERROR: %d tried to update %d's profile" % (int(data_parsed['pid']), self.profileid)) return data_str = "\\data\\" length = int(data_parsed['length']) if len(data) < length: # The packet isn't complete yet, keep loop until we get the entire packet. # The length entire packet SHOULD always be greater than the data field, so this check should be fine. return if data_str in data: idx = data.index(data_str) + len(data_str) data = data[idx:idx+length].rstrip("\\") else: logger.log(logging.ERROR, "ERROR: Could not find \data\ in setpd command: %s", data) data = "" current_data = self.db.pd_get(self.profileid, data_parsed['dindex'], data_parsed['ptype']) if current_data and data and 'data' in current_data: current_data = current_data['data'].lstrip('\\').split('\\') new_data = data.lstrip('\\').split('\\') current_data = dict(zip(current_data[0::2],current_data[1::2])) new_data = dict(zip(new_data[0::2],new_data[1::2])) for k in new_data.keys(): current_data[k] = new_data[k] data = "\\" for k in current_data.keys(): data += k+"\\"+current_data[k]+"\\" data = data.rstrip("\\")#Don't put trailing \ into db self.db.pd_insert(self.profileid, data_parsed['dindex'], data_parsed['ptype'], data)
def get_buddy_authorized(self): buddies = self.db.buddy_need_auth_message(self.profileid) for buddy in buddies: msg = gs_query.create_gamespy_message([ ('__cmd__', "bm"), ('__cmd_val__', "1"), ('f', buddy['userProfileId']), ('msg', "I have authorized your request to add me to your list"), ]) self.transport.write(bytes(msg)) self.db.buddy_sent_auth_message(buddy['userProfileId'], buddy['buddyProfileId'])
def send_buddy_request(self, session, profileid, senttime=None): sig = utils.generate_random_hex_str(32) msg = "\r\n\r\n" msg += "|signed|" + sig if senttime is None: senttime = int(time.time()) msg = gs_query.create_gamespy_message( [("__cmd__", "bm"), ("__cmd_val__", "2"), ("f", profileid), ("date", senttime), ("msg", msg)] ) session.transport.write(bytes(msg))
def perform_getpd(self, data_parsed): pid = int(data_parsed['pid']) profile = self.db.pd_get(pid, data_parsed['dindex'], data_parsed['ptype']) if profile == None: self.log(logging.WARNING, "Could not find profile for %d %s %s" % (pid, data_parsed['dindex'], data_parsed['ptype'])) keys = data_parsed['keys'].split('\x01') profile_data = None data = "" # Someone figure out if this is actually a good way to handle this when no profile is found if profile != None and 'data' in profile: profile_data = profile['data'] if profile_data.endswith("\\"): profile_data = profile_data[:-1] profile_data = gs_query.parse_gamespy_message("\\prof\\" + profile_data + "\\final\\") if profile_data != None: profile_data = profile_data[0][0] else: self.log(logging.WARNING, "Could not get data section from profile for %d" % pid) if len(keys) > 0 and keys[0] != "": for key in (key for key in keys if key not in ("__cmd__", "__cmd_val__", "")): data += "\\" + key + "\\" if profile_data != None and key in profile_data: data += profile_data[key] else: self.log(logging.WARNING, "No keys requested, defaulting to all keys: %s" % (profile['data'])) data = profile['data'] modified = int(time.time()) msg = gs_query.create_gamespy_message([ ('__cmd__', "getpdr"), ('__cmd_val__', 1), ('lid', self.lid), ('pid', pid), ('mod', modified), ('length', len(data)), ('data', data), ]) self.log(logging.DEBUG, "SENDING: '%s'..." % msg) msg = self.crypt(msg) self.transport.write(bytes(msg))
def perform_getpd(self, data_parsed): logger.log(logging.DEBUG, "FIXME: Implement getpd: %s" % data_parsed) # Return all of the data regardless of whatever the parameters passed to the function are. # I'll properly implement this once I get a real example of it in action. data = self.db.pd_get(self.profileid, data_parsed['dindex'], data_parsed['ptype']) msg_d = [] msg_d.append(('__cmd__', "getpdr")) msg_d.append(('__cmd_val__', 1)) msg_d.append(('lid', self.lid)) msg_d.append(('pid', self.profileid)) msg_d.append(('length', len(data))) msg_d.append(('data', data)) msg = gs_query.create_gamespy_message(msg_d)
def get_buddy_authorized(self): buddies = self.db.buddy_need_auth_message(self.profileid) for buddy in buddies: msg = gs_query.create_gamespy_message( [ ("__cmd__", "bm"), ("__cmd_val__", "1"), ("f", buddy["userProfileId"]), ("msg", "I have authorized your request to add me to" " your list"), ] ) self.transport.write(bytes(msg)) self.db.buddy_sent_auth_message(buddy["userProfileId"], buddy["buddyProfileId"])
def perform_bm(self, data_parsed): if data_parsed['__cmd_val__'] == "1": # Message to/from clients? if "t" in data_parsed: # Send message to the profile id in "t" dest_profileid = int(data_parsed['t']) dest_msg = data_parsed['msg'] msg_d = [] msg_d.append(('__cmd__', "bm")) msg_d.append(('__cmd_val__', "1")) msg_d.append(('f', self.profileid)) msg_d.append(('msg', dest_msg)) msg = gs_query.create_gamespy_message(msg_d) self.log(logging.DEBUG, "SENDING TO %s:%s: %s" % (self.sessions[dest_profileid].address.host, self.sessions[dest_profileid].address.port, msg)) self.sessions[dest_profileid].transport.write(bytes(msg))
def send_status_to_friends(self): # TODO: Cache buddy list so we don't have to query the database every time buddies = self.db.get_buddy_list(self.profileid) status_msg = "|s|%s|ss|%s|ls|%s|ip|%d|p|0|qm|0" % (self.status, self.statstring, self.locstring, self.get_ip_as_int(self.address.host)) msg_d = [] msg_d.append(('__cmd__', "bm")) msg_d.append(('__cmd_val__', "100")) msg_d.append(('f', self.profileid)) msg_d.append(('msg', status_msg)) msg = gs_query.create_gamespy_message(msg_d) for buddy in buddies: if buddy['buddyProfileId'] in self.sessions: self.sessions[buddy['buddyProfileId']].transport.write(bytes(msg))
def send_buddy_request(self, session, profileid, senttime=None): sig = utils.generate_random_hex_str(32) msg = "\r\n\r\n" msg += "|signed|" + sig if senttime == None: senttime = int(time.time()) msg_d = [] msg_d.append(('__cmd__', "bm")) msg_d.append(('__cmd_val__', "2")) msg_d.append(('f', profileid)) msg_d.append(('date', senttime)) msg_d.append(('msg', msg)) msg = gs_query.create_gamespy_message(msg_d) session.transport.write(bytes(msg))
def send_buddy_request(self, session, profileid, senttime = None): sig = utils.generate_random_hex_str(32) msg = "\r\n\r\n" msg += "|signed|" + sig if senttime == None: senttime = int(time.time()) msg_d = [] msg_d.append(('__cmd__', "bm")) msg_d.append(('__cmd_val__', "2")) msg_d.append(('f', profileid)) msg_d.append(('date', senttime)) msg_d.append(('msg', msg)) msg = gs_query.create_gamespy_message(msg_d) session.transport.write(bytes(msg))
def connectionMade(self): self.log(logging.INFO, "Received connection from %s:%d" % (self.address.host, self.address.port)) # Generate a random challenge string self.challenge = utils.generate_random_str(10, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") # The first command sent to the client is always a login challenge containing the server challenge key. msg_d = [] msg_d.append(('__cmd__', "lc")) msg_d.append(('__cmd_val__', "1")) msg_d.append(('challenge', self.challenge)) msg_d.append(('id', "1")) msg = gs_query.create_gamespy_message(msg_d) self.log(logging.DEBUG, "SENDING: '%s'..." % msg) msg = self.crypt(msg) self.transport.write(bytes(msg))
def perform_auth(self, data_parsed): self.log(logging.DEBUG, "Parsing 'auth'...") if "gamename" in data_parsed: self.gameid = data_parsed['gamename'] self.session = utils.generate_random_number_str(10) msg = gs_query.create_gamespy_message([('__cmd__', "lc"), ('__cmd_val__', "2"), ('sesskey', self.session), ('proof', 0), ('id', "1"),]) self.log(logging.DEBUG, "SENDING: '%s'..." % msg) msg = self.crypt(msg) self.transport.write(bytes(msg))
def get_buddy_requests(self): # Get list people who have added the user but haven't been accepted yet. buddies = self.db.get_pending_buddy_requests(self.profileid) profile = self.db.get_profile_from_profileid(self.profileid) sig = utils.generate_random_hex_str(32) msg = "\r\n\r\n" msg += "|signed|" + sig for buddy in buddies: msg_d = [] msg_d.append(('__cmd__', "bm")) msg_d.append(('__cmd_val__', "2")) msg_d.append(('f', buddy['userProfileId'])) msg_d.append(('date', buddy['time'])) msg_d.append(('msg', msg)) msg = gs_query.create_gamespy_message(msg_d) self.transport.write(bytes(msg))
def send_status_to_friends(self): # TODO: Cache buddy list so we don't have to query the database every time self.buddies = self.db.get_buddy_list(self.profileid) if self.status == "0" and self.statstring == "Offline": # Going offline, don't need to send the other information. status_msg = "|s|%s|ss|%s" % (self.status, self.statstring) else: status_msg = "|s|%s|ss|%s|ls|%s|ip|%d|p|0|qm|0" % (self.status, self.statstring, self.locstring, self.get_ip_as_int(self.address.host)) msg = gs_query.create_gamespy_message([ ('__cmd__', "bm"), ('__cmd_val__', "100"), ('f', self.profileid), ('msg', status_msg), ]) for buddy in self.buddies: if buddy['buddyProfileId'] in self.sessions: self.sessions[buddy['buddyProfileId']].transport.write(bytes(msg))
def perform_auth(self, data_parsed): self.log(logging.DEBUG, "%s", "Parsing 'auth'...") if "gamename" in data_parsed: self.gameid = data_parsed['gamename'] self.session = utils.generate_random_number_str(10) msg = gs_query.create_gamespy_message([ ('__cmd__', "lc"), ('__cmd_val__', "2"), ('sesskey', self.session), ('proof', 0), ('id', "1"), ]) self.log(logging.DEBUG, "SENDING: '%s'...", msg) msg = self.crypt(msg) self.transport.write(bytes(msg))
def perform_getprofile(self, data_parsed): # profile = self.db.get_profile_from_session_key( # data_parsed['sesskey'] # ) profile = self.db.get_profile_from_profileid(data_parsed["profileid"]) # Wii example: # \pi\\profileid\474888031\nick\5pde5vhn1WR9E2g1t533\userid\442778352 # \email\5pde5vhn1WR9E2g1t533@nds\sig\b126556e5ee62d4da9629dfad0f6b2a8 # \uniquenick\5pde5vhn1WR9E2g1t533\pid\11\lon\0.000000\lat\0.000000 # \loc\\id\2\final\ sig = utils.generate_random_hex_str(32) msg_d = [ ("__cmd__", "pi"), ("__cmd_val__", ""), ("profileid", profile["profileid"]), ("nick", profile["uniquenick"]), ("userid", profile["userid"]), ("email", profile["email"]), ("sig", sig), ("uniquenick", profile["uniquenick"]), ("pid", profile["pid"]), ] if profile["firstname"]: # Wii gets a firstname msg_d.append(("firstname", profile["firstname"])) if profile["lastname"]: msg_d.append(("lastname", profile["lastname"])) msg_d.extend( [("lon", profile["lon"]), ("lat", profile["lat"]), ("loc", profile["loc"]), ("id", data_parsed["id"])] ) msg = gs_query.create_gamespy_message(msg_d) self.log(logging.DEBUG, "SENDING: %s", msg) self.transport.write(bytes(msg))
def send_status_to_friends(self): # TODO: Cache buddy list so we don't have to query the database every time self.buddies = self.db.get_buddy_list(self.profileid) if self.status == "0" and self.statstring == "Offline": # Going offline, don't need to send the other information. status_msg = "|s|%s|ss|%s" % (self.status, self.statstring) else: status_msg = "|s|%s|ss|%s|ls|%s|ip|%d|p|0|qm|0" % ( self.status, self.statstring, self.locstring, self.get_ip_as_int(self.address.host)) msg_d = [] msg_d.append(('__cmd__', "bm")) msg_d.append(('__cmd_val__', "100")) msg_d.append(('f', self.profileid)) msg_d.append(('msg', status_msg)) msg = gs_query.create_gamespy_message(msg_d) for buddy in self.buddies: if buddy['buddyProfileId'] in self.sessions: self.sessions[buddy['buddyProfileId']].transport.write( bytes(msg))
def perform_getpd(self, data_parsed): pid = int(data_parsed['pid']) profile = self.db.pd_get(pid, data_parsed['dindex'], data_parsed['ptype']) if profile == None: self.log(logging.WARNING, "Could not find profile for %d %s %s" % (pid, data_parsed['dindex'], data_parsed['ptype'])) keys = data_parsed['keys'].split('\x01') profile_data = None data = "" # Someone figure out if this is actually a good way to handle this when # no profile is found if profile != None and 'data' in profile: profile_data = profile['data'] if profile_data.endswith("\\"): profile_data = profile_data[:-1] profile_data = gs_query.parse_gamespy_message("\\prof\\" + profile_data + "\\final\\") if profile_data != None: profile_data = profile_data[0][0] else: self.log(logging.WARNING, "Could not get data section from profile for %d" % pid) if len(keys): for key in (key for key in keys if key not in ("__cmd__", "__cmd_val__", "")): data += "\\" + key + "\\" if profile_data != None and key in profile_data: data += profile_data[key] else: self.log(logging.WARNING, "No keys requested, defaulting to all keys: %s" % (profile['data'])) data = profile['data'] modified = int(time.time()) msg = gs_query.create_gamespy_message([('__cmd__', "getpdr"), ('__cmd_val__', 1), ('lid', self.lid), ('pid', pid), ('mod', modified), ('length', len(data)), ('data', data),]) msg = msg.replace("\\data\\","\\data\\\\") # data needs to be preceded by an extra slash datastring = "" try: datastring = re.findall('.*data\\\\(.*)',msg)[0].replace("\\final\\","") except: pass # This works because the data string is a key-value pair, splitting the # string by \ should yield a list with an even number of elements. # But, # because of the extra \ prepended to the datastring, it'll be odd. # So ultimately I expect the list to have an odd number of elements. # If it's even, len(list)%2 will be zero... and that means the last # field in the datastring is empty and doesn't have a closing \. if datastring and not len(datastring.split('\\')) % 2: msg = msg.replace("\\final\\","\\\\final\\") # An empty field must be terminated by \ before \final\ self.log(logging.DEBUG, "SENDING: '%s'..." % msg) msg = self.crypt(msg) self.transport.write(bytes(msg))
def perform_login(self, data_parsed): authtoken_parsed = gs_utils.parse_authtoken(data_parsed['authtoken'], self.db) if authtoken_parsed == None: self.log(logging.WARNING, "Invalid Authtoken.") msg = gs_query.create_gamespy_message([ ('__cmd__', "error"), ('__cmd_val__', ""), ('err', '266'), ('fatal', ''), ('errmsg', 'There was an error validating the pre-authentication.'), ('id', data_parsed['id']), ]) self.transport.write(bytes(msg)) return if 'sdkrevision' in data_parsed: self.sdkrevision = data_parsed['sdkrevision'] # Verify the client's response valid_response = gs_utils.generate_response(self.challenge, authtoken_parsed['challenge'], data_parsed['challenge'], data_parsed['authtoken']) if data_parsed['response'] != valid_response: self.log(logging.ERROR, "ERROR: Got invalid response. Got %s, expected %s" % (data_parsed['response'], valid_response)) proof = gs_utils.generate_proof(self.challenge, authtoken_parsed['challenge'], data_parsed['challenge'], data_parsed['authtoken']) userid, profileid, gsbrcd, uniquenick = gs_utils.login_profile_via_parsed_authtoken(authtoken_parsed, self.db) if profileid != None: # Successfully logged in or created account, continue creating session. loginticket = gs_utils.base64_encode(utils.generate_random_str(16)) self.sesskey = self.db.create_session(profileid, loginticket) self.sessions[profileid] = self self.buddies = self.db.get_buddy_list(self.profileid) self.blocked = self.db.get_blocked_list(self.profileid) if self.sdkrevision == "11": # Used in Tatsunoko vs Capcom def make_list(data): list = [] for d in data: if d['status'] == 1: list.append(str(d['buddyProfileId'])) return list block_list = make_list(self.blocked) msg = gs_query.create_gamespy_message([ ('__cmd__', "blk"), ('__cmd_val__', str(len(block_list))), ('list', ','.join(block_list)), ]) self.log(logging.DEBUG, "SENDING: %s" % msg) self.transport.write(bytes(msg)) buddy_list = make_list(self.buddies) msg = gs_query.create_gamespy_message([ ('__cmd__', "bdy"), ('__cmd_val__', str(len(buddy_list))), ('list', ','.join(buddy_list)), ]) self.log(logging.DEBUG, "SENDING: %s" % msg) self.transport.write(bytes(msg)) msg = gs_query.create_gamespy_message([ ('__cmd__', "lc"), ('__cmd_val__', "2"), ('sesskey', self.sesskey), ('proof', proof), ('userid', userid), ('profileid', profileid), ('uniquenick', uniquenick), # Some kind of token... don't know it gets used or generated, but it doesn't seem to have any negative effects if it's not properly generated. ('lt', loginticket), ('id', data_parsed['id']), ]) # Take the first 4 letters of gsbrcd instead of gamecd because they should be consistent across game # regions. For example, the US version of Metroid Prime Hunters has the gamecd "AMHE" and the first 4 letters # of gsbrcd are "AMHE". However, the Japanese version of Metroid Prime Hunters has the gamecd "AMHJ" with # the first 4 letters of bsbrcd as "AMHE". Tetris DS is the other way, with the first 4 letters as the # Japanese version (ATRJ) while the gamecd is region specific (ATRE for US and ATRJ for JP). # gameid is used to send all people on the player's friends list a status updates, so don't make it region # specific. self.gameid = gsbrcd[:4] self.profileid = int(profileid) self.log(logging.DEBUG, "SENDING: %s" % msg) self.transport.write(bytes(msg)) # Get pending messages. self.get_pending_messages() # Send any friend statuses when the user logs in. # This will allow the user to see if their friends are hosting a game as soon as they log in. self.get_status_from_friends() self.send_status_to_friends() # profile = self.db.get_profile_from_profileid(profileid) # if profile != None: # self.statstring = profile['stat'] # self.locstring = profile['loc'] else: self.log(logging.INFO, "Invalid password or banned user") msg = gs_query.create_gamespy_message([ ('__cmd__', "error"), ('__cmd_val__', ""), ('err', '256'), ('fatal', ''), ('errmsg', 'Login failed.'), ('id', data_parsed['id']), ]) self.log(logging.DEBUG, "SENDING: %s" % msg) self.transport.write(bytes(msg))
def perform_login(self, data_parsed): authtoken_parsed = gs_utils.parse_authtoken(data_parsed['authtoken'], self.db) #print authtoken_parsed # Track what console is connecting and save it in the database during user creation just in case we can use # the information in the future. console = 0 # 0 = NDS, 1 = Wii # get correct information userid = authtoken_parsed['userid'] # The Wii does not use passwd, so take another uniquely generated string as the password. if "passwd" in authtoken_parsed: password = authtoken_parsed['passwd'] else: password = authtoken_parsed['gsbrcd'] console = 1 gsbrcd = authtoken_parsed['gsbrcd'] gameid = gsbrcd[:4] uniquenick = utils.base32_encode(int(userid)) + gsbrcd email = uniquenick + "@nds" # The Wii also seems to use @nds. # Wii: Serial number if "csnum" in authtoken_parsed: csnum = authtoken_parsed['csnum'] console = 1 else: csnum = "" # Wii: Friend code if "cfc" in authtoken_parsed: cfc = authtoken_parsed['cfc'] console = 1 else: cfc = "" # NDS: Wifi network's BSSID if "bssid" in authtoken_parsed: bssid = authtoken_parsed['bssid'] else: bssid = "" # NDS: Device name if "devname" in authtoken_parsed: devname = authtoken_parsed['devname'] else: devname = "" # NDS: User's birthday if "birth" in authtoken_parsed: birth = authtoken_parsed['birth'] else: birth = "" # Verify the client's response valid_response = gs_utils.generate_response( self.challenge, authtoken_parsed['challenge'], data_parsed['challenge'], data_parsed['authtoken']) if data_parsed['response'] != valid_response: self.log( logging.ERROR, "ERROR: Got invalid response. Got %s, expected %s" % (data_parsed['response'], valid_response)) proof = gs_utils.generate_proof(self.challenge, authtoken_parsed['challenge'], data_parsed['challenge'], data_parsed['authtoken']) valid_user = self.db.check_user_exists(userid, gsbrcd) if valid_user == False: profileid = self.db.create_user(userid, password, email, uniquenick, gsbrcd, console, csnum, cfc, bssid, devname, birth, gameid) else: profileid = self.db.perform_login(userid, password, gsbrcd) if profileid == None: # Handle case where the user is invalid self.log(logging.ERROR, "Invalid password") if profileid != None: # Successfully logged in or created account, continue creating session. sesskey = self.db.create_session(profileid) self.sessions[profileid] = self msg_d = [] msg_d.append(('__cmd__', "lc")) msg_d.append(('__cmd_val__', "2")) msg_d.append(('sesskey', sesskey)) msg_d.append(('proof', proof)) msg_d.append(('userid', userid)) msg_d.append(('profileid', profileid)) msg_d.append(('uniquenick', uniquenick)) msg_d.append( ('lt', gs_utils.base64_encode(utils.generate_random_str(16))) ) # Some kind of token... don't know it gets used or generated, but it doesn't seem to have any negative effects if it's not properly generated. msg_d.append(('id', data_parsed['id'])) msg = gs_query.create_gamespy_message(msg_d) # Take the first 4 letters of gsbrcd instead of gamecd because they should be consistent across game # regions. For example, the US version of Metroid Prime Hunters has the gamecd "AMHE" and the first 4 letters # of gsbrcd are "AMHE". However, the Japanese version of Metroid Prime Hunters has the gamecd "AMHJ" with # the first 4 letters of bsbrcd as "AMHE". Tetris DS is the other way, with the first 4 letters as the # Japanese version (ATRJ) while the gamecd is region specific (ATRE for US and ATRJ for JP). # gameid is used to send all people on the player's friends list a status updates, so don't make it region # specific. self.gameid = gsbrcd[0:4] self.profileid = int(profileid) self.log(logging.DEBUG, "SENDING: %s" % msg) self.transport.write(bytes(msg)) self.buddies = self.db.get_buddy_list(self.profileid) self.blocked = self.db.get_blocked_list(self.profileid) # Get pending messages. self.get_pending_messages() # Send any friend statuses when the user logs in. # This will allow the user to see if their friends are hosting a game as soon as they log in. self.get_status_from_friends() self.send_status_to_friends()
def perform_login(self, data_parsed): authtoken_parsed = gs_utils.parse_authtoken(data_parsed['authtoken'], self.db) if authtoken_parsed is None: self.log(logging.WARNING, "%s", "Invalid Authtoken.") msg = gs_query.create_gamespy_message([ ('__cmd__', "error"), ('__cmd_val__', ""), ('err', '266'), ('fatal', ''), ('errmsg', 'There was an error validating the' ' pre-authentication.'), ('id', data_parsed['id']), ]) self.transport.write(bytes(msg)) return if 'sdkrevision' in data_parsed: self.sdkrevision = data_parsed['sdkrevision'] # Verify the client's response valid_response = gs_utils.generate_response( self.challenge, authtoken_parsed['challenge'], data_parsed['challenge'], data_parsed['authtoken']) if data_parsed['response'] != valid_response: self.log(logging.ERROR, "ERROR: Got invalid response." " Got %s, expected %s", data_parsed['response'], valid_response) proof = gs_utils.generate_proof(self.challenge, authtoken_parsed['challenge'], data_parsed['challenge'], data_parsed['authtoken']) userid, profileid, gsbrcd, uniquenick = \ gs_utils.login_profile_via_parsed_authtoken(authtoken_parsed, self.db) if profileid is not None: # Successfully logged in or created account, continue # creating session. loginticket = gs_utils.base64_encode(utils.generate_random_str(16)) self.sesskey = self.db.create_session(profileid, loginticket) self.sessions[profileid] = self self.buddies = self.db.get_buddy_list(self.profileid) self.blocked = self.db.get_blocked_list(self.profileid) if self.sdkrevision == "11": # Used in Tatsunoko vs Capcom def make_list(data): return [ str(d['buddyProfileId']) for d in data if d['status'] == 1 ] block_list = make_list(self.blocked) msg = gs_query.create_gamespy_message([ ('__cmd__', "blk"), ('__cmd_val__', str(len(block_list))), ('list', ','.join(block_list)), ]) self.log(logging.DEBUG, "SENDING: %s", msg) self.transport.write(bytes(msg)) buddy_list = make_list(self.buddies) msg = gs_query.create_gamespy_message([ ('__cmd__', "bdy"), ('__cmd_val__', str(len(buddy_list))), ('list', ','.join(buddy_list)), ]) self.log(logging.DEBUG, "SENDING: %s", msg) self.transport.write(bytes(msg)) msg = gs_query.create_gamespy_message([ ('__cmd__', "lc"), ('__cmd_val__', "2"), ('sesskey', self.sesskey), ('proof', proof), ('userid', userid), ('profileid', profileid), ('uniquenick', uniquenick), # Some kind of token... don't know it gets used or generated, # but it doesn't seem to have any negative effects if it's # not properly generated. ('lt', loginticket), ('id', data_parsed['id']), ]) # Take the first 4 letters of gsbrcd instead of gamecd because # they should be consistent across game regions. For example, the # US version of Metroid Prime Hunters has the gamecd "AMHE" and # the first 4 letters of gsbrcd are "AMHE". However, the Japanese # version of Metroid Prime Hunters has the gamecd "AMHJ" with the # first 4 letters of bsbrcd as "AMHE". Tetris DS is the other way, # with the first 4 letters as the Japanese version (ATRJ) while # the gamecd is region specific (ATRE for US and ATRJ for JP). # gameid is used to send all people on the player's friends list a # status updates, so don't make it region specific. self.gameid = gsbrcd[:4] self.profileid = int(profileid) self.log(logging.DEBUG, "SENDING: %s", msg) self.transport.write(bytes(msg)) # Get pending messages. self.get_pending_messages() # Send any friend statuses when the user logs in. # This will allow the user to see if their friends are hosting a # game as soon as they log in. self.get_status_from_friends() self.send_status_to_friends() # profile = self.db.get_profile_from_profileid(profileid) # if profile is not None: # self.statstring = profile['stat'] # self.locstring = profile['loc'] else: self.log(logging.INFO, "%s", "Invalid password or banned user") msg = gs_query.create_gamespy_message([ ('__cmd__', "error"), ('__cmd_val__', ""), ('err', '256'), ('fatal', ''), ('errmsg', 'Login failed.'), ('id', data_parsed['id']), ]) self.log(logging.DEBUG, "SENDING: %s", msg) self.transport.write(bytes(msg))
def perform_getpd(self, data_parsed): pid = int(data_parsed['pid']) profile = self.db.pd_get(pid, data_parsed['dindex'], data_parsed['ptype']) if profile is None: self.log(logging.WARNING, "Could not find profile for %d %s %s", pid, data_parsed['dindex'], data_parsed['ptype']) keys = data_parsed['keys'].split('\x01') profile_data = None data = "" # Someone figure out if this is actually a good way to handle this # when no profile is found if profile is not None and 'data' in profile: profile_data = profile['data'] if profile_data.endswith("\\"): profile_data = profile_data[:-1] profile_data = \ gs_query.parse_gamespy_message("\\prof\\" + profile_data + "\\final\\") if profile_data is not None: profile_data = profile_data[0][0] else: self.log(logging.WARNING, "Could not get data section from profile for %d", pid) if len(keys): # TODO: more clean/pythonic way to do (join?) for key in keys: if key in ("__cmd__", "__cmd_val__", ""): continue data += "\\" + key + "\\" if profile_data is not None and key in profile_data: data += profile_data[key] else: self.log(logging.WARNING, "No keys requested, defaulting to all keys: %s", profile['data']) data = profile['data'] modified = int(time.time()) # Check if there is a nul byte and data after it data_blocks = data.split('\x00') if len(data_blocks) > 1 and any(block for block in data_blocks[1:]): self.log(logging.WARNING, "Data after nul byte: %s", data) data = data_blocks[0] msg = gs_query.create_gamespy_message([('__cmd__', "getpdr"), ('__cmd_val__', 1), ('lid', self.lid), ('pid', pid), ('mod', modified), ('length', len(data)), ('data', ''), (data, )]) if msg.count('\\') % 2: # An empty field must be terminated by \ before \final\ msg = msg.replace("\\final\\", "\\\\final\\") self.log(logging.DEBUG, "SENDING: '%s'...", msg) msg = self.crypt(msg) self.transport.write(bytes(msg))
def perform_authp(self, data_parsed): authtoken_parsed = gs_utils.parse_authtoken(data_parsed['authtoken'], self.db) #print authtoken_parsed if "lid" in data_parsed: self.lid = data_parsed['lid'] # Track what console is connecting and save it in the database during user creation just in case we can use # the information in the future. console = 0 # 0 = NDS, 1 = Wii # get correct information userid = authtoken_parsed['userid'] # The Wii does not use passwd, so take another uniquely generated string as the password. if "passwd" in authtoken_parsed: password = authtoken_parsed['passwd'] else: password = authtoken_parsed['gsbrcd'] console = 1 gsbrcd = authtoken_parsed['gsbrcd'] gameid = gsbrcd[:4] uniquenick = utils.base32_encode(int(userid)) + gsbrcd email = uniquenick + "@nds" # The Wii also seems to use @nds. # Wii: Serial number if "csnum" in authtoken_parsed: csnum = authtoken_parsed['csnum'] console = 1 else: csnum = "" # Wii: Friend code if "cfc" in authtoken_parsed: cfc = authtoken_parsed['cfc'] console = 1 else: cfc = "" # NDS: Wifi network's BSSID if "bssid" in authtoken_parsed: bssid = authtoken_parsed['bssid'] else: bssid = "" # NDS: Device name if "devname" in authtoken_parsed: devname = authtoken_parsed['devname'] else: devname = "" # NDS: User's birthday if "birth" in authtoken_parsed: birth = authtoken_parsed['birth'] else: birth = "" valid_user = self.db.check_user_exists(userid, gsbrcd) profileid = None if valid_user: profileid = self.db.perform_login(userid, password, gsbrcd) if profileid == None: # Handle case where the user is invalid self.log(logging.ERROR, "Invalid password") if profileid != None: # Successfully logged in or created account, continue creating session. sesskey = self.db.create_session(profileid) self.sessions[profileid] = self msg_d = [] msg_d.append(('__cmd__', "pauthr")) msg_d.append(('__cmd_val__', profileid)) msg_d.append(('lid', self.lid)) msg = gs_query.create_gamespy_message(msg_d) self.profileid = int(profileid) self.log(logging.DEBUG, "SENDING: '%s'..." % msg) msg = self.crypt(msg) self.transport.write(bytes(msg)) else: # Return error pass