diff --git a/EnvelopeGenerator.Extensions/DecodingExtensions.cs b/EnvelopeGenerator.Extensions/DecodingExtensions.cs index 1fa41809..9fcb93ff 100644 --- a/EnvelopeGenerator.Extensions/DecodingExtensions.cs +++ b/EnvelopeGenerator.Extensions/DecodingExtensions.cs @@ -64,34 +64,34 @@ namespace EnvelopeGenerator.Extensions return input.IndexOf('=') == -1; // No padding allowed except at the end } - public static bool TryDecode(this string encoded, out string[] decoded) + public static bool TryDecode(this string encodedKey, out string[] decodedKeys) { - if (!encoded.IsBase64String()) + if (!encodedKey.IsBase64String()) { - decoded = Array.Empty(); + decodedKeys = Array.Empty(); return false; } - byte[] bytes = Convert.FromBase64String(encoded); + byte[] bytes = Convert.FromBase64String(encodedKey); string decodedString = Encoding.UTF8.GetString(bytes); - decoded = decodedString.Split(new string[] { "::" }, StringSplitOptions.None); + decodedKeys = decodedString.Split(new string[] { "::" }, StringSplitOptions.None); return true; } - public static EncodeType GetEncodeType(this string[] decoded) => decoded.Length switch + public static EncodeType GetEncodeType(this string[] decodedKeys) => decoded.Length switch { 2 => EncodeType.EnvelopeReceiver, 3 => long.TryParse(decoded[1], out var _) ? EncodeType.EnvelopeReceiverReadOnly : EncodeType.Undefined, _ => EncodeType.Undefined, }; - public static (string? EnvelopeUuid, string? ReceiverSignature) ToEnvelopeReceiverId(this string[] decoded) - => decoded.GetEncodeType() == EncodeType.EnvelopeReceiver - ? (EnvelopeUuid: decoded[0], ReceiverSignature: decoded[1]) - : throw new InvalidOperationException("Attempted to convert a decoded other than type EnvelopeReceiver to EnvelopeReceiver. "); + public static (string? EnvelopeUuid, string? ReceiverSignature) ParseEnvelopeReceiverId(this string[] decodedKeys) + => decodedKeys.GetEncodeType() == EncodeType.EnvelopeReceiver + ? (EnvelopeUuid: decodedKeys[0], ReceiverSignature: decodedKeys[1]) + : throw new InvalidOperationException("Attempted to convert a decoded other than type EnvelopeReceiver to EnvelopeReceiver."); - public static long ToReadOnlyId(this string[] decoded) - => decoded.GetEncodeType() == EncodeType.EnvelopeReceiverReadOnly - ? long.Parse(decoded[1]) + public static long ParseReadOnlyId(this string[] decodedKeys) + => decodedKeys.GetEncodeType() == EncodeType.EnvelopeReceiverReadOnly + ? long.Parse(decodedKeys[1]) : throw new InvalidOperationException("Attempted to convert a decoded other than type EnvelopeReceiver to EnvelopeReceiver. "); /// diff --git a/EnvelopeGenerator.Extensions/EncodingExtensions.cs b/EnvelopeGenerator.Extensions/EncodingExtensions.cs index f2e0a1f8..e1acf0e9 100644 --- a/EnvelopeGenerator.Extensions/EncodingExtensions.cs +++ b/EnvelopeGenerator.Extensions/EncodingExtensions.cs @@ -10,6 +10,7 @@ namespace EnvelopeGenerator.Extensions { public static string EncodeEnvelopeReceiverId(this long readOnlyId) { + //The random number is used as a salt to increase security but it is not saved in the database. string combinedString = $"{Random.Shared.Next()}::{readOnlyId}::{Random.Shared.Next()}"; byte[] bytes = Encoding.UTF8.GetBytes(combinedString); string base64String = Convert.ToBase64String(bytes); diff --git a/EnvelopeGenerator.Web/Controllers/HomeController.cs b/EnvelopeGenerator.Web/Controllers/HomeController.cs index 3cedf1ac..5ecb81a7 100644 --- a/EnvelopeGenerator.Web/Controllers/HomeController.cs +++ b/EnvelopeGenerator.Web/Controllers/HomeController.cs @@ -15,8 +15,6 @@ using System.Text.Encodings.Web; using EnvelopeGenerator.Web.Models; using EnvelopeGenerator.Application.Resources; using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver; -using EnvelopeGenerator.Domain.Entities; -using System.Text.RegularExpressions; using static EnvelopeGenerator.Common.Constants; namespace EnvelopeGenerator.Web.Controllers @@ -307,15 +305,36 @@ namespace EnvelopeGenerator.Web.Controllers } [Authorize] - [HttpGet("EnvelopeKey/{envelopeReceiverId}/ReadOnly")] - public async Task EnvelopeReceiverReadOnly(string readOnlyId) + [HttpGet("EnvelopeKey/{readOnlyId}/ReadOnly")] + public async Task EnvelopeReceiverReadOnly(string readOnlyKey) { try { - return Ok(); + readOnlyKey = _urlEncoder.Encode(readOnlyKey); + + // check if the readOnlyId is valid + if (!readOnlyKey.TryDecode(out var decodedKeys) || decodedKeys.GetEncodeType() != EncodeType.EnvelopeReceiverReadOnly) + { + Response.StatusCode = StatusCodes.Status401Unauthorized; + return this.ViewDocumentNotFound(); + } + + var readOnlyId = decodedKeys.ParseReadOnlyId(); + return await _readOnlyService.ReadByIdAsync(readOnlyId).ThenAsync( + Success: erro => + { + ViewData["model"] = erro; + return View("ShowEnvelope"); + }, + Fail: IActionResult (msg, ntc) => + { + _logger.LogNotice(ntc); + return this.ViewInnerServiceError(); + }); } catch (Exception ex) { + _logger.LogError(ex, "An unexpected error occurred while displaying a read-only envelope. Read-only key is {readOnlyKey}. {message}", readOnlyKey, ex.Message); return this.ViewInnerServiceError(); } }