using EnvelopeGenerator.Application.Contracts; using EnvelopeGenerator.Application.Services; using EnvelopeGenerator.Common; using EnvelopeGenerator.Web.Services; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Mvc; using System.Security.Claims; using Microsoft.AspNetCore.Authorization; using DigitalData.Core.API; using EnvelopeGenerator.Application; using Microsoft.Extensions.Localization; using DigitalData.Core.DTO; using EnvelopeGenerator.Application.Resources; using EnvelopeGenerator.Application.DTOs; using Microsoft.AspNetCore.Localization; using System.Text.Encodings.Web; namespace EnvelopeGenerator.Web.Controllers { public class HomeController : BaseController { private readonly EnvelopeOldService envelopeOldService; private readonly IEnvelopeReceiverService _envRcvService; private readonly IEnvelopeHistoryService _historyService; private readonly IStringLocalizer _localizer; private readonly IConfiguration _configuration; private readonly UrlEncoder _urlEncoder; public HomeController(DatabaseService databaseService, EnvelopeOldService envelopeOldService, ILogger logger, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeHistoryService historyService, IStringLocalizer localizer, IConfiguration configuration, UrlEncoder urlEncoder) : base(databaseService, logger) { this.envelopeOldService = envelopeOldService; _envRcvService = envelopeReceiverService; _historyService = historyService; _localizer = localizer; _configuration = configuration; _urlEncoder = urlEncoder; } [HttpGet("/EnvelopeKey/{envelopeReceiverId}")] public async Task SendAccessCode([FromRoute] string envelopeReceiverId) { try { envelopeReceiverId = _urlEncoder.Encode(envelopeReceiverId); ViewData["EnvelopeKey"] = envelopeReceiverId; return await _envRcvService.ReadByEnvelopeReceiverIdAsync(envelopeReceiverId: envelopeReceiverId).ThenAsync( SuccessAsync: async er => { EnvelopeResponse response = await envelopeOldService.LoadEnvelope(envelopeReceiverId); bool accessCodeAlreadyRequested = await _historyService.AccessCodeAlreadyRequested(envelopeId: er.Envelope!.Id, userReference: er.Receiver!.EmailAddress); if (!accessCodeAlreadyRequested) { // Send email with password bool actionResult = database.Services.actionService.RequestAccessCode(response.Envelope, response.Receiver); bool result = database.Services.emailService.SendDocumentAccessCodeReceivedEmail(response.Envelope, response.Receiver); } return Redirect($"{envelopeReceiverId}/Locked"); }, Fail: (messages, notices) => { _logger.LogNotice(notices); return this.ViewEnvelopeNotFound(); }); } catch(Exception ex) { _logger.LogEnvelopeError(envelopeEeceiverId: envelopeReceiverId, exception:ex, message: _localizer[MessageKey.UnexpectedError]); return this.ViewInnerServiceError(); } } [HttpGet("EnvelopeKey/{envelopeReceiverId}/Locked")] public async Task EnvelopeLocked([FromRoute] string envelopeReceiverId) { try { envelopeReceiverId = _urlEncoder.Encode(envelopeReceiverId); ViewData["Languages"] = _configuration.GetSection("Languages").Get()!; ViewData["UserLanguage"] = UserLanguage; return await _envRcvService.IsExisting(envelopeReceiverId: envelopeReceiverId).ThenAsync( Success: isExisting => isExisting ? View().WithData("EnvelopeKey", envelopeReceiverId) : this.ViewEnvelopeNotFound(), Fail: IActionResult (messages,notices) => { _logger.LogNotice(notices); return this.ViewEnvelopeNotFound(); }); } catch(Exception ex) { _logger.LogEnvelopeError(envelopeEeceiverId: envelopeReceiverId, exception: ex); return this.ViewInnerServiceError(); } } [HttpPost("/EnvelopeKey/{envelopeReceiverId}/Locked")] public async Task LogInEnvelope([FromRoute] string envelopeReceiverId, [FromForm] string access_code) { try { envelopeReceiverId = _urlEncoder.Encode(envelopeReceiverId); (string? uuid, string? signature) = envelopeReceiverId.DecodeEnvelopeReceiverId(); if(uuid is null || signature is null) { _logger.LogEnvelopeError(uuid: uuid, signature: signature, message: _localizer[MessageKey.WrongEnvelopeReceiverId]); return BadRequest(_localizer[MessageKey.WrongEnvelopeReceiverId]); } _logger.LogInformation($"Envelope UUID: [{uuid}]\nReceiver Signature: [{signature}]"); return await _envRcvService.VerifyAccessCodeAsync(uuid: uuid, signature: signature, accessCode: access_code).ThenAsync( SuccessAsync: async isVerified => { EnvelopeResponse response = await envelopeOldService.LoadEnvelope(envelopeReceiverId); if (isVerified) { //todo: write using crud-service (mostlikely history-service) to make it async if (envelopeOldService.ReceiverAlreadySigned(response.Envelope, response.Receiver.Id)) { return View("EnvelopeSigned"); } database.Services.actionService.EnterCorrectAccessCode(response.Envelope, response.Receiver); //for history ViewData["EnvelopeKey"] = envelopeReceiverId; ViewData["EnvelopeResponse"] = response; return await _envRcvService.ReadByUuidSignatureAsync(uuid: uuid, signature: signature).ThenAsync( SuccessAsync: async er => { if (response.Envelope.Documents.Count() > 0) { var document = await envelopeOldService.GetDocument(response.Envelope.Documents[0].Id, envelopeReceiverId); byte[] bytes = await envelopeOldService.GetDocumentContents(document); ViewData["DocumentBytes"] = bytes; } else { return this.ViewDocumentNotFound(); } var claims = new List { new(ClaimTypes.NameIdentifier, uuid), new(ClaimTypes.Hash, signature) }; var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); var authProperties = new AuthenticationProperties { }; await HttpContext.SignInAsync( CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), authProperties); //add PSPDFKit licence key ViewData["PSPDFKitLicenseKey"] = _configuration["PSPDFKitLicenseKey"]; return View("ShowEnvelope", er); }, Fail: (messages, notices) => { _logger.LogNotice(notices); return this.ViewEnvelopeNotFound(); } ); } else { database.Services.actionService.EnterIncorrectAccessCode(response.Envelope, response.Receiver); //for history return Unauthorized(); } }, Fail: (messages, notices) => { _logger.LogNotice(notices); return notices.HasFlag(Flag.SecurityBreach) ? Forbid() : StatusCode(StatusCodes.Status500InternalServerError, messages.Join()); }); } catch(Exception ex) { _logger.LogEnvelopeError(envelopeEeceiverId: envelopeReceiverId, exception: ex); return this.ViewInnerServiceError(); } } [HttpGet("/EnvelopeKey/{envelopeReceiverId}/Success")] public async Task EnvelopeSigned(string envelopeReceiverId) { try { envelopeReceiverId = _urlEncoder.Encode(envelopeReceiverId); return await _envRcvService.IsExisting(envelopeReceiverId: envelopeReceiverId).ThenAsync( SuccessAsync: async isExisting => { if(!isExisting) return this.ViewEnvelopeNotFound(); EnvelopeResponse response = await envelopeOldService.LoadEnvelope(envelopeReceiverId); if (!envelopeOldService.ReceiverAlreadySigned(response.Envelope, response.Receiver.Id)) return Redirect($"/EnvelopeKey/{envelopeReceiverId}/Locked"); await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); ViewData["EnvelopeKey"] = envelopeReceiverId; return View(); }, Fail: IActionResult (messages, notices) => { _logger.LogNotice(notices); return this.ViewEnvelopeNotFound(); }); } catch (Exception ex) { _logger.LogEnvelopeError(envelopeEeceiverId: envelopeReceiverId, exception: ex); return this.ViewInnerServiceError(); } } [Authorize] [HttpGet("IsAuthenticated")] public IActionResult IsAuthenticated() { var envelopeUuid = User.FindFirst(ClaimTypes.NameIdentifier)?.Value; var receiverSignature = User.FindFirst(ClaimTypes.Hash)?.Value; return Ok(new { EnvelopeUuid = envelopeUuid, ReceiverSignature = receiverSignature }); } [HttpGet("lang")] public IActionResult GetLanguage() => Ok(UserLanguage); [HttpPost("lang")] public IActionResult SetLanguage([FromForm] string language) { try { language = _urlEncoder.Encode(language); var cookieOptions = new CookieOptions() { Expires = DateTimeOffset.UtcNow.AddYears(1), Secure = false, Path = "/", SameSite = SameSiteMode.Strict, HttpOnly = true }; Response.Cookies.Append( CookieRequestCultureProvider.DefaultCookieName, CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(language)), cookieOptions); return Redirect(Request.Headers["Referer"].ToString()); } catch(Exception ex) { _logger.LogError(ex, ex.Message); return this.ViewEnvelopeNotFound(); } } private string UserLanguage { get { return Request.Cookies[CookieRequestCultureProvider.DefaultCookieName] ?? _configuration.GetSection("Languages").Get()![0]; } set { Response.Cookies.Append(CookieRequestCultureProvider.DefaultCookieName, CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(value)), new CookieOptions() { Expires = DateTimeOffset.UtcNow.AddYears(1), }); } } public IActionResult Error404() => this.ViewError404(); } }