/// <summary> /// "login" packet. This is the response to the server's login challenge. /// </summary> private void OnReceive_Login(NetState ns, GsTcpReader reader) { string clientChallenge = reader.GetParameter("challenge"); // 32 chars ASCII upper/lower. Verifies server. string sessionToken = reader.GetParameter("authtoken"); // identifies account DS wishes to log in with. string response = reader.GetParameter("response"); // 128bit (as 32char hex) response LOGIN_CHALLENGE. string firewall = reader.GetParameter("firewall"); // whether the client is behind a firewall. string port = reader.GetParameter("port"); // port open on the device for communications. string product = reader.GetParameter("productid"); // GameSpy-specific ID indicating the product attempting to connect to GameSpy. string gamename = reader.GetParameter("gamename"); // GameSpy-specific name of the game // string nmspace = reader.GetParameter("nmspace"); // indicates presence of additional login parameters in this packet int seqNum = int.Parse(reader.GetParameter("id")); // sequence ID of the previous LOGIN_CHALLENGE. // get account AccountRequestLogin info = new AccountRequestLogin(sessionToken); EventSink.InvokeAccountLogin(info); if (info.IsHandled && info.IsSuccess) { // verify client authentication: string verify = GsMd5Sum.HashChallenge(info.Account.GsLoginPassword, info.Account.GsLoginToken, clientChallenge, ns.GsServerChallenge); if (verify != response) { throw new NetStateMsgException(ns, "sent incorrect LOGIN verification.", reader); } // client authenticated! Create server authentication proof and then login client: string proof = GsMd5Sum.HashChallenge(info.Account.GsLoginPassword, info.Account.GsLoginToken, ns.GsServerChallenge, clientChallenge); ns.Account = info.Account; ns.GenerateGamespySessionData(); ns.Account.GenerateGamespyLoginData(info); Kernel.WriteLine(TypeName, $"{ns} logged in as '{ns.Account}'."); Send(ns, new GsSmsgLoggedIn(proof, ns, seqNum)); } else if (info.IsHandled) { Send(ns, GsSmsgError.ErrFatalLoginFailed(seqNum)); throw new NetStateMsgException(ns, $"sent wrong credentials: {info.FailReason}", reader); } else { Send(ns, GsSmsgError.ErrFatalDatabaseError(seqNum)); throw new NetStateMsgException(ns, "sent Login; EventSink did not handle the message.", reader); } }