refactor(HomeController): Als Home- und Envelope-Controller aufteilen
This commit is contained in:
parent
d64d46920a
commit
01ec2b3df2
416
EnvelopeGenerator.Web/Controllers/EnvelopeController.cs
Normal file
416
EnvelopeGenerator.Web/Controllers/EnvelopeController.cs
Normal file
@ -0,0 +1,416 @@
|
||||
using DigitalData.Core.Abstraction.Application.DTO;
|
||||
using DigitalData.Core.API;
|
||||
using DigitalData.Core.Client;
|
||||
using EnvelopeGenerator.Application.EnvelopeReceivers.Queries;
|
||||
using EnvelopeGenerator.Application.Resources;
|
||||
using EnvelopeGenerator.Web.Extensions;
|
||||
using EnvelopeGenerator.Web.Models;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Newtonsoft.Json;
|
||||
using OtpNet;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.Application.Common.Dto;
|
||||
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
|
||||
using EnvelopeGenerator.Application.Common.Extensions;
|
||||
using EnvelopeGenerator.Application.Common.Interfaces.Services;
|
||||
|
||||
namespace EnvelopeGenerator.Web.Controllers;
|
||||
|
||||
[Route("Envelope")]
|
||||
public class EnvelopeController : ViewControllerBase
|
||||
{
|
||||
[Obsolete("Use MediatR")]
|
||||
private readonly IEnvelopeReceiverService _envRcvService;
|
||||
[Obsolete("Use MediatR")]
|
||||
private readonly IEnvelopeHistoryService _historyService;
|
||||
private readonly IConfiguration _configuration;
|
||||
[Obsolete("Use MediatR")]
|
||||
private readonly IEnvelopeMailService _mailService;
|
||||
[Obsolete("Use MediatR")]
|
||||
private readonly IEnvelopeReceiverReadOnlyService _readOnlyService;
|
||||
private readonly IAuthenticator _authenticator;
|
||||
[Obsolete("Use MediatR")]
|
||||
private readonly IReceiverService _rcvService;
|
||||
private readonly IEnvelopeSmsHandler _envSmsHandler;
|
||||
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
[Obsolete("Use MediatR")]
|
||||
public EnvelopeController(ILogger<HomeController> logger, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeHistoryService historyService, IStringLocalizer<Resource> localizer, IConfiguration configuration, Cultures cultures, IEnvelopeMailService envelopeMailService, IEnvelopeReceiverReadOnlyService readOnlyService, IAuthenticator authenticator, IReceiverService receiverService, IEnvelopeSmsHandler envelopeSmsService, IMediator mediator) : base(logger, cultures, localizer)
|
||||
{
|
||||
_envRcvService = envelopeReceiverService;
|
||||
_historyService = historyService;
|
||||
_configuration = configuration;
|
||||
_mailService = envelopeMailService;
|
||||
_readOnlyService = readOnlyService;
|
||||
_authenticator = authenticator;
|
||||
_rcvService = receiverService;
|
||||
_envSmsHandler = envelopeSmsService;
|
||||
_mediator = mediator;
|
||||
}
|
||||
|
||||
[HttpGet("{envelopeReceiverId}")]
|
||||
[Obsolete("Use MediatR")]
|
||||
public async Task<IActionResult> Main([FromRoute] string envelopeReceiverId)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!envelopeReceiverId.TryDecode(out var decoded))
|
||||
{
|
||||
Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||
return this.ViewDocumentNotFound();
|
||||
}
|
||||
|
||||
if(decoded.GetEncodeType() == EncodeType.EnvelopeReceiverReadOnly)
|
||||
return await EnvelopeReceiverReadOnly(decoded.ParseReadOnlyId());
|
||||
|
||||
ViewData["EnvelopeKey"] = envelopeReceiverId;
|
||||
|
||||
var er = await _mediator.ReadEnvelopeReceiverAsync(envelopeReceiverId);
|
||||
|
||||
if (er is null)
|
||||
return this.ViewEnvelopeNotFound();
|
||||
|
||||
bool accessCodeAlreadyRequested = await _historyService.AccessCodeAlreadyRequested(envelopeId: er.Envelope!.Id, userReference: er.Receiver!.EmailAddress);
|
||||
if (!accessCodeAlreadyRequested)
|
||||
{
|
||||
await _historyService.RecordAsync(er.EnvelopeId, er.Receiver.EmailAddress, EnvelopeStatus.AccessCodeRequested);
|
||||
|
||||
var mailRes = await _mailService.SendAccessCodeAsync(envelopeReceiverDto: er);
|
||||
if (mailRes.IsFailed)
|
||||
{
|
||||
_logger.LogNotice(mailRes);
|
||||
return this.ViewAccessCodeNotSent();
|
||||
}
|
||||
}
|
||||
|
||||
return Redirect($"{envelopeReceiverId}/Locked");
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, exception:ex, message: _localizer.UnexpectedError());
|
||||
return this.ViewInnerServiceError();
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("{envelopeReceiverId}/Locked")]
|
||||
[Obsolete("Use DigitalData.Core.Exceptions and .Middleware")]
|
||||
public async Task<IActionResult> EnvelopeLocked([FromRoute] string envelopeReceiverId, CancellationToken cancel)
|
||||
{
|
||||
try
|
||||
{
|
||||
var er = await _mediator.ReadEnvelopeReceiverAsync(envelopeReceiverId, cancel);
|
||||
|
||||
if (er is null)
|
||||
{
|
||||
Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||
return this.ViewEnvelopeNotFound();
|
||||
}
|
||||
|
||||
if (User.IsInRole(ReceiverRole.FullyAuth))
|
||||
return await CreateShowEnvelopeView(envelopeReceiverId, er);
|
||||
else
|
||||
{
|
||||
ViewData["EnvelopeKey"] = envelopeReceiverId;
|
||||
ViewData["TFAEnabled"] = er.Envelope!.TFAEnabled;
|
||||
ViewData["HasPhoneNumber"] = er.HasPhoneNumber;
|
||||
ViewData["SenderEmail"] = er.Envelope.User!.Email;
|
||||
ViewData["EnvelopeTitle"] = er.Envelope.Title;
|
||||
return View();
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, exception: ex);
|
||||
return this.ViewInnerServiceError();
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use MediatR")]
|
||||
private async Task<IActionResult> CreateShowEnvelopeView(string envelopeReceiverId, EnvelopeReceiverDto er)
|
||||
{
|
||||
try
|
||||
{
|
||||
ViewData["EnvelopeKey"] = envelopeReceiverId;
|
||||
(string? uuid, string? signature) = envelopeReceiverId.DecodeEnvelopeReceiverId();
|
||||
|
||||
if (uuid is null || signature is null)
|
||||
{
|
||||
_logger.LogEnvelopeError(uuid: uuid, signature: signature, message: _localizer.WrongEnvelopeReceiverId());
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
_logger.LogInformation("Envelope UUID: [{uuid}]\nReceiver Signature: [{signature}]", uuid, signature);
|
||||
|
||||
//check rejection
|
||||
var rejRcvrs = await _historyService.ReadRejectingReceivers(er.Envelope!.Id);
|
||||
if (rejRcvrs.Any())
|
||||
{
|
||||
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
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))
|
||||
{
|
||||
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
return View("EnvelopeSigned");
|
||||
}
|
||||
|
||||
if (er.Envelope.Documents?.FirstOrDefault() is DocumentDto 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();
|
||||
}
|
||||
|
||||
await HttpContext.SignInEnvelopeAsync(er, ReceiverRole.FullyAuth);
|
||||
|
||||
//add PSPDFKit licence key
|
||||
ViewData["PSPDFKitLicenseKey"] = _configuration["PSPDFKitLicenseKey"];
|
||||
|
||||
return View("ShowEnvelope", er);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, exception: ex);
|
||||
return this.ViewInnerServiceError();
|
||||
}
|
||||
}
|
||||
|
||||
#region TFA Views
|
||||
[NonAction]
|
||||
private async Task<IActionResult> TFAViewAsync(bool viaSms, EnvelopeReceiverSecretDto er_secret, string envelopeReceiverId)
|
||||
{
|
||||
if (viaSms)
|
||||
{
|
||||
var (smsRes, expiration) = await _envSmsHandler.SendTotpAsync(er_secret);
|
||||
|
||||
ViewData["EnvelopeKey"] = envelopeReceiverId;
|
||||
ViewData["TFAEnabled"] = er_secret.Envelope!.TFAEnabled;
|
||||
ViewData["HasPhoneNumber"] = er_secret.HasPhoneNumber;
|
||||
ViewData["SenderEmail"] = er_secret.Envelope.User!.Email;
|
||||
ViewData["EnvelopeTitle"] = er_secret.Envelope.Title;
|
||||
|
||||
if (smsRes?.Failed ?? false)
|
||||
{
|
||||
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("TfaRegDeadline", er_secret.Receiver?.TfaRegDeadline);
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use MediatR")]
|
||||
[NonAction]
|
||||
private async Task<IActionResult?> HandleAccessCodeAsync(Auth auth, EnvelopeReceiverSecretDto er_secret, string envelopeReceiverId)
|
||||
{
|
||||
//check the access code verification
|
||||
if (er_secret.AccessCode != auth.AccessCode)
|
||||
{
|
||||
//EnvelopeStatusQuery.AccessCodeIncorrect
|
||||
await _historyService.RecordAsync(er_secret.EnvelopeId, er_secret.Receiver!.EmailAddress, EnvelopeStatus.AccessCodeIncorrect);
|
||||
Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||
return View("EnvelopeLocked")
|
||||
.WithData("EnvelopeKey", envelopeReceiverId)
|
||||
.WithData("TFAEnabled", er_secret.Envelope!.TFAEnabled)
|
||||
.WithData("HasPhoneNumber", er_secret.HasPhoneNumber)
|
||||
.WithData("SenderEmail", er_secret.Envelope.User!.Email)
|
||||
.WithData("EnvelopeTitle", er_secret.Envelope.Title)
|
||||
.WithData("ErrorMessage", _localizer.WrongAccessCode());
|
||||
}
|
||||
|
||||
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.TotpSecretkey is null)
|
||||
{
|
||||
rcv.TotpSecretkey = _authenticator.GenerateTotpSecretKey();
|
||||
await _rcvService.UpdateAsync(rcv);
|
||||
}
|
||||
|
||||
await HttpContext.SignInEnvelopeAsync(er_secret, ReceiverRole.PreAuth);
|
||||
|
||||
return await TFAViewAsync(auth.UserSelectSMS, er_secret, envelopeReceiverId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
[NonAction]
|
||||
private async Task<IActionResult?> 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)}");
|
||||
|
||||
if (!User.IsInRole(ReceiverRole.PreAuth) || !_envSmsHandler.VerifyTotp(auth.SmsCode!, er_secret.Receiver.TotpSecretkey))
|
||||
{
|
||||
Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||
ViewData["ErrorMessage"] = _localizer.WrongAccessCode();
|
||||
return await TFAViewAsync(viaSms: true, er_secret, envelopeReceiverId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
[NonAction]
|
||||
private async Task<IActionResult?> HandleAuthenticatorAsync(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 (!User.IsInRole(ReceiverRole.PreAuth) || !_authenticator.VerifyTotp(auth.AuthenticatorCode!, er_secret.Receiver.TotpSecretkey, window: VerificationWindow.RfcSpecifiedNetworkDelay))
|
||||
{
|
||||
Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||
ViewData["ErrorMessage"] = _localizer.WrongAccessCode();
|
||||
return await TFAViewAsync(viaSms: false, er_secret, envelopeReceiverId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
[HttpPost("{envelopeReceiverId}/Locked")]
|
||||
[Obsolete("Use MediatR")]
|
||||
public async Task<IActionResult> LogInEnvelope([FromRoute] string envelopeReceiverId, [FromForm] Auth auth)
|
||||
{
|
||||
try
|
||||
{
|
||||
ViewData["EnvelopeKey"] = envelopeReceiverId;
|
||||
(string? uuid, string? signature) = envelopeReceiverId.DecodeEnvelopeReceiverId();
|
||||
|
||||
if (uuid is null || signature is null)
|
||||
{
|
||||
_logger.LogEnvelopeError(uuid: uuid, signature: signature, message: _localizer.WrongEnvelopeReceiverId());
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
_logger.LogInformation("Envelope UUID: [{uuid}]\nReceiver Signature: [{signature}]", uuid, signature);
|
||||
|
||||
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;
|
||||
|
||||
// show envelope if already logged in
|
||||
if (User.IsInRole(ReceiverRole.FullyAuth))
|
||||
return await CreateShowEnvelopeView(envelopeReceiverId, er_secret);
|
||||
|
||||
if (auth.HasMulti)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
else if (auth.HasAccessCode)
|
||||
{
|
||||
if (await HandleAccessCodeAsync(auth, er_secret, envelopeReceiverId) is IActionResult acView)
|
||||
return acView;
|
||||
}
|
||||
else if (auth.HasSmsCode)
|
||||
{
|
||||
if (await HandleSmsAsync(auth, er_secret, envelopeReceiverId) is IActionResult smsView)
|
||||
return smsView;
|
||||
}
|
||||
else if (auth.HasAuthenticatorCode)
|
||||
{
|
||||
if(await HandleAuthenticatorAsync(auth, er_secret, envelopeReceiverId) is IActionResult aView)
|
||||
return aView;
|
||||
}
|
||||
else
|
||||
{
|
||||
Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||
return View("EnvelopeLocked")
|
||||
.WithData("EnvelopeKey", envelopeReceiverId)
|
||||
.WithData("TFAEnabled", er_secret.Envelope!.TFAEnabled)
|
||||
.WithData("HasPhoneNumber", er_secret.HasPhoneNumber)
|
||||
.WithData("SenderEmail", er_secret.Envelope.User!.Email)
|
||||
.WithData("EnvelopeTitle", er_secret.Envelope.Title)
|
||||
.WithData("ErrorMessage", _localizer.WrongEnvelopeReceiverId());
|
||||
}
|
||||
|
||||
await HttpContext.SignInEnvelopeAsync(er_secret, ReceiverRole.FullyAuth);
|
||||
|
||||
return await CreateShowEnvelopeView(envelopeReceiverId, er_secret);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, exception: ex);
|
||||
return this.ViewInnerServiceError();
|
||||
}
|
||||
}
|
||||
|
||||
[NonAction]
|
||||
[Obsolete("Use MediatR")]
|
||||
public async Task<IActionResult> EnvelopeReceiverReadOnly([FromRoute] long readOnlyId)
|
||||
{
|
||||
var erro_res = await _readOnlyService.ReadByIdAsync(readOnlyId);
|
||||
if (erro_res.IsFailed)
|
||||
{
|
||||
_logger.LogNotice(erro_res.Notices);
|
||||
return this.ViewInnerServiceError();
|
||||
}
|
||||
|
||||
var erro = erro_res.Data;
|
||||
|
||||
if (DateTime.Now > erro.DateValid)
|
||||
return View("EnvelopeExpired");
|
||||
|
||||
return await _envRcvService.ReadByUuidSignatureAsync(uuid: erro.Envelope!.Uuid, erro.Receiver!.Signature).ThenAsync(
|
||||
SuccessAsync: async er =>
|
||||
{
|
||||
var envelopeKey = (er.Envelope!.Uuid, er.Receiver!.Signature).ToEnvelopeKey();
|
||||
|
||||
//TODO: implement multi-threading to history process (Task)
|
||||
var hist_res = await _historyService.RecordAsync((int)erro.EnvelopeId, erro.AddedWho, EnvelopeStatus.EnvelopeViewed);
|
||||
if (hist_res.IsFailed)
|
||||
{
|
||||
_logger.LogError(
|
||||
"Although the envelope was sent as read-only, the EnvelopeShared hisotry could not be saved. ReadOnly-Id: {readOnlyKey}\nEnvelope Receiver:\n{envelopeReceiver}",
|
||||
readOnlyId, JsonConvert.SerializeObject(er));
|
||||
_logger.LogNotice(hist_res.Notices);
|
||||
}
|
||||
|
||||
if (er.Envelope.Documents?.FirstOrDefault() is DocumentDto doc && doc.ByteData is not null)
|
||||
{
|
||||
ViewData["DocumentBytes"] = doc.ByteData;
|
||||
ViewData["EnvelopeKey"] = envelopeKey;
|
||||
ViewData["IsReadOnly"] = true;
|
||||
ViewData["ReadOnly"] = erro;
|
||||
ViewData["PSPDFKitLicenseKey"] = _configuration["PSPDFKitLicenseKey"];
|
||||
return View("ShowEnvelope", er);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogEnvelopeError(envelopeReceiverId: envelopeKey, message: "No document byte-data was found in ENVELOPE_DOCUMENT table.");
|
||||
return this.ViewDocumentNotFound();
|
||||
}
|
||||
},
|
||||
Fail: (messages, notices) =>
|
||||
{
|
||||
_logger.LogNotice(notices);
|
||||
return this.ViewEnvelopeNotFound();
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1,60 +1,21 @@
|
||||
using DigitalData.Core.Abstraction.Application.DTO;
|
||||
using DigitalData.Core.API;
|
||||
using DigitalData.Core.Client;
|
||||
using EnvelopeGenerator.Application.EnvelopeReceivers.Queries;
|
||||
using EnvelopeGenerator.Application.Resources;
|
||||
using EnvelopeGenerator.Application.Resources;
|
||||
using EnvelopeGenerator.Web.Extensions;
|
||||
using EnvelopeGenerator.Web.Models;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Newtonsoft.Json;
|
||||
using OtpNet;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.Application.Common.Dto;
|
||||
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
|
||||
using EnvelopeGenerator.Application.Common.Extensions;
|
||||
using EnvelopeGenerator.Application.Common.Interfaces.Services;
|
||||
|
||||
namespace EnvelopeGenerator.Web.Controllers;
|
||||
|
||||
[Route("Envelope")]
|
||||
public class HomeController : ViewControllerBase
|
||||
{
|
||||
[Obsolete("Use MediatR")]
|
||||
private readonly IEnvelopeReceiverService _envRcvService;
|
||||
[Obsolete("Use MediatR")]
|
||||
private readonly IEnvelopeHistoryService _historyService;
|
||||
private readonly IConfiguration _configuration;
|
||||
[Obsolete("Use MediatR")]
|
||||
private readonly IEnvelopeMailService _mailService;
|
||||
[Obsolete("Use MediatR")]
|
||||
private readonly IEnvelopeReceiverReadOnlyService _readOnlyService;
|
||||
private readonly IAuthenticator _authenticator;
|
||||
[Obsolete("Use MediatR")]
|
||||
private readonly IReceiverService _rcvService;
|
||||
private readonly IEnvelopeSmsHandler _envSmsHandler;
|
||||
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
[Obsolete("Use MediatR")]
|
||||
public HomeController(ILogger<HomeController> logger, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeHistoryService historyService, IStringLocalizer<Resource> localizer, IConfiguration configuration, Cultures cultures, IEnvelopeMailService envelopeMailService, IEnvelopeReceiverReadOnlyService readOnlyService, IAuthenticator authenticator, IReceiverService receiverService, IEnvelopeSmsHandler envelopeSmsService, IMediator mediator) : base(logger, cultures, localizer)
|
||||
public HomeController(IConfiguration configuration, ILogger logger, Cultures cultures, IStringLocalizer<Resource> localizer) : base(logger, cultures, localizer)
|
||||
{
|
||||
_envRcvService = envelopeReceiverService;
|
||||
_historyService = historyService;
|
||||
_configuration = configuration;
|
||||
_mailService = envelopeMailService;
|
||||
_readOnlyService = readOnlyService;
|
||||
_authenticator = authenticator;
|
||||
_rcvService = receiverService;
|
||||
_envSmsHandler = envelopeSmsService;
|
||||
_mediator = mediator;
|
||||
}
|
||||
|
||||
[HttpGet("/")]
|
||||
[HttpGet]
|
||||
public IActionResult Main()
|
||||
{
|
||||
return View(new MainViewModel()
|
||||
@ -63,367 +24,6 @@ public class HomeController : ViewControllerBase
|
||||
});
|
||||
}
|
||||
|
||||
[HttpGet("{envelopeReceiverId}")]
|
||||
[Obsolete("Use MediatR")]
|
||||
public async Task<IActionResult> MainAsync([FromRoute] string envelopeReceiverId)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!envelopeReceiverId.TryDecode(out var decoded))
|
||||
{
|
||||
Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||
return this.ViewDocumentNotFound();
|
||||
}
|
||||
|
||||
if(decoded.GetEncodeType() == EncodeType.EnvelopeReceiverReadOnly)
|
||||
return await EnvelopeReceiverReadOnly(decoded.ParseReadOnlyId());
|
||||
|
||||
ViewData["EnvelopeKey"] = envelopeReceiverId;
|
||||
|
||||
var er = await _mediator.ReadEnvelopeReceiverAsync(envelopeReceiverId);
|
||||
|
||||
if (er is null)
|
||||
return this.ViewEnvelopeNotFound();
|
||||
|
||||
bool accessCodeAlreadyRequested = await _historyService.AccessCodeAlreadyRequested(envelopeId: er.Envelope!.Id, userReference: er.Receiver!.EmailAddress);
|
||||
if (!accessCodeAlreadyRequested)
|
||||
{
|
||||
await _historyService.RecordAsync(er.EnvelopeId, er.Receiver.EmailAddress, EnvelopeStatus.AccessCodeRequested);
|
||||
|
||||
var mailRes = await _mailService.SendAccessCodeAsync(envelopeReceiverDto: er);
|
||||
if (mailRes.IsFailed)
|
||||
{
|
||||
_logger.LogNotice(mailRes);
|
||||
return this.ViewAccessCodeNotSent();
|
||||
}
|
||||
}
|
||||
|
||||
return Redirect($"{envelopeReceiverId}/Locked");
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, exception:ex, message: _localizer.UnexpectedError());
|
||||
return this.ViewInnerServiceError();
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("{envelopeReceiverId}/Locked")]
|
||||
[Obsolete("Use DigitalData.Core.Exceptions and .Middleware")]
|
||||
public async Task<IActionResult> EnvelopeLocked([FromRoute] string envelopeReceiverId, CancellationToken cancel)
|
||||
{
|
||||
try
|
||||
{
|
||||
var er = await _mediator.ReadEnvelopeReceiverAsync(envelopeReceiverId, cancel);
|
||||
|
||||
if (er is null)
|
||||
{
|
||||
Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||
return this.ViewEnvelopeNotFound();
|
||||
}
|
||||
|
||||
if (User.IsInRole(ReceiverRole.FullyAuth))
|
||||
return await CreateShowEnvelopeView(envelopeReceiverId, er);
|
||||
else
|
||||
{
|
||||
ViewData["EnvelopeKey"] = envelopeReceiverId;
|
||||
ViewData["TFAEnabled"] = er.Envelope!.TFAEnabled;
|
||||
ViewData["HasPhoneNumber"] = er.HasPhoneNumber;
|
||||
ViewData["SenderEmail"] = er.Envelope.User!.Email;
|
||||
ViewData["EnvelopeTitle"] = er.Envelope.Title;
|
||||
return View();
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, exception: ex);
|
||||
return this.ViewInnerServiceError();
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use MediatR")]
|
||||
private async Task<IActionResult> CreateShowEnvelopeView(string envelopeReceiverId, EnvelopeReceiverDto er)
|
||||
{
|
||||
try
|
||||
{
|
||||
ViewData["EnvelopeKey"] = envelopeReceiverId;
|
||||
(string? uuid, string? signature) = envelopeReceiverId.DecodeEnvelopeReceiverId();
|
||||
|
||||
if (uuid is null || signature is null)
|
||||
{
|
||||
_logger.LogEnvelopeError(uuid: uuid, signature: signature, message: _localizer.WrongEnvelopeReceiverId());
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
_logger.LogInformation("Envelope UUID: [{uuid}]\nReceiver Signature: [{signature}]", uuid, signature);
|
||||
|
||||
//check rejection
|
||||
var rejRcvrs = await _historyService.ReadRejectingReceivers(er.Envelope!.Id);
|
||||
if (rejRcvrs.Any())
|
||||
{
|
||||
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
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))
|
||||
{
|
||||
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
return View("EnvelopeSigned");
|
||||
}
|
||||
|
||||
if (er.Envelope.Documents?.FirstOrDefault() is DocumentDto 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();
|
||||
}
|
||||
|
||||
await HttpContext.SignInEnvelopeAsync(er, ReceiverRole.FullyAuth);
|
||||
|
||||
//add PSPDFKit licence key
|
||||
ViewData["PSPDFKitLicenseKey"] = _configuration["PSPDFKitLicenseKey"];
|
||||
|
||||
return View("ShowEnvelope", er);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, exception: ex);
|
||||
return this.ViewInnerServiceError();
|
||||
}
|
||||
}
|
||||
|
||||
#region TFA Views
|
||||
[NonAction]
|
||||
private async Task<IActionResult> TFAViewAsync(bool viaSms, EnvelopeReceiverSecretDto er_secret, string envelopeReceiverId)
|
||||
{
|
||||
if (viaSms)
|
||||
{
|
||||
var (smsRes, expiration) = await _envSmsHandler.SendTotpAsync(er_secret);
|
||||
|
||||
ViewData["EnvelopeKey"] = envelopeReceiverId;
|
||||
ViewData["TFAEnabled"] = er_secret.Envelope!.TFAEnabled;
|
||||
ViewData["HasPhoneNumber"] = er_secret.HasPhoneNumber;
|
||||
ViewData["SenderEmail"] = er_secret.Envelope.User!.Email;
|
||||
ViewData["EnvelopeTitle"] = er_secret.Envelope.Title;
|
||||
|
||||
if (smsRes?.Failed ?? false)
|
||||
{
|
||||
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("TfaRegDeadline", er_secret.Receiver?.TfaRegDeadline);
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use MediatR")]
|
||||
[NonAction]
|
||||
private async Task<IActionResult?> HandleAccessCodeAsync(Auth auth, EnvelopeReceiverSecretDto er_secret, string envelopeReceiverId)
|
||||
{
|
||||
//check the access code verification
|
||||
if (er_secret.AccessCode != auth.AccessCode)
|
||||
{
|
||||
//EnvelopeStatusQuery.AccessCodeIncorrect
|
||||
await _historyService.RecordAsync(er_secret.EnvelopeId, er_secret.Receiver!.EmailAddress, EnvelopeStatus.AccessCodeIncorrect);
|
||||
Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||
return View("EnvelopeLocked")
|
||||
.WithData("EnvelopeKey", envelopeReceiverId)
|
||||
.WithData("TFAEnabled", er_secret.Envelope!.TFAEnabled)
|
||||
.WithData("HasPhoneNumber", er_secret.HasPhoneNumber)
|
||||
.WithData("SenderEmail", er_secret.Envelope.User!.Email)
|
||||
.WithData("EnvelopeTitle", er_secret.Envelope.Title)
|
||||
.WithData("ErrorMessage", _localizer.WrongAccessCode());
|
||||
}
|
||||
|
||||
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.TotpSecretkey is null)
|
||||
{
|
||||
rcv.TotpSecretkey = _authenticator.GenerateTotpSecretKey();
|
||||
await _rcvService.UpdateAsync(rcv);
|
||||
}
|
||||
|
||||
await HttpContext.SignInEnvelopeAsync(er_secret, ReceiverRole.PreAuth);
|
||||
|
||||
return await TFAViewAsync(auth.UserSelectSMS, er_secret, envelopeReceiverId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
[NonAction]
|
||||
private async Task<IActionResult?> 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)}");
|
||||
|
||||
if (!User.IsInRole(ReceiverRole.PreAuth) || !_envSmsHandler.VerifyTotp(auth.SmsCode!, er_secret.Receiver.TotpSecretkey))
|
||||
{
|
||||
Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||
ViewData["ErrorMessage"] = _localizer.WrongAccessCode();
|
||||
return await TFAViewAsync(viaSms: true, er_secret, envelopeReceiverId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
[NonAction]
|
||||
private async Task<IActionResult?> HandleAuthenticatorAsync(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 (!User.IsInRole(ReceiverRole.PreAuth) || !_authenticator.VerifyTotp(auth.AuthenticatorCode!, er_secret.Receiver.TotpSecretkey, window: VerificationWindow.RfcSpecifiedNetworkDelay))
|
||||
{
|
||||
Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||
ViewData["ErrorMessage"] = _localizer.WrongAccessCode();
|
||||
return await TFAViewAsync(viaSms: false, er_secret, envelopeReceiverId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
[HttpPost("{envelopeReceiverId}/Locked")]
|
||||
[Obsolete("Use MediatR")]
|
||||
public async Task<IActionResult> LogInEnvelope([FromRoute] string envelopeReceiverId, [FromForm] Auth auth)
|
||||
{
|
||||
try
|
||||
{
|
||||
ViewData["EnvelopeKey"] = envelopeReceiverId;
|
||||
(string? uuid, string? signature) = envelopeReceiverId.DecodeEnvelopeReceiverId();
|
||||
|
||||
if (uuid is null || signature is null)
|
||||
{
|
||||
_logger.LogEnvelopeError(uuid: uuid, signature: signature, message: _localizer.WrongEnvelopeReceiverId());
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
_logger.LogInformation("Envelope UUID: [{uuid}]\nReceiver Signature: [{signature}]", uuid, signature);
|
||||
|
||||
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;
|
||||
|
||||
// show envelope if already logged in
|
||||
if (User.IsInRole(ReceiverRole.FullyAuth))
|
||||
return await CreateShowEnvelopeView(envelopeReceiverId, er_secret);
|
||||
|
||||
if (auth.HasMulti)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
else if (auth.HasAccessCode)
|
||||
{
|
||||
if (await HandleAccessCodeAsync(auth, er_secret, envelopeReceiverId) is IActionResult acView)
|
||||
return acView;
|
||||
}
|
||||
else if (auth.HasSmsCode)
|
||||
{
|
||||
if (await HandleSmsAsync(auth, er_secret, envelopeReceiverId) is IActionResult smsView)
|
||||
return smsView;
|
||||
}
|
||||
else if (auth.HasAuthenticatorCode)
|
||||
{
|
||||
if(await HandleAuthenticatorAsync(auth, er_secret, envelopeReceiverId) is IActionResult aView)
|
||||
return aView;
|
||||
}
|
||||
else
|
||||
{
|
||||
Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||
return View("EnvelopeLocked")
|
||||
.WithData("EnvelopeKey", envelopeReceiverId)
|
||||
.WithData("TFAEnabled", er_secret.Envelope!.TFAEnabled)
|
||||
.WithData("HasPhoneNumber", er_secret.HasPhoneNumber)
|
||||
.WithData("SenderEmail", er_secret.Envelope.User!.Email)
|
||||
.WithData("EnvelopeTitle", er_secret.Envelope.Title)
|
||||
.WithData("ErrorMessage", _localizer.WrongEnvelopeReceiverId());
|
||||
}
|
||||
|
||||
await HttpContext.SignInEnvelopeAsync(er_secret, ReceiverRole.FullyAuth);
|
||||
|
||||
return await CreateShowEnvelopeView(envelopeReceiverId, er_secret);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, exception: ex);
|
||||
return this.ViewInnerServiceError();
|
||||
}
|
||||
}
|
||||
|
||||
[NonAction]
|
||||
[Obsolete("Use MediatR")]
|
||||
public async Task<IActionResult> EnvelopeReceiverReadOnly([FromRoute] long readOnlyId)
|
||||
{
|
||||
var erro_res = await _readOnlyService.ReadByIdAsync(readOnlyId);
|
||||
if (erro_res.IsFailed)
|
||||
{
|
||||
_logger.LogNotice(erro_res.Notices);
|
||||
return this.ViewInnerServiceError();
|
||||
}
|
||||
|
||||
var erro = erro_res.Data;
|
||||
|
||||
if (DateTime.Now > erro.DateValid)
|
||||
return View("EnvelopeExpired");
|
||||
|
||||
return await _envRcvService.ReadByUuidSignatureAsync(uuid: erro.Envelope!.Uuid, erro.Receiver!.Signature).ThenAsync(
|
||||
SuccessAsync: async er =>
|
||||
{
|
||||
var envelopeKey = (er.Envelope!.Uuid, er.Receiver!.Signature).ToEnvelopeKey();
|
||||
|
||||
//TODO: implement multi-threading to history process (Task)
|
||||
var hist_res = await _historyService.RecordAsync((int)erro.EnvelopeId, erro.AddedWho, EnvelopeStatus.EnvelopeViewed);
|
||||
if (hist_res.IsFailed)
|
||||
{
|
||||
_logger.LogError(
|
||||
"Although the envelope was sent as read-only, the EnvelopeShared hisotry could not be saved. ReadOnly-Id: {readOnlyKey}\nEnvelope Receiver:\n{envelopeReceiver}",
|
||||
readOnlyId, JsonConvert.SerializeObject(er));
|
||||
_logger.LogNotice(hist_res.Notices);
|
||||
}
|
||||
|
||||
if (er.Envelope.Documents?.FirstOrDefault() is DocumentDto doc && doc.ByteData is not null)
|
||||
{
|
||||
ViewData["DocumentBytes"] = doc.ByteData;
|
||||
ViewData["EnvelopeKey"] = envelopeKey;
|
||||
ViewData["IsReadOnly"] = true;
|
||||
ViewData["ReadOnly"] = erro;
|
||||
ViewData["PSPDFKitLicenseKey"] = _configuration["PSPDFKitLicenseKey"];
|
||||
return View("ShowEnvelope", er);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogEnvelopeError(envelopeReceiverId: envelopeKey, message: "No document byte-data was found in ENVELOPE_DOCUMENT table.");
|
||||
return this.ViewDocumentNotFound();
|
||||
}
|
||||
},
|
||||
Fail: (messages, notices) =>
|
||||
{
|
||||
_logger.LogNotice(notices);
|
||||
return this.ViewEnvelopeNotFound();
|
||||
});
|
||||
}
|
||||
|
||||
[HttpGet("Error404")]
|
||||
public IActionResult Error404() => this.ViewError404();
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user