migrate2efcore #16

Merged
rainote merged 3 commits from migrate2efcore into master 2023-08-14 11:53:22 +00:00
10 changed files with 223 additions and 25 deletions

2
.gitignore vendored
View file

@ -480,5 +480,3 @@ $RECYCLE.BIN/
.idea
.vscode
settings.json

View file

@ -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;

View file

@ -0,0 +1,60 @@
// <auto-generated />
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
{
/// <inheritdoc />
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<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text");
b.Property<byte[]>("Password")
.IsRequired()
.HasColumnType("bytea");
b.Property<byte>("PermissionLevel")
.HasColumnType("smallint");
b.Property<byte[]>("Salt")
.IsRequired()
.HasColumnType("bytea");
b.Property<string>("Username")
.IsRequired()
.HasColumnType("varchar(20)");
b.HasKey("Id");
b.ToTable("Accounts");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -0,0 +1,38 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Server.DB.Migrations
{
/// <inheritdoc />
public partial class Initial : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Accounts",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Username = table.Column<string>(type: "varchar(20)", nullable: false),
Password = table.Column<byte[]>(type: "bytea", nullable: false),
Email = table.Column<string>(type: "text", nullable: false),
PermissionLevel = table.Column<byte>(type: "smallint", nullable: false),
Salt = table.Column<byte[]>(type: "bytea", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Accounts", x => x.Id);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Accounts");
}
}
}

View file

@ -0,0 +1,57 @@
// <auto-generated />
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<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text");
b.Property<byte[]>("Password")
.IsRequired()
.HasColumnType("bytea");
b.Property<byte>("PermissionLevel")
.HasColumnType("smallint");
b.Property<byte[]>("Salt")
.IsRequired()
.HasColumnType("bytea");
b.Property<string>("Username")
.IsRequired()
.HasColumnType("varchar(20)");
b.HasKey("Id");
b.ToTable("Accounts");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -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<WonderkingContext> 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<Account> 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<Account>(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<Account> Accounts { get; set; }
}

View file

@ -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<LoginInfoPacket>
var finalAccount =
await this.wonderkingContext.Accounts.AddAsync(new Account(packet.Username, Array.Empty<byte>(), "",
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<LoginInfoPacket>
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

View file

@ -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<WonderkingContext>(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<WonderkingContext>();
builder.Services.AddSingleton<PacketDistributorService>();
builder.Services.AddHostedService<PacketDistributorService>(provider =>
provider.GetService<PacketDistributorService>() ?? throw new InvalidOperationException());
@ -36,5 +31,11 @@ builder.Services.AddHostedService<WonderkingAuthServer>(provider => new Wonderki
provider.GetService<IServiceProvider>() ?? throw new InvalidOperationException()));
using var host = builder.Build();
await using (var scope = host.Services.CreateAsyncScope())
{
var db = scope.ServiceProvider.GetRequiredService<WonderkingContext>();
await db.Database.MigrateAsync();
}
await host.RunAsync();
#pragma warning restore AV1500

View file

@ -17,8 +17,6 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="CouchDB.NET" Version="3.4.0"/>
<PackageReference Include="CouchDB.NET.DependencyInjection" Version="3.4.0"/>
<PackageReference Include="DotNext" Version="4.13.1" />
<PackageReference Include="DotNext.IO" Version="4.13.1" />
<PackageReference Include="DotNext.Metaprogramming" Version="4.13.1" />
@ -36,6 +34,14 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="7.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Analyzers" Version="7.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0"/>
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="7.0.0"/>
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0"/>
@ -49,6 +55,7 @@
</PackageReference>
<PackageReference Include="NetCoreServer" Version="7.0.0"/>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3"/>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.4" />
<PackageReference Include="Nullable.Extended.Analyzer" Version="1.10.4539">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

12
Server/settings.json Normal file
View file

@ -0,0 +1,12 @@
{
"DB": {
"Username": "continuitydevuser",
"Host": "perf.rainote.dev",
"Password": "7>CU`D2/LKw6hD/7",
"Database": "continuity",
"Port": "13543"
},
"Testing": {
"CreateAccountOnLogin": true
}
}