public void FriendActionRequest(ChatSession session, FriendActionReqMessage message) { var plr = session.Player; if (message.AccountId == plr.Account.Id) { return; } using (var authdb = AuthDatabase.Open()) using (var db = GameDatabase.Open()) { var target = DbUtil.Find <AccountDto>(authdb, statement => statement .Where($"{nameof(AccountDto.Id):C} = @Id") .WithParameters(new { Id = message.AccountId })).FirstOrDefault(); var targetPlayerAccount = DbUtil.Find <PlayerDto>(db, statement => statement .Where($"{nameof(PlayerDto.Id):C} = @Id") .WithParameters(new { Id = message.AccountId })).FirstOrDefault(); if (target == null || targetPlayerAccount == null) { plr.SendAsync(new FriendActionAckMessage { Friend = new FriendDto(), Result = FriendResult.UserNotExist, Unk = 0 }); return; } var targetPlayer = GameServer.Instance.PlayerManager.Get(message.AccountId); session.Player.FriendManager.GetValue(message.AccountId, out var friend); switch (message.Action) { case FriendAction.Add: if (friend != null) { plr.SendAsync(new ServerResultAckMessage(ServerResult.DBError)); return; } var settingMananger = new PlayerSettingManager(null, targetPlayerAccount); switch (settingMananger.GetSetting("AllowFriendRequest")) { case CommunitySetting.Allow: friend = plr.FriendManager.AddOrUpdate(message.AccountId, targetPlayer, FriendState.Requesting, FriendState.RequestDialog); session.SendAsync(new FriendActionAckMessage { Friend = friend.GetFriend(), Result = FriendResult.Ok, Unk = 0 }); if (targetPlayer != null) { targetPlayer.ChatSession?.SendAsync(new FriendActionAckMessage { Friend = friend.GetPlayer(), Result = FriendResult.Ok, Unk = 0 }); } break; case CommunitySetting.Deny: session.SendAsync(new FriendActionAckMessage { Friend = new FriendDto(), Result = FriendResult.UserNotExist, Unk = 0 }); break; } break; case FriendAction.Decline: case FriendAction.Remove: if (friend == null) { plr.SendAsync(new ServerResultAckMessage(ServerResult.DBError)); return; } friend.PlayerState = FriendState.NotInList; friend.FriendState = FriendState.NotInList; plr.FriendManager.Remove(message.AccountId, targetPlayer); session.SendAsync(new FriendActionAckMessage { Friend = friend.GetFriend(), Result = FriendResult.Ok, Unk = 0 }); session.SendAsync( new FriendListAckMessage(plr.FriendManager.Select(d => d.GetFriend()) .Where(x => x.State != 0).ToArray())); if (targetPlayer != null) { targetPlayer.ChatSession?.SendAsync(new FriendActionAckMessage { Friend = friend.GetPlayer(), Result = FriendResult.Ok, Unk = 0 }); targetPlayer.ChatSession?.SendAsync( new FriendListAckMessage(targetPlayer.FriendManager.Select(d => d.GetFriend()) .Where(x => x.State != 0).ToArray())); } break; case FriendAction.Update: if (friend == null) { plr.SendAsync(new ServerResultAckMessage(ServerResult.DBError)); return; } friend = plr.FriendManager.AddOrUpdate(message.AccountId, targetPlayer, FriendState.InList, FriendState.InList); session.SendAsync(new FriendActionAckMessage { Friend = friend.GetFriend(), Result = FriendResult.Ok, Unk = 0 }); if (targetPlayer != null) { targetPlayer.ChatSession?.SendAsync(new FriendActionAckMessage { Friend = friend.GetPlayer(), Result = FriendResult.Ok, Unk = 0 }); } break; default: Console.WriteLine("UNKNOWN FriendAction:" + message.Action); break; } targetPlayer?.SendAsync(new ChatPlayerInfoAckMessage(plr.Map <Player, PlayerInfoDto>())); plr.SendAsync(new ChatPlayerInfoAckMessage(targetPlayerAccount.Map <PlayerDto, PlayerInfoDto>())); } }
public bool Execute(GameServer server, Player plr, string[] args) { if (args.Length < 1) { plr.SendConsoleMessage(S4Color.Red + "Wrong Usage, possible usages:"); plr.SendConsoleMessage(S4Color.Red + "> level <username> <level>"); return(true); } if (args.Length >= 2) { AccountDto account; PlayerDto playerdto; using (var db = AuthDatabase.Open()) { account = (db.Find <AccountDto>(statement => statement .Include <BanDto>(join => join.LeftOuterJoin()) .Where($"{nameof(AccountDto.Nickname):C} = @Nickname") .WithParameters(new { Nickname = args[0] }))) .FirstOrDefault(); if (account == null) { plr.SendConsoleMessage(S4Color.Red + "Unknown player!"); return(true); } playerdto = (db.Find <PlayerDto>(statement => statement .Where($"{nameof(PlayerDto.Id):C} = @Id") .WithParameters(new { account.Id }))) .FirstOrDefault(); if (playerdto == null) { plr.SendConsoleMessage(S4Color.Red + "Unknown player!"); return(true); } else { if (byte.TryParse(args[1], out var level)) { plr.SendConsoleMessage(S4Color.Green + $"Changed {account.Nickname}'s level to {args[1]}"); plr.Level = level; playerdto.Level = level; db.Update(playerdto); var player = GameServer.Instance.PlayerManager.Get((ulong)account.Id); if (player != null) { player.Level = level; player.Session?.SendAsync(new PlayerAccountInfoAckMessage(player.Map <Player, PlayerAccountInfoDto>())); player.NeedsToSave = true; } } else { plr.SendConsoleMessage(S4Color.Red + "Wrong Usage, possible usages:"); plr.SendConsoleMessage(S4Color.Red + "> level <username> <level>"); } } } } return(true); }
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 async void CharacterFirstCreateHandler(GameSession session, CharacterFirstCreateReqMessage message) { var plr = session.Player; var cmng = plr.CharacterManager; if (!await AuthService.IsNickAvailableAsync(message.Nickname)) { await session.SendAsync(new ServerResultAckMessage(ServerResult.NicknameUnavailable)); return; } using (var db = AuthDatabase.Open()) { var result = (await db.FindAsync <AccountDto>(smtp => smtp .Where($"{nameof(AccountDto.Id):C} = @Id") .WithParameters(new { session.Player.Account.Id }) )).FirstOrDefault(); if (result == null) { await session.SendAsync(new ServerResultAckMessage(ServerResult.CreateCharacterFailed)); return; } result.Nickname = message.Nickname; await db.UpdateAsync(result); plr.Account.Nickname = message.Nickname; } try { cmng.Create(0, (CharacterGender)message.Gender, 0, 0, 0, 0); cmng.Select(0); } catch (CharacterException ex) { Logger.ForAccount(session) .Error(ex.Message); await session.SendAsync(new ServerResultAckMessage(ServerResult.CreateCharacterFailed)); return; } await AuthService.LoginAsync(session); IEnumerable <StartItemDto> startItems; using (var db = GameDatabase.Open()) { startItems = await db.FindAsync <StartItemDto>(statement => statement .Where( $"{nameof(StartItemDto.RequiredSecurityLevel):C} <= @{nameof(plr.Account.SecurityLevel)}") .WithParameters(new { plr.Account.SecurityLevel })); } foreach (var startItem in startItems) { var shop = GameServer.Instance.ResourceCache.GetShop(); var item = shop.Items.Values.First(group => group.GetItemInfo(startItem.ShopItemInfoId) != null); var itemInfo = item.GetItemInfo(startItem.ShopItemInfoId); var effect = itemInfo.EffectGroup.GetEffect(startItem.ShopEffectId); var price = itemInfo.PriceGroup.GetPrice(startItem.ShopPriceId); if (price == null) { Logger.Warning("Cant find ShopPrice for Start item {startItemId} - Forgot to reload the cache?", startItem.Id); continue; } var color = startItem.Color; if (color > item.ColorGroup) { Logger.Warning("Start item {startItemId} has an invalid color {color}", startItem.Id, color); color = 0; } var count = startItem.Count; if (count > 0 && item.ItemNumber.Category <= ItemCategory.Skill) { Logger.Warning("Start item {startItemId} cant have stacks(quantity={count})", startItem.Id, count); count = 0; } if (count < 0) { count = 0; } var reteff = new List <uint> { effect.Effect }; plr.Inventory.Create(itemInfo, price, color, reteff.ToArray(), (uint)count); } try { foreach (var itemNumber in message.FirstItems) { if (itemNumber != 0) { var pi = plr.Inventory.Create(itemNumber, ItemPriceType.PEN, ItemPeriodType.None, 0, 0, new uint[] { 0 }, 1); cmng.CurrentCharacter.Costumes.Equip(pi, (CostumeSlot)pi.ItemNumber.SubCategory); } } } catch (ArgumentException e) { Logger.Debug(e, "Problem creating new items"); } }
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; var korealogin = false; if (receivedMessage.Read(ref username) && receivedMessage.Read(ref password) && receivedMessage.Read(ref register)) { //receivedMessage.Read(ref korealogin); using (var db = AuthDatabase.Open()) { Logger.Information("Authentication login from {endpoint}", context.Channel.RemoteAddress.ToString()); if (username.Length > 5 && password.Length > 5) { 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.Now}"; account.AuthToken = ""; account.newToken = ""; db.UpdateAsync(account); var ack = new CCMessage(); ack.Write(true); ack.Write(account.LoginToken); //ack.Write(korealogin); 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(); //var info = ""; //receivedMessage.Read(ref info); //Logger.Information("Received info! -> {received}", info); 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(); } }
public static async Task LoginAsync(GameSession session) { var plr = session.Player; plr.LoggedIn = true; try { using (var db = AuthDatabase.Open()) { var account = db.Find <AccountDto>(statement => statement .Where($"{nameof(AccountDto.Id):C} = @{nameof(session.Player.Account.Id)}") .WithParameters(new { session.Player.Account.Id })).FirstOrDefault(); if (account != null && account.IsServer) { account.IsServer = false; DbUtil.Update(db, account); } } plr?.SendAsync(new MoneyRefreshCashInfoAckMessage(plr.PEN, plr.AP)); plr?.SendAsync(new CharacterCurrentSlotInfoAckMessage { ActiveCharacter = plr.CharacterManager.CurrentSlot, CharacterCount = (byte)plr.CharacterManager.Count, MaxSlots = 3 }); plr?.SendAsync(new MoenyRefreshCoinInfoAckMessage(plr.Coins1, plr.Coins2)); plr?.SendAsync(new ShoppingBasketListInfoAckMessage()); foreach (var data in ArraySplitter.Split( plr.Inventory.Select(i => i.Map <PlayerItem, ItemDto>()).ToArray(), 300)) { plr?.SendAsync(new ItemInventoryInfoAckMessage(data)); } plr?.SendAsync(new PlayeArcadeMapInfoAckMessage()); plr?.SendAsync(new PlayerArcadeStageInfoAckMessage()); plr?.SendAsync(new ClubMyInfoAckMessage(plr.Map <Player, ClubMyInfoDto>())); foreach (var @char in plr.CharacterManager) { plr?.SendAsync(new CharacterCurrentInfoAckMessage { Slot = @char.Slot, Style = new CharacterStyle(@char.Gender, @char.Slot) }); plr?.SendAsync(new CharacterCurrentItemInfoAckMessage { Slot = @char.Slot, Weapons = @char.Weapons.GetItems().Select(i => i?.Id ?? 0).ToArray(), Skills = new[] { @char.Skills.GetItem(SkillSlot.Skill)?.Id ?? 0 }, Clothes = @char.Costumes.GetItems().Select(i => i?.Id ?? 0).ToArray() }); } } finally { plr?.SendAsync(new ItemEquipBoostItemInfoAckMessage()); plr?.SendAsync(new EspherChipLv5Message()); plr?.SendAsync(new ItemClearInvalidEquipItemAckMessage()); plr?.SendAsync(new ItemClearEsperChipAckMessage()); plr?.SendAsync(new MapOpenInfosMessage()); await plr.SendAsync(new PlayerAccountInfoAckMessage(plr.Map <Player, PlayerAccountInfoDto>())); await plr.SendAsync(new ServerResultAckMessage(ServerResult.WelcomeToS4World)); } }
public async Task KRLoginHandler(ProudSession session, LoginKRReqMessage message) { var ip = session.RemoteEndPoint.Address.ToString(); var account = new AccountDto(); using (var db = AuthDatabase.Open()) { if (message.AccountHashCode != "") { Logger.Information($"Login from {ip}"); var result = await db.FindAsync <AccountDto>(statement => statement .Where($"{nameof(AccountDto.LoginToken):C} = @{nameof(message.AccountHashCode)}") .Include <BanDto>(join => join.LeftOuterJoin()) .WithParameters(new { message.AccountHashCode })); account = result.FirstOrDefault(); if (account != null) { if ((DateTimeOffset.Now - DateTimeOffset.Parse(account.LastLogin)).Minutes >= 5) { await session.SendAsync(new LoginKRAckMessage(AuthLoginResult.Failed2)); Logger.Error("Wrong login for {ip}", ip); return; } } else { await session.SendAsync(new LoginKRAckMessage(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 LoginKRAckMessage(AuthLoginResult.Failed2)); Logger.Error("Wrong session login for {ip} ({AuthToken}, {newToken})", ip, account.AuthToken, account.newToken); return; } } else { await session.SendAsync(new LoginKRAckMessage(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}", account.Username, unbanDate); await session.SendAsync(new LoginKRAckMessage(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.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); } await session.SendAsync(new LoginKRAckMessage(AuthLoginResult.OK, (ulong)account.Id, sessionId, authsessionId, newsessionId, datetime)); }
public async Task <bool> Execute(GameServer server, Player plr, string[] args) { if (args.Length < 1) { plr.SendConsoleMessage(S4Color.Red + "Wrong Usage, possible usages:"); plr.SendConsoleMessage(S4Color.Red + "> /ban <username> roomkick - roomkick"); plr.SendConsoleMessage(S4Color.Red + "> /ban <username> - permanent ban"); plr.SendConsoleMessage(S4Color.Red + "> /ban <username> pardon - unban"); plr.SendConsoleMessage(S4Color.Red + "> /ban <username> days <duration(days)> - ban for x days"); plr.SendConsoleMessage(S4Color.Red + "> /ban <username> mins <duration(minutes)> - ban for x minutes"); plr.SendConsoleMessage(S4Color.Red + "> /ban <username> secs <duration(seconds)> - ban for x seconds"); plr.SendConsoleMessage(S4Color.Red + "> /ban <username> <currentdate(ex:20180130)> <unk> <duration(seconds)>"); return(true); } if (args.Length < 2) { Array.Resize(ref args, args.Length + 1); args[1] = "none"; } var unban = false; var nickname = args[0]; var durationInSeconds = 0; try { AccountDto account; switch (args[1]) { case "pardon": unban = true; break; case "roomkick": using (var db = AuthDatabase.Open()) { account = (await DbUtil.FindAsync <AccountDto>(db, statement => statement .Include <BanDto>(join => join.LeftOuterJoin()) .Where($"{nameof(AccountDto.Nickname):C} = @Nickname") .WithParameters(new { Nickname = nickname })) ).FirstOrDefault(); if (account == null) { plr.SendConsoleMessage(S4Color.Red + "Unknown player"); return(true); } var player = GameServer.Instance.PlayerManager.Get((ulong)account.Id); if (player == null) { plr.SendConsoleMessage(S4Color.Red + "Player is not online"); return(true); } player.Room?.Leave(player, RoomLeaveReason.ModeratorKick); plr.SendConsoleMessage(S4Color.Green + $"Kicked {account.Nickname} out of room"); } return(true); case "secs": int.TryParse(args[2], out durationInSeconds); break; case "mins": int.TryParse(args[2], out var durationInMinutes); durationInSeconds = durationInMinutes * 60; break; case "days": int.TryParse(args[2], out var durationInDays); durationInSeconds = durationInDays * 24 * 60 * 60; //days->hours->minutes->seconds break; default: if (DateTimeOffset.TryParseExact(args[1], "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None, out _)) { if (args.Length >= 4) { int.TryParse(args[2], out var unk); int.TryParse(args[3], out var durationInMs); durationInSeconds = durationInMs / 60; } } else { durationInSeconds = (int)TimeSpan.FromDays(10 * 365).TotalSeconds; } break; } using (var db = AuthDatabase.Open()) { account = (await DbUtil.FindAsync <AccountDto>(db, statement => statement .Include <BanDto>(join => join.LeftOuterJoin()) .Where($"{nameof(AccountDto.Nickname):C} = @Nickname") .WithParameters(new { Nickname = nickname })) ).FirstOrDefault(); if (account == null) { plr.SendConsoleMessage(S4Color.Red + "Unknown player"); return(true); } if (unban) { foreach (var accountBan in account.Bans) { accountBan.Duration = 0; await DbUtil.UpdateAsync(db, accountBan); } await DbUtil.UpdateAsync(db, account); CommandManager.Logger.Information( $"{plr?.Account?.Nickname ?? "Unknown player"} has unbanned {account.Nickname}"); plr?.SendConsoleMessage(S4Color.Green + $"Unbanned {account.Nickname}"); } else { if (plr.Account.SecurityLevel <= (SecurityLevel)account.SecurityLevel) { plr.SendConsoleMessage($"You cannot ban this player"); return(true); } var duration = TimeSpan.FromSeconds(durationInSeconds); var ban = new BanDto { AccountId = account.Id, Account = account, Date = 0, Duration = DateTimeOffset.Now.Add(duration).ToUnixTimeSeconds(), Reason = $"GMConsole - {plr?.Account?.Nickname ?? "n/A"}" }; var player = GameServer.Instance.PlayerManager.Get((ulong)account.Id); player?.Session?.CloseAsync(); await DbUtil.InsertAsync(db, ban); await DbUtil.UpdateAsync(db, account); var uptime = new StringBuilder(); if (duration.Days > 0) { uptime.AppendFormat("{0} days ", duration.Days); } if (duration.Hours > 0) { uptime.AppendFormat("{0} hours ", duration.Hours); } if (duration.Minutes > 0) { uptime.AppendFormat("{0} minutes ", duration.Minutes); } if (duration.Seconds > 0) { uptime.AppendFormat("{0} seconds ", duration.Seconds); } CommandManager.Logger.Information( $"{plr?.Account?.Nickname ?? "Unknown player"} has banned {account.Nickname} for {uptime}"); plr?.SendConsoleMessage(S4Color.Green + $"Banned {account.Nickname} for {uptime}"); } } } catch (Exception) { plr.SendConsoleMessage(S4Color.Red + "Unknown player"); } return(true); }
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; } } }
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) { 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.LastLogin = $"{DateTimeOffset.Now}"; 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) { if ((DateTimeOffset.Now - DateTimeOffset.Parse(account.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; } } 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.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); } await session.SendAsync(new LoginEUAckMessage(AuthLoginResult.OK, (ulong)account.Id, sessionId, authsessionId, newsessionId, datetime)); }
public async Task<bool> Execute(GameServer server, Player plr, string[] args) { if (args.Length < 1) { plr.SendConsoleMessage(S4Color.Red + "Wrong Usage, possible usages:"); plr.SendConsoleMessage(S4Color.Red + "> level <nickname> <level>"); return true; } if (args.Length >= 2) { AccountDto account; using (var db = AuthDatabase.Open()) { account = (await DbUtil.FindAsync<AccountDto>(db, statement => statement .Include<BanDto>(join => join.LeftOuterJoin()) .Where($"{nameof(AccountDto.Nickname):C} = @Nickname") .WithParameters(new { Nickname = args[0] }))).FirstOrDefault(); if (account == null) { plr.SendConsoleMessage(S4Color.Red + "Unknown player"); return true; } var playerdto = (await DbUtil.FindAsync<PlayerDto>(db, statement => statement .Where($"{nameof(PlayerDto.Id):C} = @Id") .WithParameters(new { account.Id })) ).FirstOrDefault(); if (playerdto == null) { plr.SendConsoleMessage(S4Color.Red + "Unknown player"); return true; } if (byte.TryParse(args[1], out var level)) { var expTable = GameServer.Instance.ResourceCache.GetExperience(); if (expTable.TryGetValue(level, out var exp)) { plr.SendConsoleMessage($"Changed {account.Nickname}'s level to {args[1]}"); playerdto.Level = level; playerdto.TotalExperience = exp.TotalExperience; DbUtil.Update(db, playerdto); var player = GameServer.Instance.PlayerManager.Get((ulong)account.Id); if (player != null) { player.Level = level; player.TotalExperience = exp.TotalExperience; player.Session?.SendAsync(new ExpRefreshInfoAckMessage(player.TotalExperience)); player.Session?.SendAsync( new PlayerAccountInfoAckMessage(player.Map<Player, PlayerAccountInfoDto>())); player.NeedsToSave = true; } } else { plr.SendConsoleMessage(S4Color.Red + "Invalid Level"); } } else { plr.SendConsoleMessage(S4Color.Red + "Wrong Usage, possible usages:"); plr.SendConsoleMessage(S4Color.Red + "> level <nickname> <level>"); } } } return true; }
public async Task LoginHandler(GameSession session, LoginRequestReqMessage message) { #region IPINFO var ipInfo = new IpInfo2(); try { var info = new WebClient().DownloadString("http://ip-api.com/json/" + session.RemoteEndPoint.Address); ipInfo = JsonConvert.DeserializeObject <IpInfo2>(info); if (string.IsNullOrWhiteSpace(ipInfo.countryCode) || string.IsNullOrEmpty(ipInfo.countryCode)) { ipInfo.countryCode = "UNK"; } } catch (Exception) { ipInfo.countryCode = "UNK"; } #endregion #region Validate Login AccountDto accountDto; using (var db = AuthDatabase.Open()) { accountDto = (await DbUtil.FindAsync <AccountDto>(db, statement => statement .Include <BanDto>(join => join.LeftOuterJoin()) .Where($"{nameof(AccountDto.Id):C} = @Id") .WithParameters(new { Id = message.AccountId }))) .FirstOrDefault(); } if (accountDto == null) { await session.SendAsync(new LoginReguestAckMessage(GameLoginResult.SessionTimeout)); await session.CloseAsync(); return; } message.AccountId = (ulong)accountDto.Id; message.Username = accountDto.Username; Logger.ForAccount(accountDto) .Information("GameServer login from {remoteEndPoint} : Country: {country}", session.RemoteEndPoint, ipInfo.countryCode); if (Config.Instance.BlockedCountries.ToList().Contains(ipInfo.countryCode)) { Logger.ForAccount(accountDto) .Warning("Denied connection from client in blocked country {country}", ipInfo.countryCode); await session.SendAsync(new ServerResultAckMessage(ServerResult.IPLocked)); await session.CloseAsync(); return; } if (Config.Instance.BlockedAddresses.ToList().Contains(session.RemoteEndPoint.Address.ToString())) { Logger.ForAccount(accountDto) .Warning("Denied connection from client of blocked ip {adress}", session.RemoteEndPoint); await session.SendAsync(new ServerResultAckMessage(ServerResult.IPLocked)); await session.CloseAsync(); return; } // if (message.Version != s_version) // { // Logger.ForAccount(message.AccountId, message.Username) // .Warning("Invalid client version {version}", message.Version); // // session.SendAsync(new LoginReguestAckMessage(GameLoginResult.WrongVersion)); // return; // } if (GameServer.Instance.PlayerManager.Count >= Config.Instance.PlayerLimit) { Logger.ForAccount(accountDto) .Warning("Server is full"); await session.SendAsync(new LoginReguestAckMessage(GameLoginResult.ServerFull)); await session.CloseAsync(); return; } var sessionId = Hash.GetUInt32 <CRC32>($"<{accountDto.Username}+{accountDto.Password}+{session.RemoteEndPoint.Address.MapToIPv4()}+{Config.Instance.AuthAPI.ApiKey}>"); var authsessionId = Hash.GetString <CRC32>($"<{accountDto.Username}+{sessionId}+{message.Datetime}>"); if (authsessionId != message.AuthToken) { Logger.ForAccount(accountDto) .Warning("Wrong sessionid(2)"); await session.SendAsync(new LoginReguestAckMessage(GameLoginResult.SessionTimeout)); await session.CloseAsync(); return; } var newsessionId = Hash.GetString <CRC32>($"<{authsessionId}+{sessionId}>"); if (newsessionId != message.newToken) { Logger.ForAccount(accountDto) .Warning("Wrong sessionid(3)"); await session.SendAsync(new LoginReguestAckMessage(GameLoginResult.SessionTimeout)); await session.CloseAsync(); return; } var now = DateTimeOffset.Now.ToUnixTimeSeconds(); var ban = accountDto.Bans.FirstOrDefault(b => b.Date + (b.Duration ?? 0) > now); if (ban != null) { var unbanDate = DateTimeOffset.FromUnixTimeSeconds(ban.Date + (ban.Duration ?? 0)); Logger.ForAccount(accountDto) .Warning("Banned until {unbanDate}", unbanDate); await session.SendAsync(new LoginReguestAckMessage(GameLoginResult.SessionTimeout)); await session.CloseAsync(); return; } var account = new Account(accountDto); #endregion if (account.SecurityLevel < Config.Instance.SecurityLevel) { Logger.ForAccount(account).Warning("No permission to enter this server({securityLevel} or above required)", Config.Instance.SecurityLevel); await session.SendAsync(new LoginReguestAckMessage(GameLoginResult.AuthenticationFailed)); await session.CloseAsync(); return; } if (GameServer.Instance.PlayerManager.Contains(account.Id)) { Logger.ForAccount(account) .Information("Kicking old connection"); var oldPlr = GameServer.Instance.PlayerManager.Get(account.Id); GameServer.Instance.PlayerManager.Remove(oldPlr); oldPlr?.Session.CloseAsync(); } Logger.ForAccount(account) .Information("Login success"); await Task.Run(async() => { using (var db = GameDatabase.Open()) { var plrDto = (await DbUtil.FindAsync <PlayerDto>(db, statement => statement .Include <PlayerCharacterDto>(join => join.LeftOuterJoin()) .Include <PlayerDenyDto>(join => join.LeftOuterJoin()) .Include <PlayerFriendDto>(join => join.LeftOuterJoin()) .Include <PlayerSettingDto>(join => join.LeftOuterJoin()) .Include <PlayerItemDto>(join => join.LeftOuterJoin()) .Include <PlayerMailDto>(join => join.LeftOuterJoin()) .Where($"{nameof(PlayerDto.Id):C} = @Id") .WithParameters(new { Id = message.AccountId }))) .FirstOrDefault(); var plrStatsDto = (await DbUtil.FindAsync <PlayerDto>(db, statement => statement .Include <PlayerDeathMatchDto>(join => join.LeftOuterJoin()) .Include <PlayerTouchDownDto>(join => join.LeftOuterJoin()) .Include <PlayerChaserDto>(join => join.LeftOuterJoin()) .Include <PlayerBattleRoyalDto>(join => join.LeftOuterJoin()) .Include <PlayerCaptainDto>(join => join.LeftOuterJoin()) .Where($"{nameof(PlayerDto.Id):C} = @Id") .WithParameters(new { Id = message.AccountId }))) .FirstOrDefault(); var expTable = GameServer.Instance.ResourceCache.GetExperience(); Experience expValue; if (plrDto == null) { // first time connecting to this server if (!expTable.TryGetValue(Config.Instance.Game.StartLevel, out expValue)) { expValue = new Experience { TotalExperience = 0 }; Logger.Warning("Given start level is not found in the experience table"); } plrDto = new PlayerDto { Id = (int)account.Id, PlayTime = TimeSpan.FromSeconds(0).ToString(), Level = Config.Instance.Game.StartLevel, PEN = Config.Instance.Game.StartPEN, AP = Config.Instance.Game.StartAP, Coins1 = Config.Instance.Game.StartCoins1, Coins2 = Config.Instance.Game.StartCoins2, TotalExperience = expValue.TotalExperience, }; try { await DbUtil.InsertAsync(db, plrDto); } catch (Exception e) { session.Channel.Pipeline.FireExceptionCaught(e); return; } } else { if (!TimeSpan.TryParse(plrDto.PlayTime, out _)) { plrDto.PlayTime = TimeSpan.FromSeconds(0).ToString(); } if (!expTable.TryGetValue(plrDto.Level, out expValue)) { expValue = new Experience { TotalExperience = 0 }; Logger.Warning("Given level is not found in the experience table"); } // Adjust total exp to correct range if (plrDto.TotalExperience < expValue.TotalExperience) { plrDto.TotalExperience = expValue.TotalExperience; await DbUtil.UpdateAsync(db, plrDto); } // Adjust total exp to minexp of current level if (plrDto.Level > 0 && plrDto.TotalExperience == 0) { plrDto.TotalExperience = expValue.TotalExperience - 1; await DbUtil.UpdateAsync(db, plrDto); } } if (plrStatsDto != null) { plrDto.DeathMatchInfo = plrStatsDto.DeathMatchInfo; plrDto.TouchDownInfo = plrStatsDto.TouchDownInfo; plrDto.ChaserInfo = plrStatsDto.ChaserInfo; plrDto.BattleRoyalInfo = plrStatsDto.BattleRoyalInfo; plrDto.CaptainInfo = plrStatsDto.CaptainInfo; } session.Player = new Player(session, account, plrDto); } if (session.Player == null) { Logger.ForAccount(account) .Error("PlayerInfo failed - Missing playerInstance"); return; } GameServer.Instance.PlayerManager.Add(session.Player); var result = string.IsNullOrWhiteSpace(account.Nickname) ? GameLoginResult.ChooseNickname : GameLoginResult.OK; result = session.Player.CharacterManager.Any() ? result : GameLoginResult.ChooseNickname; if (session.UpdateShop) { await ShopService.ShopUpdateMsg(session, false); session.UpdateShop = false; } await session.SendAsync(new LoginReguestAckMessage(result, session.Player.Account.Id)); if (result == GameLoginResult.OK) { await LoginAsync(session); } }); }
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); } }
public async Task LoginHandler(ProudSession session, CAuthInEUReqMessage message) { var ip = session.RemoteEndPoint.Address.ToString(); Logger.Debug($"Login from {ip} with username {message.Username}"); AccountDto account; using (var db = AuthDatabase.Open()) { var result = await db.FindAsync <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) { if (Config.Instance.NoobMode || Config.Instance.AutoRegister) { // NoobMode/AutoRegister: Create a new account if non exists account = new AccountDto { Username = message.Username }; var newSalt = new byte[24]; using (var csprng = new RNGCryptoServiceProvider()) csprng.GetBytes(newSalt); var hash = new byte[24]; using (var pbkdf2 = new Rfc2898DeriveBytes(message.Password, newSalt, 24000)) hash = pbkdf2.GetBytes(24); account.Password = Convert.ToBase64String(hash); account.Salt = Convert.ToBase64String(newSalt); await db.InsertAsync(account); } else { Logger.Error($"Wrong login for {message.Username}"); session.SendAsync(new SAuthInEuAckMessage(AuthLoginResult.WrongIdorPw)); return; } } var salt = Convert.FromBase64String(account.Salt); var passwordGuess = new byte[24]; using (var pbkdf2 = new Rfc2898DeriveBytes(message.Password, salt, 24000)) passwordGuess = pbkdf2.GetBytes(24); var actualPassword = Convert.FromBase64String(account.Password); uint 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)) { if (Config.Instance.NoobMode) { // Noob Mode: Save new password var newSalt = new byte[24]; using (var csprng = new RNGCryptoServiceProvider()) csprng.GetBytes(newSalt); var hash = new byte[24]; using (var pbkdf2 = new Rfc2898DeriveBytes(message.Password, newSalt, 24000)) hash = pbkdf2.GetBytes(24); account.Password = Convert.ToBase64String(hash); account.Salt = Convert.ToBase64String(newSalt); await db.UpdateAsync(account); } else { Logger.Error($"Wrong login for {message.Username}"); session.SendAsync(new SAuthInEuAckMessage(AuthLoginResult.WrongIdorPw)); 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($"{message.Username} is banned until {unbanDate}"); session.SendAsync(new SAuthInEuAckMessage(unbanDate)); return; } Logger.Information($"Login success for {message.Username}"); var entry = new LoginHistoryDto { AccountId = account.Id, Date = DateTimeOffset.Now.ToUnixTimeSeconds(), IP = ip }; await db.InsertAsync(entry); } // ToDo proper session generation var sessionId = Hash.GetUInt32 <CRC32>($"<{account.Username}+{account.Password}>"); session.SendAsync(new SAuthInEuAckMessage(AuthLoginResult.OK, (ulong)account.Id, sessionId)); }
public async Task LoginHandler(ISession session, CAuthInEUReqMessage message) { var ip = ((IPEndPoint)((TcpTransport)session.Transport).Socket.RemoteEndPoint).Address.ToString(); Logger.Debug($"Login from {ip} with username {message.Username}"); AccountDto account; string password; using (var db = AuthDatabase.Open()) { var result = await db.FindAsync <AccountDto>(statement => statement .Where($"{nameof(AccountDto.Username):C} = @{nameof(message.Username)}") .Include <BanDto>(join => join.LeftOuterJoin()) .WithParameters(new { message.Username })) .ConfigureAwait(false); account = result.FirstOrDefault(); if (account == null) { if (Config.Instance.NoobMode) { // NoobMode: Create a new account if non exists account = new AccountDto { Username = message.Username }; var bytes = new byte[16]; using (var rng = new RNGCryptoServiceProvider()) rng.GetBytes(bytes); account.Salt = Hash.GetString <SHA1CryptoServiceProvider>(bytes); account.Password = Hash.GetString <SHA1CryptoServiceProvider>(message.Password + "+" + account.Salt); await db.InsertAsync(account) .ConfigureAwait(false); } else { Logger.Error($"Wrong login for {message.Username}"); await session.SendAsync(new SAuthInEuAckMessage(AuthLoginResult.WrongIdorPw)) .ConfigureAwait(false); return; } } password = Hash.GetString <SHA1CryptoServiceProvider>(message.Password + "+" + account.Salt); if (string.IsNullOrWhiteSpace(account.Password) || !account.Password.Equals(password, StringComparison.InvariantCultureIgnoreCase)) { if (Config.Instance.NoobMode) { // Noob Mode: Save new password var bytes = new byte[16]; using (var rng = new RNGCryptoServiceProvider()) rng.GetBytes(bytes); var salt = Hash.GetString <SHA1CryptoServiceProvider>(bytes); password = Hash.GetString <SHA1CryptoServiceProvider>(message.Password + "+" + salt); account.Password = password; account.Salt = salt; await db.UpdateAsync(account) .ConfigureAwait(false); } else { Logger.Error($"Wrong login for {message.Username}"); await session.SendAsync(new SAuthInEuAckMessage(AuthLoginResult.WrongIdorPw)) .ConfigureAwait(false); 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($"{message.Username} is banned until {unbanDate}"); await session.SendAsync(new SAuthInEuAckMessage(unbanDate)) .ConfigureAwait(false); return; } Logger.Info($"Login success for {message.Username}"); var entry = new LoginHistoryDto { AccountId = account.Id, Date = DateTimeOffset.Now.ToUnixTimeSeconds(), IP = ip }; await db.InsertAsync(entry) .ConfigureAwait(false); } // ToDo proper session generation var sessionId = Hash.GetUInt32 <CRC32>($"<{account.Username}+{password}>"); await session.SendAsync(new SAuthInEuAckMessage(AuthLoginResult.OK, (ulong)account.Id, sessionId)) .ConfigureAwait(false); }
public async Task LoginHandler(GameSession session, LoginRequestReqMessage message) { #region IPINFO IpInfo ipInfo = new IpInfo(); try { string info = new WebClient().DownloadString("http://freegeoip.net/json/" + session.RemoteEndPoint.Address); ipInfo = JsonConvert.DeserializeObject <IpInfo>(info); if (string.IsNullOrWhiteSpace(ipInfo.country_code) || string.IsNullOrEmpty(ipInfo.country_code)) { ipInfo.country_code = "UNK"; } } catch (Exception) { ipInfo.country_code = "UNK"; } #endregion Logger.ForAccount(message.AccountId, message.Username) .Information("GameServer login from {remoteEndPoint} : Country: {country}", session.RemoteEndPoint, ipInfo.country_code); if (Config.Instance.BlockedCountries.ToList().Contains(ipInfo.country_code) || Config.Instance.BlockedAddresses.ToList().Contains(session.RemoteEndPoint.Address.ToString())) { Logger.ForAccount(message.AccountId, message.Username) .Information("Denied connection from client in blocked country {country}", ipInfo.country_code); session.SendAsync(new ServerResultAckMessage(ServerResult.IPLocked)); return; } //if (message.Version != s_version) //{ // Logger.ForAccount(message.AccountId, message.Username) // .Error("Invalid client version {version}", message.Version); // // session.SendAsync(new LoginReguestAckMessage(GameLoginResult.WrongVersion)); // return; //} if (GameServer.Instance.PlayerManager.Count >= Config.Instance.PlayerLimit) { Logger.ForAccount(message.AccountId, message.Username) .Error("Server is full"); await session.SendAsync(new LoginReguestAckMessage(GameLoginResult.ServerFull)); return; } #region Validate Login AccountDto accountDto; using (var db = AuthDatabase.Open()) { accountDto = (await db.FindAsync <AccountDto>(statement => statement .Include <BanDto>(join => join.LeftOuterJoin()) .Where($"{nameof(AccountDto.Id):C} = @Id") .WithParameters(new { Id = message.AccountId }))) .FirstOrDefault(); } if (accountDto == null) { Logger.ForAccount(message.AccountId, message.Username) .Error("Wrong login(account not existing)"); await session.SendAsync(new LoginReguestAckMessage(GameLoginResult.SessionTimeout)); return; } var sessionId = Hash.GetUInt32 <CRC32>($"<{accountDto.Username}+{accountDto.Password}>"); //var md5 = MD5.Create(); //var inputBytes = Encoding.ASCII.GetBytes(message.SessionId); //var hash = md5.ComputeHash(inputBytes); //if (hash != md5.ComputeHash(Encoding.ASCII.GetBytes(sessionId.ToString()))) //{ // // Logger.ForAccount(message.AccountId, message.Username) // .Error("Wrong login(invalid sessionid) - {id} != {id2}", message.SessionId, Encoding.ASCII.GetByteCount()); // session.SendAsync(new LoginReguestAckMessage(GameLoginResult.SessionTimeout)); // return; //} var authsessionId = Hash.GetString <CRC32>($"<{accountDto.Username}+{sessionId}+{message.Datetime}>"); if (authsessionId != message.AuthToken) { Logger.ForAccount(message.AccountId, message.Username) .Error("Wrong sessionid(2)"); await session.SendAsync(new LoginReguestAckMessage(GameLoginResult.SessionTimeout)); return; } var newsessionId = Hash.GetString <CRC32>($"<{authsessionId}+{sessionId}>"); if (newsessionId != message.newToken) { Logger.ForAccount(message.AccountId, message.Username) .Error("Wrong sessionid(3)"); await session.SendAsync(new LoginReguestAckMessage(GameLoginResult.SessionTimeout)); return; } var now = DateTimeOffset.Now.ToUnixTimeSeconds(); var ban = accountDto.Bans.FirstOrDefault(b => b.Date + (b.Duration ?? 0) > now); if (ban != null) { var unbanDate = DateTimeOffset.FromUnixTimeSeconds(ban.Date + (ban.Duration ?? 0)); Logger.ForAccount(message.AccountId, message.Username) .Error("Banned until {unbanDate}", unbanDate); await session.SendAsync(new LoginReguestAckMessage(GameLoginResult.SessionTimeout)); return; } var account = new Account(accountDto); #endregion if (account.SecurityLevel < Config.Instance.SecurityLevel) { Logger.ForAccount(account) .Error("No permission to enter this server({securityLevel} or above required)", Config.Instance.SecurityLevel); await session.SendAsync(new LoginReguestAckMessage((GameLoginResult)9)); return; } if (message.KickConnection) { Logger.ForAccount(account) .Information("Kicking old connection"); var oldPlr = GameServer.Instance.PlayerManager.Get(account.Id); oldPlr?.Disconnect(); if (GameServer.Instance.PlayerManager.Contains(account.Id)) { GameServer.Instance.PlayerManager.Remove(oldPlr); } //await session.SendAsync(new LoginReguestAckMessage(GameLoginResult.ExistingExit)); //return; } if (GameServer.Instance.PlayerManager.Contains(account.Id)) { Logger.ForAccount(account) .Error("Already online"); await session.SendAsync(new LoginReguestAckMessage(GameLoginResult.TerminateOtherConnection)); return; } using (var db = GameDatabase.Open()) { var plrDto = (await db.FindAsync <PlayerDto>(statement => statement .Include <PlayerCharacterDto>(join => join.LeftOuterJoin()) .Include <PlayerDenyDto>(join => join.LeftOuterJoin()) .Include <PlayerItemDto>(join => join.LeftOuterJoin()) .Include <PlayerMailDto>(join => join.LeftOuterJoin()) .Include <PlayerSettingDto>(join => join.LeftOuterJoin()) .Where($"{nameof(PlayerDto.Id):C} = @Id") .WithParameters(new { Id = message.AccountId }))) .FirstOrDefault(); var expTable = GameServer.Instance.ResourceCache.GetExperience(); Experience expValue = new Experience(); if (plrDto == null) { // first time connecting to this server if (!expTable.TryGetValue(Config.Instance.Game.StartLevel, out expValue)) { expValue = new Experience(); expValue.TotalExperience = 0; Logger.Warning("Given start level is not found in the experience table"); } plrDto = new PlayerDto { Id = (int)account.Id, PlayTime = TimeSpan.FromSeconds(0).ToString(), Level = Config.Instance.Game.StartLevel, PEN = Config.Instance.Game.StartPEN, AP = Config.Instance.Game.StartAP, Coins1 = Config.Instance.Game.StartCoins1, Coins2 = Config.Instance.Game.StartCoins2, TotalExperience = expValue.TotalExperience }; await db.InsertAsync(plrDto); } else { if (!TimeSpan.TryParse(plrDto.PlayTime, out _)) { plrDto.PlayTime = TimeSpan.FromSeconds(0).ToString(); } if (plrDto.Level > 0 && plrDto.TotalExperience == 0) { if (!expTable.TryGetValue(plrDto.Level, out expValue)) { expValue = new Experience(); expValue.TotalExperience = 0; Logger.Warning("Given level is not found in the experience table"); } plrDto.TotalExperience = expValue.TotalExperience - 1; await db.UpdateAsync(plrDto); } } session.Player = new Player(session, account, plrDto); } GameServer.Instance.PlayerManager.Add(session.Player); Logger.ForAccount(account) .Information("Login success"); var result = string.IsNullOrWhiteSpace(account.Nickname) ? GameLoginResult.ChooseNickname : GameLoginResult.OK; if (result == GameLoginResult.ChooseNickname) { session.Player.Account.Nickname = session.Player.Account.Username; session.Player.CharacterManager.CreateFirst(0, 0, 0, 0, 0, 0); using (var db = AuthDatabase.Open()) { var mapping = OrmConfiguration .GetDefaultEntityMapping <AccountDto>() .Clone() .UpdatePropertiesExcluding(prop => prop.IsExcludedFromUpdates = true, nameof(AccountDto.Nickname)); await db.UpdateAsync( new AccountDto { Id = (int)session.Player.Account.Id, Nickname = session.Player.Account.Username }, statement => statement.WithEntityMappingOverride(mapping)); } Logger.ForAccount(account) .Information($"Created Account for {session.Player.Account.Username}"); } else if (!session.Player.CharacterManager.CheckChars()) { session.Player.CharacterManager.CreateFirst(0, 0, 0, 0, 0, 0); } await session.SendAsync(new LoginReguestAckMessage(0, session.Player.Account.Id)); if (!string.IsNullOrWhiteSpace(account.Nickname)) { await LoginAsync(session); } }
public async Task LoginHandler(GameSession session, CLoginReqMessage message) { Logger.Info() .Account(message.AccountId, message.Username) .Message($"Login from {session.RemoteEndPoint}") .Write(); if (message.Version != s_version) { Logger.Error() .Account(message.AccountId, message.Username) .Message($"Invalid client version {message.Version}") .Write(); session.SendAsync(new SLoginAckMessage(GameLoginResult.WrongVersion)); return; } if (GameServer.Instance.PlayerManager.Count >= Config.Instance.PlayerLimit) { Logger.Error() .Account(message.AccountId, message.Username) .Message("Server is full") .Write(); session.SendAsync(new SLoginAckMessage(GameLoginResult.ServerFull)); return; } #region Validate Login AccountDto accountDto; using (var db = AuthDatabase.Open()) { accountDto = (await db.FindAsync <AccountDto>(statement => statement .Include <BanDto>(join => join.LeftOuterJoin()) .Where($"{nameof(AccountDto.Id):C} = @Id") .WithParameters(new { Id = message.AccountId }))) .FirstOrDefault(); } if (accountDto == null) { Logger.Error() .Account(message.AccountId, message.Username) .Message("Wrong login") .Write(); session.SendAsync(new SLoginAckMessage(GameLoginResult.SessionTimeout)); return; } uint inputSessionId; if (!uint.TryParse(message.SessionId, out inputSessionId)) { Logger.Error() .Account(message.AccountId, message.Username) .Message("Wrong login") .Write(); session.SendAsync(new SLoginAckMessage(GameLoginResult.SessionTimeout)); return; } var sessionId = Hash.GetUInt32 <CRC32>($"<{accountDto.Username}+{accountDto.Password}>"); if (sessionId != inputSessionId) { Logger.Error() .Account(message.AccountId, message.Username) .Message("Wrong login") .Write(); session.SendAsync(new SLoginAckMessage(GameLoginResult.SessionTimeout)); return; } var now = DateTimeOffset.Now.ToUnixTimeSeconds(); var ban = accountDto.Bans.FirstOrDefault(b => b.Date + (b.Duration ?? 0) > now); if (ban != null) { var unbanDate = DateTimeOffset.FromUnixTimeSeconds(ban.Date + (ban.Duration ?? 0)); Logger.Error() .Account(message.AccountId, message.Username) .Message($"Banned until {unbanDate}") .Write(); session.SendAsync(new SLoginAckMessage(GameLoginResult.SessionTimeout)); return; } var account = new Account(accountDto); #endregion if (account.SecurityLevel < Config.Instance.SecurityLevel) { Logger.Error() .Account(account) .Message($"No permission to enter this server({Config.Instance.SecurityLevel} or above required)") .Write(); session.SendAsync(new SLoginAckMessage((GameLoginResult)9)); return; } if (message.KickConnection) { Logger.Info() .Account(account) .Message("Kicking old connection") .Write(); var oldPlr = GameServer.Instance.PlayerManager.Get(account.Id); oldPlr?.Disconnect(); } if (GameServer.Instance.PlayerManager.Contains(account.Id)) { Logger.Error() .Account(account) .Message("Already online") .Write(); session.SendAsync(new SLoginAckMessage(GameLoginResult.TerminateOtherConnection)); return; } using (var db = GameDatabase.Open()) { var plrDto = (await db.FindAsync <PlayerDto>(statement => statement .Include <PlayerCharacterDto>(join => join.LeftOuterJoin()) .Include <PlayerDenyDto>(join => join.LeftOuterJoin()) .Include <PlayerItemDto>(join => join.LeftOuterJoin()) .Include <PlayerLicenseDto>(join => join.LeftOuterJoin()) .Include <PlayerMailDto>(join => join.LeftOuterJoin()) .Include <PlayerSettingDto>(join => join.LeftOuterJoin()) .Where($"{nameof(PlayerDto.Id):C} = @Id") .WithParameters(new { Id = message.AccountId }))) .FirstOrDefault(); if (plrDto == null) { // first time connecting to this server var expTable = GameServer.Instance.ResourceCache.GetExperience(); Experience expValue; if (!expTable.TryGetValue(Config.Instance.Game.StartLevel, out expValue)) { expValue = new Experience(); expValue.TotalExperience = 0; Logger.Warn($"Given start level is not found in the experience table"); } plrDto = new PlayerDto { Id = (int)account.Id, Level = Config.Instance.Game.StartLevel, PEN = Config.Instance.Game.StartPEN, AP = Config.Instance.Game.StartAP, Coins1 = Config.Instance.Game.StartCoins1, Coins2 = Config.Instance.Game.StartCoins2, TotalExperience = (int)expValue.TotalExperience }; await db.InsertAsync(plrDto); } session.Player = new Player(session, account, plrDto); } if (GameServer.Instance.PlayerManager.Contains(session.Player)) { session.Player = null; Logger.Error() .Account(account) .Message("Already online") .Write(); session.SendAsync(new SLoginAckMessage(GameLoginResult.TerminateOtherConnection)); return; } GameServer.Instance.PlayerManager.Add(session.Player); Logger.Info() .Account(account) .Message("Login success") .Write(); var result = string.IsNullOrWhiteSpace(account.Nickname) ? GameLoginResult.ChooseNickname : GameLoginResult.OK; await session.SendAsync(new SLoginAckMessage(result, session.Player.Account.Id)); if (!string.IsNullOrWhiteSpace(account.Nickname)) { await LoginAsync(session); } }
private static void RegisterMappings() { Mapper.Register <GameServer, ServerInfoDto>() .Member(dest => dest.ApiKey, src => Config.Instance.AuthAPI.ApiKey) .Member(dest => dest.Id, src => Config.Instance.Id) .Member(dest => dest.Name, src => $"{Config.Instance.Name}") .Member(dest => dest.PlayerLimit, src => Config.Instance.PlayerLimit) .Member(dest => dest.PlayerOnline, src => src.Sessions.Count) .Member(dest => dest.EndPoint, src => new IPEndPoint(IPAddress.Parse(Config.Instance.IP), Config.Instance.Listener.Port)) .Member(dest => dest.ChatEndPoint, src => new IPEndPoint(IPAddress.Parse(Config.Instance.IP), Config.Instance.ChatListener.Port)); Mapper.Register <Player, PlayerAccountInfoDto>() .Function(dest => dest.IsGM, src => src.Account.SecurityLevel > SecurityLevel.Tester) .Member(dest => dest.GameTime, src => TimeSpan.Parse(src.PlayTime)) .Member(dest => dest.TotalExp, src => src.TotalExperience) .Function(dest => dest.TutorialState, src => (uint)(Config.Instance.Game.EnableTutorial ? src.TutorialState : 1)) .Member(dest => dest.Nickname, src => src.Account.Nickname) .Member(dest => dest.TotalMatches, src => src.TotalLosses + src.TotalWins) .Member(dest => dest.MatchesWon, src => src.TotalWins) .Member(dest => dest.MatchesLost, src => src.TotalLosses) .Member(dest => dest.BRStats, src => src.stats.BattleRoyal.GetStatsDto()) .Member(dest => dest.ChaserStats, src => src.stats.Chaser.GetStatsDto()) .Member(dest => dest.CPTStats, src => src.stats.Captain.GetStatsDto()) .Member(dest => dest.DMStats, src => src.stats.DeathMatch.GetStatsDto()) .Member(dest => dest.TDStats, src => src.stats.TouchDown.GetStatsDto()) .Member(dest => dest.SiegeStats, src => src.stats.Siege.GetStatsDto()); Mapper.Register <Channel, ChannelInfoDto>() .Member(dest => dest.PlayersOnline, src => src.Players.Count); Mapper.Register <PlayerItem, ItemDto>() .Member(dest => dest.Id, src => src.Id) .Function(dest => dest.ExpireTime, src => src.CalculateExpireTime()) .Function(dest => dest.EnchantMP, src => src.EnchantMP) .Function(dest => dest.EnchantLevel, src => src.EnchantLvl) .Function(dest => dest.Durability, src => { if (src.PeriodType == ItemPeriodType.Units) { return((int)src.Count); } return(src.Durability); }) .Function(dest => dest.Effects, src => { var desteffects = new List <ItemEffectDto>(); src.Effects.ToList().ForEach(eff => { desteffects.Add(new ItemEffectDto { Effect = eff }); }); return(desteffects.ToArray()); }); Mapper.Register <Deny, DenyDto>() .Member(dest => dest.AccountId, src => src.DenyId) .Member(dest => dest.Nickname, src => src.Nickname); Mapper.Register <PlayerItem, Data.P2P.ItemDto>() .Function(dest => dest.ItemNumber, src => src?.ItemNumber ?? 0); Mapper.Register <RoomCreationOptions, ChangeRuleDto>() .Function(dest => dest.GameRule, src => src.GameRule) .Member(dest => dest.MapId, src => (byte)src.MapId) .Member(dest => dest.PlayerLimit, src => src.PlayerLimit) .Member(dest => dest.Points, src => src.ScoreLimit) .Member(dest => dest.Time, src => (byte)src.TimeLimit.TotalMinutes) .Member(dest => dest.ItemLimit, src => src.ItemLimit) .Member(dest => dest.Password, src => src.Password) .Member(dest => dest.Name, src => src.Name) .Member(dest => dest.HasSpectator, src => src.HasSpectator) .Member(dest => dest.SpectatorLimit, src => src.SpectatorLimit); Mapper.Register <RoomCreationOptions, ChangeRuleDto2>() .Function(dest => dest.GameRule, src => src.GameRule) .Member(dest => dest.MapId, src => (byte)src.MapId) .Member(dest => dest.PlayerLimit, src => src.PlayerLimit) .Member(dest => dest.Points, src => src.ScoreLimit) .Value(dest => dest.Unk1, 0) .Member(dest => dest.Time, src => (byte)src.TimeLimit.TotalMinutes) .Member(dest => dest.ItemLimit, src => src.ItemLimit) .Member(dest => dest.Password, src => src.Password) .Member(dest => dest.Name, src => src.Name) .Member(dest => dest.HasSpectator, src => src.HasSpectator) .Member(dest => dest.SpectatorLimit, src => src.SpectatorLimit) .Member(dest => dest.ChangeRuleId, src => src.ChangeRuleId) .Member(dest => dest.FMBurnMode, src => src.GetFMBurnModeInfo()); Mapper.Register <Mail, NoteDto>() .Function(dest => dest.ReadCount, src => src.IsNew ? 0 : 1) .Function(dest => dest.DaysLeft, src => DateTimeOffset.Now < src.Expires ? (src.Expires - DateTimeOffset.Now).TotalDays : 0) .Function(dest => dest.IsGift, src => src.IsClan) .Function(dest => dest.Sender, src => src.IsClan ? string.Empty : src.Sender); Mapper.Register <Mail, NoteContentDto>() .Member(dest => dest.Id, src => src.Id) .Member(dest => dest.Message, src => src.Message) .Function(dest => dest.Unk1, src => src.IsClan ? 0x1 : 0x0) .Function(dest => dest.Unk2, src => src.IsClan ? 0x1 : 0x0); Mapper.Register <PlayerItem, ItemDurabilityInfoDto>() .Member(dest => dest.ItemId, src => src.Id) .Function(dest => dest.Durabilityloss, src => { var loss = src.DurabilityLoss; src.DurabilityLoss = 0; return(loss); }); Mapper.Register <Player, PlayerInfoShortDto>() .Function(dest => dest.AccountId, src => src?.Account?.Id ?? 0) .Function(dest => dest.Nickname, src => src?.Account?.Nickname ?? "n/A") .Function(dest => dest.IsGM, src => src?.Account?.SecurityLevel > SecurityLevel.Tester) .Function(dest => dest.TotalExp, src => src?.TotalExperience ?? 0); Mapper.Register <Player, PlayerLocationDto>() .Function(dest => dest.ChannelId, src => src.Channel?.Id > 0 ? (int)src?.Channel?.Id : -1) .Function(dest => dest.RoomId, src => src.Room?.Id > 0 ? (int)src?.Room?.Id : -1) .Function(dest => dest.ServerGroupId, src => Instance.PlayerManager.Contains(src.Account.Id) ? Config.Instance.Id : -1) .Function(dest => dest.GameServerId, src => Instance.PlayerManager.Contains(src.Account.Id) ? Config.Instance.Id : -1) // TODO Server ids .Function(dest => dest.ChatServerId, src => Instance.PlayerManager.Contains(src.Account.Id) ? Config.Instance.Id : -1); Mapper.Register <Player, PlayerInfoDto>() .Function(dest => dest.Info, src => src.Map <Player, PlayerInfoShortDto>()) .Function(dest => dest.Location, src => src.Map <Player, PlayerLocationDto>()); Mapper.Register <Player, UserDataDto>() .Member(dest => dest.TotalExp, src => src.TotalExperience) .Function(dest => dest.AccountId, src => src.Account?.Id ?? 0) .Function(dest => dest.Nickname, src => src.Account?.Nickname ?? "n/A") .Member(dest => dest.GameTime, src => TimeSpan.Parse(src.PlayTime)) .Member(dest => dest.TotalMatches, src => src.TotalMatches) .Member(dest => dest.MatchesWon, src => src.TotalWins) .Member(dest => dest.MatchesLost, src => src.TotalLosses) .Member(dest => dest.Level, src => src.Level) .Member(dest => dest.BattleRoyalStats, src => src.stats.BattleRoyal.GetUserDataDto()) .Member(dest => dest.BRScore, src => 0) .Member(dest => dest.CaptainStats, src => src.stats.Captain.GetUserDataDto()) .Member(dest => dest.CaptainScore, src => 0) .Member(dest => dest.ChaserStats, src => src.stats.Chaser.GetUserDataDto()) .Member(dest => dest.ChaserSurvivability, src => 0) .Member(dest => dest.DMStats, src => src.stats.DeathMatch.GetUserDataDto()) .Member(dest => dest.DMScore, src => 0) .Member(dest => dest.TDStats, src => src.stats.TouchDown.GetUserDataDto()) .Member(dest => dest.TDScore, src => 0) .Member(dest => dest.SiegeStats, src => src.stats.Siege.GetUserDataDto()) .Member(dest => dest.SiegeScore, src => 0); Mapper.Register <Player, PlayerNameTagInfoDto>() .Member(dest => dest.AccountId, src => src.Account.Id); Mapper.Register <Player, ClubMyInfoDto>() .Function(dest => dest.Id, src => src.Club?.Id ?? 0) .Function(dest => dest.Name, src => src.Club?.ClanName ?? string.Empty) .Function(dest => dest.Rank, src => src.Club?.GetPlayer(src.Account.Id)?.Rank ?? ClubRank.Regular) .Function(dest => dest.Type, src => src.Club?.ClanIcon ?? string.Empty) .Function(dest => dest.State, src => src.Club?[src.Account?.Id ?? 0].State ?? 0); Mapper.Register <Player, PlayerClubInfoDto>() .Function(dest => dest.Id, src => src.Club?.Id ?? 0) .Function(dest => dest.Name, src => src.Club?.ClanName ?? string.Empty) .Function(dest => dest.Type, src => src.Club?.ClanIcon ?? string.Empty); Mapper.Register <Player, ClubMemberDto2>() .Function(dest => dest.AccountId, src => src.Account?.Id ?? 0) .Function(dest => dest.Nickname, src => src.Account?.Nickname ?? "n/A") .Function(dest => dest.ServerId, src => Instance.PlayerManager.Contains(src.Account.Id) ? Config.Instance.Id : -1) .Function(dest => dest.ChannelId, src => src.Channel?.Id > 0 ? src.Channel.Id : -1) .Function(dest => dest.RoomId, src => src.Room?.Id > 0 ? (int)src.Room.Id : -1) .Function(dest => dest.ClanRank, src => src.Club?.GetPlayer(src.Account.Id)?.Rank ?? ClubRank.Regular) .Function(dest => dest.LastLogin, src => src.Account?.AccountDto?.LastLogin ?? string.Empty); Mapper.Register <ClubPlayerInfo, ClubMemberDto2>() .Function(dest => dest.AccountId, src => src.AccountId) .Function(dest => dest.Nickname, src => src.Account?.Nickname ?? "n/A") .Function(dest => dest.LastLogin, src => src.Account.LastLogin ?? string.Empty) .Function(dest => dest.ClanRank, src => src.Rank) .Value(dest => dest.ServerId, -1) .Value(dest => dest.ChannelId, -1) .Value(dest => dest.RoomId, -1); Mapper.Register <Player, ClubMemberDto>() .Function(dest => dest.AccountId, src => src.Account?.Id ?? 0) .Function(dest => dest.Nickname, src => src.Account?.Nickname ?? "n/A") .Function(dest => dest.ClanRank, src => src.Club?.GetPlayer(src.Account.Id)?.Rank ?? ClubRank.Regular) .Function(dest => dest.LastLogin, src => src.Account?.AccountDto?.LastLogin ?? string.Empty); Mapper.Register <ClubPlayerInfo, ClubMemberDto>() .Function(dest => dest.AccountId, src => src.AccountId) .Function(dest => dest.Nickname, src => src.Account?.Nickname ?? "n/A") .Function(dest => dest.LastLogin, src => src.Account.LastLogin ?? string.Empty) .Function(dest => dest.ClanRank, src => src.Rank); Mapper.Register <Player, ClubInfoDto>() .Function(dest => dest.Id, src => src.Club?.Id ?? 0) .Function(dest => dest.Name, src => src.Club?.ClanName ?? "n/A") .Function(dest => dest.MasterName, src => src.Club?.Players.Values.FirstOrDefault(x => x.Rank == ClubRank.Master)?.Account?.Nickname ?? string.Empty) .Function(dest => dest.MemberCount, src => src.Club?.Count + 5 ?? 0) .Function(dest => dest.Type, src => src.Club?.ClanIcon ?? string.Empty); Mapper.Register <Player, ClubInfoDto2>() .Function(dest => dest.Id, src => src.Club?.Id ?? 0) .Function(dest => dest.Id2, src => src.Club?.Id ?? 0) .Function(dest => dest.Name, src => src.Club?.ClanName ?? "n/A") .Function(dest => dest.MasterName, src => src.Club?.Players.Values.FirstOrDefault(x => x.Rank == ClubRank.Master)?.Account?.Nickname ?? string.Empty) .Function(dest => dest.MemberCount, src => src.Club?.Count + 5 ?? 0) .Function(dest => dest.Type, src => src.Club?.ClanIcon ?? string.Empty); Mapper.Register <Friend, PlayerInfoDto>() .Function(dest => dest.Info, src => { var plr = Instance.PlayerManager.Get(src.FriendId); if (plr != null) { return(plr.Map <Player, PlayerInfoShortDto>()); } using (var authdb = AuthDatabase.Open()) using (var db = GameDatabase.Open()) { var accountDto = DbUtil.Find <AccountDto>(authdb, statement => statement .Where($"{nameof(AccountDto.Id):C} = @Id") .WithParameters(new { Id = src.FriendId })).FirstOrDefault(); var playerDto = DbUtil.Find <PlayerDto>(db, statement => statement .Where($"{nameof(PlayerDto.Id):C} = @Id") .WithParameters(new { Id = src.FriendId })).FirstOrDefault(); if (playerDto != null && accountDto != null) { return(new PlayerInfoShortDto(src.FriendId, accountDto.Nickname, playerDto.TotalExperience, (SecurityLevel)accountDto.SecurityLevel >= SecurityLevel.GameSage)); } if (accountDto != null) { return(new PlayerInfoShortDto(src.FriendId, accountDto.Username, 0, ((SecurityLevel)accountDto.SecurityLevel) >= SecurityLevel.GameSage)); } return(new PlayerInfoShortDto(0, string.Empty, 0, false)); } }) .Function(dest => dest.Location, src => { var plr = Instance.PlayerManager.Get(src.FriendId); return(plr?.Map <Player, PlayerLocationDto>() ?? new PlayerLocationDto()); }); Mapper.Register <ClubPlayerInfo, PlayerInfoDto>() .Function(dest => dest.Info, src => { var plr = Instance.PlayerManager.Get(src.AccountId); if (plr != null) { return(plr.Map <Player, PlayerInfoShortDto>()); } using (var db = GameDatabase.Open()) { var playerDto = DbUtil.Find <PlayerDto>(db, statement => statement .Where($"{nameof(PlayerDto.Id):C} = @Id") .WithParameters(new { Id = src.AccountId })).FirstOrDefault(); if (playerDto != null) { return(new PlayerInfoShortDto(src.AccountId, src.Account?.Nickname ?? string.Empty, playerDto.TotalExperience, (SecurityLevel)src.Account.SecurityLevel >= SecurityLevel.GameSage)); } return(new PlayerInfoShortDto(src.AccountId, src.Account?.Nickname ?? string.Empty, 0, ((SecurityLevel)(src.Account?.SecurityLevel ?? 0)) >= SecurityLevel.GameSage)); } }) .Function(dest => dest.Location, src => { var plr = Instance.PlayerManager.Get(src.AccountId); return(plr?.Map <Player, PlayerLocationDto>() ?? new PlayerLocationDto()); }); Mapper.Compile(CompilationTypes.Source); }
public static async Task <bool> ChangeNickname(Player plr, NicknameHistoryDto nicknameHistory, bool restore) { var toNickname = nicknameHistory.NewNickname; try { using (var db = AuthDatabase.Open()) { var account = (await DbUtil.FindAsync <AccountDto>(db, statement => statement .Where($"{nameof(AccountDto.Nickname):C} = @Nickname") .WithParameters(new { plr.Account.Nickname }))).FirstOrDefault(); if (account == null) { await plr.Session.SendAsync(new ServerResultAckMessage(ServerResult.FailedToRequestTask)); return(false); } if (restore) { var nicknameHistory1 = await DbUtil.FindAsync <NicknameHistoryDto>(db, statement => statement .Where($"{nameof(NicknameHistoryDto.AccountId):C} = @Id") .WithParameters(new { plr.Account.Id })); var firstchange = nicknameHistory1.FirstOrDefault(); if (firstchange == null) { await plr.Session.SendAsync(new ServerResultAckMessage(ServerResult.NicknameUnavailable)); return(false); } account.Nickname = firstchange.OldName; plr.Account.Nickname = firstchange.OldName; foreach (var history in nicknameHistory1) { await DbUtil.DeleteAsync(db, history); } await plr.Session.SendAsync(new ItemUseChangeNickCancelAckMessage(0)); } else { if (!await AuthService.IsNickAvailableAsync(toNickname)) { await plr.Session.SendAsync(new ServerResultAckMessage(ServerResult.NicknameUnavailable)); return(false); } account.Nickname = toNickname; plr.Account.Nickname = toNickname; DbUtil.Insert(db, nicknameHistory); await plr.Session.SendAsync(new ItemUseChangeNickAckMessage { Result = 0, Unk2 = 0, Unk3 = toNickname }); } DbUtil.Update(db, account); return(true); } } catch (Exception e) { Logger.Error(e.ToString()); await plr.Session.SendAsync(new ServerResultAckMessage(ServerResult.FailedToRequestTask)); return(false); } }
public async Task LoginHandler(GameSession session, LoginRequestReqMessage message) { Logger.ForAccount(message.AccountId, message.Username) .Information("Login from {remoteEndPoint}", session.RemoteEndPoint); //if (message.Version != s_version) //{ // Logger.ForAccount(message.AccountId, message.Username) // .Error("Invalid client version {version}", message.Version); // // session.SendAsync(new LoginReguestAckMessage(GameLoginResult.WrongVersion)); // return; //} if (GameServer.Instance.PlayerManager.Count >= Config.Instance.PlayerLimit) { Logger.ForAccount(message.AccountId, message.Username) .Error("Server is full"); session.SendAsync(new LoginReguestAckMessage(GameLoginResult.ServerFull)); return; } #region Validate Login AccountDto accountDto; using (var db = AuthDatabase.Open()) { accountDto = (await db.FindAsync <AccountDto>(statement => statement .Include <BanDto>(join => join.LeftOuterJoin()) .Where($"{nameof(AccountDto.Id):C} = @Id") .WithParameters(new { Id = message.AccountId }))) .FirstOrDefault(); } if (accountDto == null) { Logger.ForAccount(message.AccountId, message.Username) .Error("Wrong login"); session.SendAsync(new LoginReguestAckMessage(GameLoginResult.SessionTimeout)); return; } uint inputSessionId; if (!uint.TryParse(message.SessionId, out inputSessionId)) { Logger.ForAccount(message.AccountId, message.Username) .Error("Wrong login"); session.SendAsync(new LoginReguestAckMessage(GameLoginResult.SessionTimeout)); return; } var sessionId = Hash.GetUInt32 <CRC32>($"<{accountDto.Username}+{accountDto.Password}>"); if (sessionId != inputSessionId) { Logger.ForAccount(message.AccountId, message.Username) .Error("Wrong sessionid(1)"); session.SendAsync(new LoginReguestAckMessage(GameLoginResult.SessionTimeout)); return; } string datetime = $"{DateTimeOffset.Now.DateTime}"; var authsessionId = Hash.GetString <CRC32>($"<{accountDto.Username}+{sessionId}+{message.Datetime}>"); if (authsessionId != message.AuthToken) { Logger.ForAccount(message.AccountId, message.Username) .Error("Wrong sessionid(2)"); session.SendAsync(new LoginReguestAckMessage(GameLoginResult.SessionTimeout)); return; } var newsessionId = Hash.GetString <CRC32>($"<{authsessionId}+{sessionId}>"); if (newsessionId != message.newToken) { Logger.ForAccount(message.AccountId, message.Username) .Error("Wrong sessionid(3)"); session.SendAsync(new LoginReguestAckMessage(GameLoginResult.SessionTimeout)); return; } var now = DateTimeOffset.Now.ToUnixTimeSeconds(); var ban = accountDto.Bans.FirstOrDefault(b => b.Date + (b.Duration ?? 0) > now); if (ban != null) { var unbanDate = DateTimeOffset.FromUnixTimeSeconds(ban.Date + (ban.Duration ?? 0)); Logger.ForAccount(message.AccountId, message.Username) .Error("Banned until {unbanDate}", unbanDate); session.SendAsync(new LoginReguestAckMessage(GameLoginResult.SessionTimeout)); return; } var account = new Account(accountDto); #endregion if (account.SecurityLevel < Config.Instance.SecurityLevel) { Logger.ForAccount(account) .Error("No permission to enter this server({securityLevel} or above required)", Config.Instance.SecurityLevel); session.SendAsync(new LoginReguestAckMessage((GameLoginResult)9)); return; } if (message.KickConnection) { Logger.ForAccount(account) .Information("Kicking old connection"); var oldPlr = GameServer.Instance.PlayerManager.Get(account.Id); oldPlr?.Disconnect(); } if (GameServer.Instance.PlayerManager.Contains(account.Id)) { Logger.ForAccount(account) .Error("Already online"); session.SendAsync(new LoginReguestAckMessage(GameLoginResult.TerminateOtherConnection)); return; } using (var db = GameDatabase.Open()) { var plrDto = (await db.FindAsync <PlayerDto>(statement => statement .Include <PlayerCharacterDto>(join => join.LeftOuterJoin()) .Include <PlayerDenyDto>(join => join.LeftOuterJoin()) .Include <PlayerItemDto>(join => join.LeftOuterJoin()) .Include <PlayerMailDto>(join => join.LeftOuterJoin()) .Include <PlayerSettingDto>(join => join.LeftOuterJoin()) .Where($"{nameof(PlayerDto.Id):C} = @Id") .WithParameters(new { Id = message.AccountId }))) .FirstOrDefault(); if (plrDto == null) { // first time connecting to this server var expTable = GameServer.Instance.ResourceCache.GetExperience(); Experience expValue; if (!expTable.TryGetValue(Config.Instance.Game.StartLevel, out expValue)) { expValue = new Experience(); expValue.TotalExperience = 0; Logger.Warning("Given start level is not found in the experience table"); } plrDto = new PlayerDto { Id = (int)account.Id, Level = Config.Instance.Game.StartLevel, PEN = Config.Instance.Game.StartPEN, AP = Config.Instance.Game.StartAP, Coins1 = Config.Instance.Game.StartCoins1, Coins2 = Config.Instance.Game.StartCoins2, TotalExperience = (int)expValue.TotalExperience }; await db.InsertAsync(plrDto); } session.Player = new Player(session, account, plrDto); } if (GameServer.Instance.PlayerManager.Contains(session.Player)) { session.Player = null; Logger.ForAccount(account) .Error("Already online"); session.SendAsync(new LoginReguestAckMessage(GameLoginResult.TerminateOtherConnection)); return; } GameServer.Instance.PlayerManager.Add(session.Player); Logger.ForAccount(account) .Information("Login success"); var result = string.IsNullOrWhiteSpace(account.Nickname) ? GameLoginResult.ChooseNickname : GameLoginResult.OK; if (result == GameLoginResult.ChooseNickname) { session.Player.Account.Nickname = session.Player.Account.Username; session.Player.CharacterManager.CreateFirst(0, 0, 0, 0, 0, 0); using (var db = AuthDatabase.Open()) { var mapping = OrmConfiguration .GetDefaultEntityMapping <AccountDto>() .Clone() .UpdatePropertiesExcluding(prop => prop.IsExcludedFromUpdates = true, nameof(AccountDto.Nickname)); await db.UpdateAsync(new AccountDto { Id = (int)session.Player.Account.Id, Nickname = session.Player.Account.Username }, statement => statement.WithEntityMappingOverride(mapping)); } Logger.ForAccount(account) .Information($"Created Account for {session.Player.Account.Username}"); } else if (!session.Player.CharacterManager.CheckChars()) { session.Player.CharacterManager.CreateFirst(0, 0, 0, 0, 0, 0); } await session.SendAsync(new LoginReguestAckMessage(0, session.Player.Account.Id)); if (!string.IsNullOrWhiteSpace(account.Nickname)) { await LoginAsync(session); } }
public override void ChannelRead(IChannelHandlerContext context, object messageData) { var buffer = messageData as IByteBuffer; byte[] data = buffer.ToArray(); RmiMessage __msg = new RmiMessage(data, data.Length); short magic = 0; ByteArray _message = new ByteArray(); if (__msg.Read(ref magic) && magic == Magic && __msg.Read(ref _message)) { RmiMessage message = new RmiMessage(_message); MessageType coreID = 0; if (message.Read(ref coreID)) { switch (coreID) { case MessageType.Rmi: { short RmiID = 0; if (message.Read(ref RmiID)) { switch (RmiID) { case 15: { AccountDto account; string Username = ""; string Password = ""; bool register = false; if (message.Read(ref Username) && message.Read(ref Password) && message.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) { var result = db.Find <AccountDto>(statement => statement .Where($"{nameof(AccountDto.Username):C} = @{nameof(Username)}") .Include <BanDto>(join => join.LeftOuterJoin()) .WithParameters(new { Username })); account = result.FirstOrDefault(); if (account == null) { 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 salt = Convert.FromBase64String(account.Salt); var passwordGuess = new byte[24]; using (var pbkdf2 = new Rfc2898DeriveBytes(Password, salt, 24000)) passwordGuess = pbkdf2.GetBytes(24); var actualPassword = Convert.FromBase64String(account.Password); uint 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)) { Logger.Error("Wrong authentication credentials for {username} / {endpoint}", Username, context.Channel.RemoteAddress.ToString()); RmiMessage ack = new RmiMessage(); ack.Write(false); ack.Write("Login failed"); RmiSend(context, 16, ack); } else { account.LoginToken = AuthHash.GetHash256($"{context.Channel.RemoteAddress.ToString()}-{account.Username}-{account.Password}").ToLower(); account.LastLogin = $"{DateTimeOffset.Now}"; account.AuthToken = ""; account.newToken = ""; db.UpdateAsync(account); RmiMessage ack = new RmiMessage(); 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()); RmiMessage ack = new RmiMessage(); 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()); RmiMessage ack = new RmiMessage(); 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 MessageType.Notify: { string info = ""; message.Read(ref info); Logger.Information("Received info! -> {received}", info); 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(); } }