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); } }
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; } } }