Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| db431e1682 | |||
| cf439c5006 | |||
| ad2ea48592 | |||
| bf36bb6bbc | |||
| 0a9a459892 | |||
| 00d43c8f10 | |||
| f5a69de0a0 | |||
| 40a5f94941 | |||
| fc4db32f20 | |||
| 9cb4b8264d | |||
| ddd823afab | |||
| a9aa0a675a | |||
| 6418d27f5a | |||
| a763e5e40e | |||
| 9b15e296df | |||
| 1ef5e52ed9 | |||
| f4a615277f | |||
| c06cf13add | |||
| 4e9e428ab5 | |||
| 92c60e6616 | |||
| 9099610185 | |||
| 21788c66a3 | |||
| dfaa62ea75 | |||
| 54ef7a6e5f | |||
| 0ec7ef4861 |
@@ -11,7 +11,7 @@
|
|||||||
<!-- Quartz Scheduler-->
|
<!-- Quartz Scheduler-->
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Bogus" Version="35.6.5" />
|
<PackageReference Include="Bogus" Version="35.6.5" />
|
||||||
<PackageReference Include="Meziantou.Analyzer" Version="3.0.103">
|
<PackageReference Include="Meziantou.Analyzer" Version="3.0.104">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|||||||
+1
-5
@@ -12,11 +12,7 @@
|
|||||||
<PackageReference Include="coverlet.collector" Version="10.0.1">
|
<PackageReference Include="coverlet.collector" Version="10.0.1">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Mediator.SourceGenerator" Version="3.0.2">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.6.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.6.0" />
|
||||||
<PackageReference Include="xunit" Version="2.9.3" />
|
<PackageReference Include="xunit" Version="2.9.3" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
|
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
<!-- Quartz Scheduler-->
|
<!-- Quartz Scheduler-->
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Humanizer" Version="3.0.10" />
|
<PackageReference Include="Humanizer" Version="3.0.10" />
|
||||||
<PackageReference Include="Meziantou.Analyzer" Version="3.0.103">
|
<PackageReference Include="Meziantou.Analyzer" Version="3.0.104">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace LiteCharms.Features.MidrandBooks.Payments.Entities;
|
namespace LiteCharms.Features.MidrandBooks.Payments.Entities;
|
||||||
|
|
||||||
[EntityTypeConfiguration<PaymentGatewayConfiguration, PaymentGateway>]
|
[EntityTypeConfiguration<PaymentGatewayConfiguration, PaymentGateway>]
|
||||||
public class PaymentGateway : Models.PaymentGateway;
|
public sealed class PaymentGateway : Models.PaymentGateway;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|||||||
namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class Init : Migration
|
public sealed partial class Init : Migration
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|||||||
namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class AddedCategories : Migration
|
public sealed partial class AddedCategories : Migration
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|||||||
namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class AddedProductCategories : Migration
|
public sealed partial class AddedProductCategories : Migration
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|||||||
namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class AddedPaymentObjects : Migration
|
public sealed partial class AddedPaymentObjects : Migration
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class RemovedPassphraseFromPaymentGateway : Migration
|
public sealed partial class RemovedPassphraseFromPaymentGateway : Migration
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|||||||
namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class AddedPaymentGatewayLedger : Migration
|
public sealed partial class AddedPaymentGatewayLedger : Migration
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class AddedPayfastPaymentIdToPaymentGatewayLedger : Migration
|
public sealed partial class AddedPayfastPaymentIdToPaymentGatewayLedger : Migration
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class OnlyEmailIsMandatoryOnCustomer : Migration
|
public sealed partial class OnlyEmailIsMandatoryOnCustomer : Migration
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
<!-- Mediator -->
|
<!-- Mediator -->
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Mediator.Abstractions" Version="3.0.2" />
|
|
||||||
<PackageReference Include="Mediator.SourceGenerator" Version="3.0.2">
|
<PackageReference Include="Mediator.SourceGenerator" Version="3.0.2">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
|||||||
@@ -12,11 +12,7 @@
|
|||||||
<PackageReference Include="coverlet.collector" Version="10.0.1">
|
<PackageReference Include="coverlet.collector" Version="10.0.1">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Mediator.SourceGenerator" Version="3.0.2">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.6.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.6.0" />
|
||||||
<PackageReference Include="xunit" Version="2.9.3" />
|
<PackageReference Include="xunit" Version="2.9.3" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
|
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
namespace LiteCharms.Features;
|
||||||
|
|
||||||
|
public sealed class CancellationTokenProvider : IDisposable
|
||||||
|
{
|
||||||
|
private readonly CancellationTokenSource source = new();
|
||||||
|
|
||||||
|
public CancellationToken Token => source.Token;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
source.Cancel();
|
||||||
|
source.Dispose();
|
||||||
|
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
using LiteCharms.Features.Api;
|
using LiteCharms.Features.Api;
|
||||||
using LiteCharms.Features.Api.Configuration;
|
using LiteCharms.Features.Api.Configuration;
|
||||||
using LiteCharms.Features.Api.Sdk;
|
using LiteCharms.Features.Api.Sdk;
|
||||||
|
using LiteCharms.Features.Postgres;
|
||||||
|
|
||||||
namespace LiteCharms.Features.Extensions;
|
namespace LiteCharms.Features.Extensions;
|
||||||
|
|
||||||
@@ -53,6 +54,22 @@ public static class Api
|
|||||||
|
|
||||||
public static IServiceCollection AddLiteCharmsWebSecurity(this IServiceCollection services, IConfiguration configuration)
|
public static IServiceCollection AddLiteCharmsWebSecurity(this IServiceCollection services, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
|
var certString = configuration["DataProtection:Certificate"] ?? configuration["DataProtection__Certificate"];
|
||||||
|
var certPassword = configuration["DataProtection:Password"] ?? configuration["DataProtection__Password"];
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(certString))
|
||||||
|
throw new InvalidOperationException("Data Protection Certificate configuration is missing.");
|
||||||
|
|
||||||
|
var certificate = X509CertificateLoader.LoadPkcs12(Convert.FromBase64String(certString), certPassword);
|
||||||
|
|
||||||
|
services.AddDataProtection().PersistKeysToDbContext<DataProtectionDbContext>()
|
||||||
|
.ProtectKeysWithCertificate(certificate)
|
||||||
|
.SetApplicationName("LiteCharmsApp");
|
||||||
|
|
||||||
|
services.Configure<DataProtectionOptions>(options => options.ApplicationDiscriminator = "LiteCharmsApp");
|
||||||
|
|
||||||
|
services.ConfigureCookieOidcSameSiteSupport();
|
||||||
|
|
||||||
var configSection = configuration.GetSection(nameof(LiteCharmsSettings));
|
var configSection = configuration.GetSection(nameof(LiteCharmsSettings));
|
||||||
|
|
||||||
var authOptions = new LiteCharmsSettings();
|
var authOptions = new LiteCharmsSettings();
|
||||||
@@ -65,37 +82,48 @@ public static class Api
|
|||||||
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||||
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
|
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
|
||||||
})
|
})
|
||||||
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
|
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
|
||||||
|
{
|
||||||
|
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
|
||||||
|
options.Cookie.SameSite = SameSiteMode.Lax;
|
||||||
|
options.Cookie.Name = "LiteCharmsApp.Session";
|
||||||
|
})
|
||||||
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
|
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
|
||||||
{
|
{
|
||||||
options.Authority = authOptions.Authority;
|
options.Authority = authOptions.Authority;
|
||||||
|
|
||||||
options.ClientId = authOptions.ClientId;
|
options.ClientId = authOptions.ClientId;
|
||||||
options.ClientSecret = authOptions.ClientSecret;
|
options.ClientSecret = authOptions.ClientSecret;
|
||||||
options.ResponseType = "code";
|
options.ResponseType = "code";
|
||||||
|
|
||||||
options.SaveTokens = true;
|
options.SaveTokens = true;
|
||||||
options.GetClaimsFromUserInfoEndpoint = true;
|
options.GetClaimsFromUserInfoEndpoint = true;
|
||||||
|
options.CorrelationCookie.SecurePolicy = CookieSecurePolicy.Always;
|
||||||
|
options.CorrelationCookie.SameSite = SameSiteMode.None;
|
||||||
|
|
||||||
|
options.NonceCookie.SecurePolicy = CookieSecurePolicy.Always;
|
||||||
|
options.NonceCookie.SameSite = SameSiteMode.None;
|
||||||
|
|
||||||
|
options.ForwardSignOut = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||||
|
|
||||||
options.Scope.Clear();
|
options.Scope.Clear();
|
||||||
options.Scope.Add("openid");
|
options.Scope.Add("openid");
|
||||||
options.Scope.Add("profile");
|
options.Scope.Add("profile");
|
||||||
options.Scope.Add("email");
|
options.Scope.Add("email");
|
||||||
|
|
||||||
options.Events = new OpenIdConnectEvents
|
options.Events = new OpenIdConnectEvents
|
||||||
{
|
{
|
||||||
OnRedirectToIdentityProviderForSignOut = context =>
|
OnRedirectToIdentityProviderForSignOut = context =>
|
||||||
{
|
{
|
||||||
var idToken = context.ProtocolMessage.IdTokenHint;
|
var idToken = context.ProtocolMessage.IdTokenHint;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(idToken))
|
if (string.IsNullOrEmpty(idToken))
|
||||||
{
|
{
|
||||||
var tokens = context.Properties.GetTokens();
|
var tokens = context.Properties.GetTokens();
|
||||||
var idTokenItem = tokens.FirstOrDefault(t => string.Equals(t.Name, "id_token", StringComparison.Ordinal));
|
var idTokenItem = tokens.FirstOrDefault(t => string.Equals(t.Name, "id_token", StringComparison.Ordinal));
|
||||||
|
|
||||||
if (idTokenItem != null) context.ProtocolMessage.IdTokenHint = idTokenItem.Value;
|
if (idTokenItem != null) context.ProtocolMessage.IdTokenHint = idTokenItem.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -106,6 +134,30 @@ public static class Api
|
|||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void ConfigureCookieOidcSameSiteSupport(this IServiceCollection services) =>
|
||||||
|
services.Configure<CookiePolicyOptions>(options =>
|
||||||
|
{
|
||||||
|
options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
|
||||||
|
options.OnAppendCookie = cookieContext => CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
|
||||||
|
options.OnDeleteCookie = cookieContext => CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
|
||||||
|
});
|
||||||
|
|
||||||
|
private static void CheckSameSite(HttpContext httpContext, CookieOptions options)
|
||||||
|
{
|
||||||
|
if (options.SameSite == SameSiteMode.None)
|
||||||
|
{
|
||||||
|
bool isSecure = httpContext.Request.IsHttps;
|
||||||
|
|
||||||
|
if (!isSecure && httpContext.Request.Headers.TryGetValue("X-Forwarded-Proto", out var proto))
|
||||||
|
isSecure = string.Equals(proto, "https", StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
if (!isSecure && httpContext.Request.Headers.TryGetValue("Forwarded", out var forwarded))
|
||||||
|
isSecure = forwarded.ToString().Contains("proto=https", StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
if (!isSecure) options.SameSite = SameSiteMode.Unspecified;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static IServiceCollection AddLiteCharmsApiSecurity(this IServiceCollection services, IConfiguration configuration)
|
public static IServiceCollection AddLiteCharmsApiSecurity(this IServiceCollection services, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
var configSection = configuration.GetSection(nameof(LiteCharmsSettings));
|
var configSection = configuration.GetSection(nameof(LiteCharmsSettings));
|
||||||
@@ -159,7 +211,6 @@ public static class Api
|
|||||||
authProperties.Parameters.Add("id_token_hint", idToken);
|
authProperties.Parameters.Add("id_token_hint", idToken);
|
||||||
|
|
||||||
await context.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme, authProperties);
|
await context.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme, authProperties);
|
||||||
await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return app;
|
return app;
|
||||||
@@ -190,7 +241,7 @@ public static class Api
|
|||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(urls))
|
if (!string.IsNullOrWhiteSpace(urls))
|
||||||
{
|
{
|
||||||
string firstUrl = urls.Split(';').FirstOrDefault(s => s.Contains("http://"))!
|
string firstUrl = urls.Split(';').FirstOrDefault(s => s.Contains("http://", StringComparison.InvariantCultureIgnoreCase))!
|
||||||
.Replace("0.0.0.0", "localhost")
|
.Replace("0.0.0.0", "localhost")
|
||||||
.Replace("*", "localhost")
|
.Replace("*", "localhost")
|
||||||
.Replace("+", "localhost");
|
.Replace("+", "localhost");
|
||||||
|
|||||||
@@ -1,6 +1,19 @@
|
|||||||
namespace LiteCharms.Features.Extensions;
|
using LiteCharms.Features.Postgres;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Extensions;
|
||||||
|
|
||||||
public static class Postgres
|
public static class Postgres
|
||||||
{
|
{
|
||||||
public const string SchedulerDbConfigName = "PostgresScheduler";
|
public const string SchedulerDbConfigName = "PostgresScheduler";
|
||||||
|
public const string DataProtectionDbConfigName = "PostgresDataProtection";
|
||||||
|
|
||||||
|
public static IServiceCollection AddDataProtectionDatabase(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var connectionString = configuration.GetConnectionString(DataProtectionDbConfigName);
|
||||||
|
|
||||||
|
services.AddPooledDbContextFactory<DataProtectionDbContext>(options =>
|
||||||
|
options.UseNpgsql(connectionString));
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public static class S3
|
|||||||
AuthenticationRegion = configuration.GetSection($"{BookshopS3SettingsSection}:Region").Value,
|
AuthenticationRegion = configuration.GetSection($"{BookshopS3SettingsSection}:Region").Value,
|
||||||
ForcePathStyle = true,
|
ForcePathStyle = true,
|
||||||
EndpointDiscoveryEnabled = true,
|
EndpointDiscoveryEnabled = true,
|
||||||
UseHttp = configuration.GetSection($"{BookshopS3SettingsSection}:ServiceUrl").Value!.Contains("http://")
|
UseHttp = configuration.GetSection($"{BookshopS3SettingsSection}:ServiceUrl").Value!.Contains("http://", StringComparison.InvariantCultureIgnoreCase),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
services.AddKeyedScoped<IS3Service, BookshopS3Service>(BookshopBucketName);
|
services.AddKeyedScoped<IS3Service, BookshopS3Service>(BookshopBucketName);
|
||||||
@@ -36,7 +36,7 @@ public static class S3
|
|||||||
AuthenticationRegion = configuration.GetSection($"{BookshopInvoicesS3SettingsSection}:Region").Value,
|
AuthenticationRegion = configuration.GetSection($"{BookshopInvoicesS3SettingsSection}:Region").Value,
|
||||||
ForcePathStyle = true,
|
ForcePathStyle = true,
|
||||||
EndpointDiscoveryEnabled = true,
|
EndpointDiscoveryEnabled = true,
|
||||||
UseHttp = configuration.GetSection($"{BookshopS3SettingsSection}:ServiceUrl").Value!.Contains("http://")
|
UseHttp = configuration.GetSection($"{BookshopS3SettingsSection}:ServiceUrl").Value!.Contains("http://", StringComparison.InvariantCultureIgnoreCase),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
services.AddKeyedScoped<IS3Service, BookshopInvoicesS3Service>(BookshopInvoicesBucketName);
|
services.AddKeyedScoped<IS3Service, BookshopInvoicesS3Service>(BookshopInvoicesBucketName);
|
||||||
@@ -53,7 +53,7 @@ public static class S3
|
|||||||
AuthenticationRegion = configuration.GetSection($"{BookshopQuotesS3SettingsSection}:Region").Value,
|
AuthenticationRegion = configuration.GetSection($"{BookshopQuotesS3SettingsSection}:Region").Value,
|
||||||
ForcePathStyle = true,
|
ForcePathStyle = true,
|
||||||
EndpointDiscoveryEnabled = true,
|
EndpointDiscoveryEnabled = true,
|
||||||
UseHttp = configuration.GetSection($"{BookshopS3SettingsSection}:ServiceUrl").Value!.Contains("http://")
|
UseHttp = configuration.GetSection($"{BookshopS3SettingsSection}:ServiceUrl").Value!.Contains("http://", StringComparison.InvariantCultureIgnoreCase),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
services.AddKeyedScoped<IS3Service, BookshopQuotesS3Service>(BookshopQuotesBucketName);
|
services.AddKeyedScoped<IS3Service, BookshopQuotesS3Service>(BookshopQuotesBucketName);
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
namespace LiteCharms.Features.Extensions;
|
||||||
|
|
||||||
|
public static class TaskCancellation
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddCancellationToken(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddScoped<CancellationTokenProvider>();
|
||||||
|
services.AddScoped(typeof(CancellationToken),
|
||||||
|
provider => provider.GetRequiredService<CancellationTokenProvider>().Token);
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
<!-- Quartz Scheduler-->
|
<!-- Quartz Scheduler-->
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Hashids.net" Version="1.7.0" />
|
<PackageReference Include="Hashids.net" Version="1.7.0" />
|
||||||
<PackageReference Include="Meziantou.Analyzer" Version="3.0.103">
|
<PackageReference Include="Meziantou.Analyzer" Version="3.0.104">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
@@ -153,9 +153,11 @@
|
|||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.2" />
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.2" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.DataProtection.EntityFrameworkCore" Version="10.0.9" />
|
||||||
|
|
||||||
<!-- Global Usings -->
|
<!-- Global Usings -->
|
||||||
<Using Include="Npgsql" />
|
<Using Include="Npgsql" />
|
||||||
|
<Using Include="Microsoft.AspNetCore.DataProtection.EntityFrameworkCore" />
|
||||||
<Using Include="Microsoft.EntityFrameworkCore" />
|
<Using Include="Microsoft.EntityFrameworkCore" />
|
||||||
<Using Include="Microsoft.EntityFrameworkCore.Design" />
|
<Using Include="Microsoft.EntityFrameworkCore.Design" />
|
||||||
<Using Include="Microsoft.EntityFrameworkCore.Metadata.Builders" />
|
<Using Include="Microsoft.EntityFrameworkCore.Metadata.Builders" />
|
||||||
@@ -194,6 +196,8 @@
|
|||||||
|
|
||||||
<!-- Shared Usings -->
|
<!-- Shared Usings -->
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Using Include="Microsoft.AspNetCore.DataProtection" />
|
||||||
|
<Using Include="System.Security.Cryptography.X509Certificates" />
|
||||||
<Using Include="Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage" />
|
<Using Include="Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage" />
|
||||||
<Using Include="System.Text.Json.Serialization" />
|
<Using Include="System.Text.Json.Serialization" />
|
||||||
<Using Include="System.Reflection" />
|
<Using Include="System.Reflection" />
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
namespace LiteCharms.Features.Postgres;
|
||||||
|
|
||||||
|
public sealed class DataProtectionDbContext(DbContextOptions<DataProtectionDbContext> options) : DbContext(options), IDataProtectionKeyContext
|
||||||
|
{
|
||||||
|
public DbSet<DataProtectionKey> DataProtectionKeys { get; set; }
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
base.OnModelCreating(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity<DataProtectionKey>(entity => entity.ToTable(nameof(DataProtectionKeys), schema: "security"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using static LiteCharms.Features.Extensions.Postgres;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Postgres;
|
||||||
|
|
||||||
|
public sealed class DataProtectionDbContextFactory : IDesignTimeDbContextFactory<DataProtectionDbContext>
|
||||||
|
{
|
||||||
|
public DataProtectionDbContext CreateDbContext(string[] args)
|
||||||
|
{
|
||||||
|
var configuration = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
|
.AddUserSecrets(typeof(DataProtectionDbContext).Assembly)
|
||||||
|
.AddEnvironmentVariables()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var optionsBuilder = new DbContextOptionsBuilder<DataProtectionDbContext>();
|
||||||
|
optionsBuilder.UseNpgsql(configuration.GetConnectionString(DataProtectionDbConfigName));
|
||||||
|
|
||||||
|
return new DataProtectionDbContext(optionsBuilder.Options);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using LiteCharms.Features.Postgres;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Postgres.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DataProtectionDbContext))]
|
||||||
|
[Migration("20260614075149_Init")]
|
||||||
|
partial class Init
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "10.0.9")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.DataProtectionKey", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("FriendlyName")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Xml")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("DataProtectionKeys", "security");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Postgres.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public sealed partial class Init : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.EnsureSchema(
|
||||||
|
name: "security");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "DataProtectionKeys",
|
||||||
|
schema: "security",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
FriendlyName = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Xml = table.Column<string>(type: "text", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_DataProtectionKeys", x => x.Id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "DataProtectionKeys",
|
||||||
|
schema: "security");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using LiteCharms.Features.Postgres;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Postgres.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DataProtectionDbContext))]
|
||||||
|
partial class DataProtectionDbContextModelSnapshot : ModelSnapshot
|
||||||
|
{
|
||||||
|
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "10.0.9")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.DataProtectionKey", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("FriendlyName")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Xml")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("DataProtectionKeys", "security");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user