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.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Server.LoggerMessages;
|
||||||
using Wonderking.Packets.Incoming;
|
using Wonderking.Packets.Incoming;
|
||||||
using Wonderking.Packets.Outgoing;
|
using Wonderking.Packets.Outgoing;
|
||||||
|
|
||||||
|
@ -25,39 +26,39 @@ public class LoginHandler : IPacketHandler<LoginInfoPacket>
|
||||||
this._configuration = configuration;
|
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
|
// 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."
|
// "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,
|
MemorySize = 1024 * 19,
|
||||||
Iterations = 2,
|
Iterations = 2,
|
||||||
DegreeOfParallelism = 1
|
DegreeOfParallelism = 1,
|
||||||
|
Salt = salt,
|
||||||
|
AssociatedData = userId.ToByteArray()
|
||||||
};
|
};
|
||||||
if (account == null)
|
return argon2Id.GetBytesAsync(16);
|
||||||
{
|
}
|
||||||
if (this._configuration.GetSection("Testing").GetValue<bool>("CreateAccountOnLogin"))
|
|
||||||
|
private async Task<LoginResponseReason> CreateAccountOnLoginAsync(string username, string password)
|
||||||
{
|
{
|
||||||
|
LoginResponseReason loginResponseReason;
|
||||||
var transaction =
|
var transaction =
|
||||||
await _wonderkingContext.Database.BeginTransactionAsync().ConfigureAwait(true);
|
await _wonderkingContext.Database.BeginTransactionAsync().ConfigureAwait(true);
|
||||||
await using (transaction.ConfigureAwait(true))
|
await using (transaction.ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
argon2Id.Salt = RandomNumberGenerator.GetBytes(16);
|
var salt = RandomNumberGenerator.GetBytes(16);
|
||||||
var finalAccount =
|
var finalAccount =
|
||||||
await this._wonderkingContext.Accounts.AddAsync(new Account(packet.Username,
|
await this._wonderkingContext.Accounts.AddAsync(new Account(username,
|
||||||
Array.Empty<byte>(), "",
|
Array.Empty<byte>(), "",
|
||||||
0, argon2Id.Salt)).ConfigureAwait(true);
|
0, salt)).ConfigureAwait(true);
|
||||||
await this._wonderkingContext.SaveChangesAsync().ConfigureAwait(true);
|
await this._wonderkingContext.SaveChangesAsync().ConfigureAwait(true);
|
||||||
argon2Id.AssociatedData = finalAccount.Entity.Id.ToByteArray();
|
finalAccount.Entity.Password =
|
||||||
finalAccount.Entity.Password = await argon2Id.GetBytesAsync(16).ConfigureAwait(true);
|
await LoginHandler.GetPasswordHashAsync(password, salt, finalAccount.Entity.Id)
|
||||||
|
.ConfigureAwait(true);
|
||||||
this._wonderkingContext.Accounts.Update(finalAccount.Entity);
|
this._wonderkingContext.Accounts.Update(finalAccount.Entity);
|
||||||
loginResponseReason = LoginResponseReason.Ok;
|
loginResponseReason = LoginResponseReason.Ok;
|
||||||
await this._wonderkingContext.SaveChangesAsync().ConfigureAwait(true);
|
await this._wonderkingContext.SaveChangesAsync().ConfigureAwait(true);
|
||||||
|
@ -70,18 +71,34 @@ public class LoginHandler : IPacketHandler<LoginInfoPacket>
|
||||||
throw;
|
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"))
|
||||||
|
{
|
||||||
|
loginResponseReason = await CreateAccountOnLoginAsync(packet.Username, packet.Password)
|
||||||
|
.ConfigureAwait(true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this._logger.LogInformation("Requested account for user: {Username} does not exist", packet.Username);
|
this._logger.RequestedAccountDoesNotExist(packet.Username);
|
||||||
loginResponseReason = LoginResponseReason.AccountDoesNotExit;
|
loginResponseReason = LoginResponseReason.AccountDoesNotExit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
argon2Id.Salt = account.Salt;
|
var salt = account.Salt;
|
||||||
argon2Id.AssociatedData = account.Id.ToByteArray();
|
var tempPasswordBytes = await LoginHandler.GetPasswordHashAsync(packet.Password, salt, account.Id)
|
||||||
var tempPasswordBytes = await argon2Id.GetBytesAsync(16).ConfigureAwait(true);
|
.ConfigureAwait(false);
|
||||||
loginResponseReason = tempPasswordBytes.SequenceEqual(account.Password)
|
loginResponseReason = tempPasswordBytes.SequenceEqual(account.Password)
|
||||||
? LoginResponseReason.Ok
|
? LoginResponseReason.Ok
|
||||||
: LoginResponseReason.WrongPassword;
|
: LoginResponseReason.WrongPassword;
|
||||||
|
@ -100,6 +117,7 @@ public class LoginHandler : IPacketHandler<LoginInfoPacket>
|
||||||
sess.AccountId = account.Id;
|
sess.AccountId = account.Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation("LoginResponsePacket: {@LoginResponsePacket}", loginResponsePacket);
|
||||||
sess?.Send(loginResponsePacket);
|
sess?.Send(loginResponsePacket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue