diff --git a/Server/DB/Documents/Account.cs b/Server/DB/Documents/Account.cs index 8914684..746225f 100644 --- a/Server/DB/Documents/Account.cs +++ b/Server/DB/Documents/Account.cs @@ -1,9 +1,11 @@ namespace Server.DB.Documents; -using CouchDB.Driver.Types; +using Microsoft.EntityFrameworkCore; -public class Account : CouchDocument +public class Account { + public Guid Id { get; set; } + public Account(string username, byte[] password, string email, byte permissionLevel, byte[] salt) { this.Username = username; diff --git a/Server/DB/WonderkingContext.cs b/Server/DB/WonderkingContext.cs index 687464b..8a58af5 100644 --- a/Server/DB/WonderkingContext.cs +++ b/Server/DB/WonderkingContext.cs @@ -1,14 +1,37 @@ namespace Server.DB; -using CouchDB.Driver; -using CouchDB.Driver.Options; +using System.Data.Common; using Documents; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Npgsql; -public class WonderkingContext : CouchContext +public class WonderkingContext : DbContext { - public WonderkingContext(CouchOptions options) : base(options) + private readonly ILoggerFactory loggerFactory; + private readonly IConfiguration configuration; + + public WonderkingContext(ILoggerFactory loggerFactory, IConfiguration configuration) { + this.loggerFactory = loggerFactory; + this.configuration = configuration; } - public CouchDatabase Accounts { get; set; } + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => + optionsBuilder + .UseNpgsql( + $"Host={this.configuration["DB:Host"]};Username={this.configuration["DB:Username"]};Password={this.configuration["DB:Password"]};Database={this.configuration["DB:Database"]};Port={this.configuration["DB:Port"]}") + .EnableSensitiveDataLogging().UseLoggerFactory(this.loggerFactory); + + protected override void OnModelCreating(ModelBuilder modelBuilder) => + modelBuilder.Entity(builder => + { + builder.Property(b => b.Username).HasColumnType("varchar(20)"); + builder.Property(b => b.Password).HasColumnType("bytea"); + builder.Property(b => b.Salt).HasColumnType("bytea"); + builder.HasKey(b => b.Id); + }); + + public DbSet Accounts { get; set; } } diff --git a/Server/PacketHandlers/LoginHandler.cs b/Server/PacketHandlers/LoginHandler.cs index a85f34a..05d1566 100644 --- a/Server/PacketHandlers/LoginHandler.cs +++ b/Server/PacketHandlers/LoginHandler.cs @@ -2,10 +2,8 @@ using System.Security.Cryptography; using System.Text; -using CouchDB.Driver.Query.Extensions; using DB; using DB.Documents; -using DotNext; using Konscious.Security.Cryptography; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; @@ -47,10 +45,12 @@ public class LoginHandler : IPacketHandler var finalAccount = await this.wonderkingContext.Accounts.AddAsync(new Account(packet.Username, Array.Empty(), "", 0, argon2Id.Salt)); - argon2Id.AssociatedData = Guid.Parse(finalAccount.Id).ToByteArray(); - finalAccount.Password = await argon2Id.GetBytesAsync(128); - await this.wonderkingContext.Accounts.AddOrUpdateAsync(finalAccount); + await this.wonderkingContext.SaveChangesAsync(); + argon2Id.AssociatedData = finalAccount.Entity.Id.ToByteArray(); + finalAccount.Entity.Password = await argon2Id.GetBytesAsync(128); + this.wonderkingContext.Accounts.Update(finalAccount.Entity); loginResponseReason = LoginResponseReason.Ok; + await this.wonderkingContext.SaveChangesAsync(); } else { @@ -62,7 +62,7 @@ public class LoginHandler : IPacketHandler else { argon2Id.Salt = account.Salt; - argon2Id.AssociatedData = Guid.Parse(account.Id).ToByteArray(); + argon2Id.AssociatedData = account.Id.ToByteArray(); var tempPasswordBytes = await argon2Id.GetBytesAsync(128); loginResponseReason = tempPasswordBytes.SequenceEqual(account.Password) ? LoginResponseReason.Ok diff --git a/Server/Program.cs b/Server/Program.cs index 5666de1..d2e9ce0 100644 --- a/Server/Program.cs +++ b/Server/Program.cs @@ -1,8 +1,8 @@ #pragma warning disable AV1500 using System.Net; using System.Reflection; -using CouchDB.Driver.DependencyInjection; using MassTransit; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -16,13 +16,8 @@ var configurationRoot = builder.Configuration.AddJsonFile("settings.json", false builder.Services.AddLogging(); builder.Logging.AddFile("Logs/Server-{Date}.log", LogLevel.Debug); builder.Logging.AddFile("Logs/Server-{Date}.json.log", LogLevel.Debug, isJson: true); -builder.Services.AddCouchContext(cfg => -{ - cfg.UseEndpoint(configurationRoot["DB:Endpoint"] ?? throw new InvalidOperationException()) - .UseBasicAuthentication(configurationRoot["DB:User"] ?? throw new InvalidOperationException(), - configurationRoot["DB:Password"] ?? throw new InvalidOperationException()) - .EnsureDatabaseExists(); -}); +builder.Services.AddEntityFrameworkNpgsql(); +builder.Services.AddDbContext(); builder.Services.AddSingleton(); builder.Services.AddHostedService(provider => provider.GetService() ?? throw new InvalidOperationException()); @@ -36,5 +31,11 @@ builder.Services.AddHostedService(provider => new Wonderki provider.GetService() ?? throw new InvalidOperationException())); using var host = builder.Build(); +await using (var scope = host.Services.CreateAsyncScope()) +{ + var db = scope.ServiceProvider.GetRequiredService(); + await db.Database.MigrateAsync(); +} + await host.RunAsync(); #pragma warning restore AV1500 diff --git a/Server/Server.csproj b/Server/Server.csproj index 108f613..a560cca 100644 --- a/Server/Server.csproj +++ b/Server/Server.csproj @@ -17,8 +17,6 @@ - - @@ -36,6 +34,14 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + @@ -49,6 +55,7 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive