Example #1
0
        public void ClubNameCheckReq(GameSession session, ClubNameCheckReqMessage message)
        {
            var plr = session.Player;

            if (plr == null)
            {
                return;
            }

            var ascii = Config.Instance.Game.NickRestrictions.AsciiOnly;

            if (!Namecheck.IsNameValid(message.Name, true) ||
                ascii && message.Name.Any(c => c > 127) ||
                !ascii && message.Name.Any(c => c > 255))
            {
                session.SendAsync(new NickCheckAckMessage(true));
                return;
            }

            if (GameServer.Instance.ClubManager.Any(c => c.ClanName == message.Name))
            {
                session.SendAsync(new ClubNameCheckAckMessage(2));
                return;
            }

            session.SendAsync(new ClubNameCheckAckMessage(0));
        }
        public async Task CheckNickHandler(GameSession session, NickCheckReqMessage message)
        {
            var plr = session.Player;

            if (plr == null)
            {
                return;
            }

            var ascii = Config.Instance.Game.NickRestrictions.AsciiOnly;

            if (!await AuthService.IsNickAvailableAsync(message.Nickname))
            {
                await plr.Session.SendAsync(new ServerResultAckMessage(ServerResult.NicknameUnavailable));
            }

            if (!Namecheck.IsNameValid(message.Nickname, true) || ascii && message.Nickname.Any(c => c > 127) ||
                !ascii && message.Nickname.Any(c => c > 255))
            {
                await session.SendAsync(new NickCheckAckMessage(true));

                return;
            }

            await session.SendAsync(new NickCheckAckMessage(false));
        }
Example #3
0
        public async Task UseChangeNameItem(GameSession session, ItemUseChangeNickReqMessage message)
        {
            var plr  = session.Player;
            var item = plr.Inventory[message.ItemId];

            var ascii = Config.Instance.Game.NickRestrictions.AsciiOnly;

            if (!await AuthService.IsNickAvailableAsync(message.Nickname))
            {
                await plr.Session.SendAsync(new ServerResultAckMessage(ServerResult.NicknameUnavailable));
            }

            if (!Namecheck.IsNameValid(message.Nickname, true) || ascii && message.Nickname.Any(c => c > 127) ||
                !ascii && message.Nickname.Any(c => c > 255))
            {
                await session.SendAsync(new NickCheckAckMessage(true));

                return;
            }

            var nickname = new NicknameHistoryDto
            {
                AccountId   = (int)plr.Account.Id,
                OldName     = plr.Account.Nickname,
                NewNickname = message.Nickname
            };

            switch (item.ItemNumber)
            {
            case 4000001: //Perm Change
                nickname.ExpireDate = -1;
                if (await ChangeNickname(session.Player, nickname, false))
                {
                    plr.Inventory.RemoveOrDecrease(item);
                }

                break;

            default:
                await session.SendAsync(new ServerResultAckMessage(ServerResult.FailedToRequestTask));

                return;
            }
        }
Example #4
0
        public async Task ClubCreateReq2(GameSession session, ClubCreateReq2Message message)
        {
            var plr = session.Player;

            if (plr == null)
            {
                return;
            }

            var ascii = Config.Instance.Game.NickRestrictions.AsciiOnly;

            if (GameServer.Instance.ClubManager.Any(c =>
                                                    c.ClanName == message.Name || c.Players.ContainsKey(plr.Account.Id)) ||
                !Namecheck.IsNameValid(message.Name, true) ||
                ascii && message.Name.Any(c => c > 127) ||
                !ascii && message.Name.Any(c => c > 255))
            {
                Logger.ForAccount(plr).Information($"Couldnt create Clan : {message.Name}");
                await session.SendAsync(new ClubCreateAck2Message(1));
            }
            else
            {
                var clubDto = new ClubDto
                {
                    Name = message.Name,
                    Icon = ""
                };

                using (var db = GameDatabase.Open())
                {
                    try
                    {
                        using (var transaction = DbUtil.BeginTransaction(db))
                        {
                            await DbUtil.InsertAsync(db, clubDto,
                                                     statement => statement.AttachToTransaction(transaction));

                            var clubPlayerInfo = new ClubPlayerInfo
                            {
                                AccountId = session.Player.Account.Id,
                                Account   = session.Player.Account.AccountDto,
                                State     = ClubState.Joined,
                                Rank      = ClubRank.Master
                            };

                            var club = new Club(clubDto, new[] { clubPlayerInfo });
                            GameServer.Instance.ClubManager.Add(club);
                            transaction.Commit();

                            var clubplrdto = new ClubPlayerDto
                            {
                                PlayerId = (int)session.Player.Account.Id,
                                ClubId   = club.Id,
                                Rank     = (byte)ClubRank.Master,
                                State    = (int)ClubState.Joined
                            };
                            await DbUtil.InsertAsync(db, clubplrdto);

                            session.Player.Club = club;
                        }
                    }
                    catch (Exception ex)
                    {
                        Logger.Error(ex.ToString());
                        await session.SendAsync(new ClubCreateAck2Message(1));

                        return;
                    }

                    await session.SendAsync(new ClubCreateAck2Message(0));

                    await session.SendAsync(new ClubMyInfoAckMessage(plr.Map <Player, ClubMyInfoDto>()));

                    Club.LogOn(plr);
                }
            }
        }
        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));
        }
        private static async Task LoginAsync(IChannelHandlerContext context, string username, string password,
                                             string hwid, string secretkey)
        {
            // This var is used for sending the unban date to the launcher
            var unbandate = DateTimeOffset.Now;

            try
            {
                var endpoint = new IPEndPoint(((IPEndPoint)context.Channel.RemoteAddress).Address.MapToIPv4(),
                                              ((IPEndPoint)context.Channel.RemoteAddress).Port);
                if (username.Length >= 20)
                {
                    Logger.Error("Login & Password to long for {0}", endpoint);
                    var check = new CCMessage();
                    check.Write(false);
                    check.Write("Username is more than 20 chars");
                    RmiSend(context, 16, check);
                    return;
                }

                if (hwid == string.Empty)
                {
                    Logger.Error("No HWID found on endpoint {0}", endpoint);
                    var check = new CCMessage();
                    check.Write(false);
                    check.Write("Cannot Generate HWID");
                    RmiSend(context, 16, check);
                    return;
                }


                if (Config.Instance.AuthAPI.BlockedHWIDS.Contains(hwid))
                {
                    Logger.Error("Hwid ban(conf): {0}, Address: {1}", hwid, endpoint);
                    goto hwidban;
                }

                if (Config.Instance.LauncherCheck)
                {
                    // Launcher Check
                    if (secretkey != Config.Instance.LauncherCheckKey)
                    {
                        Logger.Error("Wrong Launcher => User: "******" hwid: " + hwid + " from " + endpoint);
                        var keycheck = new CCMessage();
                        keycheck.Write(false);
                        keycheck.Write("Invalid Launcher");
                        RmiSend(context, 16, keycheck);
                        return;
                    }
                }

                using (var db = AuthDatabase.Open())
                {
                    Logger.Information("AuthAPI login from {0}, HWID: {1}", endpoint, hwid);


                    if (username.Length < 4 || password.Length < 4)
                    {
                        Logger.Error("Too short credentials for {username} / {endpoint}", username, endpoint);
                        var lengtherr = new CCMessage();
                        lengtherr.Write(false);
                        lengtherr.Write("Invalid length of username/password");
                        RmiSend(context, 16, lengtherr);
                        return;
                    }

                    if (!Namecheck.IsNameValid(username))
                    {
                        Logger.Error("Invalid username for {username} / {endpoint}", username, endpoint);
                        var nickerr = new CCMessage();
                        nickerr.Write(false);
                        nickerr.Write("Username contains invalid characters");
                        RmiSend(context, 16, nickerr);
                        return;
                    }

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

                    var account = result.FirstOrDefault();

                    var hwidResult = await db.FindAsync <HwidBanDto>(statement => statement
                                                                     .Where($"{nameof(HwidBanDto.Hwid):C} = @{nameof(hwid)}")
                                                                     .WithParameters(new { Hwid = hwid }));

                    if (hwidResult?.Any() ?? false)
                    {
                        Logger.Error("Hwid ban(db): {0}, Address: {1}", hwid, endpoint);
                        goto hwidban;
                    }

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

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

                        var hash = new byte[24];
                        using (var pbkdf2 = new Rfc2898DeriveBytes(password, newSalt, 24000))
                        {
                            hash = pbkdf2.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(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)
                    {
                        Logger.Error("Wrong credentials for {username} / {endpoint}", username, endpoint);
                        goto wrong;
                    }

                    if (account != null)
                    {
                        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));
                            unbandate = DateTimeOffset.FromUnixTimeSeconds(ban.Date + (ban.Duration ?? 0));
                            Logger.Error("{user} is banned until {until}", account.Username, unbanDate);
                            goto ban;
                        }

                        account.LoginToken = AuthHash
                                             .GetHash256(
                            $"{context.Channel.RemoteAddress}-{account.Username}-{account.Password}-{endpoint.Address.MapToIPv4()}")
                                             .ToLower();
                        account.LastLogin = $"{DateTimeOffset.UtcNow:yyyyMMddHHmmss}";
                        account.AuthToken = string.Empty;
                        account.newToken  = string.Empty;
                        await db.UpdateAsync(account);

                        var history = new AuthHistoryDto
                        {
                            Account   = account,
                            AccountId = account.Id,
                            Date      = DateTimeOffset.Now.ToUnixTimeSeconds(),
                            HWID      = hwid
                        };

                        await db.InsertAsync(history);

                        var ack = new CCMessage();
                        ack.Write(true);
                        ack.Write(account.LoginToken);
                        RmiSend(context, 16, ack);
                    }

                    Logger.Information("AuthAPI login success for {username}", username);
                    return;
                }
            }
            catch (Exception e)
            {
                Logger.Error(e.ToString());
                goto error;
            }

wrong:
            {
                var error = new CCMessage();
                error.Write(false);
                error.Write("Invalid username or password");
                RmiSend(context, 16, error);
            }

error:
            {
                var error = new CCMessage();
                error.Write(false);
                error.Write("Login error");
                RmiSend(context, 16, error);
            }

ban:
            {
                var error = new CCMessage();
                error.Write(false);
                error.Write("Account is banned until " + unbandate);
                RmiSend(context, 16, error);
            }

hwidban:
            {
                var error = new CCMessage();
                error.Write(false);
                error.Write("You have been blocked");
                RmiSend(context, 16, error);
            }
        }
        public override void ChannelRead(IChannelHandlerContext context, object messageData)
        {
            var buffer = messageData as IByteBuffer;
            var data   = new byte[0];

            if (buffer != null)
            {
                data = buffer.ToArray();
            }

            var   msg     = new CCMessage(data, data.Length);
            short magic   = 0;
            var   message = new ByteArray();

            if (msg.Read(ref magic) &&
                magic == Magic &&
                msg.Read(ref message))
            {
                var receivedMessage          = new CCMessage(message);
                CCMessage.MessageType coreId = 0;
                if (!receivedMessage.Read(ref coreId))
                {
                    return;
                }

                switch (coreId)
                {
                case CCMessage.MessageType.Rmi:
                    short rmiId = 0;
                    if (receivedMessage.Read(ref rmiId))
                    {
                        switch (rmiId)
                        {
                        case 15:
                        {
                            var username = "";
                            var password = "";
                            var register = false;

                            if (receivedMessage.Read(ref username) &&
                                receivedMessage.Read(ref password) &&
                                receivedMessage.Read(ref register))
                            {
                                using (var db = AuthDatabase.Open())
                                {
                                    Logger.Information("Authentication login from {endpoint}",
                                                       context.Channel.RemoteAddress.ToString());

                                    if (username.Length > 5 && password.Length > 5 && Namecheck.IsNameValid(username))
                                    {
                                        var result = db.Find <AccountDto>(statement => statement
                                                                          .Where($"{nameof(AccountDto.Username):C} = @{nameof(username)}")
                                                                          .Include <BanDto>(join => @join.LeftOuterJoin())
                                                                          .WithParameters(new { Username = username }));

                                        var account = result.FirstOrDefault();

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

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

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

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

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

                                        var passwordGuess  = new Rfc2898DeriveBytes(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)
                                        {
                                            Logger.Error(
                                                "Wrong authentication credentials for {username} / {endpoint}",
                                                username, context.Channel.RemoteAddress.ToString());
                                            var ack = new CCMessage();
                                            ack.Write(false);
                                            ack.Write("Login failed");
                                            RmiSend(context, 16, ack);
                                        }
                                        else
                                        {
                                            if (account != null)
                                            {
                                                account.LoginToken = AuthHash
                                                                     .GetHash256(
                                                    $"{context.Channel.RemoteAddress}-{account.Username}-{account.Password}")
                                                                     .ToLower();
                                                account.LastLogin = $"{DateTimeOffset.UtcNow:yyyyMMddHHmmss}";
                                                account.AuthToken = "";
                                                account.newToken  = "";
                                                db.UpdateAsync(account);

                                                var ack = new CCMessage();
                                                ack.Write(true);
                                                ack.Write(account.LoginToken);
                                                RmiSend(context, 16, ack);
                                            }
                                            Logger.Information("Authentication success for {username}",
                                                               username);
                                        }
                                    }
                                    else
                                    {
                                        Logger.Error(
                                            "Wrong authentication credentials for {username} / {endpoint}",
                                            username, context.Channel.RemoteAddress.ToString());
                                        var ack = new CCMessage();
                                        ack.Write(false);
                                        ack.Write("Invalid length of username/password");
                                        RmiSend(context, 16, ack);
                                    }
                                }
                            }
                            else
                            {
                                Logger.Error("Wrong login for {endpoint}",
                                             context.Channel.RemoteAddress.ToString());
                                var ack = new CCMessage();
                                ack.Write(false);
                                ack.Write("Invalid loginpacket");
                                RmiSend(context, 16, ack);
                            }
                            break;
                        }

                        case 17:
                            context.CloseAsync();
                            break;

                        default:
                            Logger.Error("Received unknown rmiId{rmi} from {endpoint}", rmiId,
                                         context.Channel.RemoteAddress.ToString());
                            break;
                        }
                    }
                    break;

                case CCMessage.MessageType.Notify:
                    context.CloseAsync();
                    break;

                default:
                    Logger.Error("Received unknown coreID{coreid} from {endpoint}", coreId,
                                 context.Channel.RemoteAddress.ToString());
                    break;
                }
            }
            else
            {
                Logger.Error("Received invalid packetstruct from {endpoint}", context.Channel.RemoteAddress.ToString());
                context.CloseAsync();
            }
        }
Example #8
0
        private static async void LoginAsync(IChannelHandlerContext context, string username, string password, string hwid, string test)
        {
            lock (_loginSync)
            {
                try
                {
                    using (var db = AuthDatabase.Open())
                    {
                        Logger.Information("Authentication login from {endpoint}",
                            context.Channel.RemoteAddress.ToString());

                        if (test != "test")
                            goto loginerror;

                        var hwidban = db.Find<HwidBanDto>(statement => statement
                        .Where(
                            $"{nameof(HwidBanDto.Hwid):C} = @{nameof(hwid)}")
                        .WithParameters(new { hwid }));

                        if (hwidban.Any())
                        {
                            Logger.Error("Hwid ban {0} for {1}", hwid, context.Channel.RemoteAddress);
                            goto HwidBan;
                        }

                        if (username.Length > 5 && password.Length > 5 &&
                            Namecheck.IsNameValid(username))
                        {
                            var result = db.Find<AccountDto>(statement => statement
                                .Where(
                                    $"{nameof(AccountDto.Username):C} = @{nameof(username)}")
                                .WithParameters(new { Username = username }));

                            var account = result.FirstOrDefault();

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

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

                                var hash = new byte[24];
                                using (var pbkdf2 = new Rfc2898DeriveBytes(password, newSalt, 24000))
                                {
                                    hash = pbkdf2.GetBytes(24);
                                }

                                account.Password = Convert.ToBase64String(hash);
                                account.Salt = Convert.ToBase64String(newSalt);

                                db.InsertAsync(account);
                            }

                             var ban = db.Find<BanDto>(statement => statement
                                .Where($"{nameof(BanDto.AccountId):C} = @{nameof(account.Id)}")
                                .WithParameters(new { account.Id })).FirstOrDefault();

                            if (ban != null)
                            {
                                var unbanDate = DateTimeOffset.FromUnixTimeSeconds(ban.Date + (ban.Duration ?? 0));
                                Logger.Error("{user} is banned until {until}", account.Username, unbanDate);

                                CCMessage error = new CCMessage();
                                error.Write(false);
                                error.Write("You ban until " + unbanDate);
                                RmiSend(context, 16, error);
                            }

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

                            var passwordGuess =
                                new Rfc2898DeriveBytes(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)
                            {
                                Logger.Error(
                                    "Wrong authentication credentials for {username} / {endpoint}",
                                    username, context.Channel.RemoteAddress.ToString());
                                var ack = new CCMessage();
                                ack.Write(false);
                                ack.Write("Login failed");
                                RmiSend(context, 16, ack);
                            }
                            else
                            {
                                if (account != null)
                                {
                                    account.LoginToken = AuthHash
                                        .GetHash256(
                                            $"{context.Channel.RemoteAddress}-{account.Username}-{account.Password}")
                                        .ToLower();
                                    account.LastLogin =
                                        $"{DateTimeOffset.UtcNow:yyyyMMddHHmmss}";
                                    account.AuthToken = "";
                                    account.newToken = "";
                                    db.UpdateAsync(account);

                                    var ack = new CCMessage();
                                    ack.Write(true);
                                    ack.Write(account.LoginToken);
                                    RmiSend(context, 16, ack);
                                }

                                var authhistory = new AuthHistoryDto()
                                {
                                    AccountId = account.Id,
                                    Date = DateTime.UtcNow.ToString(),
                                    HWID = hwid
                                };
                                db.Insert(authhistory);

                                Logger.Information("Authentication success for {username}",
                                    username);

                                if (account.LoginToken != "" && account.LoginToken.Length == 64)
                                {
                                    account.IsConnect = true;
                                    db.Update(account);
                                }
                            }
                        }
                        else
                        {
                            Logger.Error(
                                "Wrong authentication credentials for {username} / {endpoint}",
                                username, context.Channel.RemoteAddress.ToString());
                            var ack = new CCMessage();
                            ack.Write(false);
                            ack.Write("Invalid length of username/password");
                            RmiSend(context, 16, ack);
                        }
                    }
                }
                catch (Exception e)
                {
                    Logger.Error(e.ToString());
                    var ack = new CCMessage();
                    ack.Write(false);
                    ack.Write("Login Error");
                    RmiSend(context, 16, ack);
                }

                HwidBan:
                {
                    var error = new CCMessage();
                    error.Write(false);
                    error.Write("You Banned.");
                    RmiSend(context, 16, error);
                    return;
                }
                loginerror:
                {
                    var error = new CCMessage();
                    error.Write(false);
                    error.Write("Failed to login.");
                    RmiSend(context, 16, error);
                    return;
                }
            }
        }
Example #9
0
        public static async Task <bool> IsNickAvailableAsync(string nickname)
        {
            var minLength  = Config.Instance.Game.NickRestrictions.MinLength;
            var maxLength  = Config.Instance.Game.NickRestrictions.MaxLength;
            var whitespace = Config.Instance.Game.NickRestrictions.WhitespaceAllowed;
            var ascii      = Config.Instance.Game.NickRestrictions.AsciiOnly;

            if (ascii)
            {
                if (nickname.Any(c => c > 127))
                {
                    return(false);
                }
            }
            else
            {
                if (nickname.Any(c => c > 255))
                {
                    return(false);
                }
            }

            if (!Namecheck.IsNameValid(nickname))
            {
                return(false);
            }

            if (nickname.Length < minLength || nickname.Length > maxLength ||
                ascii && Encoding.UTF8.GetByteCount(nickname) != nickname.Length)
            {
                return(false);
            }

            // check for repeating chars example: (AAAHello, HeLLLLo)
            var maxRepeat = Config.Instance.Game.NickRestrictions.MaxRepeat;

            if (maxRepeat > 0)
            {
                var counter = 1;
                var current = nickname[0];
                for (var i = 1; i < nickname.Length; i++)
                {
                    if (current != nickname[i])
                    {
                        if (counter > maxRepeat)
                        {
                            return(false);
                        }

                        counter = 0;
                        current = nickname[i];
                    }

                    counter++;
                }
            }

            var now = DateTimeOffset.Now.ToUnixTimeSeconds();

            using (var db = AuthDatabase.Open())
            {
                var nickExists = (await DbUtil.FindAsync <AccountDto>(db, statement => statement
                                                                      .Where($"{nameof(AccountDto.Nickname):C} = @{nameof(nickname)}")
                                                                      .WithParameters(new { nickname })))
                                 .Any();

                var nickReserved = (await DbUtil.FindAsync <NicknameHistoryDto>(db, statement => statement
                                                                                .Where(
                                                                                    $"{nameof(NicknameHistoryDto.OldName):C} = @{nameof(nickname)} AND ({nameof(NicknameHistoryDto.ExpireDate):C} = -1 OR {nameof(NicknameHistoryDto.ExpireDate):C} > @{nameof(now)})")
                                                                                .WithParameters(new { nickname, now })))
                                   .Any();

                return(!nickExists && !nickReserved);
            }
        }