From 0704d9f07d6cb47640851c552f623df54e1a426e Mon Sep 17 00:00:00 2001 From: Timothy Schenk Date: Fri, 24 Nov 2023 18:29:24 +0100 Subject: [PATCH] feat: compiledqueries + tracing --- .../LoginHandler.CompiledQueries.cs | 21 ++++++++++++ Server/PacketHandlers/LoginHandler.cs | 33 +++++++++++-------- 2 files changed, 40 insertions(+), 14 deletions(-) create mode 100644 Server/PacketHandlers/LoginHandler.CompiledQueries.cs diff --git a/Server/PacketHandlers/LoginHandler.CompiledQueries.cs b/Server/PacketHandlers/LoginHandler.CompiledQueries.cs new file mode 100644 index 0000000..53ddc66 --- /dev/null +++ b/Server/PacketHandlers/LoginHandler.CompiledQueries.cs @@ -0,0 +1,21 @@ +// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License. + +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; +using Server.DB; +using Server.DB.Documents; + +namespace Server.PacketHandlers; + +public partial class LoginHandler +{ + private static readonly Func>> _addAccount = + EF.CompileQuery((WonderkingContext context, Account account) => context.Accounts.AddAsync(account, default)); + + private static readonly Func>> _updateAccount = + EF.CompileAsyncQuery((WonderkingContext context, Account account) => context.Accounts.Update(account)); + + private static readonly Func> _getAccount = + EF.CompileQuery((WonderkingContext context, string username) => + context.Accounts.FirstOrDefaultAsync(a => a.Username == username, default)); +} diff --git a/Server/PacketHandlers/LoginHandler.cs b/Server/PacketHandlers/LoginHandler.cs index dc645c3..e395765 100644 --- a/Server/PacketHandlers/LoginHandler.cs +++ b/Server/PacketHandlers/LoginHandler.cs @@ -1,9 +1,10 @@ // Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License. +using System.Diagnostics; using System.Security.Cryptography; using System.Text; +using DotNext; using Konscious.Security.Cryptography; -using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using NetCoreServer; @@ -16,11 +17,12 @@ using Wonderking.Packets.Outgoing.Data; namespace Server.PacketHandlers; -public class LoginHandler : IPacketHandler +public partial class LoginHandler : IPacketHandler { private readonly IConfiguration _configuration; private readonly ILogger _logger; private readonly WonderkingContext _wonderkingContext; + private static readonly ActivitySource _activitySource = new ActivitySource(nameof(Server)); public LoginHandler(ILogger logger, WonderkingContext wonderkingContext, IConfiguration configuration) { @@ -33,14 +35,14 @@ public class LoginHandler : IPacketHandler { LoginResponseReason loginResponseReason; _logger.LoginData(packet.Username, packet.Password); - var account = await _wonderkingContext.Accounts.FirstOrDefaultAsync(a => a.Username == packet.Username); + var account = await _getAccount(_wonderkingContext, packet.Username); if (account == null) { if (_configuration.GetSection("Testing").GetValue("CreateAccountOnLogin")) { loginResponseReason = await CreateAccountOnLoginAsync(packet.Username, packet.Password); - account = await _wonderkingContext.Accounts.FirstOrDefaultAsync(a => a.Username == packet.Username); + account = await _getAccount(_wonderkingContext, packet.Username); } else { @@ -52,18 +54,21 @@ public class LoginHandler : IPacketHandler { var salt = account.Salt; var tempPasswordBytes = await GetPasswordHashAsync(packet.Password, salt, account.Id); - loginResponseReason = tempPasswordBytes.SequenceEqual(account.Password) + loginResponseReason = tempPasswordBytes.BitwiseEquals(account.Password) ? LoginResponseReason.Ok : LoginResponseReason.WrongPassword; } + var channelData = new ServerChannelData[1]; + channelData[0] = new ServerChannelData { ChannelId = 0, LoadPercentage = 0, ServerId = 0 }; var loginResponsePacket = new LoginResponsePacket { ResponseReason = loginResponseReason, - ChannelData = new[] { new ServerChannelData { ChannelId = 0, LoadPercentage = 0, ServerId = 0 } }, + ChannelData = channelData.ToArray(), UnknownFlag = 1, IsGameMaster = true }; + var authSession = session as AuthSession; if (account != null && authSession != null) { @@ -71,11 +76,12 @@ public class LoginHandler : IPacketHandler } _logger.LogInformation("LoginResponsePacket: {@LoginResponsePacket}", loginResponsePacket); - authSession?.SendAsync(loginResponsePacket); + _ = authSession?.SendAsync(loginResponsePacket); } - private static Task GetPasswordHashAsync(string password, byte[] salt, Guid userId) + private static async Task GetPasswordHashAsync(string password, byte[] salt, Guid userId) { + using var activity = _activitySource.StartActivity("GetPasswordHashAsync"); // 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(password)) @@ -86,11 +92,12 @@ public class LoginHandler : IPacketHandler Salt = salt, AssociatedData = userId.ToByteArray() }; - return argon2Id.GetBytesAsync(16); + return await argon2Id.GetBytesAsync(16); } private async Task CreateAccountOnLoginAsync(string username, string password) { + using var activity = _activitySource.StartActivity("CreateAccountOnLoginAsync"); LoginResponseReason loginResponseReason; var transaction = await _wonderkingContext.Database.BeginTransactionAsync(); @@ -99,14 +106,12 @@ public class LoginHandler : IPacketHandler try { var salt = RandomNumberGenerator.GetBytes(16); - var finalAccount = - await _wonderkingContext.Accounts.AddAsync(new Account(username, - Array.Empty(), "", - 0, salt)); + var finalAccount = await _addAccount(_wonderkingContext, new Account(username, + Array.Empty(), "", 0, salt)); await _wonderkingContext.SaveChangesAsync(); finalAccount.Entity.Password = await GetPasswordHashAsync(password, salt, finalAccount.Entity.Id); - _wonderkingContext.Accounts.Update(finalAccount.Entity); + _updateAccount(_wonderkingContext, finalAccount.Entity); loginResponseReason = LoginResponseReason.Ok; await _wonderkingContext.SaveChangesAsync();