refactor: Complexity & Method length
This commit is contained in:
parent
9356a729b0
commit
1a13c3fb1b
2 changed files with 71 additions and 38 deletions
15
Server/LoggerMessages/LoginHandlerLoggerMessages.cs
Normal file
15
Server/LoggerMessages/LoginHandlerLoggerMessages.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
using Server.PacketHandlers;
|
||||
|
||||
namespace Server.LoggerMessages;
|
||||
|
||||
public static partial class LoginHandlerLoggerMessages
|
||||
{
|
||||
[LoggerMessage(EventId = 0, Level = LogLevel.Information,
|
||||
Message = "Login data: Username {Username} & Password {Password}")]
|
||||
public static partial void LoginData(this ILogger<LoginHandler> logger, string username, string password);
|
||||
|
||||
[LoggerMessage(EventId = 1, Level = LogLevel.Information,
|
||||
Message = "Requested account for user: {Username} does not exist")]
|
||||
public static partial void RequestedAccountDoesNotExist(this ILogger<LoginHandler> logger, string username);
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Server.LoggerMessages;
|
||||
using Wonderking.Packets.Incoming;
|
||||
using Wonderking.Packets.Outgoing;
|
||||
|
||||
|
@ -25,63 +26,79 @@ public class LoginHandler : IPacketHandler<LoginInfoPacket>
|
|||
this._configuration = configuration;
|
||||
}
|
||||
|
||||
public async Task HandleAsync(LoginInfoPacket packet, TcpSession session)
|
||||
private static Task<byte[]> GetPasswordHashAsync(string password, byte[] salt, Guid userId)
|
||||
{
|
||||
LoginResponseReason loginResponseReason;
|
||||
this._logger.LogInformation("Login data: Username {Username} & Password {Password}", packet.Username,
|
||||
packet.Password);
|
||||
var account = this._wonderkingContext.Accounts.FirstOrDefault(a => a.Username == packet.Username);
|
||||
|
||||
// https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Chea1t_Sheet.html#argon2id
|
||||
// "Use Argon2id with a minimum configuration of 19 MiB of memory, an iteration count of 2, and 1 degree of parallelism."
|
||||
var argon2Id = new Argon2id(Encoding.ASCII.GetBytes(packet.Password))
|
||||
var argon2Id = new Argon2id(Encoding.ASCII.GetBytes(password))
|
||||
{
|
||||
MemorySize = 1024 * 19,
|
||||
Iterations = 2,
|
||||
DegreeOfParallelism = 1
|
||||
DegreeOfParallelism = 1,
|
||||
Salt = salt,
|
||||
AssociatedData = userId.ToByteArray()
|
||||
};
|
||||
return argon2Id.GetBytesAsync(16);
|
||||
}
|
||||
|
||||
private async Task<LoginResponseReason> CreateAccountOnLoginAsync(string username, string password)
|
||||
{
|
||||
LoginResponseReason loginResponseReason;
|
||||
var transaction =
|
||||
await _wonderkingContext.Database.BeginTransactionAsync().ConfigureAwait(true);
|
||||
await using (transaction.ConfigureAwait(false))
|
||||
{
|
||||
try
|
||||
{
|
||||
var salt = RandomNumberGenerator.GetBytes(16);
|
||||
var finalAccount =
|
||||
await this._wonderkingContext.Accounts.AddAsync(new Account(username,
|
||||
Array.Empty<byte>(), "",
|
||||
0, salt)).ConfigureAwait(true);
|
||||
await this._wonderkingContext.SaveChangesAsync().ConfigureAwait(true);
|
||||
finalAccount.Entity.Password =
|
||||
await LoginHandler.GetPasswordHashAsync(password, salt, finalAccount.Entity.Id)
|
||||
.ConfigureAwait(true);
|
||||
this._wonderkingContext.Accounts.Update(finalAccount.Entity);
|
||||
loginResponseReason = LoginResponseReason.Ok;
|
||||
await this._wonderkingContext.SaveChangesAsync().ConfigureAwait(true);
|
||||
|
||||
await transaction.CommitAsync().ConfigureAwait(true);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await transaction.RollbackAsync().ConfigureAwait(true); // Rollback the transaction on error
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
return loginResponseReason;
|
||||
}
|
||||
|
||||
public async Task HandleAsync(LoginInfoPacket packet, TcpSession session)
|
||||
{
|
||||
LoginResponseReason loginResponseReason;
|
||||
this._logger.LoginData(packet.Username, packet.Password);
|
||||
var account = this._wonderkingContext.Accounts.FirstOrDefault(a => a.Username == packet.Username);
|
||||
|
||||
if (account == null)
|
||||
{
|
||||
if (this._configuration.GetSection("Testing").GetValue<bool>("CreateAccountOnLogin"))
|
||||
{
|
||||
var transaction =
|
||||
await _wonderkingContext.Database.BeginTransactionAsync().ConfigureAwait(true);
|
||||
await using (transaction.ConfigureAwait(true))
|
||||
{
|
||||
try
|
||||
{
|
||||
argon2Id.Salt = RandomNumberGenerator.GetBytes(16);
|
||||
var finalAccount =
|
||||
await this._wonderkingContext.Accounts.AddAsync(new Account(packet.Username,
|
||||
Array.Empty<byte>(), "",
|
||||
0, argon2Id.Salt)).ConfigureAwait(true);
|
||||
await this._wonderkingContext.SaveChangesAsync().ConfigureAwait(true);
|
||||
argon2Id.AssociatedData = finalAccount.Entity.Id.ToByteArray();
|
||||
finalAccount.Entity.Password = await argon2Id.GetBytesAsync(16).ConfigureAwait(true);
|
||||
this._wonderkingContext.Accounts.Update(finalAccount.Entity);
|
||||
loginResponseReason = LoginResponseReason.Ok;
|
||||
await this._wonderkingContext.SaveChangesAsync().ConfigureAwait(true);
|
||||
|
||||
await transaction.CommitAsync().ConfigureAwait(true);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await transaction.RollbackAsync().ConfigureAwait(true); // Rollback the transaction on error
|
||||
throw;
|
||||
}
|
||||
}
|
||||
loginResponseReason = await CreateAccountOnLoginAsync(packet.Username, packet.Password)
|
||||
.ConfigureAwait(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
this._logger.LogInformation("Requested account for user: {Username} does not exist", packet.Username);
|
||||
this._logger.RequestedAccountDoesNotExist(packet.Username);
|
||||
loginResponseReason = LoginResponseReason.AccountDoesNotExit;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
argon2Id.Salt = account.Salt;
|
||||
argon2Id.AssociatedData = account.Id.ToByteArray();
|
||||
var tempPasswordBytes = await argon2Id.GetBytesAsync(16).ConfigureAwait(true);
|
||||
var salt = account.Salt;
|
||||
var tempPasswordBytes = await LoginHandler.GetPasswordHashAsync(packet.Password, salt, account.Id)
|
||||
.ConfigureAwait(false);
|
||||
loginResponseReason = tempPasswordBytes.SequenceEqual(account.Password)
|
||||
? LoginResponseReason.Ok
|
||||
: LoginResponseReason.WrongPassword;
|
||||
|
@ -100,6 +117,7 @@ public class LoginHandler : IPacketHandler<LoginInfoPacket>
|
|||
sess.AccountId = account.Id;
|
||||
}
|
||||
|
||||
_logger.LogInformation("LoginResponsePacket: {@LoginResponsePacket}", loginResponsePacket);
|
||||
sess?.Send(loginResponsePacket);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue