From 713c2f3ed2f0c94efb9f22529e4eff4842094e14 Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Fri, 24 Jan 2025 17:11:38 +0100 Subject: [PATCH 01/27] refactor(GTXMessagingResponse): In die Anwendungsschicht verschoben. --- .../DTOs/Messaging}/GtxMessagingResponse.cs | 2 +- EnvelopeGenerator.Application/Extensions/MappingExtensions.cs | 2 +- .../MappingProfiles/BasicDtoMappingProfile.cs | 1 - EnvelopeGenerator.Application/Services/GTXMessagingService.cs | 3 --- 4 files changed, 2 insertions(+), 6 deletions(-) rename {EnvelopeGenerator.Domain/HttpResponse => EnvelopeGenerator.Application/DTOs/Messaging}/GtxMessagingResponse.cs (55%) diff --git a/EnvelopeGenerator.Domain/HttpResponse/GtxMessagingResponse.cs b/EnvelopeGenerator.Application/DTOs/Messaging/GtxMessagingResponse.cs similarity index 55% rename from EnvelopeGenerator.Domain/HttpResponse/GtxMessagingResponse.cs rename to EnvelopeGenerator.Application/DTOs/Messaging/GtxMessagingResponse.cs index cc948e52..e198038c 100644 --- a/EnvelopeGenerator.Domain/HttpResponse/GtxMessagingResponse.cs +++ b/EnvelopeGenerator.Application/DTOs/Messaging/GtxMessagingResponse.cs @@ -1,4 +1,4 @@ -namespace EnvelopeGenerator.Domain.HttpResponse +namespace EnvelopeGenerator.Application.DTOs.Messaging { public class GtxMessagingResponse : Dictionary { } } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Extensions/MappingExtensions.cs b/EnvelopeGenerator.Application/Extensions/MappingExtensions.cs index bd996b58..3a8a65f7 100644 --- a/EnvelopeGenerator.Application/Extensions/MappingExtensions.cs +++ b/EnvelopeGenerator.Application/Extensions/MappingExtensions.cs @@ -1,4 +1,4 @@ -using EnvelopeGenerator.Domain.HttpResponse; +using EnvelopeGenerator.Application.DTOs.Messaging; namespace EnvelopeGenerator.Application.Extensions { diff --git a/EnvelopeGenerator.Application/MappingProfiles/BasicDtoMappingProfile.cs b/EnvelopeGenerator.Application/MappingProfiles/BasicDtoMappingProfile.cs index cf3c006b..ae14252e 100644 --- a/EnvelopeGenerator.Application/MappingProfiles/BasicDtoMappingProfile.cs +++ b/EnvelopeGenerator.Application/MappingProfiles/BasicDtoMappingProfile.cs @@ -7,7 +7,6 @@ using EnvelopeGenerator.Application.DTOs.Messaging; using EnvelopeGenerator.Application.DTOs.Receiver; using EnvelopeGenerator.Application.Extensions; using EnvelopeGenerator.Domain.Entities; -using EnvelopeGenerator.Domain.HttpResponse; namespace EnvelopeGenerator.Application.MappingProfiles { diff --git a/EnvelopeGenerator.Application/Services/GTXMessagingService.cs b/EnvelopeGenerator.Application/Services/GTXMessagingService.cs index 17d179eb..8b2482fc 100644 --- a/EnvelopeGenerator.Application/Services/GTXMessagingService.cs +++ b/EnvelopeGenerator.Application/Services/GTXMessagingService.cs @@ -4,9 +4,6 @@ using DigitalData.Core.Client; using EnvelopeGenerator.Application.Configurations.GtxMessaging; using EnvelopeGenerator.Application.Contracts; using EnvelopeGenerator.Application.DTOs.Messaging; -using EnvelopeGenerator.Application.Extensions; -using EnvelopeGenerator.Domain.HttpResponse; -using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Options; namespace EnvelopeGenerator.Application.Services From 867756242e469acaa214cd38fefc484343f51e7d Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Fri, 24 Jan 2025 18:13:29 +0100 Subject: [PATCH 02/27] =?UTF-8?q?refactor(EnvelopeReceiver):=20TFAEnabled?= =?UTF-8?q?=20wurde=20in=20die=20Envelope-Tabelle=20f=C3=BCr=20Entit=C3=A4?= =?UTF-8?q?t=20und=20DTO=20verschoben.=20=20-=20Aktualisierte=20zugeh?= =?UTF-8?q?=C3=B6rige=20Felder=20in=20HomeController.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- EnvelopeGenerator.Application/DTOs/EnvelopeDto.cs | 4 +++- .../DTOs/EnvelopeReceiver/EnvelopeReceiverBasicDto.cs | 2 -- EnvelopeGenerator.Domain/Entities/Envelope.cs | 3 +++ EnvelopeGenerator.Domain/Entities/EnvelopeReceiverBase.cs | 5 +---- EnvelopeGenerator.Web/Controllers/HomeController.cs | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/EnvelopeGenerator.Application/DTOs/EnvelopeDto.cs b/EnvelopeGenerator.Application/DTOs/EnvelopeDto.cs index 02db9593..e0bbe042 100644 --- a/EnvelopeGenerator.Application/DTOs/EnvelopeDto.cs +++ b/EnvelopeGenerator.Application/DTOs/EnvelopeDto.cs @@ -51,7 +51,9 @@ namespace EnvelopeGenerator.Application.DTOs public int? ExpiresWarningWhenDays { get; set; } - public bool DmzMoved { get; set; } + public bool TFAEnabled { get; init; } + + public bool DmzMoved { get; set; } public UserReadDto? User { get; set; } public EnvelopeType? EnvelopeType { get; set; } diff --git a/EnvelopeGenerator.Application/DTOs/EnvelopeReceiver/EnvelopeReceiverBasicDto.cs b/EnvelopeGenerator.Application/DTOs/EnvelopeReceiver/EnvelopeReceiverBasicDto.cs index 1302f14f..64c5b869 100644 --- a/EnvelopeGenerator.Application/DTOs/EnvelopeReceiver/EnvelopeReceiverBasicDto.cs +++ b/EnvelopeGenerator.Application/DTOs/EnvelopeReceiver/EnvelopeReceiverBasicDto.cs @@ -27,7 +27,5 @@ namespace EnvelopeGenerator.Application.DTOs.EnvelopeReceiver public DateTime? ChangedWhen { get; init; } public bool HasPhoneNumber { get; init; } - - public bool TFAEnabled { get; init; } } } \ No newline at end of file diff --git a/EnvelopeGenerator.Domain/Entities/Envelope.cs b/EnvelopeGenerator.Domain/Entities/Envelope.cs index c422a430..e4db872e 100644 --- a/EnvelopeGenerator.Domain/Entities/Envelope.cs +++ b/EnvelopeGenerator.Domain/Entities/Envelope.cs @@ -84,6 +84,9 @@ namespace EnvelopeGenerator.Domain.Entities [Column("EXPIRES_WARNING_WHEN_DAYS")] public int? ExpiresWarningWhenDays { get; set; } + [Column("TFA_ENABLED", TypeName = "bit")] + public bool TFAEnabled { get; set; } + /// /// The sender of envelope /// diff --git a/EnvelopeGenerator.Domain/Entities/EnvelopeReceiverBase.cs b/EnvelopeGenerator.Domain/Entities/EnvelopeReceiverBase.cs index 64bc6802..bbf55d2b 100644 --- a/EnvelopeGenerator.Domain/Entities/EnvelopeReceiverBase.cs +++ b/EnvelopeGenerator.Domain/Entities/EnvelopeReceiverBase.cs @@ -45,10 +45,7 @@ namespace EnvelopeGenerator.Domain.Entities [StringLength(20)] [RegularExpression(@"^\+[0-9]+$", ErrorMessage = "Phone number must start with '+' followed by digits.")] public string? PhoneNumber { get; set; } - - [Column("TFA_ENABLED", TypeName = "bit")] - public bool TFAEnabled { get; set; } - + [NotMapped] public (int Envelope, int Receiver) Id => (Envelope: EnvelopeId, Receiver: ReceiverId); diff --git a/EnvelopeGenerator.Web/Controllers/HomeController.cs b/EnvelopeGenerator.Web/Controllers/HomeController.cs index d67d9b86..51af9827 100644 --- a/EnvelopeGenerator.Web/Controllers/HomeController.cs +++ b/EnvelopeGenerator.Web/Controllers/HomeController.cs @@ -146,7 +146,7 @@ namespace EnvelopeGenerator.Web.Controllers return await _envRcvService.ReadByEnvelopeReceiverIdAsync(envelopeReceiverId: envelopeReceiverId).ThenAsync( Success: er => View() .WithData("EnvelopeKey", envelopeReceiverId) - .WithData("TFAEnabled", er.TFAEnabled) + .WithData("TFAEnabled", er.Envelope!.TFAEnabled) .WithData("HasPhoneNumber", er.HasPhoneNumber), Fail: IActionResult (messages, notices) => { @@ -229,7 +229,7 @@ namespace EnvelopeGenerator.Web.Controllers await _historyService.RecordAsync(er_secret.EnvelopeId, er_secret.Receiver!.EmailAddress, EnvelopeStatus.AccessCodeCorrect); //check if the user has phone is added - if (er_secret.TFAEnabled) + if (er_secret.Envelope!.TFAEnabled) { var rcv = er_secret.Receiver; if (rcv.IsTotpSecretInvalid()) From 95efe58e1b4dd4763deecda955c9510cfd49c07d Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Fri, 24 Jan 2025 20:42:01 +0100 Subject: [PATCH 03/27] chore(Web): Hochgestuft auf 2.8.2 --- EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj index 97402542..57f44b17 100644 --- a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj +++ b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj @@ -5,7 +5,7 @@ enable enable EnvelopeGenerator.Web - 2.8.1 + 2.8.2 Digital Data GmbH Digital Data GmbH EnvelopeGenerator.Web From 3267acbeb3fcc44a3b77255c4bcff87b88c752af Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Sat, 25 Jan 2025 00:35:19 +0100 Subject: [PATCH 04/27] =?UTF-8?q?feat(CodeGenerator):=20GenerateTotp=20und?= =?UTF-8?q?=20VerifyTotp=20Methoden=20hinzugef=C3=BCgt.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Contracts/ICodeGenerator.cs | 14 ++- .../EnvelopeGenerator.Application.csproj | 101 +++++++++--------- .../Services/CodeGenerator.cs | 5 + 3 files changed, 66 insertions(+), 54 deletions(-) diff --git a/EnvelopeGenerator.Application/Contracts/ICodeGenerator.cs b/EnvelopeGenerator.Application/Contracts/ICodeGenerator.cs index 38a27b85..d4e93c6b 100644 --- a/EnvelopeGenerator.Application/Contracts/ICodeGenerator.cs +++ b/EnvelopeGenerator.Application/Contracts/ICodeGenerator.cs @@ -1,13 +1,19 @@ -namespace EnvelopeGenerator.Application.Contracts +using OtpNet; + +namespace EnvelopeGenerator.Application.Contracts { public interface ICodeGenerator { string GenerateCode(int length); - public string GenerateTotpSecretKey(int? length = null); + string GenerateTotpSecretKey(int? length = null); + + byte[] GenerateTotpQrCode(string userEmail, string secretKey, string? issuer = null, string? totpUrlFormat = null, int? pixelsPerModule = null); + + byte[] GenerateTotpQrCode(string userEmail, int? length = null, string? issuer = null, string? totpUrlFormat = null, int? pixelsPerModule = null); - public byte[] GenerateTotpQrCode(string userEmail, string secretKey, string? issuer = null, string? totpUrlFormat = null, int? pixelsPerModule = null); + string GenerateTotp(string secretKey, int step = 30); - public byte[] GenerateTotpQrCode(string userEmail, int? length = null, string? issuer = null, string? totpUrlFormat = null, int? pixelsPerModule = null); + bool VerifyTotp(string totpCode, string secretKey, int step = 30, VerificationWindow? window = null); } } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/EnvelopeGenerator.Application.csproj b/EnvelopeGenerator.Application/EnvelopeGenerator.Application.csproj index 6032bb17..c16b447f 100644 --- a/EnvelopeGenerator.Application/EnvelopeGenerator.Application.csproj +++ b/EnvelopeGenerator.Application/EnvelopeGenerator.Application.csproj @@ -1,59 +1,60 @@  - - net7.0 - enable - enable - + + net7.0 + enable + enable + - - - + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - + + + + - - - True - True - Model.resx - - + + + True + True + Model.resx + + - - - My.Resources - Model.en.Designer.vb - PublicResXFileCodeGenerator - - - My.Resources - Model.Designer.cs - PublicResXFileCodeGenerator - - - PreserveNewest - - - PreserveNewest - - + + + My.Resources + Model.en.Designer.vb + PublicResXFileCodeGenerator + + + My.Resources + Model.Designer.cs + PublicResXFileCodeGenerator + + + PreserveNewest + + + PreserveNewest + + diff --git a/EnvelopeGenerator.Application/Services/CodeGenerator.cs b/EnvelopeGenerator.Application/Services/CodeGenerator.cs index 89d22522..ca84bfc9 100644 --- a/EnvelopeGenerator.Application/Services/CodeGenerator.cs +++ b/EnvelopeGenerator.Application/Services/CodeGenerator.cs @@ -62,5 +62,10 @@ namespace EnvelopeGenerator.Application.Services totpUrlFormat: totpUrlFormat, pixelsPerModule: pixelsPerModule); } + + public string GenerateTotp(string secretKey, int step = 30) => new Totp(Base32Encoding.ToBytes(secretKey), step).ComputeTotp(); + + public bool VerifyTotp(string totpCode, string secretKey, int step = 30, VerificationWindow? window = null) + => new Totp(Base32Encoding.ToBytes(secretKey), step).VerifyTotp(totpCode, out _, window); } } \ No newline at end of file From af5d7c289d678706f9024b96dd6bfe00d356b8a4 Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Mon, 27 Jan 2025 13:47:26 +0100 Subject: [PATCH 05/27] refactor(HomeController): LogInEnvelope aktualisiert, um SMS-Code als TOTP zu verifizieren --- .../EnvelopeReceiverCacheParams.cs | 2 - .../Configurations/GtxMessaging/SmsParams.cs | 5 + .../Contracts/ICodeGenerator.cs | 2 + .../Contracts/IEnvelopeReceiverCache.cs | 17 -- .../Contracts/IMessagingService.cs | 13 +- .../DTOs/Messaging/SmsResponse.cs | 10 - .../Services/CodeGenerator.cs | 5 + .../Services/EnvelopeReceiverCache.cs | 50 ---- .../Services/GTXMessagingService.cs | 78 ++--- .../CacheExtensions.cs | 12 + .../Controllers/HomeController.cs | 277 +++++++++--------- 11 files changed, 197 insertions(+), 274 deletions(-) delete mode 100644 EnvelopeGenerator.Application/Contracts/IEnvelopeReceiverCache.cs delete mode 100644 EnvelopeGenerator.Application/Services/EnvelopeReceiverCache.cs create mode 100644 EnvelopeGenerator.Extensions/CacheExtensions.cs diff --git a/EnvelopeGenerator.Application/Configurations/EnvelopeReceiverCacheParams.cs b/EnvelopeGenerator.Application/Configurations/EnvelopeReceiverCacheParams.cs index b8ab323e..5d51941a 100644 --- a/EnvelopeGenerator.Application/Configurations/EnvelopeReceiverCacheParams.cs +++ b/EnvelopeGenerator.Application/Configurations/EnvelopeReceiverCacheParams.cs @@ -13,7 +13,5 @@ /// The placeholder {0} represents the envelopeReceiverId. /// public string CodeExpirationCacheKeyFormat { get; init; } = "sms-code-expiration-{0}"; - - public TimeSpan CodeCacheValidityPeriod { get; init; } = new(0, 5, 0); } } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Configurations/GtxMessaging/SmsParams.cs b/EnvelopeGenerator.Application/Configurations/GtxMessaging/SmsParams.cs index 7cea8047..9db3c8c5 100644 --- a/EnvelopeGenerator.Application/Configurations/GtxMessaging/SmsParams.cs +++ b/EnvelopeGenerator.Application/Configurations/GtxMessaging/SmsParams.cs @@ -1,5 +1,6 @@ using DigitalData.Core.Abstractions.Client; using Microsoft.Extensions.Caching.Distributed; +using OtpNet; namespace EnvelopeGenerator.Application.Configurations.GtxMessaging { @@ -21,5 +22,9 @@ namespace EnvelopeGenerator.Application.Configurations.GtxMessaging public string MessageQueryParamName { get; init; } = "text"; public int CodeLength { get; init; } = 5; + + public int SmsTotpStep { get; init; } = 300; + + public string DefaultTotpMessageFormat { get; init; } = "{0}"; } } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Contracts/ICodeGenerator.cs b/EnvelopeGenerator.Application/Contracts/ICodeGenerator.cs index d4e93c6b..c8d47976 100644 --- a/EnvelopeGenerator.Application/Contracts/ICodeGenerator.cs +++ b/EnvelopeGenerator.Application/Contracts/ICodeGenerator.cs @@ -15,5 +15,7 @@ namespace EnvelopeGenerator.Application.Contracts string GenerateTotp(string secretKey, int step = 30); bool VerifyTotp(string totpCode, string secretKey, int step = 30, VerificationWindow? window = null); + + bool GetTotpExpirationTime(int step = 30); } } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Contracts/IEnvelopeReceiverCache.cs b/EnvelopeGenerator.Application/Contracts/IEnvelopeReceiverCache.cs deleted file mode 100644 index e2ac2a7c..00000000 --- a/EnvelopeGenerator.Application/Contracts/IEnvelopeReceiverCache.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace EnvelopeGenerator.Application.Contracts -{ - public interface IEnvelopeReceiverCache - { - Task GetSmsCodeAsync(string envelopeReceiverId); - - /// - /// Asynchronously stores an SMS verification code in the cache and returns the expiration date of the code. - /// - /// The unique identifier for the recipient of the envelope to associate with the SMS code. - /// The SMS verification code to be stored. - /// A task that represents the asynchronous operation. The task result contains the expiration date and time of the stored SMS code. - Task SetSmsCodeAsync(string envelopeReceiverId, string code); - - Task GetSmsCodeExpirationAsync(string envelopeReceiverId); - } -} \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Contracts/IMessagingService.cs b/EnvelopeGenerator.Application/Contracts/IMessagingService.cs index 5940e50d..9a0c050a 100644 --- a/EnvelopeGenerator.Application/Contracts/IMessagingService.cs +++ b/EnvelopeGenerator.Application/Contracts/IMessagingService.cs @@ -1,13 +1,12 @@ using EnvelopeGenerator.Application.DTOs.Messaging; -namespace EnvelopeGenerator.Application.Contracts +namespace EnvelopeGenerator.Application.Contracts; + +public interface IMessagingService { - public interface IMessagingService - { - string ServiceProvider { get; } + string ServiceProvider { get; } - Task SendSmsAsync(string recipient, string message); + Task SendSmsAsync(string recipient, string message); - Task SendSmsCodeAsync(string recipient, string envelopeReceiverId); - } + Task SendSmsCodeAsync(string recipient, string secretKey, string messageFormat = "{0}"); } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/DTOs/Messaging/SmsResponse.cs b/EnvelopeGenerator.Application/DTOs/Messaging/SmsResponse.cs index 96b67515..a546d0c7 100644 --- a/EnvelopeGenerator.Application/DTOs/Messaging/SmsResponse.cs +++ b/EnvelopeGenerator.Application/DTOs/Messaging/SmsResponse.cs @@ -4,16 +4,6 @@ { public required bool Ok { get; init; } - public DateTime? Expiration { get; set; } - - public DateTime? AllowedAt { get; set; } - - public TimeSpan AllowedAfter => Allowed ? TimeSpan.Zero : AllowedAt!.Value - DateTime.Now; - - public bool Allowed => AllowedAt is null || DateTime.Now >= AllowedAt; - - public bool Error => !Ok && Allowed; - public dynamic? Errors { get; init; } } } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Services/CodeGenerator.cs b/EnvelopeGenerator.Application/Services/CodeGenerator.cs index ca84bfc9..94ad6720 100644 --- a/EnvelopeGenerator.Application/Services/CodeGenerator.cs +++ b/EnvelopeGenerator.Application/Services/CodeGenerator.cs @@ -67,5 +67,10 @@ namespace EnvelopeGenerator.Application.Services public bool VerifyTotp(string totpCode, string secretKey, int step = 30, VerificationWindow? window = null) => new Totp(Base32Encoding.ToBytes(secretKey), step).VerifyTotp(totpCode, out _, window); + + public bool GetTotpExpirationTime(int step = 30) + { + throw new NotImplementedException(); + } } } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Services/EnvelopeReceiverCache.cs b/EnvelopeGenerator.Application/Services/EnvelopeReceiverCache.cs deleted file mode 100644 index 525b5468..00000000 --- a/EnvelopeGenerator.Application/Services/EnvelopeReceiverCache.cs +++ /dev/null @@ -1,50 +0,0 @@ -using AngleSharp.Dom; -using EnvelopeGenerator.Application.Configurations; -using EnvelopeGenerator.Application.Contracts; -using EnvelopeGenerator.Application.Extensions; -using Microsoft.Extensions.Caching.Distributed; -using Microsoft.Extensions.Options; - -namespace EnvelopeGenerator.Application.Services -{ - public class EnvelopeReceiverCache : IEnvelopeReceiverCache - { - private readonly EnvelopeReceiverCacheParams _cacheParams; - - private readonly DistributedCacheEntryOptions _codeCacheOptions; - - private readonly IDistributedCache _cache; - - public EnvelopeReceiverCache(IOptions cacheParamOptions, IDistributedCache cache) - { - _cacheParams = cacheParamOptions.Value; - _codeCacheOptions = new() { AbsoluteExpirationRelativeToNow = cacheParamOptions.Value.CodeCacheValidityPeriod }; - _cache = cache; - } - - public async Task GetSmsCodeAsync(string envelopeReceiverId) - { - var code_key = string.Format(_cacheParams.CodeCacheKeyFormat, envelopeReceiverId); - return await _cache.GetStringAsync(code_key); - } - - public async Task SetSmsCodeAsync(string envelopeReceiverId, string code) - { - // set key - var code_key = string.Format(_cacheParams.CodeCacheKeyFormat, envelopeReceiverId); - await _cache.SetStringAsync(code_key, code, _codeCacheOptions); - - // set expiration - var code_expiration_key = string.Format(_cacheParams.CodeExpirationCacheKeyFormat, envelopeReceiverId); - var expiration = DateTime.Now + _cacheParams.CodeCacheValidityPeriod; - await _cache.SetDateTimeAsync(code_expiration_key, expiration, _codeCacheOptions); - return expiration; - } - - public async Task GetSmsCodeExpirationAsync(string envelopeReceiverId) - { - var code_expiration_key = string.Format(_cacheParams.CodeExpirationCacheKeyFormat, envelopeReceiverId); - return await _cache.GetDateTimeAsync(code_expiration_key); - } - } -} \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Services/GTXMessagingService.cs b/EnvelopeGenerator.Application/Services/GTXMessagingService.cs index 8b2482fc..78269522 100644 --- a/EnvelopeGenerator.Application/Services/GTXMessagingService.cs +++ b/EnvelopeGenerator.Application/Services/GTXMessagingService.cs @@ -6,62 +6,44 @@ using EnvelopeGenerator.Application.Contracts; using EnvelopeGenerator.Application.DTOs.Messaging; using Microsoft.Extensions.Options; -namespace EnvelopeGenerator.Application.Services -{ - public class GtxMessagingService : IMessagingService - { - private readonly IHttpClientService _smsClient; - - private readonly SmsParams _smsParams; +namespace EnvelopeGenerator.Application.Services; - private readonly IMapper _mapper; +public class GtxMessagingService : IMessagingService +{ + private readonly IHttpClientService _smsClient; - private readonly ICodeGenerator _codeGen; + private readonly SmsParams _smsParams; - private readonly IEnvelopeReceiverCache _erCache; + private readonly IMapper _mapper; - public string ServiceProvider { get; } + private readonly ICodeGenerator _codeGen; - public GtxMessagingService(IHttpClientService smsClient, IOptions smsParamsOptions, IMapper mapper, ICodeGenerator codeGenerator, IEnvelopeReceiverCache envelopeReceiverCache) - { - _smsClient = smsClient; - _smsParams = smsParamsOptions.Value; - _mapper = mapper; - ServiceProvider = GetType().Name.Replace("Service", string.Empty); - _codeGen = codeGenerator; - _erCache = envelopeReceiverCache; - } + public string ServiceProvider { get; } - public async Task SendSmsAsync(string recipient, string message) - { - return await _smsClient.FetchAsync(queryParams: new Dictionary() - { - { _smsParams.RecipientQueryParamName, recipient }, - { _smsParams.MessageQueryParamName, message } - }) - .ThenAsync(res => res.Json()) - .ThenAsync(_mapper.Map); - } + public GtxMessagingService(IHttpClientService smsClient, IOptions smsParamsOptions, IMapper mapper, ICodeGenerator codeGenerator) + { + _smsClient = smsClient; + _smsParams = smsParamsOptions.Value; + _mapper = mapper; + ServiceProvider = GetType().Name.Replace("Service", string.Empty); + _codeGen = codeGenerator; + } - public async Task SendSmsCodeAsync(string recipient, string envelopeReceiverId) + public async Task SendSmsAsync(string recipient, string message) + { + return await _smsClient.FetchAsync(queryParams: new Dictionary() { - var code = await _erCache.GetSmsCodeAsync(envelopeReceiverId); + { _smsParams.RecipientQueryParamName, recipient }, + { _smsParams.MessageQueryParamName, message } + }) + .ThenAsync(res => res.Json()) + .ThenAsync(_mapper.Map); + } - if (code is null) - { - code = _codeGen.GenerateCode(_smsParams.CodeLength); - var expiration = await _erCache.SetSmsCodeAsync(envelopeReceiverId, code); - var res = await SendSmsAsync(recipient: recipient, message: code); - res.Expiration = expiration; - return res; - } - else - { - var code_expiration = await _erCache.GetSmsCodeExpirationAsync(envelopeReceiverId); - return code_expiration is null - ? new() { Ok = false } - : new() { Ok = false, AllowedAt = code_expiration }; - } - } + public async Task SendSmsCodeAsync(string recipient, string secretKey, string? messageFormat = null) + { + var code = _codeGen.GenerateTotp(secretKey, _smsParams.SmsTotpStep); + var message = string.Format(messageFormat ?? _smsParams.DefaultTotpMessageFormat, code); + return await SendSmsAsync(recipient: recipient, message: message); } } \ No newline at end of file diff --git a/EnvelopeGenerator.Extensions/CacheExtensions.cs b/EnvelopeGenerator.Extensions/CacheExtensions.cs new file mode 100644 index 00000000..94e54af5 --- /dev/null +++ b/EnvelopeGenerator.Extensions/CacheExtensions.cs @@ -0,0 +1,12 @@ +using Microsoft.Extensions.Caching.Distributed; + +namespace EnvelopeGenerator.Extensions +{ + public static class CacheExtensions + { + public static IDistributedCache Cache(this IDistributedCache cache) + { + cache.SetStringAsync() + } + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.Web/Controllers/HomeController.cs b/EnvelopeGenerator.Web/Controllers/HomeController.cs index 51af9827..79824bd6 100644 --- a/EnvelopeGenerator.Web/Controllers/HomeController.cs +++ b/EnvelopeGenerator.Web/Controllers/HomeController.cs @@ -36,11 +36,10 @@ namespace EnvelopeGenerator.Web.Controllers private readonly IEnvelopeMailService _mailService; private readonly IEnvelopeReceiverReadOnlyService _readOnlyService; private readonly IMessagingService _msgService; - private readonly IEnvelopeReceiverCache _erCache; private readonly ICodeGenerator _codeGenerator; private readonly IReceiverService _rcvService; - public HomeController(EnvelopeOldService envelopeOldService, ILogger logger, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeHistoryService historyService, IStringLocalizer localizer, IConfiguration configuration, HtmlSanitizer sanitizer, Cultures cultures, IEnvelopeMailService envelopeMailService, IEnvelopeReceiverReadOnlyService readOnlyService, IMessagingService messagingService, IEnvelopeReceiverCache envelopeReceiverCache, ICodeGenerator codeGenerator, IReceiverService receiverService) + public HomeController(EnvelopeOldService envelopeOldService, ILogger logger, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeHistoryService historyService, IStringLocalizer localizer, IConfiguration configuration, HtmlSanitizer sanitizer, Cultures cultures, IEnvelopeMailService envelopeMailService, IEnvelopeReceiverReadOnlyService readOnlyService, IMessagingService messagingService, ICodeGenerator codeGenerator, IReceiverService receiverService) { this.envelopeOldService = envelopeOldService; _envRcvService = envelopeReceiverService; @@ -53,7 +52,6 @@ namespace EnvelopeGenerator.Web.Controllers _logger = logger; _readOnlyService = readOnlyService; _msgService = messagingService; - _erCache = envelopeReceiverCache; _codeGenerator = codeGenerator; _rcvService = receiverService; } @@ -183,153 +181,152 @@ namespace EnvelopeGenerator.Web.Controllers //check access code EnvelopeResponse response = await envelopeOldService.LoadEnvelope(envelopeReceiverId); - return await _envRcvService.ReadWithSecretByUuidSignatureAsync(uuid: uuid, signature: signature).ThenAsync( - SuccessAsync: async er_secret => + var er_secret_res = await _envRcvService.ReadWithSecretByUuidSignatureAsync(uuid: uuid, signature: signature); + + if (er_secret_res.IsFailed) + { + _logger.LogNotice(er_secret_res.Notices); + return this.ViewEnvelopeNotFound(); + } + var er_secret = er_secret_res.Data; + + async Task TFAView(bool viaSms) + { + if (viaSms) + { + //add date time cache + var res = await _msgService.SendSmsCodeAsync(er_secret.PhoneNumber!, er_secret.Receiver.TotpSecretkey); + if (res.Ok) + return View("EnvelopeLocked").WithData("CodeType", "smsCode").WithData("SmsExpiration", res.Expiration); + else if (!res.Allowed) + return View("EnvelopeLocked").WithData("CodeType", "smsCode").WithData("SmsExpiration", res.AllowedAt); + else { - async Task TFAView(bool viaSms) - { - if (viaSms) - { - var res = await _msgService.SendSmsCodeAsync(er_secret.PhoneNumber!, envelopeReceiverId: envelopeReceiverId); - if (res.Ok) - return View("EnvelopeLocked").WithData("CodeType", "smsCode").WithData("SmsExpiration", res.Expiration); - else if (!res.Allowed) - return View("EnvelopeLocked").WithData("CodeType", "smsCode").WithData("SmsExpiration", res.AllowedAt); - else - { - var res_json = JsonConvert.SerializeObject(res); - _logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, message: $"An unexpected error occurred while sending an SMS code. Response: ${res_json}"); - return this.ViewInnerServiceError(); - } - } - else - { - return View("EnvelopeLocked").WithData("CodeType", "authenticatorCode").WithData("QRCodeExpiration", er_secret.Receiver?.TotpExpiration); - } - } + var res_json = JsonConvert.SerializeObject(res); + _logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, message: $"An unexpected error occurred while sending an SMS code. Response: ${res_json}"); + return this.ViewInnerServiceError(); + } + } + else + { + return View("EnvelopeLocked").WithData("CodeType", "authenticatorCode").WithData("QRCodeExpiration", er_secret.Receiver?.TotpExpiration); + } + } - if (auth.HasMulti) - { - Response.StatusCode = StatusCodes.Status401Unauthorized; - return View("EnvelopeLocked") - .WithData("ErrorMessage", _localizer[WebKey.WrongAccessCode].Value); - } - else if (auth.HasAccessCode) - { - //check the access code verification - if (er_secret.AccessCode != auth.AccessCode) - { - //Constants.EnvelopeStatus.AccessCodeIncorrect - await _historyService.RecordAsync(er_secret.EnvelopeId, er_secret.Receiver!.EmailAddress, EnvelopeStatus.AccessCodeIncorrect); - Response.StatusCode = StatusCodes.Status401Unauthorized; - return View("EnvelopeLocked") - .WithData("ErrorMessage", _localizer[WebKey.WrongAccessCode].Value); - } - - await _historyService.RecordAsync(er_secret.EnvelopeId, er_secret.Receiver!.EmailAddress, EnvelopeStatus.AccessCodeCorrect); - - //check if the user has phone is added - if (er_secret.Envelope!.TFAEnabled) - { - var rcv = er_secret.Receiver; - if (rcv.IsTotpSecretInvalid()) - { - rcv.TotpSecretkey = _codeGenerator.GenerateTotpSecretKey(); - rcv.TotpExpiration = DateTime.Now.AddMonths(1); - await _rcvService.UpdateAsync(rcv); - await _mailService.SendTFAQrCodeAsync(er_secret); - } - return await TFAView(auth.UserSelectSMS); - } + if (auth.HasMulti) + { + Response.StatusCode = StatusCodes.Status401Unauthorized; + return View("EnvelopeLocked") + .WithData("ErrorMessage", _localizer[WebKey.WrongAccessCode].Value); + } + else if (auth.HasAccessCode) + { + //check the access code verification + if (er_secret.AccessCode != auth.AccessCode) + { + //Constants.EnvelopeStatus.AccessCodeIncorrect + await _historyService.RecordAsync(er_secret.EnvelopeId, er_secret.Receiver!.EmailAddress, EnvelopeStatus.AccessCodeIncorrect); + Response.StatusCode = StatusCodes.Status401Unauthorized; + return View("EnvelopeLocked") + .WithData("ErrorMessage", _localizer[WebKey.WrongAccessCode].Value); + } + + await _historyService.RecordAsync(er_secret.EnvelopeId, er_secret.Receiver!.EmailAddress, EnvelopeStatus.AccessCodeCorrect); + + //check if the user has phone is added + if (er_secret.Envelope!.TFAEnabled) + { + var rcv = er_secret.Receiver; + if (rcv.IsTotpSecretInvalid()) + { + rcv.TotpSecretkey = _codeGenerator.GenerateTotpSecretKey(); + rcv.TotpExpiration = DateTime.Now.AddMonths(1); + await _rcvService.UpdateAsync(rcv); + await _mailService.SendTFAQrCodeAsync(er_secret); + } + return await TFAView(auth.UserSelectSMS); + } - } - else if (auth.HasSmsCode) - { - var smsCode = await _erCache.GetSmsCodeAsync(envelopeReceiverId); - if (smsCode is null) - return RedirectToAction("EnvelopeLocked", new { envelopeReceiverId }); - - if(auth.SmsCode != smsCode) - { - Response.StatusCode = StatusCodes.Status401Unauthorized; - ViewData["ErrorMessage"] = _localizer[WebKey.WrongAccessCode].Value; - return await TFAView(viaSms: true); - } - } - else if (auth.HasAuthenticatorCode) - { - if (er_secret.Receiver!.IsTotpInvalid(totp: auth.AuthenticatorCode!)) - { - Response.StatusCode = StatusCodes.Status401Unauthorized; - ViewData["ErrorMessage"] = _localizer[WebKey.WrongAccessCode].Value; - return await TFAView(viaSms: false); - } - } - else - { - Response.StatusCode = StatusCodes.Status401Unauthorized; - return View("EnvelopeLocked") - .WithData("ErrorMessage", _localizer[WebKey.WrongAccessCode].Value); - } + } + else if (auth.HasSmsCode) + { + if (er_secret.Receiver!.TotpSecretkey is null) + throw new InvalidOperationException($"TotpSecretkey of DTO cannot validate without TotpSecretkey. Dto: {JsonConvert.SerializeObject(er_secret)}"); + + if (_codeGenerator.VerifyTotp(auth.SmsCode!, er_secret.Receiver.TotpSecretkey, step: 60 * 5)) + { + Response.StatusCode = StatusCodes.Status401Unauthorized; + ViewData["ErrorMessage"] = _localizer[WebKey.WrongAccessCode].Value; + return await TFAView(viaSms: true); + } + } + else if (auth.HasAuthenticatorCode) + { + if (er_secret.Receiver!.IsTotpInvalid(totp: auth.AuthenticatorCode!)) + { + Response.StatusCode = StatusCodes.Status401Unauthorized; + ViewData["ErrorMessage"] = _localizer[WebKey.WrongAccessCode].Value; + return await TFAView(viaSms: false); + } + } + else + { + Response.StatusCode = StatusCodes.Status401Unauthorized; + return View("EnvelopeLocked") + .WithData("ErrorMessage", _localizer[WebKey.WrongAccessCode].Value); + } - //continue the process without important data to minimize security errors. - EnvelopeReceiverDto er = er_secret; + //continue the process without important data to minimize security errors. + EnvelopeReceiverDto er = er_secret; - ViewData["EnvelopeKey"] = envelopeReceiverId; - //check rejection - var rejRcvrs = await _historyService.ReadRejectingReceivers(er.Envelope!.Id); - if(rejRcvrs.Any()) - { - ViewBag.IsExt = !rejRcvrs.Contains(er.Receiver); //external if the current user is not rejected - return View("EnvelopeRejected", er); - } + ViewData["EnvelopeKey"] = envelopeReceiverId; + //check rejection + var rejRcvrs = await _historyService.ReadRejectingReceivers(er.Envelope!.Id); + if(rejRcvrs.Any()) + { + ViewBag.IsExt = !rejRcvrs.Contains(er.Receiver); //external if the current user is not rejected + return View("EnvelopeRejected", er); + } - //check if it has already signed - if (await _historyService.IsSigned(envelopeId: er.Envelope!.Id, userReference: er.Receiver!.EmailAddress)) - return View("EnvelopeSigned"); + //check if it has already signed + if (await _historyService.IsSigned(envelopeId: er.Envelope!.Id, userReference: er.Receiver!.EmailAddress)) + return View("EnvelopeSigned"); - if (er.Envelope.Documents?.FirstOrDefault() is EnvelopeDocumentDto doc && doc.ByteData is not null) - { - ViewData["DocumentBytes"] = doc.ByteData; - } - else - { - _logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, message: "No document byte-data was found in ENVELOPE_DOCUMENT table."); - return this.ViewDocumentNotFound(); - } - - var claims = new List { - new(ClaimTypes.NameIdentifier, uuid), - new(ClaimTypes.Hash, signature), - new(ClaimTypes.Name, er.Name ?? string.Empty), - new(ClaimTypes.Email, er.Receiver.EmailAddress), - new(EnvelopeClaimTypes.Title, er.Envelope.Title), - new(EnvelopeClaimTypes.Id, er.Envelope.Id.ToString()) - }; - - var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); - var authProperties = new AuthenticationProperties - { - AllowRefresh = false, - IsPersistent = false - }; + if (er.Envelope.Documents?.FirstOrDefault() is EnvelopeDocumentDto doc && doc.ByteData is not null) + { + ViewData["DocumentBytes"] = doc.ByteData; + } + else + { + _logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, message: "No document byte-data was found in ENVELOPE_DOCUMENT table."); + return this.ViewDocumentNotFound(); + } + + var claims = new List { + new(ClaimTypes.NameIdentifier, uuid), + new(ClaimTypes.Hash, signature), + new(ClaimTypes.Name, er.Name ?? string.Empty), + new(ClaimTypes.Email, er.Receiver.EmailAddress), + new(EnvelopeClaimTypes.Title, er.Envelope.Title), + new(EnvelopeClaimTypes.Id, er.Envelope.Id.ToString()) + }; + + var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); + var authProperties = new AuthenticationProperties + { + AllowRefresh = false, + IsPersistent = false + }; - await HttpContext.SignInAsync( - CookieAuthenticationDefaults.AuthenticationScheme, - new ClaimsPrincipal(claimsIdentity), - authProperties); + await HttpContext.SignInAsync( + CookieAuthenticationDefaults.AuthenticationScheme, + new ClaimsPrincipal(claimsIdentity), + authProperties); - //add PSPDFKit licence key - ViewData["PSPDFKitLicenseKey"] = _configuration["PSPDFKitLicenseKey"]; + //add PSPDFKit licence key + ViewData["PSPDFKitLicenseKey"] = _configuration["PSPDFKitLicenseKey"]; - return View("ShowEnvelope", er); - }, - Fail: (messages, notices) => - { - _logger.LogNotice(notices); - return this.ViewEnvelopeNotFound(); - } - ); + return View("ShowEnvelope", er); } catch (Exception ex) { From c6e9ecfbca89dc7080762916c516f98c3f114cc2 Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Mon, 27 Jan 2025 14:23:06 +0100 Subject: [PATCH 06/27] =?UTF-8?q?refactor(cache):=20Unterst=C3=BCtzung=20f?= =?UTF-8?q?=C3=BCr=20CancellationToken=20in=20IDistributedCache-Erweiterun?= =?UTF-8?q?gsmethoden=20hinzuf=C3=BCgen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Aktualisierte `SetLongAsync`, `GetLongAsync`, `SetDateTimeAsync`, `GetDateTimeAsync`, `SetTimeSpanAsync` und `GetTimeSpanAsync`, um optionale `CancellationToken`-Parameter zu unterstützen. - Modifizierte `GetOrSetAsync`, um zwischen synchronen und asynchronen Fabrikfunktionen zu unterscheiden. - Sicherstellung einer konsistenten Handhabung von `CancellationToken` in allen Cache-bezogenen Operationen. --- .../Extensions/CacheExtensions.cs | 56 +++++++++---------- .../CacheExtensions.cs | 12 ---- 2 files changed, 26 insertions(+), 42 deletions(-) delete mode 100644 EnvelopeGenerator.Extensions/CacheExtensions.cs diff --git a/EnvelopeGenerator.Application/Extensions/CacheExtensions.cs b/EnvelopeGenerator.Application/Extensions/CacheExtensions.cs index 45f43109..f2adcebd 100644 --- a/EnvelopeGenerator.Application/Extensions/CacheExtensions.cs +++ b/EnvelopeGenerator.Application/Extensions/CacheExtensions.cs @@ -4,74 +4,70 @@ namespace EnvelopeGenerator.Application.Extensions { public static class CacheExtensions { - public static Task SetLongAsync(this IDistributedCache cache, string key, long value, DistributedCacheEntryOptions? options = null) + public static Task SetLongAsync(this IDistributedCache cache, string key, long value, DistributedCacheEntryOptions? options = null, CancellationToken cToken = default) => options is null - ? cache.SetAsync(key, BitConverter.GetBytes(value)) - : cache.SetAsync(key, BitConverter.GetBytes(value), options: options); + ? cache.SetAsync(key, BitConverter.GetBytes(value), token: cToken) + : cache.SetAsync(key, BitConverter.GetBytes(value), options: options, token: cToken); - public static async Task GetLongAsync(this IDistributedCache cache, string key) + public static async Task GetLongAsync(this IDistributedCache cache, string key, CancellationToken cToken = default) { - var value = await cache.GetAsync(key); + var value = await cache.GetAsync(key, cToken); return value is null ? null : BitConverter.ToInt64(value, 0); } - public static Task SetDateTimeAsync(this IDistributedCache cache, string key, DateTime value, DistributedCacheEntryOptions? options = null) - => cache.SetLongAsync(key: key, value: value.Ticks, options: options); + public static Task SetDateTimeAsync(this IDistributedCache cache, string key, DateTime value, DistributedCacheEntryOptions? options = null, CancellationToken cToken = default) + => cache.SetLongAsync(key: key, value: value.Ticks, options: options, cToken: cToken); - public static async Task GetDateTimeAsync(this IDistributedCache cache, string key) + public static async Task GetDateTimeAsync(this IDistributedCache cache, string key, CancellationToken cToken = default) { - var value = await cache.GetAsync(key); + var value = await cache.GetAsync(key, cToken); return value is null ? null : new(BitConverter.ToInt64(value, 0)); } - public static Task SetTimeSpanAsync(this IDistributedCache cache, string key, TimeSpan value, DistributedCacheEntryOptions? options = null) - => cache.SetLongAsync(key: key, value: value.Ticks, options: options); + public static Task SetTimeSpanAsync(this IDistributedCache cache, string key, TimeSpan value, DistributedCacheEntryOptions? options = null, CancellationToken cToken = default) + => cache.SetLongAsync(key: key, value: value.Ticks, options: options, cToken); - public static async Task GetTimeSpanAsync(this IDistributedCache cache, string key) + public static async Task GetTimeSpanAsync(this IDistributedCache cache, string key, CancellationToken cToken = default) { - var value = await cache.GetAsync(key); + var value = await cache.GetAsync(key, cToken); return value is null ? null : new(BitConverter.ToInt64(value, 0)); } - public static string GetOrSet(this IDistributedCache cache, string key, Func factory, DistributedCacheEntryOptions? options = null, bool cacheInBackground = false, CancellationToken token = default) + public static async Task GetOrSetAsync(this IDistributedCache cache, string key, Func factory, DistributedCacheEntryOptions? options = null, bool cacheInBackground = false, CancellationToken cToken = default) { - var value = cache.GetString(key); + var value = await cache.GetStringAsync(key, cToken); if (value is null) { // create new and save value = factory(); - void Cache() - { - if (options is null) - cache.SetString(key: key, value: value); - else - cache.SetString(key: key, value: value, options: options); - } + Task CacheAsync() => options is null + ? cache.SetStringAsync(key, value, cToken) + : cache.SetStringAsync(key, value, options, cToken); if (cacheInBackground) - _ = Task.Run(() => Cache(), token); + _ = Task.Run(async () => await CacheAsync(), cToken); else - Cache(); + await CacheAsync(); } return value; } - public static async Task GetOrSetAsync(this IDistributedCache cache, string key, Func> factory, DistributedCacheEntryOptions? options = null, bool cacheInBackground = false, CancellationToken token = default) + public static async Task GetOrSetAsync(this IDistributedCache cache, string key, Func> factoryAsync, DistributedCacheEntryOptions? options = null, bool cacheInBackground = false, CancellationToken cToken = default) { - var value = await cache.GetStringAsync(key, token: token); + var value = await cache.GetStringAsync(key, cToken); if(value is null) { // create new and save - value = await factory(); + value = await factoryAsync(); Task CacheAsync() => options is null - ? cache.SetStringAsync(key: key, value: value, token: token) - : cache.SetStringAsync(key: key, value: value, options: options, token: token); + ? cache.SetStringAsync(key: key, value: value, token: cToken) + : cache.SetStringAsync(key: key, value: value, options: options, token: cToken); if (cacheInBackground) - _ = Task.Run(async () => await CacheAsync(), token); + _ = Task.Run(async () => await CacheAsync(), cToken); else await CacheAsync(); } diff --git a/EnvelopeGenerator.Extensions/CacheExtensions.cs b/EnvelopeGenerator.Extensions/CacheExtensions.cs deleted file mode 100644 index 94e54af5..00000000 --- a/EnvelopeGenerator.Extensions/CacheExtensions.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Microsoft.Extensions.Caching.Distributed; - -namespace EnvelopeGenerator.Extensions -{ - public static class CacheExtensions - { - public static IDistributedCache Cache(this IDistributedCache cache) - { - cache.SetStringAsync() - } - } -} \ No newline at end of file From 80f9107e4eff9ac0e0d1336f4295585d1d6eb7aa Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Mon, 27 Jan 2025 14:50:23 +0100 Subject: [PATCH 07/27] =?UTF-8?q?feat(cache):=20Unterst=C3=BCtzung=20f?= =?UTF-8?q?=C3=BCr=20GetOrSetAsync=20mit=20DateTime-Typ=20hinzugef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - GetOrSetAsync für DateTime mit synchronen und asynchronen Fabrikmethoden implementiert. - Bestehende GetOrSetAsync-Methoden für Zeichenfolgen und asynchrone Zeichenfolgen refaktoriert, um Klarheit und Struktur zu verbessern. - Code mit Regionen organisiert, um ähnliche Methoden für bessere Lesbarkeit zu gruppieren. - TODO für weitere Verbesserungen bei der Codegenerierung für GetOrSetAsync-Methoden hinzugefügt. --- .../Extensions/CacheExtensions.cs | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/EnvelopeGenerator.Application/Extensions/CacheExtensions.cs b/EnvelopeGenerator.Application/Extensions/CacheExtensions.cs index f2adcebd..5e9eebd8 100644 --- a/EnvelopeGenerator.Application/Extensions/CacheExtensions.cs +++ b/EnvelopeGenerator.Application/Extensions/CacheExtensions.cs @@ -33,6 +33,10 @@ namespace EnvelopeGenerator.Application.Extensions return value is null ? null : new(BitConverter.ToInt64(value, 0)); } + //TODO: use code generator + #region GetOrSetAsync + + #region string public static async Task GetOrSetAsync(this IDistributedCache cache, string key, Func factory, DistributedCacheEntryOptions? options = null, bool cacheInBackground = false, CancellationToken cToken = default) { var value = await cache.GetStringAsync(key, cToken); @@ -74,5 +78,54 @@ namespace EnvelopeGenerator.Application.Extensions return value; } + #endregion + + #region DateTime + public static async Task GetOrSetAsync(this IDistributedCache cache, string key, Func factory, DistributedCacheEntryOptions? options = null, bool cacheInBackground = false, CancellationToken cToken = default) + { + if (await cache.GetDateTimeAsync(key, cToken) is DateTime dateTimeValue) + return dateTimeValue; + else + { + // create new and save + var newValue = factory(); + + Task CacheAsync() => options is null + ? cache.SetDateTimeAsync(key, newValue, cToken: cToken) + : cache.SetDateTimeAsync(key, newValue, options, cToken); + + if (cacheInBackground) + _ = Task.Run(async () => await CacheAsync(), cToken); + else + await CacheAsync(); + + return newValue; + } + } + + public static async Task GetOrSetAsync(this IDistributedCache cache, string key, Func> factory, DistributedCacheEntryOptions? options = null, bool cacheInBackground = false, CancellationToken cToken = default) + { + if (await cache.GetDateTimeAsync(key, cToken) is DateTime dateTimeValue) + return dateTimeValue; + else + { + // create new and save + var newValue = await factory(); + + Task CacheAsync() => options is null + ? cache.SetDateTimeAsync(key, newValue, cToken: cToken) + : cache.SetDateTimeAsync(key, newValue, options, cToken); + + if (cacheInBackground) + _ = Task.Run(async () => await CacheAsync(), cToken); + else + await CacheAsync(); + + return newValue; + } + } + #endregion + + #endregion } } \ No newline at end of file From be44f9f43629e0bd70aaec0ffc1c238eb22bf4ff Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Mon, 27 Jan 2025 15:01:34 +0100 Subject: [PATCH 08/27] =?UTF-8?q?refactor(HomeController):=20Statische=20E?= =?UTF-8?q?igenschaften=20SmsTotpStep=20und=20SmsFormat=20hinzugef=C3=BCgt?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/HomeController.cs | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/EnvelopeGenerator.Web/Controllers/HomeController.cs b/EnvelopeGenerator.Web/Controllers/HomeController.cs index 79824bd6..6aec1ca6 100644 --- a/EnvelopeGenerator.Web/Controllers/HomeController.cs +++ b/EnvelopeGenerator.Web/Controllers/HomeController.cs @@ -24,9 +24,9 @@ using EnvelopeGenerator.Application.Extensions; namespace EnvelopeGenerator.Web.Controllers { public class HomeController : Controller - { - private readonly ILogger _logger; - private readonly EnvelopeOldService envelopeOldService; + { + private readonly ILogger _logger; + private readonly EnvelopeOldService envelopeOldService; private readonly IEnvelopeReceiverService _envRcvService; private readonly IEnvelopeHistoryService _historyService; private readonly IStringLocalizer _localizer; @@ -38,6 +38,8 @@ namespace EnvelopeGenerator.Web.Controllers private readonly IMessagingService _msgService; private readonly ICodeGenerator _codeGenerator; private readonly IReceiverService _rcvService; + private static readonly int SmsTotpStep = 60 * 3; + private static readonly string SmsFormat = "{0}"; public HomeController(EnvelopeOldService envelopeOldService, ILogger logger, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeHistoryService historyService, IStringLocalizer localizer, IConfiguration configuration, HtmlSanitizer sanitizer, Cultures cultures, IEnvelopeMailService envelopeMailService, IEnvelopeReceiverReadOnlyService readOnlyService, IMessagingService messagingService, ICodeGenerator codeGenerator, IReceiverService receiverService) { @@ -72,7 +74,7 @@ namespace EnvelopeGenerator.Web.Controllers return View(); } - + [HttpGet("EnvelopeKey/{envelopeReceiverId}")] public async Task MainAsync([FromRoute] string envelopeReceiverId, [FromQuery] string? culture = null) { @@ -195,9 +197,9 @@ namespace EnvelopeGenerator.Web.Controllers if (viaSms) { //add date time cache - var res = await _msgService.SendSmsCodeAsync(er_secret.PhoneNumber!, er_secret.Receiver.TotpSecretkey); + var res = await _msgService.SendSmsCodeAsync(er_secret.PhoneNumber!, er_secret.Receiver!.TotpSecretkey!, SmsFormat); if (res.Ok) - return View("EnvelopeLocked").WithData("CodeType", "smsCode").WithData("SmsExpiration", res.Expiration); + return View("EnvelopeLocked").WithData("CodeType", "smsCode").WithData("SmsExpiration", _codeGenerator.GetTotpExpirationTime(SmsTotpStep)); else if (!res.Allowed) return View("EnvelopeLocked").WithData("CodeType", "smsCode").WithData("SmsExpiration", res.AllowedAt); else @@ -246,14 +248,14 @@ namespace EnvelopeGenerator.Web.Controllers } return await TFAView(auth.UserSelectSMS); } - + } else if (auth.HasSmsCode) { if (er_secret.Receiver!.TotpSecretkey is null) throw new InvalidOperationException($"TotpSecretkey of DTO cannot validate without TotpSecretkey. Dto: {JsonConvert.SerializeObject(er_secret)}"); - if (_codeGenerator.VerifyTotp(auth.SmsCode!, er_secret.Receiver.TotpSecretkey, step: 60 * 5)) + if (_codeGenerator.VerifyTotp(auth.SmsCode!, er_secret.Receiver.TotpSecretkey, step: SmsTotpStep)) { Response.StatusCode = StatusCodes.Status401Unauthorized; ViewData["ErrorMessage"] = _localizer[WebKey.WrongAccessCode].Value; @@ -279,14 +281,14 @@ namespace EnvelopeGenerator.Web.Controllers //continue the process without important data to minimize security errors. EnvelopeReceiverDto er = er_secret; - ViewData["EnvelopeKey"] = envelopeReceiverId; - //check rejection - var rejRcvrs = await _historyService.ReadRejectingReceivers(er.Envelope!.Id); + ViewData["EnvelopeKey"] = envelopeReceiverId; + //check rejection + var rejRcvrs = await _historyService.ReadRejectingReceivers(er.Envelope!.Id); if(rejRcvrs.Any()) { ViewBag.IsExt = !rejRcvrs.Contains(er.Receiver); //external if the current user is not rejected return View("EnvelopeRejected", er); - } + } //check if it has already signed if (await _historyService.IsSigned(envelopeId: er.Envelope!.Id, userReference: er.Receiver!.EmailAddress)) @@ -299,8 +301,8 @@ namespace EnvelopeGenerator.Web.Controllers else { _logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, message: "No document byte-data was found in ENVELOPE_DOCUMENT table."); - return this.ViewDocumentNotFound(); - } + return this.ViewDocumentNotFound(); + } var claims = new List { new(ClaimTypes.NameIdentifier, uuid), @@ -326,7 +328,7 @@ namespace EnvelopeGenerator.Web.Controllers //add PSPDFKit licence key ViewData["PSPDFKitLicenseKey"] = _configuration["PSPDFKitLicenseKey"]; - return View("ShowEnvelope", er); + return View("ShowEnvelope", er); } catch (Exception ex) { @@ -381,7 +383,8 @@ namespace EnvelopeGenerator.Web.Controllers await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); return await _envRcvService.ReadByEnvelopeReceiverIdAsync(envelopeReceiverId).ThenAsync( SuccessAsync: async (er) => - {ViewData["UserCulture"] = _cultures[UserLanguage]; + { + ViewData["UserCulture"] = _cultures[UserLanguage]; ViewData["UserCulture"] = _cultures[UserLanguage]; return await _historyService.IsRejected(envelopeId: er.EnvelopeId) ? View(er) @@ -434,7 +437,7 @@ namespace EnvelopeGenerator.Web.Controllers SuccessAsync: async er => { var envelopeKey = (er.Envelope!.Uuid, er.Receiver!.Signature).EncodeEnvelopeReceiverId(); - + EnvelopeResponse response = await envelopeOldService.LoadEnvelope(envelopeKey); //TODO: implement multi-threading to history process (Task) @@ -514,7 +517,7 @@ namespace EnvelopeGenerator.Web.Controllers var cookieValue = Request.Cookies[CookieRequestCultureProvider.DefaultCookieName]; if (string.IsNullOrEmpty(cookieValue)) - return null; + return null; var culture = CookieRequestCultureProvider.ParseCookieValue(cookieValue)?.Cultures[0]; return culture?.Value ?? null; From 6abc17c3bfc02ddb78cb2eea268c2af5c083cb69 Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Mon, 27 Jan 2025 17:09:23 +0100 Subject: [PATCH 09/27] =?UTF-8?q?feat(HomeController):=20Aktualisiert,=20u?= =?UTF-8?q?m=20SMS=20=C3=BCber=20zu=20senden.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Unnötige Parameter in SmsParams entfernt. - Code-Sendefunktion von IMessagingService entfernt. - GetTotpExpirationTime Methode im CodeGenerator entfernt. --- .../Configurations/GtxMessaging/SmsParams.cs | 9 ----- .../Contracts/ICodeGenerator.cs | 2 - .../Contracts/IMessagingService.cs | 2 - .../DTOs/Messaging/SmsResponse.cs | 2 + .../Extensions/DIExtensions.cs | 1 - .../Services/CodeGenerator.cs | 5 --- .../Services/GTXMessagingService.cs | 12 +----- .../Controllers/HomeController.cs | 39 +++++++++++++------ 8 files changed, 30 insertions(+), 42 deletions(-) diff --git a/EnvelopeGenerator.Application/Configurations/GtxMessaging/SmsParams.cs b/EnvelopeGenerator.Application/Configurations/GtxMessaging/SmsParams.cs index 9db3c8c5..eae4b63f 100644 --- a/EnvelopeGenerator.Application/Configurations/GtxMessaging/SmsParams.cs +++ b/EnvelopeGenerator.Application/Configurations/GtxMessaging/SmsParams.cs @@ -1,7 +1,4 @@ using DigitalData.Core.Abstractions.Client; -using Microsoft.Extensions.Caching.Distributed; -using OtpNet; - namespace EnvelopeGenerator.Application.Configurations.GtxMessaging { /// @@ -20,11 +17,5 @@ namespace EnvelopeGenerator.Application.Configurations.GtxMessaging public string RecipientQueryParamName { get; init; } = "to"; public string MessageQueryParamName { get; init; } = "text"; - - public int CodeLength { get; init; } = 5; - - public int SmsTotpStep { get; init; } = 300; - - public string DefaultTotpMessageFormat { get; init; } = "{0}"; } } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Contracts/ICodeGenerator.cs b/EnvelopeGenerator.Application/Contracts/ICodeGenerator.cs index c8d47976..d4e93c6b 100644 --- a/EnvelopeGenerator.Application/Contracts/ICodeGenerator.cs +++ b/EnvelopeGenerator.Application/Contracts/ICodeGenerator.cs @@ -15,7 +15,5 @@ namespace EnvelopeGenerator.Application.Contracts string GenerateTotp(string secretKey, int step = 30); bool VerifyTotp(string totpCode, string secretKey, int step = 30, VerificationWindow? window = null); - - bool GetTotpExpirationTime(int step = 30); } } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Contracts/IMessagingService.cs b/EnvelopeGenerator.Application/Contracts/IMessagingService.cs index 9a0c050a..886585a5 100644 --- a/EnvelopeGenerator.Application/Contracts/IMessagingService.cs +++ b/EnvelopeGenerator.Application/Contracts/IMessagingService.cs @@ -7,6 +7,4 @@ public interface IMessagingService string ServiceProvider { get; } Task SendSmsAsync(string recipient, string message); - - Task SendSmsCodeAsync(string recipient, string secretKey, string messageFormat = "{0}"); } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/DTOs/Messaging/SmsResponse.cs b/EnvelopeGenerator.Application/DTOs/Messaging/SmsResponse.cs index a546d0c7..1d82020b 100644 --- a/EnvelopeGenerator.Application/DTOs/Messaging/SmsResponse.cs +++ b/EnvelopeGenerator.Application/DTOs/Messaging/SmsResponse.cs @@ -4,6 +4,8 @@ { public required bool Ok { get; init; } + public bool Failed => !Ok; + public dynamic? Errors { get; init; } } } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Extensions/DIExtensions.cs b/EnvelopeGenerator.Application/Extensions/DIExtensions.cs index ae8fedf9..465b5b23 100644 --- a/EnvelopeGenerator.Application/Extensions/DIExtensions.cs +++ b/EnvelopeGenerator.Application/Extensions/DIExtensions.cs @@ -62,7 +62,6 @@ namespace EnvelopeGenerator.Application.Extensions services.AddHttpClientService(smsConfigSection); services.TryAddSingleton(); services.TryAddSingleton(); - services.TryAddSingleton(); services.TryAddSingleton(); return services; diff --git a/EnvelopeGenerator.Application/Services/CodeGenerator.cs b/EnvelopeGenerator.Application/Services/CodeGenerator.cs index 94ad6720..ca84bfc9 100644 --- a/EnvelopeGenerator.Application/Services/CodeGenerator.cs +++ b/EnvelopeGenerator.Application/Services/CodeGenerator.cs @@ -67,10 +67,5 @@ namespace EnvelopeGenerator.Application.Services public bool VerifyTotp(string totpCode, string secretKey, int step = 30, VerificationWindow? window = null) => new Totp(Base32Encoding.ToBytes(secretKey), step).VerifyTotp(totpCode, out _, window); - - public bool GetTotpExpirationTime(int step = 30) - { - throw new NotImplementedException(); - } } } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Services/GTXMessagingService.cs b/EnvelopeGenerator.Application/Services/GTXMessagingService.cs index 78269522..3d6e8620 100644 --- a/EnvelopeGenerator.Application/Services/GTXMessagingService.cs +++ b/EnvelopeGenerator.Application/Services/GTXMessagingService.cs @@ -16,17 +16,14 @@ public class GtxMessagingService : IMessagingService private readonly IMapper _mapper; - private readonly ICodeGenerator _codeGen; - public string ServiceProvider { get; } - public GtxMessagingService(IHttpClientService smsClient, IOptions smsParamsOptions, IMapper mapper, ICodeGenerator codeGenerator) + public GtxMessagingService(IHttpClientService smsClient, IOptions smsParamsOptions, IMapper mapper) { _smsClient = smsClient; _smsParams = smsParamsOptions.Value; _mapper = mapper; ServiceProvider = GetType().Name.Replace("Service", string.Empty); - _codeGen = codeGenerator; } public async Task SendSmsAsync(string recipient, string message) @@ -39,11 +36,4 @@ public class GtxMessagingService : IMessagingService .ThenAsync(res => res.Json()) .ThenAsync(_mapper.Map); } - - public async Task SendSmsCodeAsync(string recipient, string secretKey, string? messageFormat = null) - { - var code = _codeGen.GenerateTotp(secretKey, _smsParams.SmsTotpStep); - var message = string.Format(messageFormat ?? _smsParams.DefaultTotpMessageFormat, code); - return await SendSmsAsync(recipient: recipient, message: message); - } } \ No newline at end of file diff --git a/EnvelopeGenerator.Web/Controllers/HomeController.cs b/EnvelopeGenerator.Web/Controllers/HomeController.cs index 6aec1ca6..9a6ecee2 100644 --- a/EnvelopeGenerator.Web/Controllers/HomeController.cs +++ b/EnvelopeGenerator.Web/Controllers/HomeController.cs @@ -20,6 +20,11 @@ using Newtonsoft.Json; using EnvelopeGenerator.Application.DTOs; using DigitalData.Core.Client; using EnvelopeGenerator.Application.Extensions; +using Microsoft.Extensions.Caching.Distributed; +using System.Globalization; +using EnvelopeGenerator.Application.Configurations.GtxMessaging; +using EnvelopeGenerator.Application.DTOs.Messaging; +using OtpNet; namespace EnvelopeGenerator.Web.Controllers { @@ -38,10 +43,13 @@ namespace EnvelopeGenerator.Web.Controllers private readonly IMessagingService _msgService; private readonly ICodeGenerator _codeGenerator; private readonly IReceiverService _rcvService; - private static readonly int SmsTotpStep = 60 * 3; - private static readonly string SmsFormat = "{0}"; + private readonly IDistributedCache _dCache; + private static readonly int SmsTotpStep = 60 * 1; + private static readonly string SmsFormat = "signFlow TFA-Passwort ist {0}. Dieses Passwort ist bis {1} Uhr gültig."; + private static readonly string SmsCodeExpirationCacheKeyFormat = "e{0}_r{1}_sms_code_expiration"; + private static readonly (string DateTimeFormat, CultureInfo CultureInfo) SmsCodeExpiration = ("HH:mm:ss", new CultureInfo("de-DE")); - public HomeController(EnvelopeOldService envelopeOldService, ILogger logger, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeHistoryService historyService, IStringLocalizer localizer, IConfiguration configuration, HtmlSanitizer sanitizer, Cultures cultures, IEnvelopeMailService envelopeMailService, IEnvelopeReceiverReadOnlyService readOnlyService, IMessagingService messagingService, ICodeGenerator codeGenerator, IReceiverService receiverService) + public HomeController(EnvelopeOldService envelopeOldService, ILogger logger, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeHistoryService historyService, IStringLocalizer localizer, IConfiguration configuration, HtmlSanitizer sanitizer, Cultures cultures, IEnvelopeMailService envelopeMailService, IEnvelopeReceiverReadOnlyService readOnlyService, IMessagingService messagingService, ICodeGenerator codeGenerator, IReceiverService receiverService, IDistributedCache distributedCache) { this.envelopeOldService = envelopeOldService; _envRcvService = envelopeReceiverService; @@ -56,6 +64,7 @@ namespace EnvelopeGenerator.Web.Controllers _msgService = messagingService; _codeGenerator = codeGenerator; _rcvService = receiverService; + _dCache = distributedCache; } [HttpGet("/")] @@ -197,17 +206,23 @@ namespace EnvelopeGenerator.Web.Controllers if (viaSms) { //add date time cache - var res = await _msgService.SendSmsCodeAsync(er_secret.PhoneNumber!, er_secret.Receiver!.TotpSecretkey!, SmsFormat); - if (res.Ok) - return View("EnvelopeLocked").WithData("CodeType", "smsCode").WithData("SmsExpiration", _codeGenerator.GetTotpExpirationTime(SmsTotpStep)); - else if (!res.Allowed) - return View("EnvelopeLocked").WithData("CodeType", "smsCode").WithData("SmsExpiration", res.AllowedAt); - else + var key = string.Format(SmsCodeExpirationCacheKeyFormat, er_secret.EnvelopeId, er_secret.ReceiverId); + var expiration = await _dCache.GetDateTimeAsync(key); + if(expiration is null || expiration <= DateTime.Now) { - var res_json = JsonConvert.SerializeObject(res); - _logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, message: $"An unexpected error occurred while sending an SMS code. Response: ${res_json}"); - return this.ViewInnerServiceError(); + var new_expiration = DateTime.Now.AddMinutes(SmsTotpStep); + var totp = _codeGenerator.GenerateTotp(er_secret.Receiver!.TotpSecretkey!, SmsTotpStep); + var msg = string.Format(SmsFormat, totp, new_expiration.ToString(SmsCodeExpiration.DateTimeFormat, SmsCodeExpiration.CultureInfo)); + var smsRes = await _msgService.SendSmsAsync(er_secret.PhoneNumber!, msg); + if (smsRes.Failed) + { + var res_json = JsonConvert.SerializeObject(smsRes); + _logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, message: $"An unexpected error occurred while sending an SMS code. Response: ${res_json}"); + return this.ViewInnerServiceError(); + } } + + return View("EnvelopeLocked").WithData("CodeType", "smsCode").WithData("SmsExpiration", expiration); } else { From 0718f2433979b2b084374301fcda50f0c6515033 Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Mon, 27 Jan 2025 17:12:19 +0100 Subject: [PATCH 10/27] feat(HomeController): TFAView wurde als separate Methode geschrieben, um Verwirrung zu vermeiden --- .../Controllers/HomeController.cs | 67 ++++++++++--------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/EnvelopeGenerator.Web/Controllers/HomeController.cs b/EnvelopeGenerator.Web/Controllers/HomeController.cs index 9a6ecee2..e01c52dd 100644 --- a/EnvelopeGenerator.Web/Controllers/HomeController.cs +++ b/EnvelopeGenerator.Web/Controllers/HomeController.cs @@ -25,6 +25,8 @@ using System.Globalization; using EnvelopeGenerator.Application.Configurations.GtxMessaging; using EnvelopeGenerator.Application.DTOs.Messaging; using OtpNet; +using EnvelopeGenerator.Domain.Entities; +using System.ComponentModel.DataAnnotations.Schema; namespace EnvelopeGenerator.Web.Controllers { @@ -171,6 +173,36 @@ namespace EnvelopeGenerator.Web.Controllers } } + [NonAction] + private async Task TFAView(bool viaSms, EnvelopeReceiverSecretDto er_secret, string envelopeReceiverId) + { + if (viaSms) + { + //add date time cache + var key = string.Format(SmsCodeExpirationCacheKeyFormat, er_secret.EnvelopeId, er_secret.ReceiverId); + var expiration = await _dCache.GetDateTimeAsync(key); + if (expiration is null || expiration <= DateTime.Now) + { + var new_expiration = DateTime.Now.AddMinutes(SmsTotpStep); + var totp = _codeGenerator.GenerateTotp(er_secret.Receiver!.TotpSecretkey!, SmsTotpStep); + var msg = string.Format(SmsFormat, totp, new_expiration.ToString(SmsCodeExpiration.DateTimeFormat, SmsCodeExpiration.CultureInfo)); + var smsRes = await _msgService.SendSmsAsync(er_secret.PhoneNumber!, msg); + if (smsRes.Failed) + { + var res_json = JsonConvert.SerializeObject(smsRes); + _logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, message: $"An unexpected error occurred while sending an SMS code. Response: ${res_json}"); + return this.ViewInnerServiceError(); + } + } + + return View("EnvelopeLocked").WithData("CodeType", "smsCode").WithData("SmsExpiration", expiration); + } + else + { + return View("EnvelopeLocked").WithData("CodeType", "authenticatorCode").WithData("QRCodeExpiration", er_secret.Receiver?.TotpExpiration); + } + } + [HttpPost("EnvelopeKey/{envelopeReceiverId}/Locked")] public async Task LogInEnvelope([FromRoute] string envelopeReceiverId, [FromForm] Auth auth) { @@ -201,35 +233,6 @@ namespace EnvelopeGenerator.Web.Controllers } var er_secret = er_secret_res.Data; - async Task TFAView(bool viaSms) - { - if (viaSms) - { - //add date time cache - var key = string.Format(SmsCodeExpirationCacheKeyFormat, er_secret.EnvelopeId, er_secret.ReceiverId); - var expiration = await _dCache.GetDateTimeAsync(key); - if(expiration is null || expiration <= DateTime.Now) - { - var new_expiration = DateTime.Now.AddMinutes(SmsTotpStep); - var totp = _codeGenerator.GenerateTotp(er_secret.Receiver!.TotpSecretkey!, SmsTotpStep); - var msg = string.Format(SmsFormat, totp, new_expiration.ToString(SmsCodeExpiration.DateTimeFormat, SmsCodeExpiration.CultureInfo)); - var smsRes = await _msgService.SendSmsAsync(er_secret.PhoneNumber!, msg); - if (smsRes.Failed) - { - var res_json = JsonConvert.SerializeObject(smsRes); - _logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, message: $"An unexpected error occurred while sending an SMS code. Response: ${res_json}"); - return this.ViewInnerServiceError(); - } - } - - return View("EnvelopeLocked").WithData("CodeType", "smsCode").WithData("SmsExpiration", expiration); - } - else - { - return View("EnvelopeLocked").WithData("CodeType", "authenticatorCode").WithData("QRCodeExpiration", er_secret.Receiver?.TotpExpiration); - } - } - if (auth.HasMulti) { Response.StatusCode = StatusCodes.Status401Unauthorized; @@ -261,7 +264,7 @@ namespace EnvelopeGenerator.Web.Controllers await _rcvService.UpdateAsync(rcv); await _mailService.SendTFAQrCodeAsync(er_secret); } - return await TFAView(auth.UserSelectSMS); + return await TFAView(auth.UserSelectSMS, er_secret, envelopeReceiverId); } } @@ -274,7 +277,7 @@ namespace EnvelopeGenerator.Web.Controllers { Response.StatusCode = StatusCodes.Status401Unauthorized; ViewData["ErrorMessage"] = _localizer[WebKey.WrongAccessCode].Value; - return await TFAView(viaSms: true); + return await TFAView(viaSms: true, er_secret, envelopeReceiverId); } } else if (auth.HasAuthenticatorCode) @@ -283,7 +286,7 @@ namespace EnvelopeGenerator.Web.Controllers { Response.StatusCode = StatusCodes.Status401Unauthorized; ViewData["ErrorMessage"] = _localizer[WebKey.WrongAccessCode].Value; - return await TFAView(viaSms: false); + return await TFAView(viaSms: false, er_secret, envelopeReceiverId); } } else From f674be5200c1c4b76c1f0d31c1bf03b883416bec Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Tue, 28 Jan 2025 10:21:47 +0100 Subject: [PATCH 11/27] chore: Projekt wurde auf 2.9.0 aktualisiert --- EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj index 57f44b17..1c25a308 100644 --- a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj +++ b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj @@ -5,7 +5,7 @@ enable enable EnvelopeGenerator.Web - 2.8.2 + 2.9.0 Digital Data GmbH Digital Data GmbH EnvelopeGenerator.Web @@ -13,8 +13,8 @@ digital data envelope generator web EnvelopeGenerator.Web is an ASP.NET MVC application developed to manage signing processes. It uses Entity Framework Core (EF Core) for database operations. The user interface for signing processes is developed with Razor View Engine (.cshtml files) and JavaScript under wwwroot, integrated with PSPDFKit. This integration allows users to view and sign documents seamlessly. Assets\icon.ico - 2.8.1 - 2.8.1 + 2.9.0 + 2.9.0 Copyright © 2024 Digital Data GmbH. All rights reserved. From 7f26bb4766dbbd8810eec1a0c0ee7478b8bccb22 Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Thu, 30 Jan 2025 16:12:42 +0100 Subject: [PATCH 12/27] refactor(HomeController): Aufteilung in Sub-TFAView-Methoden, um die Lesbarkeit zu verbessern. --- .../Controllers/HomeController.cs | 123 ++++++++++-------- 1 file changed, 70 insertions(+), 53 deletions(-) diff --git a/EnvelopeGenerator.Web/Controllers/HomeController.cs b/EnvelopeGenerator.Web/Controllers/HomeController.cs index e01c52dd..6e40e9da 100644 --- a/EnvelopeGenerator.Web/Controllers/HomeController.cs +++ b/EnvelopeGenerator.Web/Controllers/HomeController.cs @@ -22,11 +22,6 @@ using DigitalData.Core.Client; using EnvelopeGenerator.Application.Extensions; using Microsoft.Extensions.Caching.Distributed; using System.Globalization; -using EnvelopeGenerator.Application.Configurations.GtxMessaging; -using EnvelopeGenerator.Application.DTOs.Messaging; -using OtpNet; -using EnvelopeGenerator.Domain.Entities; -using System.ComponentModel.DataAnnotations.Schema; namespace EnvelopeGenerator.Web.Controllers { @@ -173,8 +168,9 @@ namespace EnvelopeGenerator.Web.Controllers } } + #region TFA Views [NonAction] - private async Task TFAView(bool viaSms, EnvelopeReceiverSecretDto er_secret, string envelopeReceiverId) + private async Task TFAViewAsync(bool viaSms, EnvelopeReceiverSecretDto er_secret, string envelopeReceiverId) { if (viaSms) { @@ -203,6 +199,68 @@ namespace EnvelopeGenerator.Web.Controllers } } + [NonAction] + private async Task AccessCodeViewAsync(Auth auth, EnvelopeReceiverSecretDto er_secret, string envelopeReceiverId) + { + //check the access code verification + if (er_secret.AccessCode != auth.AccessCode) + { + //Constants.EnvelopeStatus.AccessCodeIncorrect + await _historyService.RecordAsync(er_secret.EnvelopeId, er_secret.Receiver!.EmailAddress, EnvelopeStatus.AccessCodeIncorrect); + Response.StatusCode = StatusCodes.Status401Unauthorized; + return View("EnvelopeLocked") + .WithData("ErrorMessage", _localizer[WebKey.WrongAccessCode].Value); + } + + await _historyService.RecordAsync(er_secret.EnvelopeId, er_secret.Receiver!.EmailAddress, EnvelopeStatus.AccessCodeCorrect); + + //check if the user has phone is added + if (er_secret.Envelope!.TFAEnabled) + { + var rcv = er_secret.Receiver; + if (rcv.IsTotpSecretInvalid()) + { + rcv.TotpSecretkey = _codeGenerator.GenerateTotpSecretKey(); + rcv.TotpExpiration = DateTime.Now.AddMonths(1); + await _rcvService.UpdateAsync(rcv); + await _mailService.SendTFAQrCodeAsync(er_secret); + } + return await TFAViewAsync(auth.UserSelectSMS, er_secret, envelopeReceiverId); + } + + return null; + } + + [NonAction] + private async Task SmsViewAsync(Auth auth, EnvelopeReceiverSecretDto er_secret, string envelopeReceiverId) + { + if (er_secret.Receiver!.TotpSecretkey is null) + throw new InvalidOperationException($"TotpSecretkey of DTO cannot validate without TotpSecretkey. Dto: {JsonConvert.SerializeObject(er_secret)}"); + + if (_codeGenerator.VerifyTotp(auth.SmsCode!, er_secret.Receiver.TotpSecretkey, step: SmsTotpStep)) + { + Response.StatusCode = StatusCodes.Status401Unauthorized; + ViewData["ErrorMessage"] = _localizer[WebKey.WrongAccessCode].Value; + return await TFAViewAsync(viaSms: true, er_secret, envelopeReceiverId); + } + + return null; + } + + [NonAction] + private async Task AuthenticatorViewAsync(Auth auth, EnvelopeReceiverSecretDto er_secret, string envelopeReceiverId) + { + if (er_secret.Receiver!.IsTotpInvalid(totp: auth.AuthenticatorCode!)) + { + Response.StatusCode = StatusCodes.Status401Unauthorized; + ViewData["ErrorMessage"] = _localizer[WebKey.WrongAccessCode].Value; + return await TFAViewAsync(viaSms: false, er_secret, envelopeReceiverId); + } + + return null; + } + #endregion + [HttpPost("EnvelopeKey/{envelopeReceiverId}/Locked")] public async Task LogInEnvelope([FromRoute] string envelopeReceiverId, [FromForm] Auth auth) { @@ -240,55 +298,14 @@ namespace EnvelopeGenerator.Web.Controllers .WithData("ErrorMessage", _localizer[WebKey.WrongAccessCode].Value); } else if (auth.HasAccessCode) - { - //check the access code verification - if (er_secret.AccessCode != auth.AccessCode) - { - //Constants.EnvelopeStatus.AccessCodeIncorrect - await _historyService.RecordAsync(er_secret.EnvelopeId, er_secret.Receiver!.EmailAddress, EnvelopeStatus.AccessCodeIncorrect); - Response.StatusCode = StatusCodes.Status401Unauthorized; - return View("EnvelopeLocked") - .WithData("ErrorMessage", _localizer[WebKey.WrongAccessCode].Value); - } - - await _historyService.RecordAsync(er_secret.EnvelopeId, er_secret.Receiver!.EmailAddress, EnvelopeStatus.AccessCodeCorrect); - - //check if the user has phone is added - if (er_secret.Envelope!.TFAEnabled) - { - var rcv = er_secret.Receiver; - if (rcv.IsTotpSecretInvalid()) - { - rcv.TotpSecretkey = _codeGenerator.GenerateTotpSecretKey(); - rcv.TotpExpiration = DateTime.Now.AddMonths(1); - await _rcvService.UpdateAsync(rcv); - await _mailService.SendTFAQrCodeAsync(er_secret); - } - return await TFAView(auth.UserSelectSMS, er_secret, envelopeReceiverId); - } - - } + if(await AccessCodeViewAsync(auth, er_secret, envelopeReceiverId) is IActionResult acView) + return acView; else if (auth.HasSmsCode) - { - if (er_secret.Receiver!.TotpSecretkey is null) - throw new InvalidOperationException($"TotpSecretkey of DTO cannot validate without TotpSecretkey. Dto: {JsonConvert.SerializeObject(er_secret)}"); - - if (_codeGenerator.VerifyTotp(auth.SmsCode!, er_secret.Receiver.TotpSecretkey, step: SmsTotpStep)) - { - Response.StatusCode = StatusCodes.Status401Unauthorized; - ViewData["ErrorMessage"] = _localizer[WebKey.WrongAccessCode].Value; - return await TFAView(viaSms: true, er_secret, envelopeReceiverId); - } - } + if(await SmsViewAsync(auth, er_secret, envelopeReceiverId) is IActionResult smsView) + return smsView; else if (auth.HasAuthenticatorCode) - { - if (er_secret.Receiver!.IsTotpInvalid(totp: auth.AuthenticatorCode!)) - { - Response.StatusCode = StatusCodes.Status401Unauthorized; - ViewData["ErrorMessage"] = _localizer[WebKey.WrongAccessCode].Value; - return await TFAView(viaSms: false, er_secret, envelopeReceiverId); - } - } + if(await AuthenticatorViewAsync(auth, er_secret, envelopeReceiverId) is IActionResult aView) + return aView; else { Response.StatusCode = StatusCodes.Status401Unauthorized; From 84e3e4e18d2388ea64aed7fa742a769e6bd27d41 Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Thu, 30 Jan 2025 16:27:09 +0100 Subject: [PATCH 13/27] refactor(HomeController): renamed authentication methods with Handle prefix for clarity --- EnvelopeGenerator.Web/Controllers/HomeController.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/EnvelopeGenerator.Web/Controllers/HomeController.cs b/EnvelopeGenerator.Web/Controllers/HomeController.cs index 6e40e9da..df62b0a0 100644 --- a/EnvelopeGenerator.Web/Controllers/HomeController.cs +++ b/EnvelopeGenerator.Web/Controllers/HomeController.cs @@ -200,7 +200,7 @@ namespace EnvelopeGenerator.Web.Controllers } [NonAction] - private async Task AccessCodeViewAsync(Auth auth, EnvelopeReceiverSecretDto er_secret, string envelopeReceiverId) + private async Task HandleAccessCodeAsync(Auth auth, EnvelopeReceiverSecretDto er_secret, string envelopeReceiverId) { //check the access code verification if (er_secret.AccessCode != auth.AccessCode) @@ -232,7 +232,7 @@ namespace EnvelopeGenerator.Web.Controllers } [NonAction] - private async Task SmsViewAsync(Auth auth, EnvelopeReceiverSecretDto er_secret, string envelopeReceiverId) + private async Task HandleSmsAsync(Auth auth, EnvelopeReceiverSecretDto er_secret, string envelopeReceiverId) { if (er_secret.Receiver!.TotpSecretkey is null) throw new InvalidOperationException($"TotpSecretkey of DTO cannot validate without TotpSecretkey. Dto: {JsonConvert.SerializeObject(er_secret)}"); @@ -248,7 +248,7 @@ namespace EnvelopeGenerator.Web.Controllers } [NonAction] - private async Task AuthenticatorViewAsync(Auth auth, EnvelopeReceiverSecretDto er_secret, string envelopeReceiverId) + private async Task HandleAuthenticatorAsync(Auth auth, EnvelopeReceiverSecretDto er_secret, string envelopeReceiverId) { if (er_secret.Receiver!.IsTotpInvalid(totp: auth.AuthenticatorCode!)) { @@ -298,13 +298,13 @@ namespace EnvelopeGenerator.Web.Controllers .WithData("ErrorMessage", _localizer[WebKey.WrongAccessCode].Value); } else if (auth.HasAccessCode) - if(await AccessCodeViewAsync(auth, er_secret, envelopeReceiverId) is IActionResult acView) + if(await HandleAccessCodeAsync(auth, er_secret, envelopeReceiverId) is IActionResult acView) return acView; else if (auth.HasSmsCode) - if(await SmsViewAsync(auth, er_secret, envelopeReceiverId) is IActionResult smsView) + if(await HandleSmsAsync(auth, er_secret, envelopeReceiverId) is IActionResult smsView) return smsView; else if (auth.HasAuthenticatorCode) - if(await AuthenticatorViewAsync(auth, er_secret, envelopeReceiverId) is IActionResult aView) + if(await HandleAuthenticatorAsync(auth, er_secret, envelopeReceiverId) is IActionResult aView) return aView; else { From 4f35fe54be96e38a3a7df8cc98d9386b9b202031 Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Thu, 30 Jan 2025 16:37:01 +0100 Subject: [PATCH 14/27] fix(HomeController): Berechnungsmethode new_expiration aktualisiert, um AddSeconds zu verwenden --- EnvelopeGenerator.Web/Controllers/HomeController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EnvelopeGenerator.Web/Controllers/HomeController.cs b/EnvelopeGenerator.Web/Controllers/HomeController.cs index df62b0a0..d551397b 100644 --- a/EnvelopeGenerator.Web/Controllers/HomeController.cs +++ b/EnvelopeGenerator.Web/Controllers/HomeController.cs @@ -179,7 +179,7 @@ namespace EnvelopeGenerator.Web.Controllers var expiration = await _dCache.GetDateTimeAsync(key); if (expiration is null || expiration <= DateTime.Now) { - var new_expiration = DateTime.Now.AddMinutes(SmsTotpStep); + var new_expiration = DateTime.Now.AddSeconds(SmsTotpStep); var totp = _codeGenerator.GenerateTotp(er_secret.Receiver!.TotpSecretkey!, SmsTotpStep); var msg = string.Format(SmsFormat, totp, new_expiration.ToString(SmsCodeExpiration.DateTimeFormat, SmsCodeExpiration.CultureInfo)); var smsRes = await _msgService.SendSmsAsync(er_secret.PhoneNumber!, msg); From 06b1aa95608da4d41d7f7fce2de50ba31b525adf Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Thu, 30 Jan 2025 16:43:14 +0100 Subject: [PATCH 15/27] =?UTF-8?q?refactor(appsetings):=20Unn=C3=B6tige=20K?= =?UTF-8?q?onfigurations-Parameter=20entfernt.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- EnvelopeGenerator.Web/appsettings.json | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/EnvelopeGenerator.Web/appsettings.json b/EnvelopeGenerator.Web/appsettings.json index 6c4b4e50..500b55c1 100644 --- a/EnvelopeGenerator.Web/appsettings.json +++ b/EnvelopeGenerator.Web/appsettings.json @@ -70,11 +70,6 @@ } ] }, - "Jwt": { - "Issuer": null, - "Audience": null, - "Key": "8RGnd7x0G2TYLOIW4m_qlIls7MfbAIGNrpQJzMAUIvULHOLiG723znRa_MG-Z4yw3SErusOU4hTui2rVBMcCaQ" - }, "ContactLink": { "Label": "Kontakt", "Href": "https://digitaldata.works/", @@ -135,8 +130,6 @@ "Headers": {}, "QueryParams": { "from": "signFlow" - }, - "CodeCacheValidityPeriod": "00:10:00" - }, - "EnvelopeReceiverCacheParams": {} + } + } } \ No newline at end of file From e54d9d2da894afdb8294ff6acd3931ccce8702d6 Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Fri, 31 Jan 2025 10:22:37 +0100 Subject: [PATCH 16/27] feat(TotpSmsParams): Erstellt, um die Konfiguration von Totp zu handhaben --- .../Controllers/HomeController.cs | 20 +++++------ EnvelopeGenerator.Web/Models/TotpSmsParams.cs | 33 +++++++++++++++++++ EnvelopeGenerator.Web/Program.cs | 3 ++ 3 files changed, 46 insertions(+), 10 deletions(-) create mode 100644 EnvelopeGenerator.Web/Models/TotpSmsParams.cs diff --git a/EnvelopeGenerator.Web/Controllers/HomeController.cs b/EnvelopeGenerator.Web/Controllers/HomeController.cs index d551397b..26aa7bc1 100644 --- a/EnvelopeGenerator.Web/Controllers/HomeController.cs +++ b/EnvelopeGenerator.Web/Controllers/HomeController.cs @@ -22,6 +22,7 @@ using DigitalData.Core.Client; using EnvelopeGenerator.Application.Extensions; using Microsoft.Extensions.Caching.Distributed; using System.Globalization; +using Microsoft.Extensions.Options; namespace EnvelopeGenerator.Web.Controllers { @@ -41,12 +42,9 @@ namespace EnvelopeGenerator.Web.Controllers private readonly ICodeGenerator _codeGenerator; private readonly IReceiverService _rcvService; private readonly IDistributedCache _dCache; - private static readonly int SmsTotpStep = 60 * 1; - private static readonly string SmsFormat = "signFlow TFA-Passwort ist {0}. Dieses Passwort ist bis {1} Uhr gültig."; - private static readonly string SmsCodeExpirationCacheKeyFormat = "e{0}_r{1}_sms_code_expiration"; - private static readonly (string DateTimeFormat, CultureInfo CultureInfo) SmsCodeExpiration = ("HH:mm:ss", new CultureInfo("de-DE")); + private readonly TotpSmsParams _totpSmsParams; - public HomeController(EnvelopeOldService envelopeOldService, ILogger logger, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeHistoryService historyService, IStringLocalizer localizer, IConfiguration configuration, HtmlSanitizer sanitizer, Cultures cultures, IEnvelopeMailService envelopeMailService, IEnvelopeReceiverReadOnlyService readOnlyService, IMessagingService messagingService, ICodeGenerator codeGenerator, IReceiverService receiverService, IDistributedCache distributedCache) + public HomeController(EnvelopeOldService envelopeOldService, ILogger logger, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeHistoryService historyService, IStringLocalizer localizer, IConfiguration configuration, HtmlSanitizer sanitizer, Cultures cultures, IEnvelopeMailService envelopeMailService, IEnvelopeReceiverReadOnlyService readOnlyService, IMessagingService messagingService, ICodeGenerator codeGenerator, IReceiverService receiverService, IDistributedCache distributedCache, IOptions totpSmsParamsOptions) { this.envelopeOldService = envelopeOldService; _envRcvService = envelopeReceiverService; @@ -62,6 +60,7 @@ namespace EnvelopeGenerator.Web.Controllers _codeGenerator = codeGenerator; _rcvService = receiverService; _dCache = distributedCache; + _totpSmsParams = totpSmsParamsOptions.Value; } [HttpGet("/")] @@ -174,14 +173,15 @@ namespace EnvelopeGenerator.Web.Controllers { if (viaSms) { + //TODO: create a service (like EnvelopeSmsService) //add date time cache - var key = string.Format(SmsCodeExpirationCacheKeyFormat, er_secret.EnvelopeId, er_secret.ReceiverId); + var key = string.Format(_totpSmsParams.Expiration.CacheKeyFormat, er_secret.EnvelopeId, er_secret.ReceiverId); var expiration = await _dCache.GetDateTimeAsync(key); if (expiration is null || expiration <= DateTime.Now) { - var new_expiration = DateTime.Now.AddSeconds(SmsTotpStep); - var totp = _codeGenerator.GenerateTotp(er_secret.Receiver!.TotpSecretkey!, SmsTotpStep); - var msg = string.Format(SmsFormat, totp, new_expiration.ToString(SmsCodeExpiration.DateTimeFormat, SmsCodeExpiration.CultureInfo)); + var new_expiration = DateTime.Now.AddSeconds(_totpSmsParams.TotpStep); + var totp = _codeGenerator.GenerateTotp(er_secret.Receiver!.TotpSecretkey!, _totpSmsParams.TotpStep); + var msg = string.Format(_totpSmsParams.Format, totp, new_expiration.ToString(_totpSmsParams.Expiration.Format, _totpSmsParams.Expiration.CultureInfo)); var smsRes = await _msgService.SendSmsAsync(er_secret.PhoneNumber!, msg); if (smsRes.Failed) { @@ -237,7 +237,7 @@ namespace EnvelopeGenerator.Web.Controllers if (er_secret.Receiver!.TotpSecretkey is null) throw new InvalidOperationException($"TotpSecretkey of DTO cannot validate without TotpSecretkey. Dto: {JsonConvert.SerializeObject(er_secret)}"); - if (_codeGenerator.VerifyTotp(auth.SmsCode!, er_secret.Receiver.TotpSecretkey, step: SmsTotpStep)) + if (_codeGenerator.VerifyTotp(auth.SmsCode!, er_secret.Receiver.TotpSecretkey, step: _totpSmsParams.TotpStep)) { Response.StatusCode = StatusCodes.Status401Unauthorized; ViewData["ErrorMessage"] = _localizer[WebKey.WrongAccessCode].Value; diff --git a/EnvelopeGenerator.Web/Models/TotpSmsParams.cs b/EnvelopeGenerator.Web/Models/TotpSmsParams.cs new file mode 100644 index 00000000..d515da53 --- /dev/null +++ b/EnvelopeGenerator.Web/Models/TotpSmsParams.cs @@ -0,0 +1,33 @@ +using System.Globalization; + +namespace EnvelopeGenerator.Web.Models +{ + public class TotpSmsParams + { + /// + /// The unit is second. + /// + public int TotpStep { get; init; } = 90; + + public string Format { get; init; } = "Ihr 2FA-Passwort lautet {0}. Gültig bis {1}"; + + public ExpirationHandler Expiration { get; init; } = new(); + + public class ExpirationHandler + { + public string CacheKeyFormat { get; init; } = "e{0}_r{1}_sms_code_expiration"; + + public string Format { get; init; } = "HH:mm:ss"; + + public string CultureName + { + get => _cultureInfo.Name; + init => _cultureInfo = new(value); + } + + private CultureInfo _cultureInfo = new("de-DE"); + + public CultureInfo CultureInfo => _cultureInfo; + } + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.Web/Program.cs b/EnvelopeGenerator.Web/Program.cs index fbf24996..98dc62d3 100644 --- a/EnvelopeGenerator.Web/Program.cs +++ b/EnvelopeGenerator.Web/Program.cs @@ -16,6 +16,7 @@ using DigitalData.EmailProfilerDispatcher; using EnvelopeGenerator.Infrastructure; using EnvelopeGenerator.Web.Sanitizers; using EnvelopeGenerator.Application.Extensions; +using Microsoft.Extensions.DependencyInjection; var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger(); logger.Info("Logging initialized!"); @@ -49,6 +50,8 @@ try // Add higher order services builder.Services.AddScoped(); + builder.Services.Configure(config.GetSection("TotpSmsParams")); + // Add controllers and razor views builder.Services.AddControllersWithViews(options => { From 22347a0202c52921671519bb86453244b709d6c2 Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Fri, 31 Jan 2025 10:37:59 +0100 Subject: [PATCH 17/27] refactor(MessagingService): umbenannt in SmsSender --- .../Contracts/{IMessagingService.cs => ISmsSender.cs} | 3 ++- EnvelopeGenerator.Application/Extensions/DIExtensions.cs | 2 +- .../Services/EnvelopeReceiverService.cs | 8 ++++---- .../Services/{GTXMessagingService.cs => GTXSmsSender.cs} | 5 +++-- EnvelopeGenerator.Web/Controllers/HomeController.cs | 4 ++-- .../Controllers/Test/TestMessagingController.cs | 4 ++-- 6 files changed, 14 insertions(+), 12 deletions(-) rename EnvelopeGenerator.Application/Contracts/{IMessagingService.cs => ISmsSender.cs} (77%) rename EnvelopeGenerator.Application/Services/{GTXMessagingService.cs => GTXSmsSender.cs} (85%) diff --git a/EnvelopeGenerator.Application/Contracts/IMessagingService.cs b/EnvelopeGenerator.Application/Contracts/ISmsSender.cs similarity index 77% rename from EnvelopeGenerator.Application/Contracts/IMessagingService.cs rename to EnvelopeGenerator.Application/Contracts/ISmsSender.cs index 886585a5..21fb28bf 100644 --- a/EnvelopeGenerator.Application/Contracts/IMessagingService.cs +++ b/EnvelopeGenerator.Application/Contracts/ISmsSender.cs @@ -2,7 +2,8 @@ namespace EnvelopeGenerator.Application.Contracts; -public interface IMessagingService +//TODO: move to DigitalData.Core +public interface ISmsSender { string ServiceProvider { get; } diff --git a/EnvelopeGenerator.Application/Extensions/DIExtensions.cs b/EnvelopeGenerator.Application/Extensions/DIExtensions.cs index 465b5b23..ba72c561 100644 --- a/EnvelopeGenerator.Application/Extensions/DIExtensions.cs +++ b/EnvelopeGenerator.Application/Extensions/DIExtensions.cs @@ -60,7 +60,7 @@ namespace EnvelopeGenerator.Application.Extensions services.Configure(envelopeReceiverCacheParamsSection); services.AddHttpClientService(smsConfigSection); - services.TryAddSingleton(); + services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); diff --git a/EnvelopeGenerator.Application/Services/EnvelopeReceiverService.cs b/EnvelopeGenerator.Application/Services/EnvelopeReceiverService.cs index ee3e07fe..742c2d41 100644 --- a/EnvelopeGenerator.Application/Services/EnvelopeReceiverService.cs +++ b/EnvelopeGenerator.Application/Services/EnvelopeReceiverService.cs @@ -17,13 +17,13 @@ namespace EnvelopeGenerator.Application.Services { private readonly IStringLocalizer _localizer; - private readonly IMessagingService _messagingService; + private readonly ISmsSender _smsSender; - public EnvelopeReceiverService(IEnvelopeReceiverRepository repository, IStringLocalizer localizer, IMapper mapper, IMessagingService messagingService) + public EnvelopeReceiverService(IEnvelopeReceiverRepository repository, IStringLocalizer localizer, IMapper mapper, ISmsSender smsSender) : base(repository, mapper) { _localizer = localizer; - _messagingService = messagingService; + _smsSender = smsSender; } public async Task>> ReadBySignatureAsync(string signature, bool withEnvelope = false, bool withReceiver = true, bool readOnly = true) @@ -171,7 +171,7 @@ namespace EnvelopeGenerator.Application.Services .Message(Key.PhoneNumberNonexists) .Notice(LogLevel.Error, Flag.NotFound, $"An attempt was made to send sms to the user whose phone number is null. Envelope recipient ID is {envelopeReceiverId}, UUID is {uuid} and signature is {signature}."); - var res = await _messagingService.SendSmsAsync(recipient: env_rcv.PhoneNumber, message: message); + var res = await _smsSender.SendSmsAsync(recipient: env_rcv.PhoneNumber, message: message); return Result.Success(res); } diff --git a/EnvelopeGenerator.Application/Services/GTXMessagingService.cs b/EnvelopeGenerator.Application/Services/GTXSmsSender.cs similarity index 85% rename from EnvelopeGenerator.Application/Services/GTXMessagingService.cs rename to EnvelopeGenerator.Application/Services/GTXSmsSender.cs index 3d6e8620..319700fb 100644 --- a/EnvelopeGenerator.Application/Services/GTXMessagingService.cs +++ b/EnvelopeGenerator.Application/Services/GTXSmsSender.cs @@ -8,7 +8,8 @@ using Microsoft.Extensions.Options; namespace EnvelopeGenerator.Application.Services; -public class GtxMessagingService : IMessagingService +//TODO: move to DigitalData.Core +public class GTXSmsSender : ISmsSender { private readonly IHttpClientService _smsClient; @@ -18,7 +19,7 @@ public class GtxMessagingService : IMessagingService public string ServiceProvider { get; } - public GtxMessagingService(IHttpClientService smsClient, IOptions smsParamsOptions, IMapper mapper) + public GTXSmsSender(IHttpClientService smsClient, IOptions smsParamsOptions, IMapper mapper) { _smsClient = smsClient; _smsParams = smsParamsOptions.Value; diff --git a/EnvelopeGenerator.Web/Controllers/HomeController.cs b/EnvelopeGenerator.Web/Controllers/HomeController.cs index 26aa7bc1..974206eb 100644 --- a/EnvelopeGenerator.Web/Controllers/HomeController.cs +++ b/EnvelopeGenerator.Web/Controllers/HomeController.cs @@ -38,13 +38,13 @@ namespace EnvelopeGenerator.Web.Controllers private readonly Cultures _cultures; private readonly IEnvelopeMailService _mailService; private readonly IEnvelopeReceiverReadOnlyService _readOnlyService; - private readonly IMessagingService _msgService; + private readonly ISmsSender _msgService; private readonly ICodeGenerator _codeGenerator; private readonly IReceiverService _rcvService; private readonly IDistributedCache _dCache; private readonly TotpSmsParams _totpSmsParams; - public HomeController(EnvelopeOldService envelopeOldService, ILogger logger, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeHistoryService historyService, IStringLocalizer localizer, IConfiguration configuration, HtmlSanitizer sanitizer, Cultures cultures, IEnvelopeMailService envelopeMailService, IEnvelopeReceiverReadOnlyService readOnlyService, IMessagingService messagingService, ICodeGenerator codeGenerator, IReceiverService receiverService, IDistributedCache distributedCache, IOptions totpSmsParamsOptions) + public HomeController(EnvelopeOldService envelopeOldService, ILogger logger, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeHistoryService historyService, IStringLocalizer localizer, IConfiguration configuration, HtmlSanitizer sanitizer, Cultures cultures, IEnvelopeMailService envelopeMailService, IEnvelopeReceiverReadOnlyService readOnlyService, ISmsSender messagingService, ICodeGenerator codeGenerator, IReceiverService receiverService, IDistributedCache distributedCache, IOptions totpSmsParamsOptions) { this.envelopeOldService = envelopeOldService; _envRcvService = envelopeReceiverService; diff --git a/EnvelopeGenerator.Web/Controllers/Test/TestMessagingController.cs b/EnvelopeGenerator.Web/Controllers/Test/TestMessagingController.cs index b0d6ee7a..ac4555e1 100644 --- a/EnvelopeGenerator.Web/Controllers/Test/TestMessagingController.cs +++ b/EnvelopeGenerator.Web/Controllers/Test/TestMessagingController.cs @@ -7,9 +7,9 @@ namespace EnvelopeGenerator.Web.Controllers.Test [ApiController] public class TestMessagingController : ControllerBase { - private readonly IMessagingService _service; + private readonly ISmsSender _service; - public TestMessagingController(IMessagingService service) + public TestMessagingController(ISmsSender service) { _service = service; } From 1941de192877e9c498b904169e95af9a83d785ee Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Fri, 31 Jan 2025 11:15:53 +0100 Subject: [PATCH 18/27] refactor(EnvelopeSmsService): Initialisiert mit Schnittstelle, DI-Injektion und Konfigurationen. --- .../Configurations}/TotpSmsParams.cs | 2 +- .../Contracts/IEnvelopeSmsService.cs | 5 +++++ .../Extensions/DIExtensions.cs | 7 +++++-- .../Services/EnvelopeSmsService.cs | 18 ++++++++++++++++++ 4 files changed, 29 insertions(+), 3 deletions(-) rename {EnvelopeGenerator.Web/Models => EnvelopeGenerator.Application/Configurations}/TotpSmsParams.cs (93%) create mode 100644 EnvelopeGenerator.Application/Contracts/IEnvelopeSmsService.cs create mode 100644 EnvelopeGenerator.Application/Services/EnvelopeSmsService.cs diff --git a/EnvelopeGenerator.Web/Models/TotpSmsParams.cs b/EnvelopeGenerator.Application/Configurations/TotpSmsParams.cs similarity index 93% rename from EnvelopeGenerator.Web/Models/TotpSmsParams.cs rename to EnvelopeGenerator.Application/Configurations/TotpSmsParams.cs index d515da53..13501fe4 100644 --- a/EnvelopeGenerator.Web/Models/TotpSmsParams.cs +++ b/EnvelopeGenerator.Application/Configurations/TotpSmsParams.cs @@ -1,6 +1,6 @@ using System.Globalization; -namespace EnvelopeGenerator.Web.Models +namespace EnvelopeGenerator.Application.Configurations { public class TotpSmsParams { diff --git a/EnvelopeGenerator.Application/Contracts/IEnvelopeSmsService.cs b/EnvelopeGenerator.Application/Contracts/IEnvelopeSmsService.cs new file mode 100644 index 00000000..6efc6abf --- /dev/null +++ b/EnvelopeGenerator.Application/Contracts/IEnvelopeSmsService.cs @@ -0,0 +1,5 @@ +namespace EnvelopeGenerator.Application.Contracts; + +public interface IEnvelopeSmsService +{ +} \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Extensions/DIExtensions.cs b/EnvelopeGenerator.Application/Extensions/DIExtensions.cs index ba72c561..2a81c47a 100644 --- a/EnvelopeGenerator.Application/Extensions/DIExtensions.cs +++ b/EnvelopeGenerator.Application/Extensions/DIExtensions.cs @@ -16,7 +16,7 @@ namespace EnvelopeGenerator.Application.Extensions { public static class DIExtensions { - public static IServiceCollection AddEnvelopeGenerator(this IServiceCollection services, IConfigurationSection dispatcherConfigSection, IConfigurationSection mailConfigSection, IConfigurationSection smsConfigSection, IConfigurationSection codeGeneratorConfigSection, IConfigurationSection envelopeReceiverCacheParamsSection) + public static IServiceCollection AddEnvelopeGenerator(this IServiceCollection services, IConfigurationSection dispatcherConfigSection, IConfigurationSection mailConfigSection, IConfigurationSection smsConfigSection, IConfigurationSection codeGeneratorConfigSection, IConfigurationSection envelopeReceiverCacheParamsSection, IConfigurationSection totpSmsParamsSection) { //Inject CRUD Service and repositoriesad services.TryAddScoped(); @@ -58,9 +58,11 @@ namespace EnvelopeGenerator.Application.Extensions services.Configure(mailConfigSection); services.Configure(codeGeneratorConfigSection); services.Configure(envelopeReceiverCacheParamsSection); + services.Configure(totpSmsParamsSection); services.AddHttpClientService(smsConfigSection); services.TryAddSingleton(); + services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); @@ -72,6 +74,7 @@ namespace EnvelopeGenerator.Application.Extensions mailConfigSection: config.GetSection("MailConfig"), smsConfigSection: config.GetSection("SmsConfig"), codeGeneratorConfigSection: config.GetSection("CodeGeneratorParams"), - envelopeReceiverCacheParamsSection: config.GetSection("EnvelopeReceiverCacheParams")); + envelopeReceiverCacheParamsSection: config.GetSection("EnvelopeReceiverCacheParams"), + totpSmsParamsSection: config.GetSection("TotpSmsParams")); } } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Services/EnvelopeSmsService.cs b/EnvelopeGenerator.Application/Services/EnvelopeSmsService.cs new file mode 100644 index 00000000..075e0249 --- /dev/null +++ b/EnvelopeGenerator.Application/Services/EnvelopeSmsService.cs @@ -0,0 +1,18 @@ +using EnvelopeGenerator.Application.Configurations; +using EnvelopeGenerator.Application.Contracts; +using Microsoft.Extensions.Options; + +namespace EnvelopeGenerator.Application.Services; + +public class EnvelopeSmsService : IEnvelopeSmsService +{ + private readonly ISmsSender _sender; + + private readonly TotpSmsParams _totpSmsParams; + + public EnvelopeSmsService(ISmsSender sender, IOptions totpSmsParamsOptions) + { + _sender = sender; + _totpSmsParams = totpSmsParamsOptions.Value; + } +} \ No newline at end of file From cd88af680768a44513330d465f20592f767acaed Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Fri, 31 Jan 2025 11:20:24 +0100 Subject: [PATCH 19/27] refactor(EnvelopeSmsService): Initialisiert mit Schnittstelle, DI-Injektion und Konfigurationen. --- EnvelopeGenerator.Application/Extensions/DIExtensions.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/EnvelopeGenerator.Application/Extensions/DIExtensions.cs b/EnvelopeGenerator.Application/Extensions/DIExtensions.cs index 2a81c47a..28e2780b 100644 --- a/EnvelopeGenerator.Application/Extensions/DIExtensions.cs +++ b/EnvelopeGenerator.Application/Extensions/DIExtensions.cs @@ -16,7 +16,7 @@ namespace EnvelopeGenerator.Application.Extensions { public static class DIExtensions { - public static IServiceCollection AddEnvelopeGenerator(this IServiceCollection services, IConfigurationSection dispatcherConfigSection, IConfigurationSection mailConfigSection, IConfigurationSection smsConfigSection, IConfigurationSection codeGeneratorConfigSection, IConfigurationSection envelopeReceiverCacheParamsSection, IConfigurationSection totpSmsParamsSection) + public static IServiceCollection AddEnvelopeGenerator(this IServiceCollection services, IConfigurationSection dispatcherConfigSection, IConfigurationSection mailConfigSection, IConfigurationSection smsConfigSection, IConfigurationSection codeGeneratorConfigSection, IConfigurationSection envelopeReceiverCacheParamsSection, IConfigurationSection totpSmsParamsSection, IConfiguration config) { //Inject CRUD Service and repositoriesad services.TryAddScoped(); @@ -69,12 +69,15 @@ namespace EnvelopeGenerator.Application.Extensions return services; } + public static IServiceCollection Configure(this IServiceCollection services, IConfiguration configuration) => services + .Configure(configuration.GetSection(nameof(T))); + public static IServiceCollection AddEnvelopeGenerator(this IServiceCollection services, IConfiguration config) => services.AddEnvelopeGenerator( dispatcherConfigSection: config.GetSection("DispatcherConfig"), mailConfigSection: config.GetSection("MailConfig"), smsConfigSection: config.GetSection("SmsConfig"), codeGeneratorConfigSection: config.GetSection("CodeGeneratorParams"), envelopeReceiverCacheParamsSection: config.GetSection("EnvelopeReceiverCacheParams"), - totpSmsParamsSection: config.GetSection("TotpSmsParams")); + totpSmsParamsSection: config.GetSection("TotpSmsParams"), config); } } \ No newline at end of file From eb0c6dabf4569174eb4825a5bb33d7cbde28325e Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Fri, 31 Jan 2025 11:20:43 +0100 Subject: [PATCH 20/27] Revert "refactor(EnvelopeSmsService): Initialisiert mit Schnittstelle, DI-Injektion und Konfigurationen." This reverts commit cd88af680768a44513330d465f20592f767acaed. --- EnvelopeGenerator.Application/Extensions/DIExtensions.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/EnvelopeGenerator.Application/Extensions/DIExtensions.cs b/EnvelopeGenerator.Application/Extensions/DIExtensions.cs index 28e2780b..2a81c47a 100644 --- a/EnvelopeGenerator.Application/Extensions/DIExtensions.cs +++ b/EnvelopeGenerator.Application/Extensions/DIExtensions.cs @@ -16,7 +16,7 @@ namespace EnvelopeGenerator.Application.Extensions { public static class DIExtensions { - public static IServiceCollection AddEnvelopeGenerator(this IServiceCollection services, IConfigurationSection dispatcherConfigSection, IConfigurationSection mailConfigSection, IConfigurationSection smsConfigSection, IConfigurationSection codeGeneratorConfigSection, IConfigurationSection envelopeReceiverCacheParamsSection, IConfigurationSection totpSmsParamsSection, IConfiguration config) + public static IServiceCollection AddEnvelopeGenerator(this IServiceCollection services, IConfigurationSection dispatcherConfigSection, IConfigurationSection mailConfigSection, IConfigurationSection smsConfigSection, IConfigurationSection codeGeneratorConfigSection, IConfigurationSection envelopeReceiverCacheParamsSection, IConfigurationSection totpSmsParamsSection) { //Inject CRUD Service and repositoriesad services.TryAddScoped(); @@ -69,15 +69,12 @@ namespace EnvelopeGenerator.Application.Extensions return services; } - public static IServiceCollection Configure(this IServiceCollection services, IConfiguration configuration) => services - .Configure(configuration.GetSection(nameof(T))); - public static IServiceCollection AddEnvelopeGenerator(this IServiceCollection services, IConfiguration config) => services.AddEnvelopeGenerator( dispatcherConfigSection: config.GetSection("DispatcherConfig"), mailConfigSection: config.GetSection("MailConfig"), smsConfigSection: config.GetSection("SmsConfig"), codeGeneratorConfigSection: config.GetSection("CodeGeneratorParams"), envelopeReceiverCacheParamsSection: config.GetSection("EnvelopeReceiverCacheParams"), - totpSmsParamsSection: config.GetSection("TotpSmsParams"), config); + totpSmsParamsSection: config.GetSection("TotpSmsParams")); } } \ No newline at end of file From 363329ca18660e6eeb31c281dc63706a9e2b522c Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Fri, 31 Jan 2025 11:54:49 +0100 Subject: [PATCH 21/27] refaktor: Vereinfachung der DI-Konfiguration und Verbesserung der Wiederverwendbarkeit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Entfernte redundante `AddEnvelopeGenerator`-Überladung. - Einführung der Erweiterungsmethode `ConfigureByTypeName` für eine sauberere Konfiguration. - Ersetzte explizite Konfigurationsaufrufe durch `ConfigureByTypeName`. - Verbesserte Wartbarkeit durch Reduzierung von redundantem Code. - Markierte `ConfigureByTypeName` zur zukünftigen Verlagerung nach `DigitalData.Core`. --- .../EnvelopeReceiverCacheParams.cs | 17 -------------- .../Extensions/DIExtensions.cs | 23 ++++++++----------- .../Controllers/HomeController.cs | 1 + EnvelopeGenerator.Web/appsettings.json | 2 +- 4 files changed, 11 insertions(+), 32 deletions(-) delete mode 100644 EnvelopeGenerator.Application/Configurations/EnvelopeReceiverCacheParams.cs diff --git a/EnvelopeGenerator.Application/Configurations/EnvelopeReceiverCacheParams.cs b/EnvelopeGenerator.Application/Configurations/EnvelopeReceiverCacheParams.cs deleted file mode 100644 index 5d51941a..00000000 --- a/EnvelopeGenerator.Application/Configurations/EnvelopeReceiverCacheParams.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace EnvelopeGenerator.Application.Configurations -{ - public class EnvelopeReceiverCacheParams - { - /// - /// Gets the cache key format for SMS codes. - /// The placeholder {0} represents the envelopeReceiverId. - /// - public string CodeCacheKeyFormat { get; init; } = "sms-code-{0}"; - - /// - /// Gets the cache expiration key format for SMS codes. - /// The placeholder {0} represents the envelopeReceiverId. - /// - public string CodeExpirationCacheKeyFormat { get; init; } = "sms-code-expiration-{0}"; - } -} \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Extensions/DIExtensions.cs b/EnvelopeGenerator.Application/Extensions/DIExtensions.cs index 2a81c47a..4ece3817 100644 --- a/EnvelopeGenerator.Application/Extensions/DIExtensions.cs +++ b/EnvelopeGenerator.Application/Extensions/DIExtensions.cs @@ -16,7 +16,7 @@ namespace EnvelopeGenerator.Application.Extensions { public static class DIExtensions { - public static IServiceCollection AddEnvelopeGenerator(this IServiceCollection services, IConfigurationSection dispatcherConfigSection, IConfigurationSection mailConfigSection, IConfigurationSection smsConfigSection, IConfigurationSection codeGeneratorConfigSection, IConfigurationSection envelopeReceiverCacheParamsSection, IConfigurationSection totpSmsParamsSection) + public static IServiceCollection AddEnvelopeGenerator(this IServiceCollection services, IConfiguration config) { //Inject CRUD Service and repositoriesad services.TryAddScoped(); @@ -54,13 +54,12 @@ namespace EnvelopeGenerator.Application.Extensions services.AddAutoMapper(typeof(BasicDtoMappingProfile).Assembly); services.AddAutoMapper(typeof(UserMappingProfile).Assembly); - services.Configure(dispatcherConfigSection); - services.Configure(mailConfigSection); - services.Configure(codeGeneratorConfigSection); - services.Configure(envelopeReceiverCacheParamsSection); - services.Configure(totpSmsParamsSection); + services.ConfigureByTypeName(config); + services.ConfigureByTypeName(config); + services.ConfigureByTypeName(config); + services.ConfigureByTypeName(config); - services.AddHttpClientService(smsConfigSection); + services.AddHttpClientService(config.GetSection(nameof(SmsParams))); services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); @@ -69,12 +68,8 @@ namespace EnvelopeGenerator.Application.Extensions return services; } - public static IServiceCollection AddEnvelopeGenerator(this IServiceCollection services, IConfiguration config) => services.AddEnvelopeGenerator( - dispatcherConfigSection: config.GetSection("DispatcherConfig"), - mailConfigSection: config.GetSection("MailConfig"), - smsConfigSection: config.GetSection("SmsConfig"), - codeGeneratorConfigSection: config.GetSection("CodeGeneratorParams"), - envelopeReceiverCacheParamsSection: config.GetSection("EnvelopeReceiverCacheParams"), - totpSmsParamsSection: config.GetSection("TotpSmsParams")); + //TODO: move to DigitalData.Core + private static IServiceCollection ConfigureByTypeName(this IServiceCollection services, IConfiguration configuration) where TOptions : class + => services.Configure(configuration.GetSection(nameof(TOptions))); } } \ No newline at end of file diff --git a/EnvelopeGenerator.Web/Controllers/HomeController.cs b/EnvelopeGenerator.Web/Controllers/HomeController.cs index 974206eb..abf5afff 100644 --- a/EnvelopeGenerator.Web/Controllers/HomeController.cs +++ b/EnvelopeGenerator.Web/Controllers/HomeController.cs @@ -23,6 +23,7 @@ using EnvelopeGenerator.Application.Extensions; using Microsoft.Extensions.Caching.Distributed; using System.Globalization; using Microsoft.Extensions.Options; +using EnvelopeGenerator.Application.Configurations; namespace EnvelopeGenerator.Web.Controllers { diff --git a/EnvelopeGenerator.Web/appsettings.json b/EnvelopeGenerator.Web/appsettings.json index 500b55c1..05320652 100644 --- a/EnvelopeGenerator.Web/appsettings.json +++ b/EnvelopeGenerator.Web/appsettings.json @@ -124,7 +124,7 @@ "GTXMessagingConfig": { "AuthKey": "ep$?A!Gs" }, - "SmsConfig": { + "SmsParams": { "Uri": "https://rest.gtx-messaging.net", "Path": "smsc/sendsms/f566f7e5-bdf2-4a9a-bf52-ed88215a432e/json", "Headers": {}, From 120c8623ddeb77d8005ccdca3df4e90c4feb134a Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Fri, 31 Jan 2025 12:51:44 +0100 Subject: [PATCH 22/27] refactor(Application.Configurations): Config-Suffix in Params umbenannt. --- .../Configurations/DispatcherConfig.cs | 13 ------------- .../Configurations/DispatcherParams.cs | 12 ++++++++++++ .../Configurations/MailConfig.cs | 7 ------- .../Configurations/MailParams.cs | 6 ++++++ .../Extensions/DIExtensions.cs | 4 ++-- .../Services/EnvelopeMailService.cs | 4 ++-- EnvelopeGenerator.Web/Program.cs | 3 --- EnvelopeGenerator.Web/appsettings.json | 4 ++-- 8 files changed, 24 insertions(+), 29 deletions(-) delete mode 100644 EnvelopeGenerator.Application/Configurations/DispatcherConfig.cs create mode 100644 EnvelopeGenerator.Application/Configurations/DispatcherParams.cs delete mode 100644 EnvelopeGenerator.Application/Configurations/MailConfig.cs create mode 100644 EnvelopeGenerator.Application/Configurations/MailParams.cs diff --git a/EnvelopeGenerator.Application/Configurations/DispatcherConfig.cs b/EnvelopeGenerator.Application/Configurations/DispatcherConfig.cs deleted file mode 100644 index 7e261241..00000000 --- a/EnvelopeGenerator.Application/Configurations/DispatcherConfig.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace EnvelopeGenerator.Application.Configurations -{ - public class DispatcherConfig - { - public int SendingProfile { get; init; } = 1; - - public string AddedWho { get; init; } = "DDEnvelopGenerator"; - - public int ReminderTypeId { get; init; } = 202377; - - public string EmailAttmt1 { get; init; } = string.Empty; - } -} \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Configurations/DispatcherParams.cs b/EnvelopeGenerator.Application/Configurations/DispatcherParams.cs new file mode 100644 index 00000000..ca152205 --- /dev/null +++ b/EnvelopeGenerator.Application/Configurations/DispatcherParams.cs @@ -0,0 +1,12 @@ +namespace EnvelopeGenerator.Application.Configurations; + +public class DispatcherParams +{ + public int SendingProfile { get; init; } = 1; + + public string AddedWho { get; init; } = "DDEnvelopGenerator"; + + public int ReminderTypeId { get; init; } = 202377; + + public string EmailAttmt1 { get; init; } = string.Empty; +} \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Configurations/MailConfig.cs b/EnvelopeGenerator.Application/Configurations/MailConfig.cs deleted file mode 100644 index b3a4d695..00000000 --- a/EnvelopeGenerator.Application/Configurations/MailConfig.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace EnvelopeGenerator.Application.Configurations -{ - public class MailConfig - { - public required Dictionary Placeholders { get; init; } - } -} \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Configurations/MailParams.cs b/EnvelopeGenerator.Application/Configurations/MailParams.cs new file mode 100644 index 00000000..f0a14796 --- /dev/null +++ b/EnvelopeGenerator.Application/Configurations/MailParams.cs @@ -0,0 +1,6 @@ +namespace EnvelopeGenerator.Application.Configurations; + +public class MailParams +{ + public required Dictionary Placeholders { get; init; } +} \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Extensions/DIExtensions.cs b/EnvelopeGenerator.Application/Extensions/DIExtensions.cs index 4ece3817..3ad13d27 100644 --- a/EnvelopeGenerator.Application/Extensions/DIExtensions.cs +++ b/EnvelopeGenerator.Application/Extensions/DIExtensions.cs @@ -54,8 +54,8 @@ namespace EnvelopeGenerator.Application.Extensions services.AddAutoMapper(typeof(BasicDtoMappingProfile).Assembly); services.AddAutoMapper(typeof(UserMappingProfile).Assembly); - services.ConfigureByTypeName(config); - services.ConfigureByTypeName(config); + services.ConfigureByTypeName(config); + services.ConfigureByTypeName(config); services.ConfigureByTypeName(config); services.ConfigureByTypeName(config); diff --git a/EnvelopeGenerator.Application/Services/EnvelopeMailService.cs b/EnvelopeGenerator.Application/Services/EnvelopeMailService.cs index 99a77ca0..235383d6 100644 --- a/EnvelopeGenerator.Application/Services/EnvelopeMailService.cs +++ b/EnvelopeGenerator.Application/Services/EnvelopeMailService.cs @@ -21,12 +21,12 @@ namespace EnvelopeGenerator.Application.Services { private readonly IEmailTemplateService _tempService; private readonly IEnvelopeReceiverService _envRcvService; - private readonly DispatcherConfig _dConfig; + private readonly DispatcherParams _dConfig; private readonly IConfigService _configService; private readonly Dictionary _placeholders; private readonly ICodeGenerator _codeGenerator; - public EnvelopeMailService(IEmailOutRepository repository, IMapper mapper, IEmailTemplateService tempService, IEnvelopeReceiverService envelopeReceiverService, IOptions dispatcherConfigOptions, IConfigService configService, IOptions mailConfig, ICodeGenerator codeGenerator) : base(repository, mapper) + public EnvelopeMailService(IEmailOutRepository repository, IMapper mapper, IEmailTemplateService tempService, IEnvelopeReceiverService envelopeReceiverService, IOptions dispatcherConfigOptions, IConfigService configService, IOptions mailConfig, ICodeGenerator codeGenerator) : base(repository, mapper) { _tempService = tempService; _envRcvService = envelopeReceiverService; diff --git a/EnvelopeGenerator.Web/Program.cs b/EnvelopeGenerator.Web/Program.cs index 98dc62d3..fbf24996 100644 --- a/EnvelopeGenerator.Web/Program.cs +++ b/EnvelopeGenerator.Web/Program.cs @@ -16,7 +16,6 @@ using DigitalData.EmailProfilerDispatcher; using EnvelopeGenerator.Infrastructure; using EnvelopeGenerator.Web.Sanitizers; using EnvelopeGenerator.Application.Extensions; -using Microsoft.Extensions.DependencyInjection; var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger(); logger.Info("Logging initialized!"); @@ -50,8 +49,6 @@ try // Add higher order services builder.Services.AddScoped(); - builder.Services.Configure(config.GetSection("TotpSmsParams")); - // Add controllers and razor views builder.Services.AddControllersWithViews(options => { diff --git a/EnvelopeGenerator.Web/appsettings.json b/EnvelopeGenerator.Web/appsettings.json index 05320652..8d71fd3c 100644 --- a/EnvelopeGenerator.Web/appsettings.json +++ b/EnvelopeGenerator.Web/appsettings.json @@ -108,13 +108,13 @@ "ShowPageClass": "dd-show-logo", "LockedPageClass": "dd-locked-logo" }, - "DispatcherConfig": { + "DispatcherParams": { "SendingProfile": 1, "AddedWho": "DDEnvelopGenerator", "ReminderTypeId": 202377, "EmailAttmt1": "" }, - "MailConfig": { + "MailParams": { "Placeholders": { "[NAME_PORTAL]": "signFlow", "[SIGNATURE_TYPE]": "signieren", From 28fdf0a1159d30595b4bdb6286506f816df26f30 Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Fri, 31 Jan 2025 13:06:11 +0100 Subject: [PATCH 23/27] renamed(SmsParams): umbenannt in GtxMessagingParams --- .../Configurations/GtxMessaging/SmsParams.cs | 21 ------------------- .../Configurations/GtxMessagingParams.cs | 20 ++++++++++++++++++ .../Extensions/DIExtensions.cs | 3 +-- .../Services/GTXSmsSender.cs | 8 +++---- EnvelopeGenerator.Web/appsettings.json | 5 +---- 5 files changed, 26 insertions(+), 31 deletions(-) delete mode 100644 EnvelopeGenerator.Application/Configurations/GtxMessaging/SmsParams.cs create mode 100644 EnvelopeGenerator.Application/Configurations/GtxMessagingParams.cs diff --git a/EnvelopeGenerator.Application/Configurations/GtxMessaging/SmsParams.cs b/EnvelopeGenerator.Application/Configurations/GtxMessaging/SmsParams.cs deleted file mode 100644 index eae4b63f..00000000 --- a/EnvelopeGenerator.Application/Configurations/GtxMessaging/SmsParams.cs +++ /dev/null @@ -1,21 +0,0 @@ -using DigitalData.Core.Abstractions.Client; -namespace EnvelopeGenerator.Application.Configurations.GtxMessaging -{ - /// - /// https://www.gtx-messaging.com/en/api-docs/sms-rest-api/ - /// - public class SmsParams : IHttpClientOptions - { - public required string Uri { get; init; } - - public string? Path { get; init; } - - public Dictionary? Headers { get; init; } - - public Dictionary? QueryParams { get; init; } - - public string RecipientQueryParamName { get; init; } = "to"; - - public string MessageQueryParamName { get; init; } = "text"; - } -} \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Configurations/GtxMessagingParams.cs b/EnvelopeGenerator.Application/Configurations/GtxMessagingParams.cs new file mode 100644 index 00000000..837baf7d --- /dev/null +++ b/EnvelopeGenerator.Application/Configurations/GtxMessagingParams.cs @@ -0,0 +1,20 @@ +using DigitalData.Core.Abstractions.Client; +namespace EnvelopeGenerator.Application.Configurations; + +/// +/// https://www.gtx-messaging.com/en/api-docs/sms-rest-api/ +/// +public class GtxMessagingParams : IHttpClientOptions +{ + public required string Uri { get; init; } + + public string? Path { get; init; } + + public Dictionary? Headers { get; init; } + + public Dictionary? QueryParams { get; init; } + + public string RecipientQueryParamName { get; init; } = "to"; + + public string MessageQueryParamName { get; init; } = "text"; +} \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Extensions/DIExtensions.cs b/EnvelopeGenerator.Application/Extensions/DIExtensions.cs index 3ad13d27..7ef576c0 100644 --- a/EnvelopeGenerator.Application/Extensions/DIExtensions.cs +++ b/EnvelopeGenerator.Application/Extensions/DIExtensions.cs @@ -9,7 +9,6 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using DigitalData.Core.Client; -using EnvelopeGenerator.Application.Configurations.GtxMessaging; using QRCoder; namespace EnvelopeGenerator.Application.Extensions @@ -59,7 +58,7 @@ namespace EnvelopeGenerator.Application.Extensions services.ConfigureByTypeName(config); services.ConfigureByTypeName(config); - services.AddHttpClientService(config.GetSection(nameof(SmsParams))); + services.AddHttpClientService(config.GetSection(nameof(GtxMessagingParams))); services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); diff --git a/EnvelopeGenerator.Application/Services/GTXSmsSender.cs b/EnvelopeGenerator.Application/Services/GTXSmsSender.cs index 319700fb..5841d5d8 100644 --- a/EnvelopeGenerator.Application/Services/GTXSmsSender.cs +++ b/EnvelopeGenerator.Application/Services/GTXSmsSender.cs @@ -1,7 +1,7 @@ using AutoMapper; using DigitalData.Core.Abstractions.Client; using DigitalData.Core.Client; -using EnvelopeGenerator.Application.Configurations.GtxMessaging; +using EnvelopeGenerator.Application.Configurations; using EnvelopeGenerator.Application.Contracts; using EnvelopeGenerator.Application.DTOs.Messaging; using Microsoft.Extensions.Options; @@ -11,15 +11,15 @@ namespace EnvelopeGenerator.Application.Services; //TODO: move to DigitalData.Core public class GTXSmsSender : ISmsSender { - private readonly IHttpClientService _smsClient; + private readonly IHttpClientService _smsClient; - private readonly SmsParams _smsParams; + private readonly GtxMessagingParams _smsParams; private readonly IMapper _mapper; public string ServiceProvider { get; } - public GTXSmsSender(IHttpClientService smsClient, IOptions smsParamsOptions, IMapper mapper) + public GTXSmsSender(IHttpClientService smsClient, IOptions smsParamsOptions, IMapper mapper) { _smsClient = smsClient; _smsParams = smsParamsOptions.Value; diff --git a/EnvelopeGenerator.Web/appsettings.json b/EnvelopeGenerator.Web/appsettings.json index 8d71fd3c..6b8481b9 100644 --- a/EnvelopeGenerator.Web/appsettings.json +++ b/EnvelopeGenerator.Web/appsettings.json @@ -121,10 +121,7 @@ "[REASON]": "" } }, - "GTXMessagingConfig": { - "AuthKey": "ep$?A!Gs" - }, - "SmsParams": { + "GtxMessagingParams": { "Uri": "https://rest.gtx-messaging.net", "Path": "smsc/sendsms/f566f7e5-bdf2-4a9a-bf52-ed88215a432e/json", "Headers": {}, From aa918d875d52db92e7bd555d8fadd8a6dca44172 Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Fri, 31 Jan 2025 13:10:55 +0100 Subject: [PATCH 24/27] refactor(JWT): Ungenutzte Schnittstelle und Controller entfernt --- .../Contracts/IJWTService.cs | 24 ----------- .../Controllers/Test/TestAuthController.cs | 42 ------------------- 2 files changed, 66 deletions(-) delete mode 100644 EnvelopeGenerator.Application/Contracts/IJWTService.cs delete mode 100644 EnvelopeGenerator.Web/Controllers/Test/TestAuthController.cs diff --git a/EnvelopeGenerator.Application/Contracts/IJWTService.cs b/EnvelopeGenerator.Application/Contracts/IJWTService.cs deleted file mode 100644 index 138b8643..00000000 --- a/EnvelopeGenerator.Application/Contracts/IJWTService.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Microsoft.IdentityModel.Tokens; -using System.IdentityModel.Tokens.Jwt; -using System.Security.Claims; -using System.Security.Cryptography; - -namespace EnvelopeGenerator.Application.Contracts -{ - public interface IJWTService - { - public static SymmetricSecurityKey GenerateSecurityKey(int byteSize = 32) - { - using var rng = RandomNumberGenerator.Create(); - var randomBytes = new byte[byteSize]; - rng.GetBytes(randomBytes); - var securityKey = new SymmetricSecurityKey(randomBytes); - - return securityKey; - } - - string GenerateToken(TClaimValue claimValue); - - JwtSecurityToken? ReadSecurityToken(string token); - } -} \ No newline at end of file diff --git a/EnvelopeGenerator.Web/Controllers/Test/TestAuthController.cs b/EnvelopeGenerator.Web/Controllers/Test/TestAuthController.cs deleted file mode 100644 index 07f838cf..00000000 --- a/EnvelopeGenerator.Web/Controllers/Test/TestAuthController.cs +++ /dev/null @@ -1,42 +0,0 @@ -using EnvelopeGenerator.Application.Contracts; -using EnvelopeGenerator.Application.Services; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using System.Security.Claims; - -namespace EnvelopeGenerator.Web.Controllers.Test -{ - [ApiController] - [Route("api/test/[controller]")] - public class TestAuthController : ControllerBase - { - private readonly IJWTService _authService; - - public TestAuthController(IJWTService authService) - { - _authService = authService; - } - - [HttpPost] - public IActionResult ProvideToken([FromQuery] string value) - { - var token = _authService.GenerateToken(value); - return Ok(token); - } - - [HttpGet] - public IActionResult GetSecurityToken([FromQuery] string token) - { - var sToken = _authService.ReadSecurityToken(token); - return Ok(sToken); - } - - [HttpGet("Username")] - [Authorize] - public IActionResult Getname() - { - var username = User.Claims?.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value; - return Ok(username); - } - } -} \ No newline at end of file From 772d5107057a2270cb68de5ea3d62e2188d094c9 Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Fri, 31 Jan 2025 14:59:39 +0100 Subject: [PATCH 25/27] =?UTF-8?q?feat(EnvelopeSmsService):=20SendTotpAsync?= =?UTF-8?q?-Methode=20hinzuf=C3=BCgen,=20um=20totp=20unter=20Ber=C3=BCcksi?= =?UTF-8?q?chtigung=20der=20Ablaufzeit=20zu=20senden.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Contracts/IEnvelopeSmsHandler.cs | 15 ++++++ .../Contracts/IEnvelopeSmsService.cs | 5 -- .../Extensions/DIExtensions.cs | 2 +- .../Services/EnvelopeSmsHandler.cs | 50 +++++++++++++++++++ .../Services/EnvelopeSmsService.cs | 18 ------- .../Controllers/HomeController.cs | 27 ++++------ 6 files changed, 76 insertions(+), 41 deletions(-) create mode 100644 EnvelopeGenerator.Application/Contracts/IEnvelopeSmsHandler.cs delete mode 100644 EnvelopeGenerator.Application/Contracts/IEnvelopeSmsService.cs create mode 100644 EnvelopeGenerator.Application/Services/EnvelopeSmsHandler.cs delete mode 100644 EnvelopeGenerator.Application/Services/EnvelopeSmsService.cs diff --git a/EnvelopeGenerator.Application/Contracts/IEnvelopeSmsHandler.cs b/EnvelopeGenerator.Application/Contracts/IEnvelopeSmsHandler.cs new file mode 100644 index 00000000..6397ecef --- /dev/null +++ b/EnvelopeGenerator.Application/Contracts/IEnvelopeSmsHandler.cs @@ -0,0 +1,15 @@ +using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver; +using EnvelopeGenerator.Application.DTOs.Messaging; + +namespace EnvelopeGenerator.Application.Contracts; + +public interface IEnvelopeSmsHandler +{ + /// + /// If expiration is passed then, sends sms and returns smsResponse and up-to-date expiration; otherwise send expiration. + /// + /// + /// + /// + Task<(SmsResponse? SmsResponse, DateTime Expiration)> SendTotpAsync(EnvelopeReceiverSecretDto er_secret, CancellationToken cToken = default); +} \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Contracts/IEnvelopeSmsService.cs b/EnvelopeGenerator.Application/Contracts/IEnvelopeSmsService.cs deleted file mode 100644 index 6efc6abf..00000000 --- a/EnvelopeGenerator.Application/Contracts/IEnvelopeSmsService.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace EnvelopeGenerator.Application.Contracts; - -public interface IEnvelopeSmsService -{ -} \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Extensions/DIExtensions.cs b/EnvelopeGenerator.Application/Extensions/DIExtensions.cs index 7ef576c0..59c56724 100644 --- a/EnvelopeGenerator.Application/Extensions/DIExtensions.cs +++ b/EnvelopeGenerator.Application/Extensions/DIExtensions.cs @@ -60,7 +60,7 @@ namespace EnvelopeGenerator.Application.Extensions services.AddHttpClientService(config.GetSection(nameof(GtxMessagingParams))); services.TryAddSingleton(); - services.TryAddSingleton(); + services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); diff --git a/EnvelopeGenerator.Application/Services/EnvelopeSmsHandler.cs b/EnvelopeGenerator.Application/Services/EnvelopeSmsHandler.cs new file mode 100644 index 00000000..e4f71d58 --- /dev/null +++ b/EnvelopeGenerator.Application/Services/EnvelopeSmsHandler.cs @@ -0,0 +1,50 @@ +using EnvelopeGenerator.Application.Configurations; +using EnvelopeGenerator.Application.Contracts; +using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver; +using EnvelopeGenerator.Application.DTOs.Messaging; +using EnvelopeGenerator.Application.Extensions; +using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.Options; + +namespace EnvelopeGenerator.Application.Services; + +public class EnvelopeSmsHandler : IEnvelopeSmsHandler +{ + private readonly ISmsSender _sender; + + private readonly TotpSmsParams _totpSmsParams; + + private readonly IDistributedCache _dCache; + + private readonly ICodeGenerator _codeGenerator; + + public EnvelopeSmsHandler(ISmsSender sender, IOptions totpSmsParamsOptions, IDistributedCache distributedCache, ICodeGenerator codeGenerator) + { + _sender = sender; + _totpSmsParams = totpSmsParamsOptions.Value; + _dCache = distributedCache; + _codeGenerator = codeGenerator; + } + + /// + /// If expiration is passed then, sends sms and returns smsResponse and up-to-date expiration; otherwise send expiration. + /// + /// + /// + /// + public async Task<(SmsResponse? SmsResponse, DateTime Expiration)> SendTotpAsync(EnvelopeReceiverSecretDto er_secret, CancellationToken cToken = default) + { + var key = string.Format(_totpSmsParams.Expiration.CacheKeyFormat, er_secret.EnvelopeId, er_secret.ReceiverId); + var expiration = await _dCache.GetDateTimeAsync(key, cToken); + + if(expiration is DateTime expirationDateTime && expirationDateTime < DateTime.Now) + return (null, expirationDateTime); + else + { + var new_expiration = DateTime.Now.AddSeconds(_totpSmsParams.TotpStep); + var totp = _codeGenerator.GenerateTotp(er_secret.Receiver!.TotpSecretkey!, _totpSmsParams.TotpStep); + var msg = string.Format(_totpSmsParams.Format, totp, new_expiration.ToString(_totpSmsParams.Expiration.Format, _totpSmsParams.Expiration.CultureInfo)); + return (await _sender.SendSmsAsync(er_secret.PhoneNumber!, msg), new_expiration); + } + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Services/EnvelopeSmsService.cs b/EnvelopeGenerator.Application/Services/EnvelopeSmsService.cs deleted file mode 100644 index 075e0249..00000000 --- a/EnvelopeGenerator.Application/Services/EnvelopeSmsService.cs +++ /dev/null @@ -1,18 +0,0 @@ -using EnvelopeGenerator.Application.Configurations; -using EnvelopeGenerator.Application.Contracts; -using Microsoft.Extensions.Options; - -namespace EnvelopeGenerator.Application.Services; - -public class EnvelopeSmsService : IEnvelopeSmsService -{ - private readonly ISmsSender _sender; - - private readonly TotpSmsParams _totpSmsParams; - - public EnvelopeSmsService(ISmsSender sender, IOptions totpSmsParamsOptions) - { - _sender = sender; - _totpSmsParams = totpSmsParamsOptions.Value; - } -} \ No newline at end of file diff --git a/EnvelopeGenerator.Web/Controllers/HomeController.cs b/EnvelopeGenerator.Web/Controllers/HomeController.cs index abf5afff..8d5db4e8 100644 --- a/EnvelopeGenerator.Web/Controllers/HomeController.cs +++ b/EnvelopeGenerator.Web/Controllers/HomeController.cs @@ -21,9 +21,9 @@ using EnvelopeGenerator.Application.DTOs; using DigitalData.Core.Client; using EnvelopeGenerator.Application.Extensions; using Microsoft.Extensions.Caching.Distributed; -using System.Globalization; using Microsoft.Extensions.Options; using EnvelopeGenerator.Application.Configurations; +using EnvelopeGenerator.Application.DTOs.Messaging; namespace EnvelopeGenerator.Web.Controllers { @@ -44,8 +44,9 @@ namespace EnvelopeGenerator.Web.Controllers private readonly IReceiverService _rcvService; private readonly IDistributedCache _dCache; private readonly TotpSmsParams _totpSmsParams; + private readonly IEnvelopeSmsHandler _envSmsHandler; - public HomeController(EnvelopeOldService envelopeOldService, ILogger logger, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeHistoryService historyService, IStringLocalizer localizer, IConfiguration configuration, HtmlSanitizer sanitizer, Cultures cultures, IEnvelopeMailService envelopeMailService, IEnvelopeReceiverReadOnlyService readOnlyService, ISmsSender messagingService, ICodeGenerator codeGenerator, IReceiverService receiverService, IDistributedCache distributedCache, IOptions totpSmsParamsOptions) + public HomeController(EnvelopeOldService envelopeOldService, ILogger logger, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeHistoryService historyService, IStringLocalizer localizer, IConfiguration configuration, HtmlSanitizer sanitizer, Cultures cultures, IEnvelopeMailService envelopeMailService, IEnvelopeReceiverReadOnlyService readOnlyService, ISmsSender messagingService, ICodeGenerator codeGenerator, IReceiverService receiverService, IDistributedCache distributedCache, IOptions totpSmsParamsOptions, IEnvelopeSmsHandler envelopeSmsService) { this.envelopeOldService = envelopeOldService; _envRcvService = envelopeReceiverService; @@ -62,6 +63,7 @@ namespace EnvelopeGenerator.Web.Controllers _rcvService = receiverService; _dCache = distributedCache; _totpSmsParams = totpSmsParamsOptions.Value; + _envSmsHandler = envelopeSmsService; } [HttpGet("/")] @@ -174,22 +176,13 @@ namespace EnvelopeGenerator.Web.Controllers { if (viaSms) { - //TODO: create a service (like EnvelopeSmsService) - //add date time cache - var key = string.Format(_totpSmsParams.Expiration.CacheKeyFormat, er_secret.EnvelopeId, er_secret.ReceiverId); - var expiration = await _dCache.GetDateTimeAsync(key); - if (expiration is null || expiration <= DateTime.Now) + var (smsRes, expiration) = await _envSmsHandler.SendTotpAsync(er_secret); + + if (smsRes is not null && smsRes.Failed) { - var new_expiration = DateTime.Now.AddSeconds(_totpSmsParams.TotpStep); - var totp = _codeGenerator.GenerateTotp(er_secret.Receiver!.TotpSecretkey!, _totpSmsParams.TotpStep); - var msg = string.Format(_totpSmsParams.Format, totp, new_expiration.ToString(_totpSmsParams.Expiration.Format, _totpSmsParams.Expiration.CultureInfo)); - var smsRes = await _msgService.SendSmsAsync(er_secret.PhoneNumber!, msg); - if (smsRes.Failed) - { - var res_json = JsonConvert.SerializeObject(smsRes); - _logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, message: $"An unexpected error occurred while sending an SMS code. Response: ${res_json}"); - return this.ViewInnerServiceError(); - } + var res_json = JsonConvert.SerializeObject(smsRes); + _logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, message: $"An unexpected error occurred while sending an SMS code. Response: ${res_json}"); + return this.ViewInnerServiceError(); } return View("EnvelopeLocked").WithData("CodeType", "smsCode").WithData("SmsExpiration", expiration); From bbd03615e11fbb9daf867855a7acc696920da085 Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Mon, 3 Feb 2025 09:52:46 +0100 Subject: [PATCH 26/27] =?UTF-8?q?feat(EnvelopeSmsHandler):=20Methode=20Ver?= =?UTF-8?q?ifyTotp=20hinzugef=C3=BCgt,=20um=20Totp=20mit=20TotpVerificatio?= =?UTF-8?q?nWindow=20von=20TotpSmsParams=20zu=20verifizieren.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Configurations/TotpSmsParams.cs | 18 +++++++++++++++++- .../Contracts/IEnvelopeSmsHandler.cs | 2 ++ .../Services/EnvelopeSmsHandler.cs | 3 +++ .../Controllers/HomeController.cs | 16 +++------------- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/EnvelopeGenerator.Application/Configurations/TotpSmsParams.cs b/EnvelopeGenerator.Application/Configurations/TotpSmsParams.cs index 13501fe4..8e9c1765 100644 --- a/EnvelopeGenerator.Application/Configurations/TotpSmsParams.cs +++ b/EnvelopeGenerator.Application/Configurations/TotpSmsParams.cs @@ -1,4 +1,5 @@ -using System.Globalization; +using OtpNet; +using System.Globalization; namespace EnvelopeGenerator.Application.Configurations { @@ -13,6 +14,21 @@ namespace EnvelopeGenerator.Application.Configurations public ExpirationHandler Expiration { get; init; } = new(); + public VerificationWindow? TotpVerificationWindow { get; private init; } = VerificationWindow.RfcSpecifiedNetworkDelay; + + private IEnumerable? _tvwParams; + + public IEnumerable? TotpVerificationWindowParams + { + get => _tvwParams; + init + { + _tvwParams = value; + if(_tvwParams is not null) + TotpVerificationWindow = new(previous: _tvwParams.ElementAtOrDefault(0), future: _tvwParams.ElementAtOrDefault(0)); + } + } + public class ExpirationHandler { public string CacheKeyFormat { get; init; } = "e{0}_r{1}_sms_code_expiration"; diff --git a/EnvelopeGenerator.Application/Contracts/IEnvelopeSmsHandler.cs b/EnvelopeGenerator.Application/Contracts/IEnvelopeSmsHandler.cs index 6397ecef..746988ab 100644 --- a/EnvelopeGenerator.Application/Contracts/IEnvelopeSmsHandler.cs +++ b/EnvelopeGenerator.Application/Contracts/IEnvelopeSmsHandler.cs @@ -12,4 +12,6 @@ public interface IEnvelopeSmsHandler /// /// Task<(SmsResponse? SmsResponse, DateTime Expiration)> SendTotpAsync(EnvelopeReceiverSecretDto er_secret, CancellationToken cToken = default); + + bool VerifyTotp(string totpCode, string secretKey); } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Services/EnvelopeSmsHandler.cs b/EnvelopeGenerator.Application/Services/EnvelopeSmsHandler.cs index e4f71d58..0a72c7d4 100644 --- a/EnvelopeGenerator.Application/Services/EnvelopeSmsHandler.cs +++ b/EnvelopeGenerator.Application/Services/EnvelopeSmsHandler.cs @@ -47,4 +47,7 @@ public class EnvelopeSmsHandler : IEnvelopeSmsHandler return (await _sender.SendSmsAsync(er_secret.PhoneNumber!, msg), new_expiration); } } + + public bool VerifyTotp(string totpCode, string secretKey) => _codeGenerator + .VerifyTotp(totpCode, secretKey, _totpSmsParams.TotpStep, _totpSmsParams.TotpVerificationWindow); } \ No newline at end of file diff --git a/EnvelopeGenerator.Web/Controllers/HomeController.cs b/EnvelopeGenerator.Web/Controllers/HomeController.cs index 8d5db4e8..3a75b946 100644 --- a/EnvelopeGenerator.Web/Controllers/HomeController.cs +++ b/EnvelopeGenerator.Web/Controllers/HomeController.cs @@ -20,10 +20,6 @@ using Newtonsoft.Json; using EnvelopeGenerator.Application.DTOs; using DigitalData.Core.Client; using EnvelopeGenerator.Application.Extensions; -using Microsoft.Extensions.Caching.Distributed; -using Microsoft.Extensions.Options; -using EnvelopeGenerator.Application.Configurations; -using EnvelopeGenerator.Application.DTOs.Messaging; namespace EnvelopeGenerator.Web.Controllers { @@ -39,14 +35,11 @@ namespace EnvelopeGenerator.Web.Controllers private readonly Cultures _cultures; private readonly IEnvelopeMailService _mailService; private readonly IEnvelopeReceiverReadOnlyService _readOnlyService; - private readonly ISmsSender _msgService; private readonly ICodeGenerator _codeGenerator; private readonly IReceiverService _rcvService; - private readonly IDistributedCache _dCache; - private readonly TotpSmsParams _totpSmsParams; private readonly IEnvelopeSmsHandler _envSmsHandler; - public HomeController(EnvelopeOldService envelopeOldService, ILogger logger, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeHistoryService historyService, IStringLocalizer localizer, IConfiguration configuration, HtmlSanitizer sanitizer, Cultures cultures, IEnvelopeMailService envelopeMailService, IEnvelopeReceiverReadOnlyService readOnlyService, ISmsSender messagingService, ICodeGenerator codeGenerator, IReceiverService receiverService, IDistributedCache distributedCache, IOptions totpSmsParamsOptions, IEnvelopeSmsHandler envelopeSmsService) + public HomeController(EnvelopeOldService envelopeOldService, ILogger logger, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeHistoryService historyService, IStringLocalizer localizer, IConfiguration configuration, HtmlSanitizer sanitizer, Cultures cultures, IEnvelopeMailService envelopeMailService, IEnvelopeReceiverReadOnlyService readOnlyService, ICodeGenerator codeGenerator, IReceiverService receiverService, IEnvelopeSmsHandler envelopeSmsService) { this.envelopeOldService = envelopeOldService; _envRcvService = envelopeReceiverService; @@ -58,11 +51,8 @@ namespace EnvelopeGenerator.Web.Controllers _mailService = envelopeMailService; _logger = logger; _readOnlyService = readOnlyService; - _msgService = messagingService; _codeGenerator = codeGenerator; _rcvService = receiverService; - _dCache = distributedCache; - _totpSmsParams = totpSmsParamsOptions.Value; _envSmsHandler = envelopeSmsService; } @@ -230,8 +220,8 @@ namespace EnvelopeGenerator.Web.Controllers { if (er_secret.Receiver!.TotpSecretkey is null) throw new InvalidOperationException($"TotpSecretkey of DTO cannot validate without TotpSecretkey. Dto: {JsonConvert.SerializeObject(er_secret)}"); - - if (_codeGenerator.VerifyTotp(auth.SmsCode!, er_secret.Receiver.TotpSecretkey, step: _totpSmsParams.TotpStep)) + + if (_envSmsHandler.VerifyTotp(auth.SmsCode!, er_secret.Receiver.TotpSecretkey)) { Response.StatusCode = StatusCodes.Status401Unauthorized; ViewData["ErrorMessage"] = _localizer[WebKey.WrongAccessCode].Value; From 808a02968b5d5a77d69148cb1a5da134875efe93 Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Mon, 3 Feb 2025 09:58:57 +0100 Subject: [PATCH 27/27] refactor(CodeGenerator): umbenannt in Authenticator --- .../{CodeGeneratorParams.cs => AuthenticatorParams.cs} | 2 +- .../Contracts/{ICodeGenerator.cs => IAuthenticator.cs} | 2 +- .../Extensions/DIExtensions.cs | 4 ++-- .../Services/{CodeGenerator.cs => Authenticator.cs} | 10 +++++----- .../Services/EnvelopeMailService.cs | 8 ++++---- .../Services/EnvelopeSmsHandler.cs | 10 +++++----- EnvelopeGenerator.Web/Controllers/HomeController.cs | 8 ++++---- 7 files changed, 22 insertions(+), 22 deletions(-) rename EnvelopeGenerator.Application/Configurations/{CodeGeneratorParams.cs => AuthenticatorParams.cs} (95%) rename EnvelopeGenerator.Application/Contracts/{ICodeGenerator.cs => IAuthenticator.cs} (94%) rename EnvelopeGenerator.Application/Services/{CodeGenerator.cs => Authenticator.cs} (88%) diff --git a/EnvelopeGenerator.Application/Configurations/CodeGeneratorParams.cs b/EnvelopeGenerator.Application/Configurations/AuthenticatorParams.cs similarity index 95% rename from EnvelopeGenerator.Application/Configurations/CodeGeneratorParams.cs rename to EnvelopeGenerator.Application/Configurations/AuthenticatorParams.cs index 2ba65399..bfec74f1 100644 --- a/EnvelopeGenerator.Application/Configurations/CodeGeneratorParams.cs +++ b/EnvelopeGenerator.Application/Configurations/AuthenticatorParams.cs @@ -1,6 +1,6 @@ namespace EnvelopeGenerator.Application.Configurations { - public class CodeGeneratorParams + public class AuthenticatorParams { public string CharPool { get; init; } = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789012345678901234567890123456789"; diff --git a/EnvelopeGenerator.Application/Contracts/ICodeGenerator.cs b/EnvelopeGenerator.Application/Contracts/IAuthenticator.cs similarity index 94% rename from EnvelopeGenerator.Application/Contracts/ICodeGenerator.cs rename to EnvelopeGenerator.Application/Contracts/IAuthenticator.cs index d4e93c6b..1e3cf1a0 100644 --- a/EnvelopeGenerator.Application/Contracts/ICodeGenerator.cs +++ b/EnvelopeGenerator.Application/Contracts/IAuthenticator.cs @@ -2,7 +2,7 @@ namespace EnvelopeGenerator.Application.Contracts { - public interface ICodeGenerator + public interface IAuthenticator { string GenerateCode(int length); diff --git a/EnvelopeGenerator.Application/Extensions/DIExtensions.cs b/EnvelopeGenerator.Application/Extensions/DIExtensions.cs index 59c56724..6ebadb61 100644 --- a/EnvelopeGenerator.Application/Extensions/DIExtensions.cs +++ b/EnvelopeGenerator.Application/Extensions/DIExtensions.cs @@ -55,13 +55,13 @@ namespace EnvelopeGenerator.Application.Extensions services.ConfigureByTypeName(config); services.ConfigureByTypeName(config); - services.ConfigureByTypeName(config); + services.ConfigureByTypeName(config); services.ConfigureByTypeName(config); services.AddHttpClientService(config.GetSection(nameof(GtxMessagingParams))); services.TryAddSingleton(); services.TryAddSingleton(); - services.TryAddSingleton(); + services.TryAddSingleton(); services.TryAddSingleton(); return services; diff --git a/EnvelopeGenerator.Application/Services/CodeGenerator.cs b/EnvelopeGenerator.Application/Services/Authenticator.cs similarity index 88% rename from EnvelopeGenerator.Application/Services/CodeGenerator.cs rename to EnvelopeGenerator.Application/Services/Authenticator.cs index ca84bfc9..af410d9a 100644 --- a/EnvelopeGenerator.Application/Services/CodeGenerator.cs +++ b/EnvelopeGenerator.Application/Services/Authenticator.cs @@ -7,17 +7,17 @@ using System.Text; namespace EnvelopeGenerator.Application.Services { - public class CodeGenerator : ICodeGenerator + public class Authenticator : IAuthenticator { - public static Lazy LazyStatic => new(() => new CodeGenerator(Options.Create(new()), new QRCodeGenerator())); + public static Lazy LazyStatic => new(() => new Authenticator(Options.Create(new()), new QRCodeGenerator())); - public static CodeGenerator Static => LazyStatic.Value; + public static Authenticator Static => LazyStatic.Value; - private readonly CodeGeneratorParams _params; + private readonly AuthenticatorParams _params; private readonly QRCodeGenerator _qrCodeGenerator; - public CodeGenerator(IOptions options, QRCodeGenerator qrCodeGenerator) + public Authenticator(IOptions options, QRCodeGenerator qrCodeGenerator) { _params = options.Value; _qrCodeGenerator = qrCodeGenerator; diff --git a/EnvelopeGenerator.Application/Services/EnvelopeMailService.cs b/EnvelopeGenerator.Application/Services/EnvelopeMailService.cs index 235383d6..afd313db 100644 --- a/EnvelopeGenerator.Application/Services/EnvelopeMailService.cs +++ b/EnvelopeGenerator.Application/Services/EnvelopeMailService.cs @@ -24,16 +24,16 @@ namespace EnvelopeGenerator.Application.Services private readonly DispatcherParams _dConfig; private readonly IConfigService _configService; private readonly Dictionary _placeholders; - private readonly ICodeGenerator _codeGenerator; + private readonly IAuthenticator _authenticator; - public EnvelopeMailService(IEmailOutRepository repository, IMapper mapper, IEmailTemplateService tempService, IEnvelopeReceiverService envelopeReceiverService, IOptions dispatcherConfigOptions, IConfigService configService, IOptions mailConfig, ICodeGenerator codeGenerator) : base(repository, mapper) + public EnvelopeMailService(IEmailOutRepository repository, IMapper mapper, IEmailTemplateService tempService, IEnvelopeReceiverService envelopeReceiverService, IOptions dispatcherConfigOptions, IConfigService configService, IOptions mailConfig, IAuthenticator authenticator) : base(repository, mapper) { _tempService = tempService; _envRcvService = envelopeReceiverService; _dConfig = dispatcherConfigOptions.Value; _configService = configService; _placeholders = mailConfig.Value.Placeholders; - _codeGenerator = codeGenerator; + _authenticator = authenticator; } private async Task> CreatePlaceholders(string? accessCode = null, EnvelopeReceiverDto? envelopeReceiverDto = null) @@ -167,7 +167,7 @@ namespace EnvelopeGenerator.Application.Services if (dto.Receiver.TotpExpiration is null) throw new ArgumentNullException(nameof(dto), $"TFA Qr Code cannot sent. Receiver.TotpExpiration is null. Envelope receiver dto is {JsonConvert.SerializeObject(dto)}"); - var totp_qr_64 = _codeGenerator.GenerateTotpQrCode(userEmail: dto.Receiver.EmailAddress, secretKey: dto.Receiver.TotpSecretkey).ToBase64String(); + var totp_qr_64 = _authenticator.GenerateTotpQrCode(userEmail: dto.Receiver.EmailAddress, secretKey: dto.Receiver.TotpSecretkey).ToBase64String(); return SendAsync(dto, EmailTemplateType.TotpSecret, new() { {"[TFA_QR_CODE]", totp_qr_64 }, diff --git a/EnvelopeGenerator.Application/Services/EnvelopeSmsHandler.cs b/EnvelopeGenerator.Application/Services/EnvelopeSmsHandler.cs index 0a72c7d4..dfea09e6 100644 --- a/EnvelopeGenerator.Application/Services/EnvelopeSmsHandler.cs +++ b/EnvelopeGenerator.Application/Services/EnvelopeSmsHandler.cs @@ -16,14 +16,14 @@ public class EnvelopeSmsHandler : IEnvelopeSmsHandler private readonly IDistributedCache _dCache; - private readonly ICodeGenerator _codeGenerator; + private readonly IAuthenticator _authenticator; - public EnvelopeSmsHandler(ISmsSender sender, IOptions totpSmsParamsOptions, IDistributedCache distributedCache, ICodeGenerator codeGenerator) + public EnvelopeSmsHandler(ISmsSender sender, IOptions totpSmsParamsOptions, IDistributedCache distributedCache, IAuthenticator authenticator) { _sender = sender; _totpSmsParams = totpSmsParamsOptions.Value; _dCache = distributedCache; - _codeGenerator = codeGenerator; + _authenticator = authenticator; } /// @@ -42,12 +42,12 @@ public class EnvelopeSmsHandler : IEnvelopeSmsHandler else { var new_expiration = DateTime.Now.AddSeconds(_totpSmsParams.TotpStep); - var totp = _codeGenerator.GenerateTotp(er_secret.Receiver!.TotpSecretkey!, _totpSmsParams.TotpStep); + var totp = _authenticator.GenerateTotp(er_secret.Receiver!.TotpSecretkey!, _totpSmsParams.TotpStep); var msg = string.Format(_totpSmsParams.Format, totp, new_expiration.ToString(_totpSmsParams.Expiration.Format, _totpSmsParams.Expiration.CultureInfo)); return (await _sender.SendSmsAsync(er_secret.PhoneNumber!, msg), new_expiration); } } - public bool VerifyTotp(string totpCode, string secretKey) => _codeGenerator + public bool VerifyTotp(string totpCode, string secretKey) => _authenticator .VerifyTotp(totpCode, secretKey, _totpSmsParams.TotpStep, _totpSmsParams.TotpVerificationWindow); } \ No newline at end of file diff --git a/EnvelopeGenerator.Web/Controllers/HomeController.cs b/EnvelopeGenerator.Web/Controllers/HomeController.cs index 3a75b946..fc4c52b8 100644 --- a/EnvelopeGenerator.Web/Controllers/HomeController.cs +++ b/EnvelopeGenerator.Web/Controllers/HomeController.cs @@ -35,11 +35,11 @@ namespace EnvelopeGenerator.Web.Controllers private readonly Cultures _cultures; private readonly IEnvelopeMailService _mailService; private readonly IEnvelopeReceiverReadOnlyService _readOnlyService; - private readonly ICodeGenerator _codeGenerator; + private readonly IAuthenticator _authenticator; private readonly IReceiverService _rcvService; private readonly IEnvelopeSmsHandler _envSmsHandler; - public HomeController(EnvelopeOldService envelopeOldService, ILogger logger, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeHistoryService historyService, IStringLocalizer localizer, IConfiguration configuration, HtmlSanitizer sanitizer, Cultures cultures, IEnvelopeMailService envelopeMailService, IEnvelopeReceiverReadOnlyService readOnlyService, ICodeGenerator codeGenerator, IReceiverService receiverService, IEnvelopeSmsHandler envelopeSmsService) + public HomeController(EnvelopeOldService envelopeOldService, ILogger logger, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeHistoryService historyService, IStringLocalizer localizer, IConfiguration configuration, HtmlSanitizer sanitizer, Cultures cultures, IEnvelopeMailService envelopeMailService, IEnvelopeReceiverReadOnlyService readOnlyService, IAuthenticator authenticator, IReceiverService receiverService, IEnvelopeSmsHandler envelopeSmsService) { this.envelopeOldService = envelopeOldService; _envRcvService = envelopeReceiverService; @@ -51,7 +51,7 @@ namespace EnvelopeGenerator.Web.Controllers _mailService = envelopeMailService; _logger = logger; _readOnlyService = readOnlyService; - _codeGenerator = codeGenerator; + _authenticator = authenticator; _rcvService = receiverService; _envSmsHandler = envelopeSmsService; } @@ -204,7 +204,7 @@ namespace EnvelopeGenerator.Web.Controllers var rcv = er_secret.Receiver; if (rcv.IsTotpSecretInvalid()) { - rcv.TotpSecretkey = _codeGenerator.GenerateTotpSecretKey(); + rcv.TotpSecretkey = _authenticator.GenerateTotpSecretKey(); rcv.TotpExpiration = DateTime.Now.AddMonths(1); await _rcvService.UpdateAsync(rcv); await _mailService.SendTFAQrCodeAsync(er_secret);