diff --git a/.gitignore b/.gitignore
index 3357906..c2a26ef 100644
--- a/.gitignore
+++ b/.gitignore
@@ -480,5 +480,3 @@ $RECYCLE.BIN/
.idea
.vscode
-
-settings.json
\ No newline at end of file
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/Migrations/20230814114414_Initial.Designer.cs b/Server/DB/Migrations/20230814114414_Initial.Designer.cs
new file mode 100644
index 0000000..9cb6461
--- /dev/null
+++ b/Server/DB/Migrations/20230814114414_Initial.Designer.cs
@@ -0,0 +1,60 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using Server.DB;
+
+#nullable disable
+
+namespace Server.DB.Migrations
+{
+ [DbContext(typeof(WonderkingContext))]
+ [Migration("20230814114414_Initial")]
+ partial class Initial
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "7.0.10")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Server.DB.Documents.Account", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Email")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Password")
+ .IsRequired()
+ .HasColumnType("bytea");
+
+ b.Property("PermissionLevel")
+ .HasColumnType("smallint");
+
+ b.Property("Salt")
+ .IsRequired()
+ .HasColumnType("bytea");
+
+ b.Property("Username")
+ .IsRequired()
+ .HasColumnType("varchar(20)");
+
+ b.HasKey("Id");
+
+ b.ToTable("Accounts");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Server/DB/Migrations/20230814114414_Initial.cs b/Server/DB/Migrations/20230814114414_Initial.cs
new file mode 100644
index 0000000..0a8961f
--- /dev/null
+++ b/Server/DB/Migrations/20230814114414_Initial.cs
@@ -0,0 +1,38 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Server.DB.Migrations
+{
+ ///
+ public partial class Initial : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "Accounts",
+ columns: table => new
+ {
+ Id = table.Column(type: "uuid", nullable: false),
+ Username = table.Column(type: "varchar(20)", nullable: false),
+ Password = table.Column(type: "bytea", nullable: false),
+ Email = table.Column(type: "text", nullable: false),
+ PermissionLevel = table.Column(type: "smallint", nullable: false),
+ Salt = table.Column(type: "bytea", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Accounts", x => x.Id);
+ });
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "Accounts");
+ }
+ }
+}
diff --git a/Server/DB/Migrations/WonderkingContextModelSnapshot.cs b/Server/DB/Migrations/WonderkingContextModelSnapshot.cs
new file mode 100644
index 0000000..5b2e1f5
--- /dev/null
+++ b/Server/DB/Migrations/WonderkingContextModelSnapshot.cs
@@ -0,0 +1,57 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using Server.DB;
+
+#nullable disable
+
+namespace Server.DB.Migrations
+{
+ [DbContext(typeof(WonderkingContext))]
+ partial class WonderkingContextModelSnapshot : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "7.0.10")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Server.DB.Documents.Account", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Email")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Password")
+ .IsRequired()
+ .HasColumnType("bytea");
+
+ b.Property("PermissionLevel")
+ .HasColumnType("smallint");
+
+ b.Property("Salt")
+ .IsRequired()
+ .HasColumnType("bytea");
+
+ b.Property("Username")
+ .IsRequired()
+ .HasColumnType("varchar(20)");
+
+ b.HasKey("Id");
+
+ b.ToTable("Accounts");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
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
diff --git a/Server/settings.json b/Server/settings.json
new file mode 100644
index 0000000..8b9e207
--- /dev/null
+++ b/Server/settings.json
@@ -0,0 +1,12 @@
+{
+ "DB": {
+ "Username": "continuitydevuser",
+ "Host": "perf.rainote.dev",
+ "Password": "7>CU`D2/LKw6hD/7",
+ "Database": "continuity",
+ "Port": "13543"
+ },
+ "Testing": {
+ "CreateAccountOnLogin": true
+ }
+}