public async Task EULoginHandler(ProudSession session, LoginEUReqMessage message)
        {
            var ip = session.RemoteEndPoint.Address.ToString();

            var account = new AccountDto();

            using (var db = AuthDatabase.Open())
            {
                if (message.Username != "" && message.Password != "")
                {
                    Logger.Information($"Login from {ip}");

                    if (message.Username.Length > 5 && message.Password.Length > 5)
                    {
                        if (!Namecheck.IsNameValid(message.Username))
                        {
                            await session.SendAsync(new LoginEUAckMessage(AuthLoginResult.WrongIdorPw));

                            Logger.Error("Wrong login for {ip}", ip);
                            return;
                        }

                        var result = db.Find <AccountDto>(statement => statement
                                                          .Where($"{nameof(AccountDto.Username):C} = @{nameof(message.Username)}")
                                                          .Include <BanDto>(join => join.LeftOuterJoin())
                                                          .WithParameters(new { message.Username }));

                        account = result.FirstOrDefault();

                        if (account == null && (Config.Instance.NoobMode || Config.Instance.AutoRegister))
                        {
                            account = new AccountDto {
                                Username = message.Username
                            };

                            var newSalt = new byte[24];
                            using (var csprng = new RNGCryptoServiceProvider())
                            {
                                csprng.GetBytes(newSalt);
                            }

                            var hash = new Rfc2898DeriveBytes(message.Password, newSalt, 24000).GetBytes(24);

                            account.Password = Convert.ToBase64String(hash);
                            account.Salt     = Convert.ToBase64String(newSalt);
                            await db.InsertAsync(account);
                        }

                        var salt = Convert.FromBase64String(account?.Salt ?? "");

                        var passwordGuess  = new Rfc2898DeriveBytes(message.Password, salt, 24000).GetBytes(24);
                        var actualPassword = Convert.FromBase64String(account?.Password ?? "");

                        var difference = (uint)passwordGuess.Length ^ (uint)actualPassword.Length;

                        for (var i = 0;
                             i < passwordGuess.Length && i < actualPassword.Length;
                             i++)
                        {
                            difference |= (uint)(passwordGuess[i] ^ actualPassword[i]);
                        }

                        if ((difference != 0 ||
                             string.IsNullOrWhiteSpace(account?.Password ?? "")) &&
                            !Config.Instance.NoobMode)
                        {
                            await session.SendAsync(new LoginEUAckMessage(AuthLoginResult.WrongIdorPw));

                            Logger.Error("Wrong login for {ip}", ip);
                            return;
                        }

                        if (account != null)
                        {
                            account.AuthToken = "";
                            account.newToken  = "";
                            await db.UpdateAsync(account);
                        }
                    }
                    else
                    {
                        await session.SendAsync(new LoginEUAckMessage(AuthLoginResult.WrongIdorPw));

                        Logger.Error("Wrong login for {ip}", ip);
                        return;
                    }
                }
                else if (message.token != "")
                {
                    Logger.Information($"Login from {ip}");

                    var result = await db.FindAsync <AccountDto>(statement => statement
                                                                 .Where($"{nameof(AccountDto.LoginToken):C} = @{nameof(message.token)}")
                                                                 .Include <BanDto>(join => join.LeftOuterJoin())
                                                                 .WithParameters(new { message.token }));

                    account = result.FirstOrDefault();

                    if (account != null)
                    {
                        var lastlogin = DateTimeOffset.ParseExact(account.LastLogin, "yyyyMMddHHmmss", CultureInfo.InvariantCulture,
                                                                  DateTimeStyles.None);

                        if ((DateTimeOffset.Now - lastlogin).Minutes >= 5)
                        {
                            await session.SendAsync(new LoginEUAckMessage(AuthLoginResult.Failed2));

                            Logger.Error("Wrong login for {ip}", ip);
                            return;
                        }
                    }
                    else
                    {
                        await session.SendAsync(new LoginEUAckMessage(AuthLoginResult.Failed2));

                        Logger.Error("Wrong login for {ip}", ip);
                        return;
                    }
                }
                else if (message.AuthToken != "" && message.NewToken != "")
                {
                    Logger.Information("Session login from {ip}", ip);

                    var result = await db.FindAsync <AccountDto>(statement => statement
                                                                 .Where($"{nameof(AccountDto.AuthToken):C} = @{nameof(message.AuthToken)}")
                                                                 .Include <BanDto>(join => join.LeftOuterJoin())
                                                                 .WithParameters(new { message.AuthToken }));

                    account = result.FirstOrDefault();

                    if (account != null)
                    {
                        if (account.AuthToken != message.AuthToken && account.newToken != message.NewToken)
                        {
                            await session.SendAsync(new LoginEUAckMessage(AuthLoginResult.Failed2));

                            Logger.Error("Wrong session login for {ip} ({AuthToken}, {newToken})", ip,
                                         account.AuthToken, account.newToken);
                            return;
                        }
                    }
                    else
                    {
                        await session.SendAsync(new LoginEUAckMessage(AuthLoginResult.Failed2));

                        Logger.Error("Wrong session login for {ip}", ip);
                        return;
                    }
                }

                if (account == null)
                {
                    return;
                }

                var now = DateTimeOffset.Now.ToUnixTimeSeconds();
                var ban = account.Bans.FirstOrDefault(b => b.Date + (b.Duration ?? 0) > now);
                if (ban != null)
                {
                    var unbanDate = DateTimeOffset.FromUnixTimeSeconds(ban.Date + (ban.Duration ?? 0));
                    Logger.Error("{user} is banned until {until}", account.Username, unbanDate);
                    await session.SendAsync(new LoginEUAckMessage(unbanDate));

                    return;
                }

                Logger.Information("Login success for {user}", account.Username);

                var entry = new LoginHistoryDto
                {
                    AccountId = account.Id,
                    Date      = DateTimeOffset.Now.ToUnixTimeSeconds(),
                    IP        = ip
                };
                await db.InsertAsync(entry);
            }


            var datetime      = $"{DateTimeOffset.UtcNow:yyyyMMddHHmmss}";
            var sessionId     = Hash.GetUInt32 <CRC32>($"<{account.Username}+{account.Password}>");
            var authsessionId = Hash.GetString <CRC32>($"<{account.Username}+{sessionId}+{datetime}>");
            var newsessionId  = Hash.GetString <CRC32>($"<{authsessionId}+{sessionId}>");

            using (var db = AuthDatabase.Open())
            {
                account.LastLogin  = $"{DateTimeOffset.UtcNow:yyyyMMddHHmmss}";
                account.LoginToken = "";
                account.AuthToken  = authsessionId;
                account.newToken   = newsessionId;
                await db.UpdateAsync(account);
            }
            await session.SendAsync(new LoginEUAckMessage(AuthLoginResult.OK, (ulong)account.Id, sessionId, authsessionId,
                                                          newsessionId, datetime));
        }
Beispiel #2
0
        public async Task EULoginHandler(ProudSession session, LoginEUReqMessage message)
        {
            var ip = session.RemoteEndPoint.Address.ToString();

            AccountDto account = new AccountDto();

            using (var db = AuthDatabase.Open())
            {
                if (message.token != "")
                {
                    Logger.Information($"Login from {ip}");

                    var result = await db.FindAsync <AccountDto>(statement => statement
                                                                 .Where($"{nameof(AccountDto.LoginToken):C} = @{nameof(message.token)}")
                                                                 .Include <BanDto>(join => join.LeftOuterJoin())
                                                                 .WithParameters(new { message.token }));

                    account = result.FirstOrDefault();

                    if (account != null)
                    {
                        if ((DateTimeOffset.Now - DateTimeOffset.Parse(account.LastLogin)).Minutes >= 5)
                        {
                            session.SendAsync(new LoginEUAckMessage(AuthLoginResult.Failed2));
                            Logger.Error("Wrong login for {ip}", ip);
                            return;
                        }
                    }
                    else
                    {
                        session.SendAsync(new LoginEUAckMessage(AuthLoginResult.Failed2));
                        Logger.Error("Wrong login for {ip}", ip);
                        return;
                    }
                }
                else if (message.AuthToken != "" && message.NewToken != "")
                {
                    Logger.Information("Session login from {ip}", ip);

                    var result = await db.FindAsync <AccountDto>(statement => statement
                                                                 .Where($"{nameof(AccountDto.AuthToken):C} = @{nameof(message.AuthToken)}")
                                                                 .Include <BanDto>(join => join.LeftOuterJoin())
                                                                 .WithParameters(new { message.AuthToken }));

                    account = result.FirstOrDefault();

                    if (account != null)
                    {
                        if (account.AuthToken != message.AuthToken && account.newToken != message.NewToken)
                        {
                            session.SendAsync(new LoginEUAckMessage(AuthLoginResult.Failed2));
                            Logger.Error("Wrong session login for {ip} ({AuthToken}, {newToken})", ip, account.AuthToken, account.newToken);
                            return;
                        }
                    }
                    else
                    {
                        session.SendAsync(new LoginEUAckMessage(AuthLoginResult.Failed2));
                        Logger.Error("Wrong session login for {ip}", ip);
                        return;
                    }
                }

                var now = DateTimeOffset.Now.ToUnixTimeSeconds();
                var ban = account.Bans.FirstOrDefault(b => b.Date + (b.Duration ?? 0) > now);
                if (ban != null)
                {
                    var unbanDate = DateTimeOffset.FromUnixTimeSeconds(ban.Date + (ban.Duration ?? 0));
                    Logger.Error("{user} is banned until {until}", message.Username, unbanDate);
                    session.SendAsync(new LoginEUAckMessage(unbanDate));
                    return;
                }

                Logger.Information("Login success for {user}", account.Username);

                var entry = new LoginHistoryDto
                {
                    AccountId = account.Id,
                    Date      = DateTimeOffset.Now.ToUnixTimeSeconds(),
                    IP        = ip
                };
                await db.InsertAsync(entry);
            }


            string datetime      = $"{DateTimeOffset.Now.DateTime}";
            var    sessionId     = Hash.GetUInt32 <CRC32>($"<{account.Username}+{account.Password}>");
            var    authsessionId = Hash.GetString <CRC32>($"<{account.Username}+{sessionId}+{datetime}>");
            var    newsessionId  = Hash.GetString <CRC32>($"<{authsessionId}+{sessionId}>");

            using (var db = AuthDatabase.Open())
            {
                account.LoginToken = "";
                account.AuthToken  = authsessionId;
                account.newToken   = newsessionId;
                await db.UpdateAsync(account);
            }
            session.SendAsync(new LoginEUAckMessage(AuthLoginResult.OK, (ulong)account.Id, sessionId, authsessionId, newsessionId, datetime));
        }