public static void UpdateStatus(GPCMClient client, Dictionary <string, string> recv, GPCMStatusChanged OnStatusChanged) { //TODO ushort testSK; if (!recv.ContainsKey("statstring") || !recv.ContainsKey("locstring") || !recv.ContainsKey("sesskey")) { return; } if (!ushort.TryParse(recv["sesskey"], out testSK)) { return; // Invalid session key } if (testSK != client.SessionKey) { return; // Are you trying to update another user? } client.PlayerInfo.PlayerStatusString = recv["statstring"]; client.PlayerInfo.PlayerLocation = recv["locstring"]; OnStatusChanged?.Invoke(client); }
/// <summary> /// This method verifies the login information sent by /// the client, and returns encrypted data for the client /// to verify as well /// </summary> public static void ProcessLogin(GPCMClient client, Dictionary <string, string> recv, GPCMConnectionUpdate OnSuccessfulLogin, GPCMStatusChanged OnStatusChanged) { uint partnerID = 0; // Make sure we have all the required data to process this login //if (!recv.ContainsKey("challenge") || !recv.ContainsKey("response")) //{ // GameSpyUtils.SendGPError(client, GPErrorCode.General, "Invalid response received from the client!"); // client.DisconnectByReason(DisconnectReason.InvalidLoginQuery); // return; //} if (IsContainAllKeys(recv) != GPErrorCode.NoError) { GameSpyUtils.SendGPError(client, GPErrorCode.General, "Invalid response received from the client!"); client.DisconnectByReason(DisconnectReason.InvalidLoginQuery); return; } // Parse the partnerid, required since it changes the challenge for Unique nick and User login ParseRequestToPlayerInfo(client, recv, ref partnerID); // Dispose connection after use try { // Try and fetch the user from the database Dictionary <string, object> queryResult; try { if (client.PlayerInfo.PlayerUniqueNick.Length > 0) { queryResult = LoginQuery.GetUserFromUniqueNick(recv); } else if (client.PlayerInfo.PlayerAuthToken.Length > 0) { //TODO! Add the database entry GameSpyUtils.SendGPError(client, GPErrorCode.General, "AuthToken is not supported yet"); return; } else { queryResult = LoginQuery.GetUserFromNickAndEmail(recv); } } catch (Exception ex) { LogWriter.Log.WriteException(ex); GameSpyUtils.SendGPError(client, GPErrorCode.DatabaseError, "This request cannot be processed because of a database error."); return; } //if no match found we disconnect the game if (queryResult == null) { if (client.PlayerInfo.PlayerUniqueNick.Length > 0) { GameSpyUtils.SendGPError(client, GPErrorCode.LoginBadUniquenick, "The uniquenick provided is incorrect!"); } else { GameSpyUtils.SendGPError(client, GPErrorCode.LoginBadUniquenick, "The information provided is incorrect!"); } client.DisconnectByReason(DisconnectReason.InvalidUsername); return; } // Check if user is banned string msg; DisconnectReason reason; GPErrorCode error = CheckUsersAccountAvailability(queryResult, out msg, out reason); if (error != GPErrorCode.NoError) { GameSpyUtils.SendGPError(client, error, msg); client.DisconnectByReason(reason); return; } // we finally set the player variables and return challengeData string challengeData = SetPlayerInfo(client, queryResult, recv); string sendingBuffer; // Use the GenerateProof method to compare with the "response" value. This validates the given password if (recv["response"] == GenerateProof(recv["challenge"], client.ServerChallengeKey, challengeData, client.PlayerInfo.PlayerAuthToken.Length > 0 ? 0 : partnerID, client.PlayerInfo)) { // Create session key client.SessionKey = Crc.ComputeChecksum(client.PlayerInfo.PlayerUniqueNick); //actually we should store sesskey in database at namespace table, when we want someone's profile we just //access to the sesskey to find the uniquenick for particular game LoginQuery.UpdateSessionKey(recv, client.SessionKey, client.PlayerInfo); // Password is correct sendingBuffer = string.Format(@"\lc\2\sesskey\{0}\proof\{1}\userid\{2}\profileid\{2}\uniquenick\{3}\lt\{4}__\id\1\final\", client.SessionKey, GenerateProof(client.ServerChallengeKey, recv["challenge"], challengeData, client.PlayerInfo.PlayerAuthToken.Length > 0 ? 0 : partnerID, client.PlayerInfo), // Do this again, Params are reversed! client.PlayerInfo.PlayerId, client.PlayerInfo.PlayerUniqueNick, // Generate LT whatever that is (some sort of random string, 22 chars long) GameSpyLib.Common.Random.GenerateRandomString(22, GameSpyLib.Common.Random.StringType.Hex) ); //Send response to client client.Send(sendingBuffer); // Log Incoming Connections //LogWriter.Log.Write(LogLevel.Info, "{0,-8} [Login] {1} - {2} - {3}", client.ServerName, client.PlayerInfo.PlayerNick, client.PlayerInfo.PlayerId, RemoteEndPoint); //string statusString = string.Format(" [Login Success!] Nick:{0} - Profileid:{1} - IP:{2}", client.PlayerInfo.PlayerNick, client.PlayerInfo.PlayerId, client.RemoteEndPoint); client.StatusToLog("Login Success", client.PlayerInfo.PlayerNick, client.PlayerInfo.PlayerId, client.RemoteEndPoint, null); // Update status last, and call success login client.PlayerInfo.LoginStatus = LoginStatus.Completed; client.PlayerInfo.PlayerStatus = PlayerStatus.Online; client.PlayerInfo.PlayerStatusString = "Online"; client.PlayerInfo.PlayerStatusLocation = ""; client.CompletedLoginProcess = true; OnSuccessfulLogin?.Invoke(client); OnStatusChanged?.Invoke(client); SendBuddiesHandler.HandleSendBuddies(client, recv); } else { // Log Incoming Connection string statusString = string.Format(@"[Login Failed!] Nick:{0} - Profileid:{1} - IP:{2}", client.PlayerInfo.PlayerNick, client.PlayerInfo.PlayerId, client.RemoteEndPoint); client.ToLog(LogLevel.Info, statusString); // Password is incorrect with database value. client.Send(@"\error\\err\260\fatal\\errmsg\The password provided is incorrect.\id\1\final\"); client.DisconnectByReason(DisconnectReason.InvalidPassword); } } catch (Exception ex) { LogWriter.Log.Write(ex.ToString(), LogLevel.Error); client.DisconnectByReason(DisconnectReason.GeneralError); return; } }