Browse Source

entity framework sql database providers

pull/2/head
Kyle Spearrin 4 years ago
parent
commit
89c6079430
  1. 2
      src/CryptoAgent/Controllers/UserKeysController.cs
  2. 14
      src/CryptoAgent/CryptoAgent.csproj
  3. 8
      src/CryptoAgent/CryptoAgentSettings.cs
  4. 68
      src/CryptoAgent/HostedServices/DatabaseMigrationHostedService.cs
  5. 55
      src/CryptoAgent/Migrations/MySql/20210817205815_InitialCreate.Designer.cs
  6. 52
      src/CryptoAgent/Migrations/MySql/20210817205815_InitialCreate.cs
  7. 53
      src/CryptoAgent/Migrations/MySql/MySqlDatabaseContextModelSnapshot.cs
  8. 57
      src/CryptoAgent/Migrations/PostgreSql/20210817205827_InitialCreate.Designer.cs
  9. 45
      src/CryptoAgent/Migrations/PostgreSql/20210817205827_InitialCreate.cs
  10. 55
      src/CryptoAgent/Migrations/PostgreSql/PostgreSqlDatabaseContextModelSnapshot.cs
  11. 57
      src/CryptoAgent/Migrations/SqlServer/20210817205227_InitialCreate.Designer.cs
  12. 45
      src/CryptoAgent/Migrations/SqlServer/20210817205227_InitialCreate.cs
  13. 55
      src/CryptoAgent/Migrations/SqlServer/SqlServerDatabaseContextModelSnapshot.cs
  14. 54
      src/CryptoAgent/Migrations/Sqlite/20210817205807_InitialCreate.Designer.cs
  15. 45
      src/CryptoAgent/Migrations/Sqlite/20210817205807_InitialCreate.cs
  16. 52
      src/CryptoAgent/Migrations/Sqlite/SqliteDatabaseContextModelSnapshot.cs
  17. 1
      src/CryptoAgent/Program.cs
  18. 38
      src/CryptoAgent/Repositories/EntityFramework/ApplicationDataRepository.cs
  19. 20
      src/CryptoAgent/Repositories/EntityFramework/BaseRepository.cs
  20. 102
      src/CryptoAgent/Repositories/EntityFramework/DatabaseContext.cs
  21. 49
      src/CryptoAgent/Repositories/EntityFramework/DatabaseContextFactory.cs
  22. 52
      src/CryptoAgent/Repositories/EntityFramework/UserKeyRepository.cs
  23. 31
      src/CryptoAgent/Startup.cs

2
src/CryptoAgent/Controllers/UserKeysController.cs

@ -92,7 +92,7 @@ namespace Bit.CryptoAgent.Controllers @@ -92,7 +92,7 @@ namespace Bit.CryptoAgent.Controllers
return new OkResult();
}
public Guid? GetProperUserId()
private Guid? GetProperUserId()
{
var userId = User.FindFirstValue(_identityOptions.ClaimsIdentity.UserIdClaimType);
if (!Guid.TryParse(userId, out var userIdGuid))

14
src/CryptoAgent/CryptoAgent.csproj

@ -1,9 +1,10 @@ @@ -1,9 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<RootNamespace>Bit.CryptoAgent</RootNamespace>
<UserSecretsId>116f49e5-0b50-4080-856f-7e812413e723</UserSecretsId>
<UserSecretsId>bitwarden-CryptoAgent</UserSecretsId>
<GenerateRuntimeConfigurationFiles>True</GenerateRuntimeConfigurationFiles>
</PropertyGroup>
<ItemGroup>
@ -16,6 +17,15 @@ @@ -16,6 +17,15 @@
<PackageReference Include="Google.Cloud.Kms.V1" Version="2.4.0" />
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="3.0.1" />
<PackageReference Include="JsonFlatFileDataStore" Version="2.2.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.9">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.9" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.7" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="5.0.1" />
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.2.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.0" />

8
src/CryptoAgent/CryptoAgentSettings.cs

@ -64,6 +64,14 @@ @@ -64,6 +64,14 @@
public string Provider { get; set; }
// json
public string JsonFilePath { get; set; }
// sqlserver
public string SqlServerConnectionString { get; set; }
// postgresql
public string PostgreSqlConnectionString { get; set; }
// mysql
public string MySqlConnectionString { get; set; }
// sqlite
public string SqliteConnectionString { get; set; }
}
}
}

68
src/CryptoAgent/HostedServices/DatabaseMigrationHostedService.cs

@ -0,0 +1,68 @@ @@ -0,0 +1,68 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Bit.CryptoAgent.Repositories.EntityFramework;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace Bit.CryptoAgent.HostedServices
{
public class DatabaseMigrationHostedService : IHostedService, IDisposable
{
private readonly IServiceScopeFactory _serviceScopeFactory;
private readonly ILogger<DatabaseMigrationHostedService> _logger;
public DatabaseMigrationHostedService(
IServiceScopeFactory serviceScopeFactory,
ILogger<DatabaseMigrationHostedService> logger)
{
_serviceScopeFactory = serviceScopeFactory;
_logger = logger;
}
public virtual async Task StartAsync(CancellationToken cancellationToken)
{
using var scope = _serviceScopeFactory.CreateScope();
var databaseContext = scope.ServiceProvider.GetRequiredService<DatabaseContext>();
// Wait 1 second to allow database to come online
await Task.Delay(1000, cancellationToken);
var maxMigrationAttempts = 10;
for (var i = 1; i <= maxMigrationAttempts; i++)
{
try
{
databaseContext.Database.Migrate();
break;
}
catch (Exception e)
{
if (i >= maxMigrationAttempts)
{
_logger.LogError(e, "Database failed to migrate.");
throw;
}
else
{
_logger.LogError(e,
"Database unavailable for migration. Trying again (attempt #{0})...", i + 1);
// Wait 5 seconds to allow database to come online
await Task.Delay(5000, cancellationToken);
}
}
}
}
public virtual Task StopAsync(CancellationToken cancellationToken)
{
return Task.FromResult(0);
}
public virtual void Dispose()
{ }
}
}

55
src/CryptoAgent/Migrations/MySql/20210817205815_InitialCreate.Designer.cs generated

@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
// <auto-generated />
using System;
using Bit.CryptoAgent.Repositories.EntityFramework;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace Bit.CryptoAgent.Migrations.MySql
{
[DbContext(typeof(MySqlDatabaseContext))]
[Migration("20210817205815_InitialCreate")]
partial class InitialCreate
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 64)
.HasAnnotation("ProductVersion", "5.0.9");
modelBuilder.Entity("Bit.CryptoAgent.Repositories.EntityFramework.ApplicationData", b =>
{
b.Property<string>("SymmetricKey")
.HasColumnType("longtext");
b.ToTable("ApplicationDatas");
});
modelBuilder.Entity("Bit.CryptoAgent.Repositories.EntityFramework.UserKey", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("char(36)");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime(6)");
b.Property<string>("Key")
.HasColumnType("longtext");
b.Property<DateTime?>("LastAccessDate")
.HasColumnType("datetime(6)");
b.Property<DateTime?>("RevisionDate")
.HasColumnType("datetime(6)");
b.HasKey("Id");
b.ToTable("UserKeys");
});
#pragma warning restore 612, 618
}
}
}

52
src/CryptoAgent/Migrations/MySql/20210817205815_InitialCreate.cs

@ -0,0 +1,52 @@ @@ -0,0 +1,52 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.CryptoAgent.Migrations.MySql
{
public partial class InitialCreate : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterDatabase()
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "ApplicationDatas",
columns: table => new
{
SymmetricKey = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
},
constraints: table =>
{
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "UserKeys",
columns: table => new
{
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
Key = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
CreationDate = table.Column<DateTime>(type: "datetime(6)", nullable: false),
RevisionDate = table.Column<DateTime>(type: "datetime(6)", nullable: true),
LastAccessDate = table.Column<DateTime>(type: "datetime(6)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_UserKeys", x => x.Id);
})
.Annotation("MySql:CharSet", "utf8mb4");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "ApplicationDatas");
migrationBuilder.DropTable(
name: "UserKeys");
}
}
}

53
src/CryptoAgent/Migrations/MySql/MySqlDatabaseContextModelSnapshot.cs

@ -0,0 +1,53 @@ @@ -0,0 +1,53 @@
// <auto-generated />
using System;
using Bit.CryptoAgent.Repositories.EntityFramework;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace Bit.CryptoAgent.Migrations.MySql
{
[DbContext(typeof(MySqlDatabaseContext))]
partial class MySqlDatabaseContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 64)
.HasAnnotation("ProductVersion", "5.0.9");
modelBuilder.Entity("Bit.CryptoAgent.Repositories.EntityFramework.ApplicationData", b =>
{
b.Property<string>("SymmetricKey")
.HasColumnType("longtext");
b.ToTable("ApplicationDatas");
});
modelBuilder.Entity("Bit.CryptoAgent.Repositories.EntityFramework.UserKey", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("char(36)");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime(6)");
b.Property<string>("Key")
.HasColumnType("longtext");
b.Property<DateTime?>("LastAccessDate")
.HasColumnType("datetime(6)");
b.Property<DateTime?>("RevisionDate")
.HasColumnType("datetime(6)");
b.HasKey("Id");
b.ToTable("UserKeys");
});
#pragma warning restore 612, 618
}
}
}

57
src/CryptoAgent/Migrations/PostgreSql/20210817205827_InitialCreate.Designer.cs generated

@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
// <auto-generated />
using System;
using Bit.CryptoAgent.Repositories.EntityFramework;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace Bit.CryptoAgent.Migrations.PostgreSql
{
[DbContext(typeof(PostgreSqlDatabaseContext))]
[Migration("20210817205827_InitialCreate")]
partial class InitialCreate
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 63)
.HasAnnotation("ProductVersion", "5.0.9")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
modelBuilder.Entity("Bit.CryptoAgent.Repositories.EntityFramework.ApplicationData", b =>
{
b.Property<string>("SymmetricKey")
.HasColumnType("text");
b.ToTable("ApplicationDatas");
});
modelBuilder.Entity("Bit.CryptoAgent.Repositories.EntityFramework.UserKey", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<DateTime>("CreationDate")
.HasColumnType("timestamp without time zone");
b.Property<string>("Key")
.HasColumnType("text");
b.Property<DateTime?>("LastAccessDate")
.HasColumnType("timestamp without time zone");
b.Property<DateTime?>("RevisionDate")
.HasColumnType("timestamp without time zone");
b.HasKey("Id");
b.ToTable("UserKeys");
});
#pragma warning restore 612, 618
}
}
}

45
src/CryptoAgent/Migrations/PostgreSql/20210817205827_InitialCreate.cs

@ -0,0 +1,45 @@ @@ -0,0 +1,45 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.CryptoAgent.Migrations.PostgreSql
{
public partial class InitialCreate : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "ApplicationDatas",
columns: table => new
{
SymmetricKey = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
});
migrationBuilder.CreateTable(
name: "UserKeys",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Key = table.Column<string>(type: "text", nullable: true),
CreationDate = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
RevisionDate = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
LastAccessDate = table.Column<DateTime>(type: "timestamp without time zone", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_UserKeys", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "ApplicationDatas");
migrationBuilder.DropTable(
name: "UserKeys");
}
}
}

55
src/CryptoAgent/Migrations/PostgreSql/PostgreSqlDatabaseContextModelSnapshot.cs

@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
// <auto-generated />
using System;
using Bit.CryptoAgent.Repositories.EntityFramework;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace Bit.CryptoAgent.Migrations.PostgreSql
{
[DbContext(typeof(PostgreSqlDatabaseContext))]
partial class PostgreSqlDatabaseContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 63)
.HasAnnotation("ProductVersion", "5.0.9")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
modelBuilder.Entity("Bit.CryptoAgent.Repositories.EntityFramework.ApplicationData", b =>
{
b.Property<string>("SymmetricKey")
.HasColumnType("text");
b.ToTable("ApplicationDatas");
});
modelBuilder.Entity("Bit.CryptoAgent.Repositories.EntityFramework.UserKey", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<DateTime>("CreationDate")
.HasColumnType("timestamp without time zone");
b.Property<string>("Key")
.HasColumnType("text");
b.Property<DateTime?>("LastAccessDate")
.HasColumnType("timestamp without time zone");
b.Property<DateTime?>("RevisionDate")
.HasColumnType("timestamp without time zone");
b.HasKey("Id");
b.ToTable("UserKeys");
});
#pragma warning restore 612, 618
}
}
}

57
src/CryptoAgent/Migrations/SqlServer/20210817205227_InitialCreate.Designer.cs generated

@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
// <auto-generated />
using System;
using Bit.CryptoAgent.Repositories.EntityFramework;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace Bit.CryptoAgent.Migrations.SqlServer
{
[DbContext(typeof(SqlServerDatabaseContext))]
[Migration("20210817205227_InitialCreate")]
partial class InitialCreate
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("ProductVersion", "5.0.9")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("Bit.CryptoAgent.Repositories.EntityFramework.ApplicationData", b =>
{
b.Property<string>("SymmetricKey")
.HasColumnType("nvarchar(max)");
b.ToTable("ApplicationDatas");
});
modelBuilder.Entity("Bit.CryptoAgent.Repositories.EntityFramework.UserKey", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<string>("Key")
.HasColumnType("nvarchar(max)");
b.Property<DateTime?>("LastAccessDate")
.HasColumnType("datetime2");
b.Property<DateTime?>("RevisionDate")
.HasColumnType("datetime2");
b.HasKey("Id");
b.ToTable("UserKeys");
});
#pragma warning restore 612, 618
}
}
}

45
src/CryptoAgent/Migrations/SqlServer/20210817205227_InitialCreate.cs

@ -0,0 +1,45 @@ @@ -0,0 +1,45 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.CryptoAgent.Migrations.SqlServer
{
public partial class InitialCreate : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "ApplicationDatas",
columns: table => new
{
SymmetricKey = table.Column<string>(type: "nvarchar(max)", nullable: true)
},
constraints: table =>
{
});
migrationBuilder.CreateTable(
name: "UserKeys",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Key = table.Column<string>(type: "nvarchar(max)", nullable: true),
CreationDate = table.Column<DateTime>(type: "datetime2", nullable: false),
RevisionDate = table.Column<DateTime>(type: "datetime2", nullable: true),
LastAccessDate = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_UserKeys", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "ApplicationDatas");
migrationBuilder.DropTable(
name: "UserKeys");
}
}
}

55
src/CryptoAgent/Migrations/SqlServer/SqlServerDatabaseContextModelSnapshot.cs

@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
// <auto-generated />
using System;
using Bit.CryptoAgent.Repositories.EntityFramework;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace Bit.CryptoAgent.Migrations.SqlServer
{
[DbContext(typeof(SqlServerDatabaseContext))]
partial class SqlServerDatabaseContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("ProductVersion", "5.0.9")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("Bit.CryptoAgent.Repositories.EntityFramework.ApplicationData", b =>
{
b.Property<string>("SymmetricKey")
.HasColumnType("nvarchar(max)");
b.ToTable("ApplicationDatas");
});
modelBuilder.Entity("Bit.CryptoAgent.Repositories.EntityFramework.UserKey", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<string>("Key")
.HasColumnType("nvarchar(max)");
b.Property<DateTime?>("LastAccessDate")
.HasColumnType("datetime2");
b.Property<DateTime?>("RevisionDate")
.HasColumnType("datetime2");
b.HasKey("Id");
b.ToTable("UserKeys");
});
#pragma warning restore 612, 618
}
}
}

54
src/CryptoAgent/Migrations/Sqlite/20210817205807_InitialCreate.Designer.cs generated

@ -0,0 +1,54 @@ @@ -0,0 +1,54 @@
// <auto-generated />
using System;
using Bit.CryptoAgent.Repositories.EntityFramework;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace Bit.CryptoAgent.Migrations.Sqlite
{
[DbContext(typeof(SqliteDatabaseContext))]
[Migration("20210817205807_InitialCreate")]
partial class InitialCreate
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "5.0.9");
modelBuilder.Entity("Bit.CryptoAgent.Repositories.EntityFramework.ApplicationData", b =>
{
b.Property<string>("SymmetricKey")
.HasColumnType("TEXT");
b.ToTable("ApplicationDatas");
});
modelBuilder.Entity("Bit.CryptoAgent.Repositories.EntityFramework.UserKey", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<DateTime>("CreationDate")
.HasColumnType("TEXT");
b.Property<string>("Key")
.HasColumnType("TEXT");
b.Property<DateTime?>("LastAccessDate")
.HasColumnType("TEXT");
b.Property<DateTime?>("RevisionDate")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("UserKeys");
});
#pragma warning restore 612, 618
}
}
}

45
src/CryptoAgent/Migrations/Sqlite/20210817205807_InitialCreate.cs

@ -0,0 +1,45 @@ @@ -0,0 +1,45 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.CryptoAgent.Migrations.Sqlite
{
public partial class InitialCreate : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "ApplicationDatas",
columns: table => new
{
SymmetricKey = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
});
migrationBuilder.CreateTable(
name: "UserKeys",
columns: table => new
{
Id = table.Column<Guid>(type: "TEXT", nullable: false),
Key = table.Column<string>(type: "TEXT", nullable: true),
CreationDate = table.Column<DateTime>(type: "TEXT", nullable: false),
RevisionDate = table.Column<DateTime>(type: "TEXT", nullable: true),
LastAccessDate = table.Column<DateTime>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_UserKeys", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "ApplicationDatas");
migrationBuilder.DropTable(
name: "UserKeys");
}
}
}

52
src/CryptoAgent/Migrations/Sqlite/SqliteDatabaseContextModelSnapshot.cs

@ -0,0 +1,52 @@ @@ -0,0 +1,52 @@
// <auto-generated />
using System;
using Bit.CryptoAgent.Repositories.EntityFramework;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace Bit.CryptoAgent.Migrations.Sqlite
{
[DbContext(typeof(SqliteDatabaseContext))]
partial class SqliteDatabaseContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "5.0.9");
modelBuilder.Entity("Bit.CryptoAgent.Repositories.EntityFramework.ApplicationData", b =>
{
b.Property<string>("SymmetricKey")
.HasColumnType("TEXT");
b.ToTable("ApplicationDatas");
});
modelBuilder.Entity("Bit.CryptoAgent.Repositories.EntityFramework.UserKey", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<DateTime>("CreationDate")
.HasColumnType("TEXT");
b.Property<string>("Key")
.HasColumnType("TEXT");
b.Property<DateTime?>("LastAccessDate")
.HasColumnType("TEXT");
b.Property<DateTime?>("RevisionDate")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("UserKeys");
});
#pragma warning restore 612, 618
}
}
}

1
src/CryptoAgent/Program.cs

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Serilog;

38
src/CryptoAgent/Repositories/EntityFramework/ApplicationDataRepository.cs

@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
namespace Bit.CryptoAgent.Repositories.EntityFramework
{
public class ApplicationDataRepository : BaseRepository, IApplicationDataRepository
{
public ApplicationDataRepository(IServiceScopeFactory serviceScopeFactory)
: base(serviceScopeFactory)
{ }
public Task<string> ReadSymmetricKeyAsync()
{
using var scope = ServiceScopeFactory.CreateScope();
var dbContext = GetDatabaseContext(scope);
return Task.FromResult(dbContext.ApplicationDatas.FirstOrDefault().SymmetricKey);
}
public async Task UpdateSymmetricKeyAsync(string key)
{
using var scope = ServiceScopeFactory.CreateScope();
var dbContext = GetDatabaseContext(scope);
if (dbContext.ApplicationDatas.FirstOrDefault() == null)
{
await dbContext.AddAsync(new ApplicationData
{
SymmetricKey = key
});
}
else
{
dbContext.ApplicationDatas.FirstOrDefault().SymmetricKey = key;
}
await dbContext.SaveChangesAsync();
}
}
}

20
src/CryptoAgent/Repositories/EntityFramework/BaseRepository.cs

@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
using System;
using Microsoft.Extensions.DependencyInjection;
namespace Bit.CryptoAgent.Repositories.EntityFramework
{
public abstract class BaseRepository
{
public BaseRepository(IServiceScopeFactory serviceScopeFactory)
{
ServiceScopeFactory = serviceScopeFactory;
}
protected IServiceScopeFactory ServiceScopeFactory { get; private set; }
protected DatabaseContext GetDatabaseContext(IServiceScope serviceScope)
{
return serviceScope.ServiceProvider.GetRequiredService<DatabaseContext>();
}
}
}

102
src/CryptoAgent/Repositories/EntityFramework/DatabaseContext.cs

@ -0,0 +1,102 @@ @@ -0,0 +1,102 @@
using System.Linq;
using Bit.CryptoAgent.Models;
using Microsoft.EntityFrameworkCore;
namespace Bit.CryptoAgent.Repositories.EntityFramework
{
public abstract class DatabaseContext : DbContext
{
public DbSet<ApplicationData> ApplicationDatas { get; set; }
public DbSet<UserKey> UserKeys { get; set; }
}
public class SqlServerDatabaseContext : DatabaseContext
{
private readonly CryptoAgentSettings _settings;
public SqlServerDatabaseContext(CryptoAgentSettings settings)
{
_settings = settings;
}
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseSqlServer(_settings.Database.SqlServerConnectionString);
}
public class PostgreSqlDatabaseContext : DatabaseContext
{
private readonly CryptoAgentSettings _settings;
public PostgreSqlDatabaseContext(CryptoAgentSettings settings)
{
_settings = settings;
}
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseNpgsql(_settings.Database.PostgreSqlConnectionString);
}
public class SqliteDatabaseContext : DatabaseContext
{
private readonly CryptoAgentSettings _settings;
public SqliteDatabaseContext(CryptoAgentSettings settings)
{
_settings = settings;
}
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseSqlite(_settings.Database.SqliteConnectionString);
}
public class MySqlDatabaseContext : DatabaseContext
{
private readonly CryptoAgentSettings _settings;
public MySqlDatabaseContext(CryptoAgentSettings settings)
{
_settings = settings;
}
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseMySql(_settings.Database.PostgreSqlConnectionString,
ServerVersion.AutoDetect(_settings.Database.MySqlConnectionString));
}
[Keyless]
public class ApplicationData
{
public string SymmetricKey { get; set; }
}
public class UserKey : UserKeyModel
{
public UserKey() { }
public UserKey(UserKeyModel model)
{
Load(model);
}
public void Load(UserKeyModel model)
{
Id = model.Id;
Key = model.Key;
RevisionDate = model.RevisionDate;
CreationDate = model.CreationDate;
LastAccessDate = model.LastAccessDate;
}
public UserKeyModel ToUserKeyModel()
{
return new UserKeyModel
{
Id = Id,
Key = Key,
RevisionDate = RevisionDate,
CreationDate = CreationDate,
LastAccessDate = LastAccessDate
};
}
}
}

49
src/CryptoAgent/Repositories/EntityFramework/DatabaseContextFactory.cs

@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;
namespace Bit.CryptoAgent.Repositories.EntityFramework
{
public class SqlServerDatabaseContextFactory : IDesignTimeDbContextFactory<SqlServerDatabaseContext>
{
public SqlServerDatabaseContext CreateDbContext(string[] args)
{
return new SqlServerDatabaseContext(SettingsFactory.Settings);
}
}
public class PostgreSqlDatabaseContextFactory : IDesignTimeDbContextFactory<PostgreSqlDatabaseContext>
{
public PostgreSqlDatabaseContext CreateDbContext(string[] args)
{
return new PostgreSqlDatabaseContext(SettingsFactory.Settings);
}
}
public class MySqlDatabaseContextFactory : IDesignTimeDbContextFactory<MySqlDatabaseContext>
{
public MySqlDatabaseContext CreateDbContext(string[] args)
{
return new MySqlDatabaseContext(SettingsFactory.Settings);
}
}
public class SqliteDatabaseContextFactory : IDesignTimeDbContextFactory<SqliteDatabaseContext>
{
public SqliteDatabaseContext CreateDbContext(string[] args)
{
return new SqliteDatabaseContext(SettingsFactory.Settings);
}
}
public static class SettingsFactory
{
public static CryptoAgentSettings Settings { get; } = new CryptoAgentSettings();
static SettingsFactory()
{
var configBuilder = new ConfigurationBuilder().AddUserSecrets<Startup>();
var config = configBuilder.Build();
ConfigurationBinder.Bind(config.GetSection("CryptoAgentSettings"), Settings);
}
}
}

52
src/CryptoAgent/Repositories/EntityFramework/UserKeyRepository.cs

@ -0,0 +1,52 @@ @@ -0,0 +1,52 @@
using Bit.CryptoAgent.Models;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Threading.Tasks;
namespace Bit.CryptoAgent.Repositories.EntityFramework
{
public class UserKeyRepository : BaseRepository, IUserKeyRepository
{
public UserKeyRepository(IServiceScopeFactory serviceScopeFactory)
: base(serviceScopeFactory)
{ }
public virtual async Task CreateAsync(UserKeyModel item)
{
using var scope = ServiceScopeFactory.CreateScope();
var dbContext = GetDatabaseContext(scope);
var entity = new UserKey(item);
await dbContext.AddAsync(entity);
await dbContext.SaveChangesAsync();
}
public virtual async Task<UserKeyModel> ReadAsync(Guid id)
{
using var scope = ServiceScopeFactory.CreateScope();
var dbContext = GetDatabaseContext(scope);
var entity = await dbContext.UserKeys.FindAsync(id);
return entity.ToUserKeyModel();
}
public virtual async Task UpdateAsync(UserKeyModel item)
{
using var scope = ServiceScopeFactory.CreateScope();
var dbContext = GetDatabaseContext(scope);
var entity = await dbContext.UserKeys.FindAsync(item.Id);
if (entity != null)
{
entity.Load(item);
await dbContext.SaveChangesAsync();
}
}
public virtual async Task DeleteAsync(Guid id)
{
using var scope = ServiceScopeFactory.CreateScope();
var dbContext = GetDatabaseContext(scope);
var entity = await dbContext.UserKeys.FindAsync(id);
dbContext.Remove(entity);
await dbContext.SaveChangesAsync();
}
}
}

31
src/CryptoAgent/Startup.cs

@ -47,6 +47,8 @@ namespace Bit.CryptoAgent @@ -47,6 +47,8 @@ namespace Bit.CryptoAgent
AddDatabase(services, settings);
services.AddControllers();
services.AddHostedService<HostedServices.DatabaseMigrationHostedService>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
@ -67,6 +69,9 @@ namespace Bit.CryptoAgent @@ -67,6 +69,9 @@ namespace Bit.CryptoAgent
private void AddDatabase(IServiceCollection services, CryptoAgentSettings settings)
{
var databaseProvider = settings.Database.Provider?.ToLowerInvariant();
var efDatabaseProvider = databaseProvider == "sqlserver" || databaseProvider == "postgresql" ||
databaseProvider == "mysql" || databaseProvider == "sqlite";
if (databaseProvider == "json")
{
// Assign foobar to keyProperty in order to not use incrementing Id functionality
@ -75,6 +80,32 @@ namespace Bit.CryptoAgent @@ -75,6 +80,32 @@ namespace Bit.CryptoAgent
services.AddSingleton<IApplicationDataRepository, Repositories.JsonFile.ApplicationDataRepository>();
services.AddSingleton<IUserKeyRepository, Repositories.JsonFile.UserKeyRepository>();
}
else if (efDatabaseProvider)
{
if (databaseProvider == "sqlserver")
{
services.AddDbContext<Repositories.EntityFramework.DatabaseContext,
Repositories.EntityFramework.SqlServerDatabaseContext>();
}
else if (databaseProvider == "postgresql")
{
services.AddDbContext<Repositories.EntityFramework.DatabaseContext,
Repositories.EntityFramework.PostgreSqlDatabaseContext>();
}
else if (databaseProvider == "mysql")
{
services.AddDbContext<Repositories.EntityFramework.DatabaseContext,
Repositories.EntityFramework.MySqlDatabaseContext>();
}
else if (databaseProvider == "sqlite")
{
services.AddDbContext<Repositories.EntityFramework.DatabaseContext,
Repositories.EntityFramework.SqliteDatabaseContext>();
}
services.AddSingleton<IApplicationDataRepository,
Repositories.EntityFramework.ApplicationDataRepository>();
services.AddSingleton<IUserKeyRepository, Repositories.EntityFramework.UserKeyRepository>();
}
else
{
throw new Exception("No database configured.");

Loading…
Cancel
Save