26 Commits

Author SHA1 Message Date
Developer 02
6a92466490 feat: hinzugefügte Index-Eigenschaft zur IAsymCryptService-Schnittstelle
- Neue Index-Eigenschaft `this[string key]` zur `IAsymCryptService`-Schnittstelle hinzugefügt.
- Ermöglicht das Abrufen spezifischer `IRSADecryptor`-Instanzen anhand eines Schlüsselstrings.
- Schnittstellendefinition aktualisiert, um die Funktionalität für implementierende Klassen zu erweitern.
2024-12-13 16:59:02 +01:00
Developer 02
5d9d756b91 feat: hinzugefügte Index-Eigenschaft zur Abfrage eines spezifischen IRSADecryptor anhand eines Schlüssels
- Neue Index-Eigenschaft `this[string key]` in `AsymCryptService` eingeführt, um spezifische `IRSADecryptor`-Instanzen basierend auf Issuer- und Audience-Schlüsseln abzurufen.
- Validierung des Schlüsselformats und Fehlerbehandlung für Fälle hinzugefügt, in denen kein passender Decryptor gefunden wird.
- Implementierung aktualisiert, um die Kompatibilität mit der bestehenden Decryptor-Enumerationslogik sicherzustellen.
2024-12-13 16:57:30 +01:00
Developer 02
f14aaa75e1 refactor(AsymCryptParams): Umbenennung von Separator in FileNameSeparator.
- KeyNameSeparator hinzugefügt.
2024-12-13 16:40:00 +01:00
Developer 02
249f5a0ae5 feat(AsymCryptService): Encryptors.get hinzugefügt, um die Verschlüsseler der Entschlüsseler zu numerieren. 2024-12-13 16:34:53 +01:00
Developer 02
30177cf0c7 feat(AsymCryptService): Implementiert IEnumerable<IRSADecryptor> 2024-12-13 16:25:21 +01:00
Developer 02
68ef0a7537 refactor(RSACryptographer): Entfernen von _pem, IsPemNull, SetPem, Init und Methoden zur Vereinfachung von RSAEncryptor 2024-12-13 16:17:35 +01:00
Developer 02
fe2ee78d14 refactor(RSADecryptor): Umbenennung der Eigenschaft Encrypt in IsEncrypted 2024-12-13 16:02:25 +01:00
Developer 02
53e6f37a09 refactor(AsymCryptParams): Umbenennung von crypt in der Schleife in decryptor 2024-12-13 15:59:28 +01:00
Developer 02
7ec85b4e30 refactor(AsymCryptParams): Unnötige Methoden entfernt 2024-12-13 15:57:17 +01:00
Developer 02
a9ebc406f3 refactor(RSAFactory): Methode CreateEncryptedPrivateKeyPem hinzugefügt, um mit direkt benutzerdefinierten pbeParametern zu erstellen.
- Umbenennung der Methode CreateRSAPrivateKeyPem in CreatePrivateKeyPem
2024-12-13 15:45:09 +01:00
Developer 02
d013d3edfa refactor(AsymCryptService): Verschlüsselungen entfernen, da sie von Entschlüsselungen erzeugt werden müssen. 2024-12-13 15:38:50 +01:00
Developer 02
f267fe955b feat(AsymCryptParams): Funktionalität erstellt, um pem aus der Datei zu setzen, wenn diese null ist.
- Wenn die pem Datei nicht existiert, erstellt
2024-12-13 15:29:42 +01:00
Developer 02
644283cf8f refactor(AsymCryptService): Nicht-generische Schnittstelle erstellt.
- Geordnete DI-Registrierungsmethoden.
2024-12-13 14:44:09 +01:00
Developer 02
82aa8d1143 refactor(DIExtensions): Alle TryAddSingelton wurden in AddSingelton umgewandelt, um im Falle einer falschen Ausnahme den Fehler zu protokollieren.
- SetAsDefault-Parameter hinzugefügt, um nicht-generische IRSAFactory im Falle einer Konfiguration über appsettings registrieren zu können.
2024-12-13 14:00:43 +01:00
Developer 02
7459f05748 refactor(RSAFactory): Schaffung einer nicht-generischen, getrennten Schnittstelle, um eine statische Standardinstanz erstellen zu können.
- Statische Instanzklasse erstellt.
 - Geordnete DI-Registrierungsmethoden.
2024-12-13 13:47:44 +01:00
Developer 02
36f75d003a refactor(AsymCryptParams): Umbenennung von Directory in PemDirectory, um Namenskonflikte zu vermeiden. 2024-12-13 11:11:12 +01:00
Developer 02
76ce64691a refactor(RSACryptographer): Verzeichnis und Dateiname wurden entfernt.
- Datei-Leseprozess in init-Methode entfernt.
2024-12-13 10:29:49 +01:00
Developer 02
7c03282066 refactor(RSACryptographer): Interne Methoden zur Konfiguration von RSACryptographen hinzugefügt.
- IsPemNull.get-Methode hinzugefügt, um zu prüfen, ob _pem null ist.
 - SetPem-Methode hinzugefügt, um pem im Projekt aktualisieren zu können.
2024-12-13 10:15:22 +01:00
Developer 02
7ae95b729f Fix: Upgrade aufgrund einer Nuget-Paket-Abhängigkeit der abstrakten Schicht 2024-12-10 23:32:49 +01:00
Developer 02
9ee8a51664 chore(Abstraktionen): Aktualisiert von 2.2.1 auf 3.0.0 2024-12-10 23:28:34 +01:00
Developer 02
b1d1a898b8 chore(API): Aktualisiert von 2.0.1 auf 2.1 2024-12-10 23:20:40 +01:00
Developer 02
4ed3e79565 chore(Anwendung): Hochgestuft von 2 auf 3 2024-12-10 23:19:27 +01:00
Developer 02
8d9de4502e refactor(Application): Verbesserung der CRUDService zur Steigerung der Typflexibilität und Wartbarkeit
- Entfernen redundanter generischer Einschränkungen für `TUpdateDto` in `CRUDService`.
- Aktualisierung der Methode `UpdateAsync`, um einen generischen Parameter für eine bessere Typflexibilität von `TUpdateDto` einzuschließen.
- Verbesserung der Typ-Einschränkungen durch Durchsetzung von `IUnique<TId>` direkt im Methodenumfang, wo zutreffend.
- Vereinfachung der Klasse zur Einhaltung bewährter Praktiken im Design generischer Dienste.
2024-12-10 23:17:41 +01:00
Developer 02
7dd91c73c4 Merge branch 'feat/client' 2024-12-10 23:03:01 +01:00
Developer 02
65c64a3f9a chore(API): Aktualisiert auf 2.0.1 2024-12-02 11:35:33 +01:00
Developer 02
1d600aa453 refactor: Nullbarkeitsannotation zu ControllerExtensions-Methoden hinzugefügt 2024-12-02 11:33:52 +01:00
24 changed files with 256 additions and 183 deletions

View File

@@ -7,7 +7,7 @@ namespace DigitalData.Core.API
[ApiController] [ApiController]
[Route("api/[controller]")] [Route("api/[controller]")]
public class BasicCRUDControllerBase<TCRUDService, TDto, TEntity, TId> : CRUDControllerBase<TCRUDService, TDto, TDto, TDto, TEntity, TId> public class BasicCRUDControllerBase<TCRUDService, TDto, TEntity, TId> : CRUDControllerBase<TCRUDService, TDto, TDto, TDto, TEntity, TId>
where TCRUDService : ICRUDService<TDto, TDto, TDto, TEntity, TId> where TCRUDService : ICRUDService<TDto, TDto, TEntity, TId>
where TDto : class, IUnique<TId> where TDto : class, IUnique<TId>
where TEntity : class, IUnique<TId> where TEntity : class, IUnique<TId>
{ {

View File

@@ -11,13 +11,12 @@ namespace DigitalData.Core.API
/// <typeparam name="TCRUDService">The derived CRUD service type implementing ICRUDService<TCreateDto, TReadDto, TUpdateDto, TEntity, TId>.</typeparam> /// <typeparam name="TCRUDService">The derived CRUD service type implementing ICRUDService<TCreateDto, TReadDto, TUpdateDto, TEntity, TId>.</typeparam>
/// <typeparam name="TCreateDto">The Data Transfer Object type for create operations.</typeparam> /// <typeparam name="TCreateDto">The Data Transfer Object type for create operations.</typeparam>
/// <typeparam name="TReadDto">The Data Transfer Object type for read operations.</typeparam> /// <typeparam name="TReadDto">The Data Transfer Object type for read operations.</typeparam>
/// <typeparam name="TUpdateDto">The Data Transfer Object type for update operations.</typeparam>
/// <typeparam name="TEntity">The entity type CRUD operations will be performed on.</typeparam> /// <typeparam name="TEntity">The entity type CRUD operations will be performed on.</typeparam>
/// <typeparam name="TId">The type of the entity's identifier.</typeparam> /// <typeparam name="TId">The type of the entity's identifier.</typeparam>
[ApiController] [ApiController]
[Route("api/[controller]")] [Route("api/[controller]")]
public class CRUDControllerBase<TCRUDService, TCreateDto, TReadDto, TUpdateDto, TEntity, TId> : ControllerBase public class CRUDControllerBase<TCRUDService, TCreateDto, TReadDto, TUpdateDto, TEntity, TId> : ControllerBase
where TCRUDService : ICRUDService<TCreateDto, TReadDto, TUpdateDto, TEntity, TId> where TCRUDService : ICRUDService<TCreateDto, TReadDto, TEntity, TId>
where TCreateDto : class where TCreateDto : class
where TReadDto : class where TReadDto : class
where TUpdateDto : class, IUnique<TId> where TUpdateDto : class, IUnique<TId>

View File

@@ -12,13 +12,12 @@ namespace DigitalData.Core.API
/// <typeparam name="TCRUDService">The derived CRUD service type implementing ICRUDService<TCreateDto, TReadDto, TUpdateDto, TEntity, TId>.</typeparam> /// <typeparam name="TCRUDService">The derived CRUD service type implementing ICRUDService<TCreateDto, TReadDto, TUpdateDto, TEntity, TId>.</typeparam>
/// <typeparam name="TCreateDto">The Data Transfer Object type for create operations.</typeparam> /// <typeparam name="TCreateDto">The Data Transfer Object type for create operations.</typeparam>
/// <typeparam name="TReadDto">The Data Transfer Object type for read operations.</typeparam> /// <typeparam name="TReadDto">The Data Transfer Object type for read operations.</typeparam>
/// <typeparam name="TUpdateDto">The Data Transfer Object type for update operations.</typeparam>
/// <typeparam name="TEntity">The entity type CRUD operations will be performed on.</typeparam> /// <typeparam name="TEntity">The entity type CRUD operations will be performed on.</typeparam>
/// <typeparam name="TId">The type of the entity's identifier.</typeparam> /// <typeparam name="TId">The type of the entity's identifier.</typeparam>
[ApiController] [ApiController]
[Route("api/[controller]")] [Route("api/[controller]")]
public class CRUDControllerBaseWithErrorHandling<TCRUDService, TCreateDto, TReadDto, TUpdateDto, TEntity, TId> : ControllerBase public class CRUDControllerBaseWithErrorHandling<TCRUDService, TCreateDto, TReadDto, TUpdateDto, TEntity, TId> : ControllerBase
where TCRUDService : ICRUDService<TCreateDto, TReadDto, TUpdateDto, TEntity, TId> where TCRUDService : ICRUDService<TCreateDto, TReadDto, TEntity, TId>
where TCreateDto : class where TCreateDto : class
where TReadDto : class where TReadDto : class
where TUpdateDto : class, IUnique<TId> where TUpdateDto : class, IUnique<TId>

View File

@@ -19,7 +19,7 @@ namespace DigitalData.Core.API
/// <param name="index">The key in the ViewData dictionary where the value will be stored.</param> /// <param name="index">The key in the ViewData dictionary where the value will be stored.</param>
/// <param name="value">The value to be stored in the ViewData dictionary.</param> /// <param name="value">The value to be stored in the ViewData dictionary.</param>
/// <returns>The same ViewResult object with updated ViewData, allowing for additional chained operations.</returns> /// <returns>The same ViewResult object with updated ViewData, allowing for additional chained operations.</returns>
public static ViewResult WithData(this ViewResult viewResult, string index, object value) public static ViewResult WithData(this ViewResult viewResult, string index, object? value)
{ {
viewResult.ViewData[index] = value; viewResult.ViewData[index] = value;
return viewResult; return viewResult;

View File

@@ -8,7 +8,7 @@
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<Description>This package provides a comprehensive set of API controllers and related utilities for the DigitalData.Core library. It includes generic CRUD controllers, localization extensions, middleware for security policies, and application model conventions.</Description> <Description>This package provides a comprehensive set of API controllers and related utilities for the DigitalData.Core library. It includes generic CRUD controllers, localization extensions, middleware for security policies, and application model conventions.</Description>
<PackageId>DigitalData.Core.API</PackageId> <PackageId>DigitalData.Core.API</PackageId>
<Version>2.0.0.0</Version> <Version>2.1.1</Version>
<Authors>Digital Data GmbH</Authors> <Authors>Digital Data GmbH</Authors>
<Company>Digital Data GmbH</Company> <Company>Digital Data GmbH</Company>
<Product>DigitalData.Core.API</Product> <Product>DigitalData.Core.API</Product>
@@ -16,6 +16,8 @@
<RepositoryUrl>http://git.dd:3000/AppStd/WebCoreModules.git</RepositoryUrl> <RepositoryUrl>http://git.dd:3000/AppStd/WebCoreModules.git</RepositoryUrl>
<PackageTags>digital data core api</PackageTags> <PackageTags>digital data core api</PackageTags>
<PackageIcon>core_icon.png</PackageIcon> <PackageIcon>core_icon.png</PackageIcon>
<AssemblyVersion>2.1.1</AssemblyVersion>
<FileVersion>2.1.1</FileVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@@ -15,7 +15,7 @@ namespace DigitalData.Core.Abstractions.Application
/// This interface is useful for entities that do not require different DTOs for different operations, /// This interface is useful for entities that do not require different DTOs for different operations,
/// allowing for a more concise and maintainable codebase when implementing services for such entities. /// allowing for a more concise and maintainable codebase when implementing services for such entities.
/// </remarks> /// </remarks>
public interface IBasicCRUDService<TDto, TEntity, TId> : ICRUDService<TDto, TDto, TDto, TEntity, TId> public interface IBasicCRUDService<TDto, TEntity, TId> : ICRUDService<TDto, TDto, TEntity, TId>
where TDto : class, IUnique<TId> where TEntity : class, IUnique<TId> where TDto : class, IUnique<TId> where TEntity : class, IUnique<TId>
{ {
} }

View File

@@ -2,8 +2,8 @@
namespace DigitalData.Core.Abstractions.Application namespace DigitalData.Core.Abstractions.Application
{ {
public interface ICRUDService<TCreateDto, TReadDto, TUpdateDto, TEntity, TId> : IReadService<TReadDto, TEntity, TId> public interface ICRUDService<TCreateDto, TReadDto, TEntity, TId> : IReadService<TReadDto, TEntity, TId>
where TCreateDto : class where TReadDto : class where TUpdateDto : IUnique<TId> where TEntity : class, IUnique<TId> where TCreateDto : class where TReadDto : class where TEntity : class, IUnique<TId>
{ {
/// <summary> /// <summary>
/// Asynchronously creates a new entity based on the provided <paramref name="createDto"/> and returns the identifier of the created entity wrapped in a <see cref="DataResult{TId}"/>. /// Asynchronously creates a new entity based on the provided <paramref name="createDto"/> and returns the identifier of the created entity wrapped in a <see cref="DataResult{TId}"/>.
@@ -20,6 +20,6 @@ namespace DigitalData.Core.Abstractions.Application
/// </summary> /// </summary>
/// <param name="updateDto">The updateDTO with updated values for the entity.</param> /// <param name="updateDto">The updateDTO with updated values for the entity.</param>
/// <returns>An Result indicating the outcome of the update operation, with an appropriate message.</returns> /// <returns>An Result indicating the outcome of the update operation, with an appropriate message.</returns>
Task<Result> UpdateAsync(TUpdateDto updateDto); Task<Result> UpdateAsync<TUpdateDto>(TUpdateDto updateDto) where TUpdateDto : IUnique<TId>;
} }
} }

View File

@@ -17,9 +17,9 @@
<RepositoryUrl>http://git.dd:3000/AppStd/WebCoreModules.git</RepositoryUrl> <RepositoryUrl>http://git.dd:3000/AppStd/WebCoreModules.git</RepositoryUrl>
<PackAsTool>False</PackAsTool> <PackAsTool>False</PackAsTool>
<PackageIcon>core_icon.png</PackageIcon> <PackageIcon>core_icon.png</PackageIcon>
<Version>2.2.1</Version> <Version>3.0.0</Version>
<AssemblyVersion>2.2.1</AssemblyVersion> <AssemblyVersion>3.0.0</AssemblyVersion>
<FileVersion>2.2.1</FileVersion> <FileVersion>3.0.0</FileVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@@ -1,9 +1,11 @@
namespace DigitalData.Core.Abstractions.Security namespace DigitalData.Core.Abstractions.Security
{ {
public interface IAsymCryptService<TParams> : IRSAFactory<TParams> public interface IAsymCryptService : IRSAFactory
{ {
public IEnumerable<IRSADecryptor> Decryptors { get; } public IEnumerable<IRSADecryptor> Decryptors { get; }
public IEnumerable<IRSAEncryptor> Encryptors { get; } public IRSADecryptor this[string key] { get; }
} }
public interface IAsymCryptService<TParams> : IAsymCryptService, IRSAFactory<TParams> { }
} }

View File

@@ -7,15 +7,9 @@ namespace DigitalData.Core.Abstractions.Security
public string Pem { get; init; } public string Pem { get; init; }
public RSAEncryptionPadding Padding { get; init; } public RSAEncryptionPadding Padding { get; init; }
public string? Directory { get; set; }
public string? FileName { get; set; }
public string Issuer { get; init; } public string Issuer { get; init; }
public string Audience { get; init; } public string Audience { get; init; }
public void Init();
} }
} }

View File

@@ -2,7 +2,7 @@
{ {
public interface IRSADecryptor : IRSACryptographer public interface IRSADecryptor : IRSACryptographer
{ {
public bool Encrypt { get; init; } public bool IsEncrypted { get; init; }
IRSAEncryptor Encryptor { get; } IRSAEncryptor Encryptor { get; }

View File

@@ -2,15 +2,22 @@
namespace DigitalData.Core.Abstractions.Security namespace DigitalData.Core.Abstractions.Security
{ {
public interface IRSAFactory<TParams> public interface IRSAFactory
{ {
string CreateRSAPrivateKeyPem(int? keySizeInBits = null); string CreatePrivateKeyPem(int? keySizeInBits = null);
string CreateEncryptedPrivateKeyPem( public string CreateEncryptedPrivateKeyPem(
int? keySizeInBits = null,
string? password = null,
PbeEncryptionAlgorithm? pbeEncryptionAlgorithm = null, PbeEncryptionAlgorithm? pbeEncryptionAlgorithm = null,
HashAlgorithmName? hashAlgorithmName = null, HashAlgorithmName? hashAlgorithmName = null,
int? iterationCount = null); int? iterationCount = null,
int? keySizeInBits = null,
string? password = null);
public string CreateEncryptedPrivateKeyPem(
PbeParameters pbeParameters,
int? keySizeInBits = null,
string? password = null);
} }
public interface IRSAFactory<TParams> : IRSAFactory { }
} }

View File

@@ -19,7 +19,7 @@ namespace DigitalData.Core.Application
/// and a culture-specific translation service for any necessary text translations, ensuring a versatile and internationalized approach to CRUD operations. /// and a culture-specific translation service for any necessary text translations, ensuring a versatile and internationalized approach to CRUD operations.
/// </remarks> /// </remarks>
public class BasicCRUDService<TCRUDRepository, TDto, TEntity, TId> : public class BasicCRUDService<TCRUDRepository, TDto, TEntity, TId> :
CRUDService<TCRUDRepository, TDto, TDto, TDto, TEntity, TId>, IBasicCRUDService<TDto, TEntity, TId> CRUDService<TCRUDRepository, TDto, TDto, TEntity, TId>, IBasicCRUDService<TDto, TEntity, TId>
where TCRUDRepository : ICRUDRepository<TEntity, TId> where TDto : class, IUnique<TId> where TEntity : class, IUnique<TId> where TCRUDRepository : ICRUDRepository<TEntity, TId> where TDto : class, IUnique<TId> where TEntity : class, IUnique<TId>
{ {
/// <summary> /// <summary>

View File

@@ -12,11 +12,10 @@ namespace DigitalData.Core.Application
/// </summary> /// </summary>
/// <typeparam name="TCreateDto">The DTO type for create operations.</typeparam> /// <typeparam name="TCreateDto">The DTO type for create operations.</typeparam>
/// <typeparam name="TReadDto">The DTO type for read operations.</typeparam> /// <typeparam name="TReadDto">The DTO type for read operations.</typeparam>
/// <typeparam name="TUpdateDto">The DTO type for update operations.</typeparam>
/// <typeparam name="TEntity">The entity type.</typeparam> /// <typeparam name="TEntity">The entity type.</typeparam>
/// <typeparam name="TId">The type of the identifier for the entity.</typeparam> /// <typeparam name="TId">The type of the identifier for the entity.</typeparam>
public class CRUDService<TCRUDRepository, TCreateDto, TReadDto, TUpdateDto, TEntity, TId> : ReadService<TCRUDRepository, TReadDto, TEntity, TId>, ICRUDService<TCreateDto, TReadDto, TUpdateDto, TEntity, TId> public class CRUDService<TCRUDRepository, TCreateDto, TReadDto, TEntity, TId> : ReadService<TCRUDRepository, TReadDto, TEntity, TId>, ICRUDService<TCreateDto, TReadDto, TEntity, TId>
where TCRUDRepository : ICRUDRepository<TEntity, TId> where TCreateDto : class where TReadDto : class where TUpdateDto : IUnique<TId> where TEntity : class, IUnique<TId> where TCRUDRepository : ICRUDRepository<TEntity, TId> where TCreateDto : class where TReadDto : class where TEntity : class, IUnique<TId>
{ {
/// <summary> /// <summary>
@@ -45,7 +44,7 @@ namespace DigitalData.Core.Application
/// </summary> /// </summary>
/// <param name="updateDto">The DTO to update an entity from.</param> /// <param name="updateDto">The DTO to update an entity from.</param>
/// <returns>A service message indicating success or failure.</returns> /// <returns>A service message indicating success or failure.</returns>
public virtual async Task<Result> UpdateAsync(TUpdateDto updateDto) public virtual async Task<Result> UpdateAsync<TUpdateDto>(TUpdateDto updateDto) where TUpdateDto : IUnique<TId>
{ {
var currentEntitiy = await _repository.ReadByIdAsync(updateDto.Id); var currentEntitiy = await _repository.ReadByIdAsync(updateDto.Id);

View File

@@ -40,7 +40,6 @@ namespace DigitalData.Core.Application
/// <typeparam name="TCRUDRepository">The repository type that provides CRUD operations for entities of type TEntity.</typeparam> /// <typeparam name="TCRUDRepository">The repository type that provides CRUD operations for entities of type TEntity.</typeparam>
/// <typeparam name="TCreateDto">The DTO type used for create operations.</typeparam> /// <typeparam name="TCreateDto">The DTO type used for create operations.</typeparam>
/// <typeparam name="TReadDto">The DTO type used for read operations.</typeparam> /// <typeparam name="TReadDto">The DTO type used for read operations.</typeparam>
/// <typeparam name="TUpdateDto">The DTO type used for update operations.</typeparam>
/// <typeparam name="TEntity">The entity type corresponding to the DTOs.</typeparam> /// <typeparam name="TEntity">The entity type corresponding to the DTOs.</typeparam>
/// <typeparam name="TId">The type of the entity's identifier.</typeparam> /// <typeparam name="TId">The type of the entity's identifier.</typeparam>
/// <typeparam name="TProfile">The AutoMapper profile type for configuring mappings between the DTOs and the entity.</typeparam> /// <typeparam name="TProfile">The AutoMapper profile type for configuring mappings between the DTOs and the entity.</typeparam>
@@ -48,9 +47,9 @@ namespace DigitalData.Core.Application
/// <param name="configureService">An optional action to configure additional services for the CRUD service.</param> /// <param name="configureService">An optional action to configure additional services for the CRUD service.</param>
/// <returns>The original <see cref="IServiceCollection"/> instance, allowing further configuration.</returns> /// <returns>The original <see cref="IServiceCollection"/> instance, allowing further configuration.</returns>
public static IServiceCollection AddCleanCRUDService<TCRUDRepository, TCreateDto, TReadDto, TUpdateDto, TEntity, TId, TProfile>(this IServiceCollection services, Action<IServiceCollection>? configureService = null) public static IServiceCollection AddCleanCRUDService<TCRUDRepository, TCreateDto, TReadDto, TUpdateDto, TEntity, TId, TProfile>(this IServiceCollection services, Action<IServiceCollection>? configureService = null)
where TCRUDRepository : ICRUDRepository<TEntity, TId> where TCreateDto : class where TReadDto : class where TUpdateDto : class, IUnique<TId> where TEntity : class, IUnique<TId> where TProfile : Profile where TCRUDRepository : ICRUDRepository<TEntity, TId> where TCreateDto : class where TReadDto : class, IUnique<TId> where TEntity : class, IUnique<TId> where TProfile : Profile
{ {
services.AddScoped<ICRUDService<TCreateDto, TReadDto, TUpdateDto, TEntity, TId>, CRUDService<TCRUDRepository, TCreateDto, TReadDto, TUpdateDto, TEntity, TId>>(); services.AddScoped<ICRUDService<TCreateDto, TReadDto, TEntity, TId>, CRUDService<TCRUDRepository, TCreateDto, TReadDto, TEntity, TId>>();
configureService?.Invoke(services); configureService?.Invoke(services);
services.AddAutoMapper(typeof(TProfile).Assembly); services.AddAutoMapper(typeof(TProfile).Assembly);

View File

@@ -14,7 +14,9 @@
<PackageIcon>core_icon.png</PackageIcon> <PackageIcon>core_icon.png</PackageIcon>
<RepositoryUrl>http://git.dd:3000/AppStd/WebCoreModules.git</RepositoryUrl> <RepositoryUrl>http://git.dd:3000/AppStd/WebCoreModules.git</RepositoryUrl>
<PackageTags>digital data core application clean architecture</PackageTags> <PackageTags>digital data core application clean architecture</PackageTags>
<Version>2.0.0.0</Version> <Version>3.0.1</Version>
<AssemblyVersion>3.0.1</AssemblyVersion>
<FileVersion>3.0.1</FileVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@@ -3,18 +3,47 @@ using DigitalData.Core.Security.Config;
using DigitalData.Core.Security.Cryptographer; using DigitalData.Core.Security.Cryptographer;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using System.Collections;
namespace DigitalData.Core.Security namespace DigitalData.Core.Security
{ {
public class AsymCryptService<TAsymCryptParams> : RSAFactory<TAsymCryptParams>, IAsymCryptService<TAsymCryptParams>, IRSAFactory<TAsymCryptParams> where TAsymCryptParams : AsymCryptParams public class AsymCryptService<TAsymCryptParams> : RSAFactory<TAsymCryptParams>, IAsymCryptService<TAsymCryptParams>, IRSAFactory<TAsymCryptParams>, IEnumerable<IRSADecryptor>
where TAsymCryptParams : AsymCryptParams
{ {
public IEnumerable<IRSADecryptor> Decryptors => _params.Decryptors; public IEnumerable<IRSADecryptor> Decryptors => _params.Decryptors;
public IEnumerable<IRSAEncryptor> Encryptors => _params.Encryptors; public IRSADecryptor this[string key]
{
get
{
var key_params = key.Split(_params.KeyNameSeparator);
if (key_params.Length != 2)
throw new ArgumentException($"Invalid key format. Expected two segments separated by '{_params.KeyNameSeparator}', but received: '{key}'.", nameof(key));
return _params.Decryptors.FirstOrDefault(d => d.Issuer == key_params[0] && d.Audience == key_params[1])
?? throw new KeyNotFoundException($"No decryptor found matching the issuer '{key_params[0]}' and audience '{key_params[1]}'.");
}
}
public AsymCryptService(IOptions<TAsymCryptParams> options, ILogger<AsymCryptService<TAsymCryptParams>>? logger = null) : base(options) public AsymCryptService(IOptions<TAsymCryptParams> options, ILogger<AsymCryptService<TAsymCryptParams>>? logger = null) : base(options)
{ {
logger?.LogInformation("Core.Secrets version: {Version}, Created on: {CreationDate}.", Secrets.Version, Secrets.CreationDate.ToString("dd.MM.yyyy")); logger?.LogInformation("Core.Secrets version: {Version}, Created on: {CreationDate}.", Secrets.Version, Secrets.CreationDate.ToString("dd.MM.yyyy"));
} }
public IEnumerator<IRSADecryptor> GetEnumerator() => Decryptors.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => Decryptors.GetEnumerator();
public IEnumerable<IRSAEncryptor> Encryptors
{
get
{
foreach (var decryptor in Decryptors)
{
yield return decryptor.Encryptor;
}
}
}
} }
} }

View File

@@ -1,58 +1,76 @@
using DigitalData.Core.Abstractions.Security; using DigitalData.Core.Security.Cryptographer;
namespace DigitalData.Core.Security.Config namespace DigitalData.Core.Security.Config
{ {
public class AsymCryptParams : RSAFactoryParams public class AsymCryptParams : RSAFactoryParams
{ {
public string Directory { get; init; } = string.Empty; public string PemDirectory { get; init; } = string.Empty;
/// <summary> /// <summary>
/// 0: Issuer - 1: Audience - 2: Type tag - 3: Version /// Represents the separator used to concatenate the components of a file-related token string.
/// </summary> /// </summary>
public string FileNameFormat { get; init; } = "{0}_-_{1}_-_{2}_-_{3}.pem"; /// <remarks>
/// The resulting file-related token string is constructed as follows:
/// <c>string.Join(FileNameSeparator, Issuer, Audience, Secret_version)</c>.
/// If <c>Secret_version</c> is not null, it will be included in the concatenation.
/// </remarks>
/// <example>
/// For example, if <c>FileNameSeparator = "_-_"</c>, the output might look like:
/// <c>"Issuer_-_Audience_-_Secret_version"</c>.
/// </example>
public string FileNameSeparator { get; init; } = "_-_";
public string EncryptorTag { get; init; } = "public"; /// <summary>
/// Represents the separator used to concatenate the components of a key-related token string.
/// </summary>
/// <remarks>
/// The resulting key-related token string is constructed as follows:
/// <c>string.Join(KeyNameSeparator, Issuer, Audience, Secret_version)</c>.
/// If <c>Secret_version</c> is not null, it will be included in the concatenation.
/// </remarks>
/// <example>
/// For example, if <c>KeyNameSeparator = ":"</c>, the output might look like:
/// <c>"Issuer:Audience:Secret_version"</c>.
/// </example>
public string KeyNameSeparator { get; init; } = ":";
public string DecryptorTag { get; init; } = "private"; public IEnumerable<RSADecryptor> Decryptors { get; init; } = new List<RSADecryptor>();
public string EncryptedDecryptorTag { get; init; } = "enc-private";
public IEnumerable<IRSADecryptor> Decryptors { get; init; } = new List<IRSADecryptor>();
public IEnumerable<IRSAEncryptor> Encryptors { get; init; } = new List<IRSAEncryptor>();
private string TypeTagOf(IRSACryptographer crypt)
{
if (crypt is IRSAEncryptor)
return EncryptorTag;
else if (crypt is IRSADecryptor decryptor)
return decryptor.Encrypt ? EncryptedDecryptorTag : DecryptorTag;
else
throw new InvalidOperationException(
"Unknown cryptographer type. The crypt parameter must be either IRSAEncryptor or IRSADecryptor.");
}
public override void OnDeserialized() public override void OnDeserialized()
{ {
base.OnDeserialized(); base.OnDeserialized();
var cryptographers = Encryptors.Cast<IRSACryptographer>().Concat(Decryptors.Cast<IRSACryptographer>()); // Create root folder if it does not exist
if (!Directory.Exists(PemDirectory))
Directory.CreateDirectory(PemDirectory);
foreach (var crypt in cryptographers) foreach (var decryptor in Decryptors)
{ {
// set default path // set default path
if (crypt.Pem is null) if (decryptor.IsPemNull)
{ {
crypt.Directory ??= Directory; var file_name_params = new List<object> { decryptor.Issuer, decryptor.Audience };
crypt.FileName ??= string.Format( if (decryptor.IsEncrypted)
FileNameFormat, file_name_params.Add(Secrets.Version);
crypt.Issuer,
crypt.Audience, var path = Path.Combine(PemDirectory, string.Join(FileNameSeparator, file_name_params));
TypeTagOf(crypt),
Secrets.Version); if (File.Exists(path))
decryptor.SetPem(File.ReadAllText(path));
else
{
var pem = decryptor.IsEncrypted
? Instance.RSAFactory.CreateEncryptedPrivateKeyPem(pbeParameters: PbeParameters, keySizeInBits: KeySizeInBits, password: Secrets.PBE_PASSWORD)
: Instance.RSAFactory.CreatePrivateKeyPem(keySizeInBits: KeySizeInBits);
decryptor.SetPem(File.ReadAllText(pem));
// Save file in background
Task.Run(async () => await File.WriteAllTextAsync(path: path, pem));
}
} }
crypt.Init(); decryptor.Init();
} }
} }
} }

View File

@@ -5,21 +5,8 @@ namespace DigitalData.Core.Security.Cryptographer
{ {
public class RSACryptographer : IRSACryptographer public class RSACryptographer : IRSACryptographer
{ {
protected string? _pem; public virtual string Pem { get; init; }
public string Pem
{
get => _pem
?? throw new InvalidOperationException($"Pem is not initialized. Please ensure that the PEM is set or properly loaded from the file. Issuer: {Issuer}, Audience: {Audience}.");
init => _pem = value;
}
public string? PemPath => FileName is null ? null : Path.Combine(Directory ?? string.Empty, FileName);
public string? Directory { get; set; }
public string? FileName { get; set; }
public RSAEncryptionPadding Padding { get; init; } = RSAEncryptionPadding.OaepSHA256; public RSAEncryptionPadding Padding { get; init; } = RSAEncryptionPadding.OaepSHA256;
protected virtual RSA RSA { get; } = RSA.Create(); protected virtual RSA RSA { get; } = RSA.Create();
@@ -28,26 +15,8 @@ namespace DigitalData.Core.Security.Cryptographer
public string Audience { get; init; } = string.Empty; public string Audience { get; init; } = string.Empty;
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
internal RSACryptographer() { } internal RSACryptographer() { }
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
public virtual void UnableToInitPemEvent() => throw new InvalidOperationException(
$"Pem is not initialized and pem file is null. Issuer is {Issuer} and audience {Audience}.");
public virtual void FileNotFoundEvent() => throw new FileNotFoundException(
$"Pem is not initialized and pem file is not found in {PemPath}. Issuer is {Issuer} and audience {Audience}.");
// TODO: make file read asynchronous, consider multiple routing
public virtual void Init()
{
if(_pem is null)
{
if(PemPath is null)
UnableToInitPemEvent();
if (File.Exists(PemPath))
_pem = File.ReadAllText(PemPath);
else
FileNotFoundEvent();
}
}
} }
} }

View File

@@ -1,5 +1,4 @@
using DigitalData.Core.Abstractions.Security; using DigitalData.Core.Abstractions.Security;
using DigitalData.Core.Security.Config;
using DigitalData.Core.Security.Extensions; using DigitalData.Core.Security.Extensions;
using System.Security.Cryptography; using System.Security.Cryptography;
@@ -7,7 +6,13 @@ namespace DigitalData.Core.Security.Cryptographer
{ {
public class RSADecryptor : RSACryptographer, IRSADecryptor, IRSACryptographer public class RSADecryptor : RSACryptographer, IRSADecryptor, IRSACryptographer
{ {
public bool Encrypt { get; init; } private string? _pem;
public override string Pem { get => _pem ?? throw PemIsNullException; init => _pem = value; }
public bool IsPemNull => _pem is null;
public bool IsEncrypted { get; init; }
private readonly Lazy<IRSAEncryptor> _lazyEncryptor; private readonly Lazy<IRSAEncryptor> _lazyEncryptor;
@@ -26,30 +31,19 @@ namespace DigitalData.Core.Security.Cryptographer
public string Decrypt(string data) => RSA.Decrypt(data.Base64ToByte(), Padding).BytesToString(); public string Decrypt(string data) => RSA.Decrypt(data.Base64ToByte(), Padding).BytesToString();
public override void Init() internal void SetPem(string pem) => _pem = pem;
public void Init()
{ {
base.Init(); if (_pem is null)
if (Encrypt) throw PemIsNullException;
if (IsEncrypted)
RSA.ImportFromEncryptedPem(Pem, Secrets.PBE_PASSWORD.AsSpan()); RSA.ImportFromEncryptedPem(Pem, Secrets.PBE_PASSWORD.AsSpan());
else else
RSA.ImportFromPem(Pem); RSA.ImportFromPem(Pem);
} }
public override void FileNotFoundEvent() private InvalidOperationException PemIsNullException => new($"Pem is not initialized. Please ensure that the PEM is set or properly loaded from the file. Issuer: {Issuer}, Audience: {Audience}.");
{
var new_decryptor = new RSADecryptor()
{
Pem = RSAFactory<RSAFactoryParams>.Static.CreateRSAPrivateKeyPem(),
Encrypt = Encrypt
};
_pem = new_decryptor.Pem;
if (PemPath is not null)
Task.Run(async () =>
{
await File.WriteAllTextAsync(_pem, PemPath);
});
}
} }
} }

View File

@@ -1,37 +1,24 @@
using DigitalData.Core.Abstractions.Security; using DigitalData.Core.Abstractions.Security;
using DigitalData.Core.Security.Config;
using DigitalData.Core.Security.Extensions; using DigitalData.Core.Security.Extensions;
namespace DigitalData.Core.Security.Cryptographer namespace DigitalData.Core.Security.Cryptographer
{ {
public class RSAEncryptor : RSACryptographer, IRSAEncryptor, IRSACryptographer public class RSAEncryptor : RSACryptographer, IRSAEncryptor, IRSACryptographer
{ {
public override string Pem
{
get => base.Pem;
init
{
base.Pem = value;
RSA.ImportFromPem(value);
}
}
public byte[] Encrypt(byte[] data) => RSA.Encrypt(data, Padding); public byte[] Encrypt(byte[] data) => RSA.Encrypt(data, Padding);
public string Encrypt(string data) => RSA.Encrypt(data.Base64ToByte(), Padding).BytesToString(); public string Encrypt(string data) => RSA.Encrypt(data.Base64ToByte(), Padding).BytesToString();
public bool Verify(string data, string signature) => Encrypt(data) == signature; public bool Verify(string data, string signature) => Encrypt(data) == signature;
public override void Init()
{
base.Init();
RSA.ImportFromPem(base.Pem);
}
public override void FileNotFoundEvent()
{
var new_decryptor = new RSADecryptor()
{
Pem = RSAFactory<RSAFactoryParams>.Static.CreateRSAPrivateKeyPem()
};
_pem = new_decryptor.Encryptor.Pem;
if (PemPath is not null)
Task.Run(async () =>
{
await File.WriteAllTextAsync(_pem, PemPath);
});
}
} }
} }

View File

@@ -7,23 +7,19 @@ namespace DigitalData.Core.Security.Cryptographer
{ {
public class RSAFactory<TRSAFactoryParams> : IRSAFactory<TRSAFactoryParams> where TRSAFactoryParams : RSAFactoryParams public class RSAFactory<TRSAFactoryParams> : IRSAFactory<TRSAFactoryParams> where TRSAFactoryParams : RSAFactoryParams
{ {
private static readonly Lazy<RSAFactory<RSAFactoryParams>> LazyInstance = new(() => new(Options.Create<RSAFactoryParams>(new())));
public static RSAFactory<RSAFactoryParams> Static => LazyInstance.Value;
protected readonly TRSAFactoryParams _params; protected readonly TRSAFactoryParams _params;
public RSAFactory(IOptions<TRSAFactoryParams> options) => _params = options.Value; public RSAFactory(IOptions<TRSAFactoryParams> options) => _params = options.Value;
public string CreateRSAPrivateKeyPem(int? keySizeInBits = null) public string CreatePrivateKeyPem(int? keySizeInBits = null)
=> RSA.Create(keySizeInBits ?? _params.KeySizeInBits).ExportRSAPrivateKeyPem(); => RSA.Create(keySizeInBits ?? _params.KeySizeInBits).ExportRSAPrivateKeyPem();
public string CreateEncryptedPrivateKeyPem( public string CreateEncryptedPrivateKeyPem(
int? keySizeInBits = null,
string? password = null,
PbeEncryptionAlgorithm? pbeEncryptionAlgorithm = null, PbeEncryptionAlgorithm? pbeEncryptionAlgorithm = null,
HashAlgorithmName? hashAlgorithmName = null, HashAlgorithmName? hashAlgorithmName = null,
int? iterationCount = null) int? iterationCount = null,
int? keySizeInBits = null,
string? password = null)
{ {
password ??= _params.PbePassword; password ??= _params.PbePassword;
@@ -40,5 +36,19 @@ namespace DigitalData.Core.Security.Cryptographer
return new string(pemChars); return new string(pemChars);
} }
public string CreateEncryptedPrivateKeyPem(
PbeParameters pbeParameters,
int? keySizeInBits = null,
string? password = null)
{
password ??= _params.PbePassword;
var encryptedPrivateKey = RSA.Create(keySizeInBits ?? _params.KeySizeInBits).ExportEncryptedPkcs8PrivateKey(password.AsSpan(), pbeParameters);
var pemChars = PemEncoding.Write(_params.EncryptedPrivateKeyPemLabel, encryptedPrivateKey);
return new string(pemChars);
}
} }
} }

View File

@@ -3,7 +3,6 @@ using DigitalData.Core.Security.Config;
using DigitalData.Core.Security.Cryptographer; using DigitalData.Core.Security.Cryptographer;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
@@ -21,35 +20,85 @@ namespace DigitalData.Core.Security
options.Converters.Add(new JsonStringEnumConverter()); options.Converters.Add(new JsonStringEnumConverter());
return options; return options;
} }
private static IServiceCollection AddAsymCryptService<TAsymCryptParams>(this IServiceCollection services, bool setAsDefault = false) where TAsymCryptParams : AsymCryptParams
=> setAsDefault
? services.AddScoped<IAsymCryptService, AsymCryptService<TAsymCryptParams>>()
: services.AddScoped<IAsymCryptService<TAsymCryptParams>, AsymCryptService<TAsymCryptParams>>();
private static IServiceCollection AddAsymCryptService<TAsymCryptParams>(this IServiceCollection services) /// <summary>
/// Registers a custom asym crypt service with specified parameters from the given configuration section.
/// </summary>
/// <typeparam name="TAsymCryptParams"></typeparam>
/// <param name="services"></param>
/// <param name="section"></param>
/// <param name="setAsDefault">If true, the factory is registered as the default <see cref="IRSAFactory"/>. Otherwise, it is registered as <see cref="IRSAFactory{TRSAFactoryParams}"/>.</param>
/// <returns></returns>
public static IServiceCollection AddAsymCryptService<TAsymCryptParams>(this IServiceCollection services, IConfigurationSection section, bool setAsDefault = false)
where TAsymCryptParams : AsymCryptParams where TAsymCryptParams : AsymCryptParams
{ => services.Configure<TAsymCryptParams>(section).AddAsymCryptService<TAsymCryptParams>(setAsDefault: setAsDefault);
services.TryAddScoped<IAsymCryptService<TAsymCryptParams>, AsymCryptService<TAsymCryptParams>>();
return services;
}
public static IServiceCollection AddAsymCryptService<TAsymCryptParams>(this IServiceCollection services, IConfigurationSection section) /// <summary>
/// Registers an asym crypt service with the specified parameters from the given instance. Optionally, sets it as the default factory.
/// </summary>
/// <typeparam name="TAsymCryptParams"></typeparam>
/// <param name="services"></param>
/// <param name="param"></param>
/// <param name="setAsDefault">If true, the factory is registered as the default <see cref="IRSAFactory"/>. Otherwise, it is registered as <see cref="IRSAFactory{TRSAFactoryParams}"/>.</param>
/// <returns></returns>
public static IServiceCollection AddAsymCryptService<TAsymCryptParams>(this IServiceCollection services, TAsymCryptParams param, bool setAsDefault = false)
where TAsymCryptParams : AsymCryptParams where TAsymCryptParams : AsymCryptParams
=> services.Configure<TAsymCryptParams>(section).AddAsymCryptService<TAsymCryptParams>(); => services.AddSingleton(Options.Create(param)).AddAsymCryptService<TAsymCryptParams>(setAsDefault: setAsDefault);
public static IServiceCollection AddAsymCryptService<TAsymCryptParams>(this IServiceCollection services, TAsymCryptParams param) /// <summary>
where TAsymCryptParams : AsymCryptParams /// Registers default asym crypt service with the specified parameters from the given instance.
=> services.AddSingleton(Options.Create(param)).AddAsymCryptService<TAsymCryptParams>(); /// </summary>
/// <param name="services"></param>
/// <param name="param"></param>
/// <returns></returns>
public static IServiceCollection AddAsymCryptService(this IServiceCollection services, AsymCryptParams param) => services.AddAsymCryptService(param: param, setAsDefault: true);
private static IServiceCollection AddRSAFactory<TRSAFactoryParams>(this IServiceCollection services) /// <summary>
/// Registers default RSA Factory instance with default params
/// </summary>
/// <param name="services"></param>
/// <param name="factoryParams"></param>
/// <returns>The updated <see cref="IServiceCollection"/> with the RSA Factory registered.</returns>
public static IServiceCollection AddRSAFactory(this IServiceCollection services, RSAFactoryParams? factoryParams = null)
=> services.AddScoped<IRSAFactory>(_ => new RSAFactory<RSAFactoryParams>(Options.Create(factoryParams ?? new())));
/// <summary>
/// Registers a custom RSA Factory with specified parameters from the given configuration section.
/// </summary>
/// <typeparam name="TRSAFactoryParams"></typeparam>
/// <param name="services"></param>
/// <param name="section"></param>
/// <param name="setAsDefault">If true, the factory is registered as the default <see cref="IRSAFactory"/>. Otherwise, it is registered as <see cref="IRSAFactory{TRSAFactoryParams}"/>.</param>
/// <returns>The updated <see cref="IServiceCollection"/> with the RSA Factory registered.</returns>
public static IServiceCollection AddRSAFactory<TRSAFactoryParams>(this IServiceCollection services, IConfigurationSection section, bool setAsDefault = false)
where TRSAFactoryParams : RSAFactoryParams where TRSAFactoryParams : RSAFactoryParams
{ {
services.TryAddScoped<IRSAFactory<TRSAFactoryParams>, RSAFactory<TRSAFactoryParams>>(); services.Configure<TRSAFactoryParams>(section);
return services; return setAsDefault
? services.AddSingleton<IRSAFactory, RSAFactory<TRSAFactoryParams>>()
: services.AddSingleton<IRSAFactory<TRSAFactoryParams>, RSAFactory<TRSAFactoryParams>>();
} }
public static IServiceCollection AddRSAFactory<TRSAFactoryParams>(this IServiceCollection services, IConfigurationSection section) /// <summary>
/// Registers an RSA Factory with the specified parameters from the given instance. Optionally, sets it as the default factory.
/// </summary>
/// <typeparam name="TRSAFactoryParams">The type of the RSA factory parameters.</typeparam>
/// <param name="services"></param>
/// <param name="rsaParams"></param>
/// <param name="setAsDefault">If true, the factory is registered as the default <see cref="IRSAFactory"/>. Otherwise, it is registered as <see cref="IRSAFactory{TRSAFactoryParams}"/>.</param>
/// <returns>The updated <see cref="IServiceCollection"/> with the RSA Factory registered.</returns>
public static IServiceCollection AddRSAFactory<TRSAFactoryParams>(this IServiceCollection services, TRSAFactoryParams rsaParams, bool setAsDefault = false)
where TRSAFactoryParams : RSAFactoryParams where TRSAFactoryParams : RSAFactoryParams
=> services.Configure<TRSAFactoryParams>(section).AddRSAFactory<TRSAFactoryParams>(); {
services.AddSingleton(Options.Create(rsaParams));
public static IServiceCollection AddRSAFactory<TRSAFactoryParams>(this IServiceCollection services, TRSAFactoryParams param) return setAsDefault
where TRSAFactoryParams : RSAFactoryParams ? services.AddSingleton<IRSAFactory, RSAFactory<TRSAFactoryParams>>()
=> services.AddSingleton(Options.Create(param)).AddRSAFactory<TRSAFactoryParams>(); : services.AddSingleton<IRSAFactory<TRSAFactoryParams>, RSAFactory<TRSAFactoryParams>>();
}
} }
} }

View File

@@ -0,0 +1,14 @@
using DigitalData.Core.Abstractions.Security;
using DigitalData.Core.Security.Config;
using DigitalData.Core.Security.Cryptographer;
using Microsoft.Extensions.Options;
namespace DigitalData.Core.Security
{
public static class Instance
{
private static readonly Lazy<RSAFactory<RSAFactoryParams>> LazyInstance = new(() => new(Options.Create<RSAFactoryParams>(new())));
public static IRSAFactory RSAFactory => LazyInstance.Value;
}
}