//log in registered player //player sends updatedetails message to register public void LoginRequest(MClient c, MNetMessage m) { if (MassiveConnections.Count >= MAXCONNECTIONS) { DisconnectClient(c.connection, "Maximum Connections exceded"); return; } MLoginMessageRequest mlir = MLoginMessageRequest.Deserialize <MLoginMessageRequest>(m.Payload); //check database //if password matches, continue //if not, send failed message IPEndPoint ipe = (IPEndPoint)c.connection.ConnectionInfo.RemoteEndPoint; string s = ipe.Address + ":" + ipe.Port; c.Account.ClientIP = s; if (c.Account.UserID == null) { c.Account.UserID = m.UserID; } _DataBase.UpdatePlayerIP(c.Account); _DataBase.UpdatePlayerUsage(c.Account); MUserAccount mu = _DataBase.GetPlayerByEmail(mlir.Email, mlir.Password); if (mu == null) { MNetMessage mli = new MNetMessage(); mli.Command = MNetMessage.ERROR; mli.Payload = "User not found. Building Disabled. Register User and Login again."; Send(c, "Message", mli.Serialize()); } else { MNetMessage mli = new MNetMessage(); mli.Command = MNetMessage.LOGIN; mli.UserID = mu.UserID; mli.Payload = mu.Serialize(); Send(c, "Message", mli.Serialize()); c.Account = mu; } ClientLoggedIn?.Invoke(this, new ServerEvent("Logged In:" + c.ToString())); }
/// <summary> /// Creates a new <see cref="Account"/> and binds it to the given <see cref="Client"/> with a <see cref="Session"/>. /// <remarks>Removes any session that is already active on the given client(if the creation was successful).</remarks> /// </summary> /// <param name="client">The <see cref="Client"/> to which the new <see cref="Account"/> should be bound with a <see cref="Session"/>.</param> /// <param name="userName">The username of the new <see cref="Account"/>.</param> /// <param name="password">The password of the new <see cref="Account"/>.</param> /// <returns>A <see cref="LoginResult"/> indicating the success of the operation and the newly created <see cref="Session"/>.</returns> public Task <LoginResult> CreateAndLoginAccountAsync(Client.Client client, string userName, string password) { if (client == null) { throw new ArgumentNullException(nameof(client)); } if (string.IsNullOrWhiteSpace(userName)) { throw new ArgumentException(@"Value cannot be null or whitespace.", nameof(userName)); } if (string.IsNullOrWhiteSpace(password)) { throw new ArgumentException(@"Value cannot be null or whitespace.", nameof(password)); } //Chain the tasks for checking the usernames existence and the creation of the new account. All of this is done in another thread. return(CheckAccountExistsAsync(userName).ContinueWith(nameCheckTask => { try { if (nameCheckTask.Result) { // The given username is already in use. Return unsuccessful. return (LoginResult) new LoginFailedResult(LoginFailedReason.UserNameAlreadyInUse, "Username already in use."); } using (var context = _ContextFactory.CreateContext()) { //Create the account in the database. AccountEntity accountEntity = new AccountEntity { UserName = userName, PasswordHash = _PasswordService.CreatePasswordHash(password), CreationTime = DateTime.Now, LastLogin = DateTime.Now, LastIpAddress = client.SystemAddress }; context.Accounts.Add(accountEntity); context.SaveChanges(); //Login the new account lock (_Lock) { //Logout the client just in case it is already logged in(this is a case that should not be allowed by the Frontend => Gothic client). LogoutClient(client); Account account = new Account(accountEntity.UserName, accountEntity.AccountId, accountEntity.PasswordHash, _ComponentSelector); Session session = new Session(client, account); _SessionByClient.Add(client, session); _ClientIdLoggedIn[client.Id] = true; //Invoke account creation event. Enqueue it on the dispatcher, so it will be executed after we leave the current lock. _Dispatcher.EnqueueAction(() => AccountCreated?.Invoke(this, new AccountCreatedEventArgs(account))); //Invoke the login event. Enqueue it on the dispatcher, so it will be executed after we leave the current lock. _Dispatcher.EnqueueAction(() => ClientLoggedIn?.Invoke(this, new LoginEventArgs(session))); return (LoginResult) new LoginSuccessfulResult(session); } } } catch (Exception e) { _Log.Error($"Something went wrong while creating a new account and login in. Exception: {e}"); return new LoginFailedResult(LoginFailedReason.None, "Internal server error."); } })); }
/// <summary> /// Logs in the given <see cref="Client"/> and binds its <see cref="Account"/> to the <see cref="Client"/> with a <see cref="Session"/>. /// <remarks>Fails if the <see cref="Client"/> is already logged in.</remarks> /// </summary> /// <param name="client">The <see cref="Client"/> that should be logged in.</param> /// <param name="userName">The username of the <see cref="Account"/> that should be used in the login.</param> /// <param name="password">The password of the <see cref="Account"/> that should be used in the login.</param> /// <returns>A <see cref="LoginResult"/> indicating the success of the operation and the newly created <see cref="Session"/>.</returns> public Task <LoginResult> LoginClientAsync(Client.Client client, string userName, string password) { if (client == null) { throw new ArgumentNullException(nameof(client)); } if (string.IsNullOrWhiteSpace(userName)) { throw new ArgumentException(@"Value cannot be null or whitespace.", nameof(userName)); } if (string.IsNullOrWhiteSpace(password)) { throw new ArgumentException(@"Value cannot be null or whitespace.", nameof(password)); } //Run the database access in another thread. var task = new Task <LoginResult>(() => { //Check that neither the client is already logged in nor the account with the given username is already in use by another client. lock (_Lock) { if (_SessionByClient.ContainsKey(client)) { throw new InvalidOperationException(@"The given client is already logged in."); } if (_SessionByClient.Values.Any(session => session.Account.UserName.Equals(userName, StringComparison.OrdinalIgnoreCase))) { return(new LoginFailedResult(LoginFailedReason.AccountAlreadyLoggedIn, string.Empty)); } using (var context = _ContextFactory.CreateContext()) { //Try to get an Account with the given username AccountEntity accountEntity = context.Accounts.FirstOrDefault(ac => ac.UserName.Equals(userName, StringComparison.OrdinalIgnoreCase)); //An account with the given name does not exist or the password is wrong or is banned. if (accountEntity == null || !_PasswordService.VerifyPassword(password, accountEntity.PasswordHash)) { return(new LoginFailedResult(LoginFailedReason.InvalidLoginData, string.Empty)); } if (accountEntity.IsBanned) { return(new LoginFailedResult(LoginFailedReason.Banned, accountEntity.BannedReasonText)); } //Save last login info to the database. accountEntity.LastLogin = DateTime.Now; accountEntity.LastIpAddress = client.SystemAddress; context.SaveChanges(); // Login successful, create an Account object and bind it to the client with a session. Account account = new Account(accountEntity.UserName, accountEntity.AccountId, accountEntity.PasswordHash, _ComponentSelector); Session session = new Session(client, account); _SessionByClient.Add(client, session); _ClientIdLoggedIn[client.Id] = true; //Invoke the login event. Enqueue it on the dispatcher, so it will be executed after we leave the current lock. _Dispatcher.EnqueueAction(() => ClientLoggedIn?.Invoke(this, new LoginEventArgs(session))); return(new LoginSuccessfulResult(session)); } } }); //Run the task. task.Start(); return(task); }
public static void LogClientIn(ClientAccount clientAccount) { LoggedClients.Add(clientAccount); CalculateMaxTasksPerClient(); ClientLoggedIn?.Invoke(LoggedClients); }