refactor(.Extensions): Extensions nach Gruppen aufgeteilt.
- erstellt dekodierende Erweiterungen. - Kodierungserweiterungen erstellt. - XSS-Erweiterungen in das Extensions-Paket verschoben. - EncodeTypes vom Paket Common in das Paket Constants verschoben.
This commit is contained in:
parent
a32f495038
commit
dc997d5ff2
@ -99,6 +99,12 @@
|
||||
DocumentShared
|
||||
End Enum
|
||||
|
||||
Public Enum EncodeType
|
||||
EnvelopeReceiver
|
||||
EnvelopeReceiverReadOnly
|
||||
Undefined
|
||||
End Enum
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "Constants"
|
||||
|
||||
148
EnvelopeGenerator.Extensions/DecodingExtensions.cs
Normal file
148
EnvelopeGenerator.Extensions/DecodingExtensions.cs
Normal file
@ -0,0 +1,148 @@
|
||||
using System.Text;
|
||||
using static EnvelopeGenerator.Common.Constants;
|
||||
|
||||
namespace EnvelopeGenerator.Extensions
|
||||
{
|
||||
public static class DecodingExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Validates whether a given string is a correctly formatted Base-64 encoded string.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method checks the string for proper Base-64 formatting, which includes validating
|
||||
/// the length of the string (must be divisible by 4). It also checks each character to ensure
|
||||
/// it belongs to the Base-64 character set (A-Z, a-z, 0-9, '+', '/', and '=' for padding).
|
||||
/// The method ensures that padding characters ('=') only appear at the end of the string and
|
||||
/// are in a valid configuration (either one '=' at the end if the string's length % 4 is 3,
|
||||
/// or two '==' if the length % 4 is 2).
|
||||
/// </remarks>
|
||||
/// <param name="input">The Base-64 encoded string to validate.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the string is a valid Base-64 encoded string; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// string testString = "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnk=";
|
||||
/// bool isValid = IsValidBase64String(testString);
|
||||
/// Console.WriteLine(isValid); // Output: true
|
||||
/// </code>
|
||||
/// </example>
|
||||
public static bool IsBase64String(this string input)
|
||||
{
|
||||
// Check if the string is null or empty
|
||||
if (string.IsNullOrEmpty(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Replace valid base-64 padding
|
||||
input = input.Trim();
|
||||
int mod4 = input.Length % 4;
|
||||
if (mod4 > 0)
|
||||
{
|
||||
// Base-64 string lengths should be divisible by 4
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check each character to ensure it is valid base-64
|
||||
foreach (char c in input)
|
||||
{
|
||||
if (!char.IsLetterOrDigit(c) && c != '+' && c != '/' && c != '=')
|
||||
{
|
||||
// Invalid character detected
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure no invalid padding scenarios exist
|
||||
if (input.EndsWith("==") && (input.Length % 4 == 0) ||
|
||||
input.EndsWith("=") && (input.Length % 4 == 3))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return input.IndexOf('=') == -1; // No padding allowed except at the end
|
||||
}
|
||||
|
||||
public static bool TryDecode(this string encoded, out string[] decoded)
|
||||
{
|
||||
if (!encoded.IsBase64String())
|
||||
{
|
||||
decoded = Array.Empty<string>();
|
||||
return false;
|
||||
}
|
||||
byte[] bytes = Convert.FromBase64String(encoded);
|
||||
string decodedString = Encoding.UTF8.GetString(bytes);
|
||||
decoded = decodedString.Split(new string[] { "::" }, StringSplitOptions.None);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static EncodeType GetEncodeType(this string[] decoded) => 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 long ToReadOnlyId(this string[] decoded)
|
||||
=> decoded.GetEncodeType() == EncodeType.EnvelopeReceiverReadOnly
|
||||
? long.Parse(decoded[1])
|
||||
: throw new InvalidOperationException("Attempted to convert a decoded other than type EnvelopeReceiver to EnvelopeReceiver. ");
|
||||
|
||||
/// <summary>
|
||||
/// Decodes the envelope receiver ID and extracts the envelope UUID and receiver signature.
|
||||
/// </summary>
|
||||
/// <param name="envelopeReceiverId">The base64 encoded string containing the envelope UUID and receiver signature.</param>
|
||||
/// <returns>A tuple containing the envelope UUID and receiver signature.</returns>
|
||||
public static (string? EnvelopeUuid, string? ReceiverSignature) DecodeEnvelopeReceiverId(this string envelopeReceiverId)
|
||||
{
|
||||
if (!envelopeReceiverId.IsBase64String())
|
||||
{
|
||||
return (null, null);
|
||||
}
|
||||
byte[] bytes = Convert.FromBase64String(envelopeReceiverId);
|
||||
string decodedString = Encoding.UTF8.GetString(bytes);
|
||||
string[] parts = decodedString.Split(new string[] { "::" }, StringSplitOptions.None);
|
||||
|
||||
if (parts.Length > 1)
|
||||
return (EnvelopeUuid: parts[0], ReceiverSignature: parts[1]);
|
||||
else
|
||||
return (string.Empty, string.Empty);
|
||||
}
|
||||
|
||||
public static long? DecodeEnvelopeReceiverReadOnlyId(this string envelopeReceiverReadOnlyId)
|
||||
{
|
||||
if (!envelopeReceiverReadOnlyId.IsBase64String())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
byte[] bytes = Convert.FromBase64String(envelopeReceiverReadOnlyId);
|
||||
string decodedString = System.Text.Encoding.UTF8.GetString(bytes);
|
||||
string[] parts = decodedString.Split(new string[] { "::" }, StringSplitOptions.None);
|
||||
|
||||
if (parts.Length > 2)
|
||||
return long.TryParse(parts[1], out long readOnlyId) ? readOnlyId : null;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the envelope UUID from the decoded envelope receiver ID.
|
||||
/// </summary>
|
||||
/// <param name="envelopeReceiverId">The base64 encoded string to decode.</param>
|
||||
/// <returns>The envelope UUID.</returns>
|
||||
public static string? GetEnvelopeUuid(this string envelopeReceiverId) => envelopeReceiverId.DecodeEnvelopeReceiverId().EnvelopeUuid;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the receiver signature from the decoded envelope receiver ID.
|
||||
/// </summary>
|
||||
/// <param name="envelopeReceiverId">The base64 encoded string to decode.</param>
|
||||
/// <returns>The receiver signature.</returns>
|
||||
public static string? GetReceiverSignature(this string envelopeReceiverId) => envelopeReceiverId.DecodeEnvelopeReceiverId().ReceiverSignature;
|
||||
}
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
namespace EnvelopeGenerator.Extensions
|
||||
{
|
||||
public enum EncodeType
|
||||
{
|
||||
EnvelopeReceiver,
|
||||
ReadOnly,
|
||||
Undefined
|
||||
}
|
||||
}
|
||||
@ -8,155 +8,6 @@ namespace EnvelopeGenerator.Extensions
|
||||
/// </summary>
|
||||
public static class EncodingExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Validates whether a given string is a correctly formatted Base-64 encoded string.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method checks the string for proper Base-64 formatting, which includes validating
|
||||
/// the length of the string (must be divisible by 4). It also checks each character to ensure
|
||||
/// it belongs to the Base-64 character set (A-Z, a-z, 0-9, '+', '/', and '=' for padding).
|
||||
/// The method ensures that padding characters ('=') only appear at the end of the string and
|
||||
/// are in a valid configuration (either one '=' at the end if the string's length % 4 is 3,
|
||||
/// or two '==' if the length % 4 is 2).
|
||||
/// </remarks>
|
||||
/// <param name="input">The Base-64 encoded string to validate.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the string is a valid Base-64 encoded string; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// string testString = "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnk=";
|
||||
/// bool isValid = IsValidBase64String(testString);
|
||||
/// Console.WriteLine(isValid); // Output: true
|
||||
/// </code>
|
||||
/// </example>
|
||||
public static bool IsBase64String(this string input)
|
||||
{
|
||||
// Check if the string is null or empty
|
||||
if (string.IsNullOrEmpty(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Replace valid base-64 padding
|
||||
input = input.Trim();
|
||||
int mod4 = input.Length % 4;
|
||||
if (mod4 > 0)
|
||||
{
|
||||
// Base-64 string lengths should be divisible by 4
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check each character to ensure it is valid base-64
|
||||
foreach (char c in input)
|
||||
{
|
||||
if (!char.IsLetterOrDigit(c) && c != '+' && c != '/' && c != '=')
|
||||
{
|
||||
// Invalid character detected
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure no invalid padding scenarios exist
|
||||
if (input.EndsWith("==") && (input.Length % 4 == 0) ||
|
||||
input.EndsWith("=") && (input.Length % 4 == 3))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return input.IndexOf('=') == -1; // No padding allowed except at the end
|
||||
}
|
||||
|
||||
public static bool TryDecode(this string encoded, out string[] decoded)
|
||||
{
|
||||
if (!encoded.IsBase64String())
|
||||
{
|
||||
decoded = Array.Empty<string>();
|
||||
return false;
|
||||
}
|
||||
byte[] bytes = Convert.FromBase64String(encoded);
|
||||
string decodedString = Encoding.UTF8.GetString(bytes);
|
||||
decoded = decodedString.Split(new string[] { "::" }, StringSplitOptions.None);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static EncodeType GetEncodeType(this string[] decoded) => decoded.Length switch
|
||||
{
|
||||
2 => EncodeType.EnvelopeReceiver,
|
||||
3 => long.TryParse(decoded[1], out var _) ? EncodeType.ReadOnly : 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 long ToReadOnlyId(this string[] decoded)
|
||||
=> decoded.GetEncodeType() == EncodeType.ReadOnly
|
||||
? long.Parse(decoded[1])
|
||||
: throw new InvalidOperationException("Attempted to convert a decoded other than type EnvelopeReceiver to EnvelopeReceiver. ");
|
||||
|
||||
/// <summary>
|
||||
/// Decodes the envelope receiver ID and extracts the envelope UUID and receiver signature.
|
||||
/// </summary>
|
||||
/// <param name="envelopeReceiverId">The base64 encoded string containing the envelope UUID and receiver signature.</param>
|
||||
/// <returns>A tuple containing the envelope UUID and receiver signature.</returns>
|
||||
public static (string? EnvelopeUuid, string? ReceiverSignature) DecodeEnvelopeReceiverId(this string envelopeReceiverId)
|
||||
{
|
||||
if (!envelopeReceiverId.IsBase64String())
|
||||
{
|
||||
return (null, null);
|
||||
}
|
||||
byte[] bytes = Convert.FromBase64String(envelopeReceiverId);
|
||||
string decodedString = Encoding.UTF8.GetString(bytes);
|
||||
string[] parts = decodedString.Split(new string[] { "::" }, StringSplitOptions.None);
|
||||
|
||||
if (parts.Length > 1)
|
||||
return (EnvelopeUuid: parts[0], ReceiverSignature: parts[1]);
|
||||
else
|
||||
return (string.Empty, string.Empty);
|
||||
}
|
||||
|
||||
public static long? DecodeEnvelopeReceiverReadOnlyId(this string envelopeReceiverReadOnlyId)
|
||||
{
|
||||
if (!envelopeReceiverReadOnlyId.IsBase64String())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
byte[] bytes = Convert.FromBase64String(envelopeReceiverReadOnlyId);
|
||||
string decodedString = System.Text.Encoding.UTF8.GetString(bytes);
|
||||
string[] parts = decodedString.Split(new string[] { "::" }, StringSplitOptions.None);
|
||||
|
||||
if (parts.Length > 2)
|
||||
return long.TryParse(parts[1], out long readOnlyId) ? readOnlyId : null;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the envelope UUID from the decoded envelope receiver ID.
|
||||
/// </summary>
|
||||
/// <param name="envelopeReceiverId">The base64 encoded string to decode.</param>
|
||||
/// <returns>The envelope UUID.</returns>
|
||||
public static string? GetEnvelopeUuid(this string envelopeReceiverId) => envelopeReceiverId.DecodeEnvelopeReceiverId().EnvelopeUuid;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the receiver signature from the decoded envelope receiver ID.
|
||||
/// </summary>
|
||||
/// <param name="envelopeReceiverId">The base64 encoded string to decode.</param>
|
||||
/// <returns>The receiver signature.</returns>
|
||||
public static string? GetReceiverSignature(this string envelopeReceiverId) => envelopeReceiverId.DecodeEnvelopeReceiverId().ReceiverSignature;
|
||||
|
||||
public static string EncodeEnvelopeReceiverId(this (string envelopeUuid, string receiverSignature) input)
|
||||
{
|
||||
string combinedString = $"{input.envelopeUuid}::{input.receiverSignature}";
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(combinedString);
|
||||
string base64String = Convert.ToBase64String(bytes);
|
||||
|
||||
return base64String;
|
||||
}
|
||||
|
||||
public static string EncodeEnvelopeReceiverId(this long readOnlyId)
|
||||
{
|
||||
string combinedString = $"{Random.Shared.Next()}::{readOnlyId}::{Random.Shared.Next()}";
|
||||
@ -166,38 +17,13 @@ namespace EnvelopeGenerator.Extensions
|
||||
return base64String;
|
||||
}
|
||||
|
||||
public static void LogEnvelopeError(this ILogger logger, string envelopeReceiverId, Exception? exception = null, string? message = null, params object?[] args)
|
||||
public static string EncodeEnvelopeReceiverId(this (string envelopeUuid, string receiverSignature) input)
|
||||
{
|
||||
var sb = new StringBuilder().AppendLine(envelopeReceiverId.DecodeEnvelopeReceiverId().ToTitle());
|
||||
string combinedString = $"{input.envelopeUuid}::{input.receiverSignature}";
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(combinedString);
|
||||
string base64String = Convert.ToBase64String(bytes);
|
||||
|
||||
if (message is not null)
|
||||
sb.AppendLine(message);
|
||||
|
||||
if(exception is null)
|
||||
logger.Log(LogLevel.Error, sb.ToString(), args);
|
||||
else
|
||||
logger.Log(LogLevel.Error, exception, sb.AppendLine(exception.Message).ToString(), args);
|
||||
}
|
||||
|
||||
public static void LogEnvelopeError(this ILogger logger, string? uuid, string? signature = null, Exception? exception = null, string? message = null, params object?[] args)
|
||||
{
|
||||
var sb = new StringBuilder($"Envelope Uuid: {uuid}");
|
||||
|
||||
if(signature is not null)
|
||||
sb.AppendLine().Append($"Receiver Signature: {signature}");
|
||||
|
||||
if (message is not null)
|
||||
sb.AppendLine().Append(message);
|
||||
|
||||
if (exception is null)
|
||||
logger.Log(LogLevel.Error, sb.ToString(), args);
|
||||
else
|
||||
logger.Log(LogLevel.Error, exception, sb.ToString(), args);
|
||||
}
|
||||
|
||||
public static string ToTitle(this (string? UUID, string? Signature) envelopeReceiverTuple)
|
||||
{
|
||||
return $"UUID is {envelopeReceiverTuple.UUID} and signature is {envelopeReceiverTuple.Signature}";
|
||||
return base64String;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7,7 +7,13 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HtmlSanitizer" Version="8.0.865" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="7.0.19" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\EnvelopeGenerator.Common\EnvelopeGenerator.Common.vbproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
42
EnvelopeGenerator.Extensions/LoggerExtensions.cs
Normal file
42
EnvelopeGenerator.Extensions/LoggerExtensions.cs
Normal file
@ -0,0 +1,42 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text;
|
||||
|
||||
namespace EnvelopeGenerator.Extensions
|
||||
{
|
||||
public static class LoggerExtensions
|
||||
{
|
||||
public static void LogEnvelopeError(this ILogger logger, string envelopeReceiverId, Exception? exception = null, string? message = null, params object?[] args)
|
||||
{
|
||||
var sb = new StringBuilder().AppendLine(envelopeReceiverId.DecodeEnvelopeReceiverId().ToTitle());
|
||||
|
||||
if (message is not null)
|
||||
sb.AppendLine(message);
|
||||
|
||||
if (exception is null)
|
||||
logger.Log(LogLevel.Error, sb.ToString(), args);
|
||||
else
|
||||
logger.Log(LogLevel.Error, exception, sb.AppendLine(exception.Message).ToString(), args);
|
||||
}
|
||||
|
||||
public static void LogEnvelopeError(this ILogger logger, string? uuid, string? signature = null, Exception? exception = null, string? message = null, params object?[] args)
|
||||
{
|
||||
var sb = new StringBuilder($"Envelope Uuid: {uuid}");
|
||||
|
||||
if (signature is not null)
|
||||
sb.AppendLine().Append($"Receiver Signature: {signature}");
|
||||
|
||||
if (message is not null)
|
||||
sb.AppendLine().Append(message);
|
||||
|
||||
if (exception is null)
|
||||
logger.Log(LogLevel.Error, sb.ToString(), args);
|
||||
else
|
||||
logger.Log(LogLevel.Error, exception, sb.ToString(), args);
|
||||
}
|
||||
|
||||
public static string ToTitle(this (string? UUID, string? Signature) envelopeReceiverTuple)
|
||||
{
|
||||
return $"UUID is {envelopeReceiverTuple.UUID} and signature is {envelopeReceiverTuple.Signature}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,7 +2,7 @@
|
||||
using Microsoft.Extensions.Localization;
|
||||
using System.Text.Encodings.Web;
|
||||
|
||||
namespace EnvelopeGenerator.Web
|
||||
namespace EnvelopeGenerator.Extensions
|
||||
{
|
||||
public static class XSSExtensions
|
||||
{
|
||||
@ -17,6 +17,7 @@ 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
|
||||
{
|
||||
@ -60,7 +61,7 @@ namespace EnvelopeGenerator.Web.Controllers
|
||||
return this.ViewDocumentNotFound();
|
||||
}
|
||||
|
||||
if(decoded.GetEncodeType() == EncodeType.ReadOnly)
|
||||
if(decoded.GetEncodeType() == EncodeType.EnvelopeReceiverReadOnly)
|
||||
return Redirect($"{envelopeReceiverId}/ReadOnly");
|
||||
|
||||
ViewData["EnvelopeKey"] = envelopeReceiverId;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
@using EnvelopeGenerator.Web
|
||||
@using EnvelopeGenerator.Web.Models
|
||||
@using EnvelopeGenerator.Web.Sanitizers
|
||||
@using EnvelopeGenerator.Extensions
|
||||
@using Microsoft.Extensions.Localization
|
||||
@using EnvelopeGenerator.Application.Resources
|
||||
@using Microsoft.Extensions.Options
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user