feat(GtxMessagingService): Zwischenspeicherung für SMS-Code und Ablauf des SMS-Codes mittels Envelope-Receiver-ID hinzugefügt

- Erweiterungsmethode für Zeitcaching hinzugefügt.
This commit is contained in:
Developer 02 2024-11-29 16:25:20 +01:00
parent 2a963a1861
commit cdec5485c6
10 changed files with 97 additions and 9 deletions

View File

@ -1,4 +1,5 @@
using DigitalData.Core.Abstractions.Client;
using Microsoft.Extensions.Caching.Distributed;
namespace EnvelopeGenerator.Application.Configurations.GtxMessaging
{
@ -20,5 +21,19 @@ namespace EnvelopeGenerator.Application.Configurations.GtxMessaging
public string MessageQueryParamName { get; init; } = "text";
public int CodeLength { get; init; } = 5;
/// <summary>
/// Gets the cache key format for SMS codes.
/// The placeholder {0} represents the envelopeReceiverId.
/// </summary>
public string CodeCacheKeyFormat { get; init; } = "sms-code-{0}";
/// <summary>
/// Gets the cache expiration key format for SMS codes.
/// The placeholder {0} represents the envelopeReceiverId.
/// </summary>
public string CodeExpirationCacheKeyFormat { get; init; } = "sms-code-expiration-{0}";
public TimeSpan CodeCacheValidityPeriod { get; init; } = new(0, 5, 0);
}
}

View File

@ -8,6 +8,6 @@ namespace EnvelopeGenerator.Application.Contracts
Task<SmsResponse> SendSmsAsync(string recipient, string message);
Task<SmsResponse> SendSmsCodeAsync(string recipient);
Task<SmsResponse> SendSmsCodeAsync(string recipient, string envelopeReceiverId);
}
}

View File

@ -0,0 +1,43 @@
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Options;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EnvelopeGenerator.Application.Extensions
{
public static class CacheExtensions
{
public static Task SetLongAsync(this IDistributedCache cache, string key, long value, DistributedCacheEntryOptions? options = null)
=> options is null
? cache.SetAsync(key, BitConverter.GetBytes(value))
: cache.SetAsync(key, BitConverter.GetBytes(value), options: options);
public static async Task<long?> GetLongAsync(this IDistributedCache cache, string key)
{
var value = await cache.GetAsync(key);
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 async Task<DateTime?> GetDateTimeAsync(this IDistributedCache cache, string key)
{
var value = await cache.GetAsync(key);
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 async Task<TimeSpan?> GetTimeSpanAsync(this IDistributedCache cache, string key)
{
var value = await cache.GetAsync(key);
return value is null ? null : new(BitConverter.ToInt64(value, 0));
}
}
}

View File

@ -11,7 +11,7 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
using DigitalData.Core.Client;
using EnvelopeGenerator.Application.Configurations.GtxMessaging;
namespace EnvelopeGenerator.Application
namespace EnvelopeGenerator.Application.Extensions
{
public static class DIExtensions
{

View File

@ -1,6 +1,6 @@
using EnvelopeGenerator.Domain.HttpResponse;
namespace EnvelopeGenerator.Application
namespace EnvelopeGenerator.Application.Extensions
{
public static class MappingExtensions
{

View File

@ -5,6 +5,7 @@ using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly;
using EnvelopeGenerator.Application.DTOs.Messaging;
using EnvelopeGenerator.Application.DTOs.Receiver;
using EnvelopeGenerator.Application.Extensions;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Domain.HttpResponse;

View File

@ -4,7 +4,9 @@ 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
@ -19,15 +21,21 @@ namespace EnvelopeGenerator.Application.Services
private readonly ICodeGenerator _codeGen;
private readonly IDistributedCache _cache;
public string ServiceProvider { get; }
public GtxMessagingService(IHttpClientService<SmsParams> smsClient, IOptions<SmsParams> smsParamsOptions, IMapper mapper, ICodeGenerator codeGenerator)
private readonly DistributedCacheEntryOptions _codeCacheOptions;
public GtxMessagingService(IHttpClientService<SmsParams> smsClient, IOptions<SmsParams> smsParamsOptions, IMapper mapper, ICodeGenerator codeGenerator, IDistributedCache distributedCache)
{
_smsClient = smsClient;
_smsParams = smsParamsOptions.Value;
_mapper = mapper;
ServiceProvider = GetType().Name.Replace("Service", string.Empty);
_codeGen = codeGenerator;
_cache = distributedCache;
_codeCacheOptions = new() { AbsoluteExpirationRelativeToNow = smsParamsOptions.Value.CodeCacheValidityPeriod };
}
public async Task<SmsResponse> SendSmsAsync(string recipient, string message)
@ -41,10 +49,30 @@ namespace EnvelopeGenerator.Application.Services
.ThenAsync(_mapper.Map<SmsResponse>);
}
public async Task<SmsResponse> SendSmsCodeAsync(string recipient)
public async Task<SmsResponse> SendSmsCodeAsync(string recipient, string envelopeReceiverId)
{
var code = _codeGen.GenerateCode(_smsParams.CodeLength);
return await SendSmsAsync(recipient: recipient, message: code);
var code_expiration_key = string.Format(_smsParams.CodeExpirationCacheKeyFormat, envelopeReceiverId);
var code_key = string.Format(_smsParams.CodeCacheKeyFormat, envelopeReceiverId);
var code = await _cache.GetStringAsync(code_key);
if (code is null)
{
code = _codeGen.GenerateCode(_smsParams.CodeLength);
await _cache.SetStringAsync(code_key, code, _codeCacheOptions);
await _cache.SetDateTimeAsync(code_expiration_key, DateTime.Now + _smsParams.CodeCacheValidityPeriod, _codeCacheOptions);
return await SendSmsAsync(recipient: recipient, message: code);
}
else
{
var code_expiration = await _cache.GetDateTimeAsync(code_expiration_key);
return code_expiration is null
? new() { Ok = false }
: new() { Ok = false, AllowedAt = code_expiration };
}
}
}
}

View File

@ -1,7 +1,7 @@
using DigitalData.Core.API;
using DigitalData.Core.Application;
using DigitalData.UserManager.Application;
using EnvelopeGenerator.Application;
using EnvelopeGenerator.Application.Extensions;
using EnvelopeGenerator.Infrastructure;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Localization;

View File

@ -190,7 +190,7 @@ namespace EnvelopeGenerator.Web.Controllers
//check if the user has phone is added
if (er_secret.HasPhoneNumber)
{
var res = await _msgService.SendSmsCodeAsync(er_secret.PhoneNumber!);
var res = await _msgService.SendSmsCodeAsync(er_secret.PhoneNumber!, envelopeReceiverId: envelopeReceiverId);
if(res.Ok)
return View("EnvelopeLocked").WithData("ViaSms", true);
else

View File

@ -15,6 +15,7 @@ using EnvelopeGenerator.Application;
using DigitalData.EmailProfilerDispatcher;
using EnvelopeGenerator.Infrastructure;
using EnvelopeGenerator.Web.Sanitizers;
using EnvelopeGenerator.Application.Extensions;
var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
logger.Info("Logging initialized!");