using EnvelopeGenerator.Application.Configurations; using EnvelopeGenerator.Application.Contracts.Services; 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 IAuthenticator _authenticator; public EnvelopeSmsHandler(ISmsSender sender, IOptions totpSmsParamsOptions, IDistributedCache distributedCache, IAuthenticator authenticator) { _sender = sender; _totpSmsParams = totpSmsParamsOptions.Value; _dCache = distributedCache; _authenticator = authenticator; } /// /// 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 = _authenticator.GenerateTotp(er_secret.Receiver!.TotpSecretkey!, _totpSmsParams.TotpStep); var msg = string.Format(_totpSmsParams.Format, totp, new_expiration.ToString(_totpSmsParams.Expiration.Format, _totpSmsParams.Expiration.CultureInfo)); await _dCache.SetDateTimeAsync(key, new_expiration, cToken: cToken); return (await _sender.SendSmsAsync(er_secret.PhoneNumber!, msg), new_expiration); } } public bool VerifyTotp(string totpCode, string secretKey) => _authenticator .VerifyTotp(totpCode, secretKey, _totpSmsParams.TotpStep, _totpSmsParams.TotpVerificationWindow); }