152 lines
6.8 KiB
C#
152 lines
6.8 KiB
C#
using System.Text;
|
|
using static EnvelopeGenerator.Domain.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 encodedKey, out string[] decodedKeys)
|
|
{
|
|
try
|
|
{
|
|
byte[] bytes = Convert.FromBase64String(encodedKey);
|
|
string decodedString = Encoding.UTF8.GetString(bytes);
|
|
decodedKeys = decodedString.Split(new string[] { "::" }, StringSplitOptions.None);
|
|
return true;
|
|
}
|
|
catch(ArgumentNullException) { }
|
|
catch (FormatException) { }
|
|
catch(ArgumentException) { }
|
|
|
|
decodedKeys = Array.Empty<string>();
|
|
return false;
|
|
}
|
|
|
|
public static EncodeType GetEncodeType(this string[] decodedKeys) => decodedKeys.Length switch
|
|
{
|
|
2 => EncodeType.EnvelopeReceiver,
|
|
3 => long.TryParse(decodedKeys[1], out var _) ? EncodeType.EnvelopeReceiverReadOnly : EncodeType.Undefined,
|
|
_ => EncodeType.Undefined,
|
|
};
|
|
|
|
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 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. ");
|
|
|
|
/// <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;
|
|
}
|
|
} |