Refactor CapyKit utilities: streamline namespaces, improve code consistency, and enhance XML documentation.
This commit is contained in:
parent
2b30a8b5e9
commit
f03f73afc7
28 changed files with 5180 additions and 4298 deletions
|
|
@ -1,11 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
namespace CapyKit.Attributes;
|
||||
|
||||
namespace CapyKit.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom attribute class for decorating enumeration fields with additional data.
|
||||
/// </summary>
|
||||
|
|
@ -15,17 +9,6 @@ namespace CapyKit.Attributes
|
|||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public abstract class EnumerationAttribute<T> : Attribute
|
||||
{
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EnumerationAttribute{T}"/> class with a
|
||||
/// specified value.
|
||||
/// </summary>
|
||||
/// <value> The value. </value>
|
||||
public T Value { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary> Gets the value of the enumeration represented by this attribute. </summary>
|
||||
|
|
@ -39,5 +22,15 @@ namespace CapyKit.Attributes
|
|||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EnumerationAttribute{T}" /> class with a
|
||||
/// specified value.
|
||||
/// </summary>
|
||||
/// <value> The value. </value>
|
||||
public T Value { get; private set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
|
@ -1,11 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
namespace CapyKit.Attributes;
|
||||
|
||||
namespace CapyKit.Attributes
|
||||
{
|
||||
/// <summary> An attribute class for decorating enumeration fields with a description. </summary>
|
||||
/// <seealso cref="EnumerationAttribute{T}" />
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
|
|
@ -22,4 +16,3 @@ namespace CapyKit.Attributes
|
|||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@ namespace CapyKit.Attributes;
|
|||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public class EnumerationIconAttribute : Attribute
|
||||
{
|
||||
/// <summary> Gets or sets the description of the enumeration. </summary>
|
||||
/// <value> The description. </value>
|
||||
public string Icon { get; private set; }
|
||||
|
||||
/// <summary> Constructor. </summary>
|
||||
/// <param name="icon"> The icon associated with the enumeration. </param>
|
||||
public EnumerationIconAttribute(string icon)
|
||||
{
|
||||
this.Icon = icon;
|
||||
}
|
||||
|
||||
/// <summary> Gets or sets the description of the enumeration. </summary>
|
||||
/// <value> The description. </value>
|
||||
public string Icon { get; private set; }
|
||||
}
|
||||
|
|
@ -4,14 +4,6 @@ namespace CapyKit.Attributes;
|
|||
/// <remarks> Accepted values are stored as discreet values similar to an enumeration. Ranges are not supported. </remarks>
|
||||
public class ParameterAcceptedValuesAttribute : Attribute
|
||||
{
|
||||
#region Properties
|
||||
|
||||
/// <summary> Gets or sets the accepted values. </summary>
|
||||
/// <value> The accepted values. </value>
|
||||
public IEnumerable<object> AcceptedValues { get; private set; }
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary> Constructor. </summary>
|
||||
|
|
@ -22,4 +14,12 @@ public class ParameterAcceptedValuesAttribute : Attribute
|
|||
}
|
||||
|
||||
#endregion Constructors
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary> Gets or sets the accepted values. </summary>
|
||||
/// <value> The accepted values. </value>
|
||||
public IEnumerable<object> AcceptedValues { get; private set; }
|
||||
|
||||
#endregion Properties
|
||||
}
|
||||
|
|
@ -13,13 +13,15 @@ public class ParameterAttribute : Attribute
|
|||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name parameter as passed in a POST method from the Browser. This can be hardcoded at the class level.
|
||||
/// Gets or sets the name parameter as passed in a POST method from the Browser. This can be hardcoded at the class
|
||||
/// level.
|
||||
/// </summary>
|
||||
/// <value> The name of the parameter. </value>
|
||||
public string ParameterName { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the description of the parameter. This serves as a human-readable explanation or label for the parameter's purpose or usage.
|
||||
/// Gets the description of the parameter. This serves as a human-readable explanation or label for the parameter's
|
||||
/// purpose or usage.
|
||||
/// </summary>
|
||||
/// <value>The description text of the parameter.</value>
|
||||
public string Description { get; private set; }
|
||||
|
|
@ -48,8 +50,10 @@ public class ParameterAttribute : Attribute
|
|||
|
||||
/// <summary> Constructor. </summary>
|
||||
/// <param name="systemName"> The name of the system. </param>
|
||||
/// <param name="description"> Name of the resource that contains the description of
|
||||
/// the parameter. </param>
|
||||
/// <param name="description">
|
||||
/// Name of the resource that contains the description of
|
||||
/// the parameter.
|
||||
/// </param>
|
||||
public ParameterAttribute(string systemName, string description)
|
||||
{
|
||||
this.ParameterName = systemName;
|
||||
|
|
@ -60,8 +64,10 @@ public class ParameterAttribute : Attribute
|
|||
|
||||
/// <summary> Constructor. </summary>
|
||||
/// <param name="systemName"> The name of the system. </param>
|
||||
/// <param name="description"> Name of the resource that contains the description of
|
||||
/// the parameter. </param>
|
||||
/// <param name="description">
|
||||
/// Name of the resource that contains the description of
|
||||
/// the parameter.
|
||||
/// </param>
|
||||
/// <param name="iconName"> The FontAwesome icon name. </param>
|
||||
public ParameterAttribute(string systemName, string description, string iconName)
|
||||
{
|
||||
|
|
@ -73,8 +79,10 @@ public class ParameterAttribute : Attribute
|
|||
|
||||
/// <summary> Constructor. </summary>
|
||||
/// <param name="systemName"> The name of the system. </param>
|
||||
/// <param name="description"> Name of the resource that contains the description of
|
||||
/// the parameter. </param>
|
||||
/// <param name="description">
|
||||
/// Name of the resource that contains the description of
|
||||
/// the parameter.
|
||||
/// </param>
|
||||
/// <param name="iconName"> The FontAwesome icon name. </param>
|
||||
/// <param name="ordinal"> The ordinal position. </param>
|
||||
public ParameterAttribute(string systemName, string description, string iconName, int ordinal)
|
||||
|
|
@ -87,8 +95,10 @@ public class ParameterAttribute : Attribute
|
|||
|
||||
/// <summary> Constructor. </summary>
|
||||
/// <param name="systemName"> The name of the system. </param>
|
||||
/// <param name="description"> Name of the resource that contains the description of
|
||||
/// the parameter. </param>
|
||||
/// <param name="description">
|
||||
/// Name of the resource that contains the description of
|
||||
/// the parameter.
|
||||
/// </param>
|
||||
/// <param name="ordinal"> The ordinal position. </param>
|
||||
public ParameterAttribute(string systemName, string description, int ordinal)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,11 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
namespace CapyKit.Attributes;
|
||||
|
||||
namespace CapyKit.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom attribute for formatting values in a specific way.
|
||||
/// </summary>
|
||||
|
|
@ -16,10 +10,22 @@ namespace CapyKit.Attributes
|
|||
|
||||
/// <summary> Gets or sets the format to use for formatting the value. </summary>
|
||||
/// <value> The format string used to format the value. </value>
|
||||
public string Format { get; private set; }
|
||||
public string Format { get; }
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary> Gets a parameterized formatted string for the specified index. </summary>
|
||||
/// <param name="index"> (Optional) Zero-based index of the item in the string to format. </param>
|
||||
/// <returns> A formatted string with the specified index and format. </returns>
|
||||
public string GetFormatParameterizedString(int index = 0)
|
||||
{
|
||||
return "{" + index + ":" + this.Format + "}";
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -42,17 +48,4 @@ namespace CapyKit.Attributes
|
|||
}
|
||||
|
||||
#endregion Constructors
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary> Gets a parameterized formatted string for the specified index. </summary>
|
||||
/// <param name="index"> (Optional) Zero-based index of the item in the string to format. </param>
|
||||
/// <returns> A formatted string with the specified index and format. </returns>
|
||||
public string GetFormatParameterizedString(int index = 0)
|
||||
{
|
||||
return "{" + index + ":" + this.Format + "}";
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime.CompilerServices;
|
||||
using CapyKit.Attributes;
|
||||
using CapyKit.Extensions;
|
||||
|
||||
namespace CapyKit
|
||||
{
|
||||
namespace CapyKit;
|
||||
|
||||
/// <summary>
|
||||
/// The CapyEventReporter class is responsible for managing event subscriptions and emissions within CapyKit.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Because consumers of CapyKit may have varied ways of handling logging, the <see cref="CapyEventReporter"/> provides
|
||||
/// Because consumers of CapyKit may have varied ways of handling logging, the <see cref="CapyEventReporter" />
|
||||
/// provides
|
||||
/// a way for subscribers to recieve events for various "events" within the library. These can be thought of as
|
||||
/// a logging solution for CapyKit. Consumers are free to treat these events however they see fit.
|
||||
/// </remarks>
|
||||
|
|
@ -24,11 +19,11 @@ namespace CapyKit
|
|||
/// <summary>
|
||||
/// A dictionary storing event handlers and their corresponding origins for each subscription level.
|
||||
/// </summary>
|
||||
private static Dictionary<EventLevel, List<(CapyEventHandler Handler, string origin)>> subscribers = new Dictionary<EventLevel, List<(CapyEventHandler Handler, string origin)>>();
|
||||
private static readonly Dictionary<EventLevel, List<(CapyEventHandler Handler, string origin)>> subscribers = new();
|
||||
|
||||
/// <summary> A hash set storing unique identifiers for events intended to only be emitted once. </summary>
|
||||
/// <seealso cref="EmitEventOnce(EventLevel, string, string, string, object[])" />
|
||||
private static HashSet<string> uniqueIdentifiers = new HashSet<string>();
|
||||
private static readonly HashSet<string> uniqueIdentifiers = new();
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
@ -47,14 +42,15 @@ namespace CapyKit
|
|||
/// <param name="origin">
|
||||
/// (Optional) The name of the method or class where the subscription is made.
|
||||
/// </param>
|
||||
public static void Subscribe(CapyEventHandler callback, EventLevel subscriptionLevel, [CallerMemberName] string origin = null)
|
||||
public static void Subscribe(CapyEventHandler callback, EventLevel subscriptionLevel,
|
||||
[CallerMemberName] string origin = null)
|
||||
{
|
||||
if (!subscribers.ContainsKey(subscriptionLevel))
|
||||
if (!CapyEventReporter.subscribers.ContainsKey(subscriptionLevel))
|
||||
{
|
||||
subscribers.Add(subscriptionLevel, new List<(CapyEventHandler Handler, string origin)>());
|
||||
CapyEventReporter.subscribers.Add(subscriptionLevel, new List<(CapyEventHandler Handler, string origin)>());
|
||||
}
|
||||
|
||||
subscribers[subscriptionLevel].Add((callback, origin ?? "[Unknown]"));
|
||||
CapyEventReporter.subscribers[subscriptionLevel].Add((callback, origin ?? "[Unknown]"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -70,7 +66,8 @@ namespace CapyKit
|
|||
{
|
||||
if (value is EventLevel)
|
||||
{
|
||||
subscribers[(EventLevel)value].RemoveAll(c => c.Handler == callback && c.origin == origin);
|
||||
CapyEventReporter.subscribers[(EventLevel)value]
|
||||
.RemoveAll(c => c.Handler == callback && c.origin == origin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -97,9 +94,10 @@ namespace CapyKit
|
|||
/// </code>
|
||||
/// </example>
|
||||
/// <seealso cref="CallerMemberNameAttribute" />
|
||||
public static void EmitEvent(EventLevel eventLevel, string message, [CallerMemberName] string method = null, params object[] args)
|
||||
public static void EmitEvent(EventLevel eventLevel, string message, [CallerMemberName] string method = null,
|
||||
params object[] args)
|
||||
{
|
||||
if (!subscribers.ContainsKey(eventLevel))
|
||||
if (!CapyEventReporter.subscribers.ContainsKey(eventLevel))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -108,7 +106,7 @@ namespace CapyKit
|
|||
|
||||
var capyEventArgs = new CapyEventArgs(eventLevel, formattedMessage, method);
|
||||
|
||||
foreach (var subscriber in subscribers[eventLevel])
|
||||
foreach (var subscriber in CapyEventReporter.subscribers[eventLevel])
|
||||
{
|
||||
subscriber.Handler(capyEventArgs);
|
||||
}
|
||||
|
|
@ -137,15 +135,16 @@ namespace CapyKit
|
|||
/// </param>
|
||||
/// <seealso cref="CallerMemberNameAttribute" />
|
||||
/// <seealso cref="Guid" />
|
||||
public static void EmitEventOnce(EventLevel eventLevel, string message, string uniqueIdentifier, [CallerMemberName] string method = null, params object[] args)
|
||||
public static void EmitEventOnce(EventLevel eventLevel, string message, string uniqueIdentifier,
|
||||
[CallerMemberName] string method = null, params object[] args)
|
||||
{
|
||||
if(uniqueIdentifiers.Contains(uniqueIdentifier))
|
||||
if (CapyEventReporter.uniqueIdentifiers.Contains(uniqueIdentifier))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uniqueIdentifiers.Add(uniqueIdentifier);
|
||||
EmitEvent(eventLevel, message, method: method, args: args);
|
||||
CapyEventReporter.uniqueIdentifiers.Add(uniqueIdentifier);
|
||||
EmitEvent(eventLevel, message, method, args);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
@ -163,6 +162,23 @@ namespace CapyKit
|
|||
/// </summary>
|
||||
public class CapyEventArgs : EventArgs
|
||||
{
|
||||
#region Constructor
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the CapyEventArgs class with the specified event level, message, and method name.
|
||||
/// </summary>
|
||||
/// <param name="level">The severity level of the event.</param>
|
||||
/// <param name="message">A descriptive message explaining the reason for the event.</param>
|
||||
/// <param name="method">The name of the method where the event was raised.</param>
|
||||
public CapyEventArgs(EventLevel level, string message, string method = null)
|
||||
{
|
||||
this.Level = level;
|
||||
this.Message = message;
|
||||
this.MethodName = method ?? "[Unknown]";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -181,43 +197,28 @@ namespace CapyKit
|
|||
public string MethodName { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the CapyEventArgs class with the specified event level, message, and method name.
|
||||
/// </summary>
|
||||
/// <param name="level">The severity level of the event.</param>
|
||||
/// <param name="message">A descriptive message explaining the reason for the event.</param>
|
||||
/// <param name="method">The name of the method where the event was raised.</param>
|
||||
public CapyEventArgs(EventLevel level, string message, string method = null)
|
||||
{
|
||||
this.Level = level;
|
||||
this.Message = message;
|
||||
this.MethodName = method ?? "[Unknown]";
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
/// <summary> Enumeration representing different event level severity values. </summary>
|
||||
public enum EventLevel
|
||||
{
|
||||
/// <summary> Represents a critical error that requires immediate attention. </summary>
|
||||
[EnumerationDescription("Represents a critical error that requires immediate attention.")]
|
||||
Critical = 0,
|
||||
|
||||
/// <summary> Represents an error that prevents the normal execution of the application. </summary>
|
||||
[EnumerationDescription("Represents an error that prevents the normal execution of the application.")]
|
||||
Error = 1,
|
||||
|
||||
/// <summary> Represents a warning indicating a non-critical issue that should be addressed. </summary>
|
||||
[EnumerationDescription("Represents a warning indicating a non-critical issue that should be addressed.")]
|
||||
Warning = 2,
|
||||
|
||||
/// <summary> Represents informational messages that provide useful context to the consumer. </summary>
|
||||
[EnumerationDescription("Represents informational messages that provide useful context to the consumer.")]
|
||||
Information = 3,
|
||||
|
||||
/// <summary> Represents detailed messages that are typically used for debugging purposes. </summary>
|
||||
[EnumerationDescription("Represents detailed messages that are typically used for debugging purposes.")]
|
||||
Debug = 4
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
namespace CapyKit;
|
||||
|
||||
namespace CapyKit
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds a value that has been encrypted.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class EncryptedValue<T>
|
||||
{
|
||||
#region Members
|
||||
|
||||
//
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -26,5 +14,10 @@ namespace CapyKit
|
|||
public T Value { get; set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#region Members
|
||||
|
||||
//
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
|
@ -1,11 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
namespace CapyKit.Enumerations;
|
||||
|
||||
namespace CapyKit.Enumerations
|
||||
{
|
||||
/// <summary>
|
||||
/// An enumeration representing different measurement systems.
|
||||
/// </summary>
|
||||
|
|
@ -17,4 +11,3 @@ namespace CapyKit.Enumerations
|
|||
/// <summary> The metric measurement system. </summary>
|
||||
Metric = 1
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,9 @@
|
|||
using CapyKit.Attributes;
|
||||
using System.Reflection;
|
||||
using CapyKit.Attributes;
|
||||
using CapyKit.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CapyKit.Extensions
|
||||
{
|
||||
namespace CapyKit.Extensions;
|
||||
|
||||
/// <summary> Provides static extentions methods for providing additional functionality for <see cref="Enum" /> types. </summary>
|
||||
public static class EnumerationExtensions
|
||||
{
|
||||
|
|
@ -62,7 +57,7 @@ namespace CapyKit.Extensions
|
|||
/// <returns> The human readable name of the enumeration. </returns>
|
||||
public static string GetPrettyName(this Enum enumeration)
|
||||
{
|
||||
return LanguageHelper.CamelCaseToHumanReadable(GetName(enumeration));
|
||||
return LanguageHelper.CamelCaseToHumanReadable(enumeration.GetName());
|
||||
}
|
||||
|
||||
/// <summary> An <see cref="Enum" /> extension method that gets a description. </summary>
|
||||
|
|
@ -75,10 +70,13 @@ namespace CapyKit.Extensions
|
|||
var memInfo = enumeration.GetType().GetMember(enumeration.GetName());
|
||||
if (memInfo.Any())
|
||||
{
|
||||
var attribute = memInfo.First().GetCustomAttribute(typeof(EnumerationDescriptionAttribute)) as EnumerationDescriptionAttribute;
|
||||
var attribute =
|
||||
memInfo.First().GetCustomAttribute(typeof(EnumerationDescriptionAttribute)) as
|
||||
EnumerationDescriptionAttribute;
|
||||
if (attribute == null)
|
||||
{
|
||||
CapyEventReporter.EmitEvent(EventLevel.Error, "Could not find the description for {0}.", args: new[] { enumeration });
|
||||
CapyEventReporter.EmitEvent(EventLevel.Error, "Could not find the description for {0}.",
|
||||
args: new[] { enumeration });
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -91,4 +89,3 @@ namespace CapyKit.Extensions
|
|||
|
||||
#endregion Methods
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace CapyKit.Extensions
|
||||
{
|
||||
/// <summary> Provides static extension methods for performing common LINQ operations on <see cref="IEnumerable{T}"/> and <see cref="IQueryable{T}"/> collections. </summary>
|
||||
namespace CapyKit.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Provides static extension methods for performing common LINQ operations on <see cref="IEnumerable{T}" /> and
|
||||
/// <see cref="IQueryable{T}" /> collections.
|
||||
/// </summary>
|
||||
public static class LINQExtensions
|
||||
{
|
||||
/// <summary>
|
||||
|
|
@ -33,11 +31,12 @@ namespace CapyKit.Extensions
|
|||
/// <returns>
|
||||
/// An enumerator that allows foreach to be used to process remove in this collection.
|
||||
/// </returns>
|
||||
public static IQueryable<T> Filter<T>(this IQueryable<T> source, System.Linq.Expressions.Expression<Func<T, bool>> predicate)
|
||||
public static IQueryable<T> Filter<T>(this IQueryable<T> source, Expression<Func<T, bool>> predicate)
|
||||
{
|
||||
if (predicate.Parameters.Count > 1)
|
||||
{
|
||||
CapyEventReporter.EmitEvent(EventLevel.Warning, "More than one parameter was found in the predicate, which could result in unexpected behavior.");
|
||||
CapyEventReporter.EmitEvent(EventLevel.Warning,
|
||||
"More than one parameter was found in the predicate, which could result in unexpected behavior.");
|
||||
}
|
||||
|
||||
var parameter = predicate.Parameters.FirstOrDefault();
|
||||
|
|
@ -68,7 +67,8 @@ namespace CapyKit.Extensions
|
|||
{
|
||||
if (pageNumber < 1)
|
||||
{
|
||||
CapyEventReporter.EmitEvent(EventLevel.Error, "pageNumber is out of range. [{0}]", args: new[] { pageNumber });
|
||||
CapyEventReporter.EmitEvent(EventLevel.Error, "pageNumber is out of range. [{0}]",
|
||||
args: new[] { pageNumber });
|
||||
throw new ArgumentOutOfRangeException("pageNumber");
|
||||
}
|
||||
|
||||
|
|
@ -102,7 +102,8 @@ namespace CapyKit.Extensions
|
|||
{
|
||||
if (pageNumber < 1)
|
||||
{
|
||||
CapyEventReporter.EmitEvent(EventLevel.Error, "pageNumber is out of range. [{0}]", args: new[] { pageNumber });
|
||||
CapyEventReporter.EmitEvent(EventLevel.Error, "pageNumber is out of range. [{0}]",
|
||||
args: new[] { pageNumber });
|
||||
throw new ArgumentOutOfRangeException("pageNumber");
|
||||
}
|
||||
|
||||
|
|
@ -171,13 +172,15 @@ namespace CapyKit.Extensions
|
|||
/// <param name="resultSelector"> The result selector. </param>
|
||||
/// <param name="defaultGenerator"> (Optional) The default generator. </param>
|
||||
/// <returns> An IQueryable<R> </returns>
|
||||
public static IQueryable<R> LeftOuterJoin<T, U, TKey, R>(this IQueryable<T> source, IQueryable<U> inner, Expression<Func<T, TKey>> outerSelector, Expression<Func<U, TKey>> innerSelector, Func<T, IEnumerable<U>, R> resultSelector, Func<T, U> defaultGenerator = null)
|
||||
public static IQueryable<R> LeftOuterJoin<T, U, TKey, R>(this IQueryable<T> source, IQueryable<U> inner,
|
||||
Expression<Func<T, TKey>> outerSelector, Expression<Func<U, TKey>> innerSelector,
|
||||
Func<T, IEnumerable<U>, R> resultSelector, Func<T, U> defaultGenerator = null)
|
||||
{
|
||||
Func<T, IEnumerable<U>, R> resultOrDefaultSelector = (i, o) =>
|
||||
{
|
||||
if (defaultGenerator == null)
|
||||
{
|
||||
defaultGenerator = (t) => default(U);
|
||||
defaultGenerator = t => default;
|
||||
}
|
||||
|
||||
if (!o.Any())
|
||||
|
|
@ -202,7 +205,9 @@ namespace CapyKit.Extensions
|
|||
/// <param name="innerSelector"> The inner selector. </param>
|
||||
/// <param name="resultSelector"> The result selector. </param>
|
||||
/// <returns> An IQueryable<R> </returns>
|
||||
private static IQueryable<R> LeftOuterJoin<T, U, TKey, R>(this IQueryable<T> source, IQueryable<U> inner, Expression<Func<T, TKey>> outerSelector, Expression<Func<U, TKey>> innerSelector, Expression<Func<T, IEnumerable<U>, R>> resultSelector)
|
||||
private static IQueryable<R> LeftOuterJoin<T, U, TKey, R>(this IQueryable<T> source, IQueryable<U> inner,
|
||||
Expression<Func<T, TKey>> outerSelector, Expression<Func<U, TKey>> innerSelector,
|
||||
Expression<Func<T, IEnumerable<U>, R>> resultSelector)
|
||||
{
|
||||
return source.GroupJoin(inner, outerSelector, innerSelector, resultSelector);
|
||||
}
|
||||
|
|
@ -221,13 +226,15 @@ namespace CapyKit.Extensions
|
|||
/// <returns>
|
||||
/// An enumerator that allows foreach to be used to process left outter join in this collection.
|
||||
/// </returns>
|
||||
public static IEnumerable<R> LeftOuterJoin<T, U, TKey, R>(this IEnumerable<T> source, IEnumerable<U> inner, Func<T, TKey> outerSelector, Func<U, TKey> innerSelector, Func<T, IEnumerable<U>, R> resultSelector, Func<T, U> defaultGenerator = null)
|
||||
public static IEnumerable<R> LeftOuterJoin<T, U, TKey, R>(this IEnumerable<T> source, IEnumerable<U> inner,
|
||||
Func<T, TKey> outerSelector, Func<U, TKey> innerSelector, Func<T, IEnumerable<U>, R> resultSelector,
|
||||
Func<T, U> defaultGenerator = null)
|
||||
{
|
||||
var combined = source.GroupJoin(inner, outerSelector, innerSelector, (i, o) => new { inner = i, outer = o });
|
||||
|
||||
if (defaultGenerator == null)
|
||||
{
|
||||
defaultGenerator = (t) => default(U);
|
||||
defaultGenerator = t => default;
|
||||
}
|
||||
|
||||
return combined.Select(anon =>
|
||||
|
|
@ -257,4 +264,3 @@ namespace CapyKit.Extensions
|
|||
return items.Distinct(propertyComparer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
namespace CapyKit.Extensions;
|
||||
|
||||
namespace CapyKit.Extensions
|
||||
{
|
||||
/// <summary> An class containing extenstions that apply to any object type. </summary>
|
||||
public static class ObjectExtensions
|
||||
{
|
||||
|
|
@ -38,7 +32,9 @@ namespace CapyKit.Extensions
|
|||
{
|
||||
var targetProperties = target.GetType().GetProperties();
|
||||
var sourceProperties = source.GetType().GetProperties();
|
||||
var matchingProperties = targetProperties.Join(sourceProperties, outer => new { outer.Name, outer.PropertyType }, inner => new { inner.Name, inner.PropertyType }, (outer, inner) => new { Target = outer, Source = inner });
|
||||
var matchingProperties = targetProperties.Join(sourceProperties,
|
||||
outer => new { outer.Name, outer.PropertyType }, inner => new { inner.Name, inner.PropertyType },
|
||||
(outer, inner) => new { Target = outer, Source = inner });
|
||||
|
||||
foreach (var propertyMatch in matchingProperties)
|
||||
{
|
||||
|
|
@ -49,4 +45,3 @@ namespace CapyKit.Extensions
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
namespace CapyKit.Extensions;
|
||||
|
||||
namespace CapyKit.Extensions
|
||||
{
|
||||
/// <summary> Provides static extentions methods for providing additional functionality for <see cref="string" /> types. </summary>
|
||||
public static class StringExtensions
|
||||
{
|
||||
|
|
@ -53,4 +47,3 @@ namespace CapyKit.Extensions
|
|||
|
||||
#endregion Methods
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,9 @@
|
|||
using CapyKit.Enumerations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using CapyKit.Enumerations;
|
||||
|
||||
namespace CapyKit.Helpers;
|
||||
|
||||
namespace CapyKit.Helpers
|
||||
{
|
||||
/// <summary> Static class providing helper methods for various calculations. </summary>
|
||||
public static class CalculationHelper
|
||||
{
|
||||
|
|
@ -37,7 +33,7 @@ namespace CapyKit.Helpers
|
|||
/// </remarks>
|
||||
public static int CalculateHash(string str)
|
||||
{
|
||||
MD5 md5Hasher = MD5.Create();
|
||||
var md5Hasher = MD5.Create();
|
||||
var md5Hash = md5Hasher.ComputeHash(Encoding.UTF8.GetBytes(str));
|
||||
var hash = BitConverter.ToInt32(md5Hash, 0);
|
||||
|
||||
|
|
@ -49,16 +45,16 @@ namespace CapyKit.Helpers
|
|||
/// <returns> The calculated 16 character hexadecimal hash. </returns>
|
||||
public static string CalculateHexHash(string str)
|
||||
{
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(str);
|
||||
var bytes = Encoding.UTF8.GetBytes(str);
|
||||
|
||||
MD5 md5Hasher = MD5.Create();
|
||||
byte[] hash = md5Hasher.ComputeHash(bytes);
|
||||
var md5Hasher = MD5.Create();
|
||||
var hash = md5Hasher.ComputeHash(bytes);
|
||||
|
||||
char[] hash2 = new char[16];
|
||||
var hash2 = new char[16];
|
||||
|
||||
// Note that here we are wasting bits of hash!
|
||||
// But it isn't really important, because hash.Length == 32
|
||||
for (int i = 0; i < hash2.Length; i++)
|
||||
for (var i = 0; i < hash2.Length; i++)
|
||||
{
|
||||
hash2[i] = CalculationHelper.chars[hash[i] % CalculationHelper.chars.Length];
|
||||
}
|
||||
|
|
@ -80,14 +76,16 @@ namespace CapyKit.Helpers
|
|||
/// to calculate the "as-the-crow-flies" distance between two points on earth.
|
||||
/// </remarks>
|
||||
/// <seealso cref="GetDistance(double, double, double, double, MeasurementSystem)" />
|
||||
public static decimal GetDistance(decimal latitudeOrigin, decimal longitudeOrigin, decimal latitudeDestination, decimal longitudeDestination, MeasurementSystem measurementSystem = MeasurementSystem.Imperial)
|
||||
public static decimal GetDistance(decimal latitudeOrigin, decimal longitudeOrigin, decimal latitudeDestination,
|
||||
decimal longitudeDestination, MeasurementSystem measurementSystem = MeasurementSystem.Imperial)
|
||||
{
|
||||
double latitudeOriginalDouble = Convert.ToDouble(latitudeOrigin);
|
||||
double longitudeOriginDouble = Convert.ToDouble(longitudeOrigin);
|
||||
double latitudeDestinationDouble = Convert.ToDouble(latitudeDestination);
|
||||
double longitudeDestinationDouble = Convert.ToDouble(longitudeDestination);
|
||||
var latitudeOriginalDouble = Convert.ToDouble(latitudeOrigin);
|
||||
var longitudeOriginDouble = Convert.ToDouble(longitudeOrigin);
|
||||
var latitudeDestinationDouble = Convert.ToDouble(latitudeDestination);
|
||||
var longitudeDestinationDouble = Convert.ToDouble(longitudeDestination);
|
||||
|
||||
var result = GetDistance(latitudeOriginalDouble, longitudeOriginDouble, latitudeDestinationDouble, longitudeDestinationDouble, measurementSystem);
|
||||
var result = GetDistance(latitudeOriginalDouble, longitudeOriginDouble, latitudeDestinationDouble,
|
||||
longitudeDestinationDouble, measurementSystem);
|
||||
|
||||
return Convert.ToDecimal(result);
|
||||
}
|
||||
|
|
@ -103,17 +101,19 @@ namespace CapyKit.Helpers
|
|||
/// Uses the <a href="https://www.movable-type.co.uk/scripts/latlong.html">haversine</a> formula
|
||||
/// to calculate the "as-the-crow-flies" distance between two points on earth.
|
||||
/// </remarks>
|
||||
public static double GetDistance(double latitudeOrigin, double longitudeOrigin, double latitudeDestination, double longitudeDestination, MeasurementSystem measurementSystem = MeasurementSystem.Imperial)
|
||||
public static double GetDistance(double latitudeOrigin, double longitudeOrigin, double latitudeDestination,
|
||||
double longitudeDestination, MeasurementSystem measurementSystem = MeasurementSystem.Imperial)
|
||||
{
|
||||
var thetaLatitude = DegreesToRadians(latitudeOrigin);
|
||||
var thetaLongitude = DegreesToRadians(longitudeOrigin);
|
||||
var deltaLatitude = DegreesToRadians(latitudeDestination - latitudeOrigin);
|
||||
var deltaLongitude = DegreesToRadians(longitudeDestination - longitudeOrigin);
|
||||
|
||||
var haversineTheta = Math.Sin(deltaLatitude / 2) * Math.Sin(deltaLatitude / 2) + Math.Cos(thetaLatitude) * Math.Cos(thetaLongitude) * Math.Sin(deltaLongitude / 2) * Math.Sin(deltaLongitude / 2);
|
||||
var haversineTheta = Math.Sin(deltaLatitude / 2) * Math.Sin(deltaLatitude / 2) + Math.Cos(thetaLatitude) *
|
||||
Math.Cos(thetaLongitude) * Math.Sin(deltaLongitude / 2) * Math.Sin(deltaLongitude / 2);
|
||||
var angularDistance = 2 * Math.Atan2(Math.Sqrt(haversineTheta), Math.Sqrt(1 - haversineTheta));
|
||||
|
||||
var distance = EARTH_RADIUS_KILOMETERS * angularDistance;
|
||||
var distance = CalculationHelper.EARTH_RADIUS_KILOMETERS * angularDistance;
|
||||
|
||||
if (measurementSystem == MeasurementSystem.Imperial)
|
||||
{
|
||||
|
|
@ -128,7 +128,7 @@ namespace CapyKit.Helpers
|
|||
/// <returns> The value in miles. </returns>
|
||||
public static double KilometersToMiles(double kilometers)
|
||||
{
|
||||
return kilometers * MILES_PER_KILOMETER;
|
||||
return kilometers * CalculationHelper.MILES_PER_KILOMETER;
|
||||
}
|
||||
|
||||
/// <summary> Converts miles to kilometers. </summary>
|
||||
|
|
@ -136,7 +136,7 @@ namespace CapyKit.Helpers
|
|||
/// <returns> The value in kilometers. </returns>
|
||||
public static double MilesToKilometers(double miles)
|
||||
{
|
||||
return miles / MILES_PER_KILOMETER;
|
||||
return miles / CalculationHelper.MILES_PER_KILOMETER;
|
||||
}
|
||||
|
||||
/// <summary> Convers degrees to radians. </summary>
|
||||
|
|
@ -157,4 +157,3 @@ namespace CapyKit.Helpers
|
|||
|
||||
#endregion Methods
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.IO.Compression;
|
||||
|
||||
namespace CapyKit.Helpers;
|
||||
|
||||
namespace CapyKit.Helpers
|
||||
{
|
||||
/// <summary> A class that contains methods for managing data compression. </summary>
|
||||
public static class CompressionHelper
|
||||
{
|
||||
|
|
@ -36,6 +31,7 @@ namespace CapyKit.Helpers
|
|||
inputStream.CopyTo(gzipStream);
|
||||
gzipStream.Flush();
|
||||
}
|
||||
|
||||
return outputStream.ToArray();
|
||||
}
|
||||
}
|
||||
|
|
@ -80,6 +76,7 @@ namespace CapyKit.Helpers
|
|||
{
|
||||
gzipStream.CopyTo(outputStream);
|
||||
}
|
||||
|
||||
var bytes = outputStream.ToArray();
|
||||
return SerializationHelper.Deserialize<T>(bytes);
|
||||
}
|
||||
|
|
@ -103,4 +100,3 @@ namespace CapyKit.Helpers
|
|||
|
||||
#endregion Methods
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.ObjectiveC;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
namespace CapyKit.Helpers;
|
||||
|
||||
namespace CapyKit.Helpers
|
||||
{
|
||||
public class EncryptionHelper
|
||||
{
|
||||
#region Members
|
||||
|
|
@ -41,4 +34,3 @@ namespace CapyKit.Helpers
|
|||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ public static class EnumerationHelper
|
|||
return (T)(object)value;
|
||||
}
|
||||
|
||||
return default(T);
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary> Gets enumeration value from a string value. </summary>
|
||||
|
|
@ -39,7 +39,7 @@ public static class EnumerationHelper
|
|||
}
|
||||
}
|
||||
|
||||
return default(T);
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -1,23 +1,20 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
|
||||
namespace CapyKit.Helpers
|
||||
{
|
||||
namespace CapyKit.Helpers;
|
||||
|
||||
/// <summary> A class that contains methods for managing key creation and validation against a master key. </summary>
|
||||
public class KeyHelper
|
||||
{
|
||||
/// <summary> The master key accessor function. </summary>
|
||||
private Func<byte[]> masterKeyAccessor;
|
||||
/// <summary> The salt size accessor function. </summary>
|
||||
private Func<int> saltSizeAccessor;
|
||||
|
||||
/// <summary> Number of parts accessor function. </summary>
|
||||
private Func<int> numPartsAccessor;
|
||||
|
||||
/// <summary> The salt size accessor function. </summary>
|
||||
private Func<int> saltSizeAccessor;
|
||||
|
||||
/// <summary> Sets the master key. </summary>
|
||||
/// <param name="accessor"> The accessor function. </param>
|
||||
public void SetMasterKeyAccessor(Func<byte[]> accessor)
|
||||
|
|
@ -38,6 +35,7 @@ namespace CapyKit.Helpers
|
|||
CapyEventReporter.EmitEvent(EventLevel.Error, errorMessage);
|
||||
throw new InvalidOperationException(errorMessage);
|
||||
}
|
||||
|
||||
return this.masterKeyAccessor();
|
||||
}
|
||||
|
||||
|
|
@ -69,13 +67,14 @@ namespace CapyKit.Helpers
|
|||
/// <returns> The number parts. </returns>
|
||||
public int GetNumParts()
|
||||
{
|
||||
int parts = this.numPartsAccessor != null ? this.numPartsAccessor() : 2;
|
||||
var parts = this.numPartsAccessor != null ? this.numPartsAccessor() : 2;
|
||||
if (parts < 2)
|
||||
{
|
||||
var errorMessage = "Number of parts must be 2 or more.";
|
||||
CapyEventReporter.EmitEvent(EventLevel.Error, errorMessage);
|
||||
throw new ArgumentException(errorMessage);
|
||||
}
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
|
|
@ -87,12 +86,12 @@ namespace CapyKit.Helpers
|
|||
/// <returns> The calculated signature. </returns>
|
||||
private byte[] ComputeSignature(byte[] salt)
|
||||
{
|
||||
byte[] masterKey = GetMasterKey();
|
||||
var masterKey = GetMasterKey();
|
||||
using (var hmac = new HMACSHA256(masterKey))
|
||||
{
|
||||
byte[] hash = hmac.ComputeHash(salt);
|
||||
int sigLength = salt.Length;
|
||||
byte[] signature = new byte[sigLength];
|
||||
var hash = hmac.ComputeHash(salt);
|
||||
var sigLength = salt.Length;
|
||||
var signature = new byte[sigLength];
|
||||
Array.Copy(hash, signature, sigLength);
|
||||
return signature;
|
||||
}
|
||||
|
|
@ -103,11 +102,12 @@ namespace CapyKit.Helpers
|
|||
/// <returns> A string. </returns>
|
||||
private string BytesToHex(byte[] bytes)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(bytes.Length * 2);
|
||||
var sb = new StringBuilder(bytes.Length * 2);
|
||||
foreach (var b in bytes)
|
||||
{
|
||||
sb.Append(b.ToString("X2"));
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
|
|
@ -125,11 +125,13 @@ namespace CapyKit.Helpers
|
|||
CapyEventReporter.EmitEvent(EventLevel.Error, errorMessage);
|
||||
throw new ArgumentException(errorMessage);
|
||||
}
|
||||
byte[] bytes = new byte[hex.Length / 2];
|
||||
for (int i = 0; i < hex.Length; i += 2)
|
||||
|
||||
var bytes = new byte[hex.Length / 2];
|
||||
for (var i = 0; i < hex.Length; i += 2)
|
||||
{
|
||||
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
|
@ -140,22 +142,25 @@ namespace CapyKit.Helpers
|
|||
/// <returns> The formatted key. </returns>
|
||||
private string FormatKey(string hex)
|
||||
{
|
||||
int parts = GetNumParts();
|
||||
int totalLength = hex.Length;
|
||||
int baseLength = totalLength / parts;
|
||||
int remainder = totalLength % parts;
|
||||
var parts = GetNumParts();
|
||||
var totalLength = hex.Length;
|
||||
var baseLength = totalLength / parts;
|
||||
var remainder = totalLength % parts;
|
||||
|
||||
StringBuilder formatted = new StringBuilder();
|
||||
int currentIndex = 0;
|
||||
for (int i = 0; i < parts; i++)
|
||||
var formatted = new StringBuilder();
|
||||
var currentIndex = 0;
|
||||
for (var i = 0; i < parts; i++)
|
||||
{
|
||||
// Distribute any extra characters across the first few groups.
|
||||
int groupLength = baseLength + (i < remainder ? 1 : 0);
|
||||
var groupLength = baseLength + (i < remainder ? 1 : 0);
|
||||
formatted.Append(hex.Substring(currentIndex, groupLength));
|
||||
currentIndex += groupLength;
|
||||
if (i < parts - 1)
|
||||
{
|
||||
formatted.Append("-");
|
||||
}
|
||||
}
|
||||
|
||||
return formatted.ToString();
|
||||
}
|
||||
|
||||
|
|
@ -163,17 +168,17 @@ namespace CapyKit.Helpers
|
|||
/// <returns> The key. </returns>
|
||||
public string GenerateKey()
|
||||
{
|
||||
int saltSize = GetSaltSize();
|
||||
byte[] salt = new byte[saltSize];
|
||||
var saltSize = GetSaltSize();
|
||||
var salt = new byte[saltSize];
|
||||
using (var rng = RandomNumberGenerator.Create())
|
||||
{
|
||||
rng.GetBytes(salt);
|
||||
}
|
||||
|
||||
byte[] signature = ComputeSignature(salt);
|
||||
string saltHex = BytesToHex(salt);
|
||||
string signatureHex = BytesToHex(signature);
|
||||
string combinedHex = saltHex + signatureHex;
|
||||
var signature = ComputeSignature(salt);
|
||||
var saltHex = BytesToHex(salt);
|
||||
var signatureHex = BytesToHex(signature);
|
||||
var combinedHex = saltHex + signatureHex;
|
||||
return FormatKey(combinedHex);
|
||||
}
|
||||
|
||||
|
|
@ -186,17 +191,21 @@ namespace CapyKit.Helpers
|
|||
public bool ValidateKey(string providedKey)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(providedKey))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove dashes.
|
||||
string cleanedKey = providedKey.Replace("-", "");
|
||||
int saltSize = GetSaltSize();
|
||||
int expectedTotalHexLength = 4 * saltSize; // salt (2*saltSize) + signature (2*saltSize)
|
||||
var cleanedKey = providedKey.Replace("-", "");
|
||||
var saltSize = GetSaltSize();
|
||||
var expectedTotalHexLength = 4 * saltSize; // salt (2*saltSize) + signature (2*saltSize)
|
||||
if (cleanedKey.Length != expectedTotalHexLength)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string saltHex = cleanedKey.Substring(0, 2 * saltSize);
|
||||
string signatureHex = cleanedKey.Substring(2 * saltSize);
|
||||
var saltHex = cleanedKey.Substring(0, 2 * saltSize);
|
||||
var signatureHex = cleanedKey.Substring(2 * saltSize);
|
||||
|
||||
byte[] salt;
|
||||
byte[] providedSignature;
|
||||
|
|
@ -210,16 +219,20 @@ namespace CapyKit.Helpers
|
|||
return false;
|
||||
}
|
||||
|
||||
byte[] expectedSignature = ComputeSignature(salt);
|
||||
var expectedSignature = ComputeSignature(salt);
|
||||
if (expectedSignature.Length != providedSignature.Length)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < expectedSignature.Length; i++)
|
||||
{
|
||||
if (expectedSignature[i] != providedSignature[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < expectedSignature.Length; i++)
|
||||
{
|
||||
if (expectedSignature[i] != providedSignature[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace CapyKit.Helpers;
|
||||
|
||||
namespace CapyKit.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class for handling text transformations.
|
||||
/// </summary>
|
||||
|
|
@ -23,11 +18,11 @@ namespace CapyKit.Helpers
|
|||
/// <returns> A string in human readable format. </returns>
|
||||
public static string CamelCaseToHumanReadable(string value)
|
||||
{
|
||||
var regex = new Regex(@"(?<=[A-Z])(?=[A-Z][a-z]) | (?<=[^A-Z])(?=[A-Z]) | (?<=[A-Za-z])(?=[^A-Za-z])", RegexOptions.IgnorePatternWhitespace);
|
||||
var regex = new Regex(@"(?<=[A-Z])(?=[A-Z][a-z]) | (?<=[^A-Z])(?=[A-Z]) | (?<=[A-Za-z])(?=[^A-Za-z])",
|
||||
RegexOptions.IgnorePatternWhitespace);
|
||||
|
||||
return regex.Replace(value, " ");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,10 @@ public static class PropertyHelper<T>
|
|||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
/// <summary> Gets the reflected <typeparamref name="TProperty"/> value of an instanced <typeparamref name="T"/> object property value as described by a <paramref name="selector"/>. </summary>
|
||||
/// <summary>
|
||||
/// Gets the reflected <typeparamref name="TProperty" /> value of an instanced <typeparamref name="T" /> object
|
||||
/// property value as described by a <paramref name="selector" />.
|
||||
/// </summary>
|
||||
/// <typeparam name="TProperty"> Type of the property. </typeparam>
|
||||
/// <param name="obj"> The instanced object. </param>
|
||||
/// <param name="selector"> The property selector function that identifies the property. </param>
|
||||
|
|
@ -54,10 +57,12 @@ public static class PropertyHelper<T>
|
|||
/// Gets the reflected <see cref="PropertyInfo" /> of an <typeparamref name="T" /> object as
|
||||
/// described by a <paramref name="selector" />.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException"> Thrown when the <paramref name="selector"/> does
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Thrown when the <paramref name="selector" /> does
|
||||
/// not return a <see cref="LambdaExpression.Body" />
|
||||
/// of type
|
||||
/// <see cref="ExpressionType.MemberAccess"/>. </exception>
|
||||
/// <see cref="ExpressionType.MemberAccess" />.
|
||||
/// </exception>
|
||||
/// <typeparam name="TProperty"> Type of the property. </typeparam>
|
||||
/// <param name="selector"> The property selector function that identifies the property. </param>
|
||||
/// <returns> The reflected <see cref="PropertyInfo" />. </returns>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,9 @@
|
|||
using CapyKit.Attributes;
|
||||
using CapyKit.Extensions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using CapyKit.Attributes;
|
||||
|
||||
namespace CapyKit.Helpers;
|
||||
|
||||
namespace CapyKit.Helpers
|
||||
{
|
||||
/// <summary> A class that contains methods for managing secure data processing and cryptography. </summary>
|
||||
public class SecurityHelper
|
||||
{
|
||||
|
|
@ -89,7 +83,8 @@ namespace CapyKit.Helpers
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares a hashed password with a plaintext password by using a specified hashing algorithm <typeparamref name="T"/>.
|
||||
/// Compares a hashed password with a plaintext password by using a specified hashing algorithm
|
||||
/// <typeparamref name="T" />.
|
||||
/// This method requires the existing hash, the plaintext password to compare, and the associated salt value.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the password hashing algorithm implementing <see cref="IPasswordAlgorithm" />.</typeparam>
|
||||
|
|
@ -125,7 +120,8 @@ namespace CapyKit.Helpers
|
|||
|
||||
/// <summary>
|
||||
/// Compares an unencrypted <paramref name="password" /> with a stored, encrypted <paramref name="existingPassword" />.
|
||||
/// This method uses the specified password hashing algorithm of type <typeparamref name="T"/> to hash the <paramref name="password"/>
|
||||
/// This method uses the specified password hashing algorithm of type <typeparamref name="T" /> to hash the
|
||||
/// <paramref name="password" />
|
||||
/// and then compares it with the <paramref name="existingPassword" />.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the password hashing algorithm, implementing <see cref="IPasswordAlgorithm" />.</typeparam>
|
||||
|
|
@ -142,7 +138,7 @@ namespace CapyKit.Helpers
|
|||
var algorithmType = algorithm.GetType();
|
||||
|
||||
var providedPassword = typeof(SecurityHelper)
|
||||
.GetMethod("GetPassword", new Type[] { typeof(string), typeof(byte[]), typeof(object[]) })
|
||||
.GetMethod("GetPassword", new[] { typeof(string), typeof(byte[]), typeof(object[]) })
|
||||
?.MakeGenericMethod(algorithmType)
|
||||
?.Invoke(null, new object[] { password, salt, args });
|
||||
|
||||
|
|
@ -163,7 +159,8 @@ namespace CapyKit.Helpers
|
|||
|
||||
/// <summary>
|
||||
/// Retrieves a <see cref="Password" /> object using the specified password and generates a random salt value.
|
||||
/// Then it uses that salt to call the overloaded <see cref="GetPassword{T}(string, byte[], object[])"/> method with the given password and
|
||||
/// Then it uses that salt to call the overloaded <see cref="GetPassword{T}(string, byte[], object[])" /> method with
|
||||
/// the given password and
|
||||
/// the generated salt as arguments.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"> The type of <see cref="IPasswordAlgorithm" /> implementation to use. </typeparam>
|
||||
|
|
@ -189,7 +186,8 @@ namespace CapyKit.Helpers
|
|||
/// constructor arguments.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method uses reflection to find a constructor for the specified password algorithm type (<typeparamref name="T"/>).
|
||||
/// This method uses reflection to find a constructor for the specified password algorithm type (
|
||||
/// <typeparamref name="T" />).
|
||||
/// It emits an error event if a suitable constructor is not found or if there is an error invoking the constructor.
|
||||
/// </remarks>
|
||||
/// <typeparam name="T">
|
||||
|
|
@ -224,7 +222,7 @@ namespace CapyKit.Helpers
|
|||
typeof(T).Name,
|
||||
string.Join(",", argTypes.Select(arg => arg.Name))
|
||||
});
|
||||
return default(Password);
|
||||
return default;
|
||||
}
|
||||
|
||||
var passwordInstance = (T)algorithmConstructor.Invoke(args);
|
||||
|
|
@ -238,14 +236,15 @@ namespace CapyKit.Helpers
|
|||
typeof(T).Name,
|
||||
string.Join(",", args)
|
||||
});
|
||||
return default(Password);
|
||||
return default;
|
||||
}
|
||||
|
||||
return new Password(password, salt, passwordInstance, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a new <see cref="Password"/> object using the PBKDF2 algorithm with the provided <paramref name="password"/>
|
||||
/// Generates a new <see cref="Password" /> object using the PBKDF2 algorithm with the provided
|
||||
/// <paramref name="password" />
|
||||
/// and <paramref name="salt" />.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
|
|
@ -268,7 +267,8 @@ namespace CapyKit.Helpers
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a new <see cref="Password"/> object using the PBKDF2 algorithm with the provided <paramref name="password"/>.
|
||||
/// Generates a new <see cref="Password" /> object using the PBKDF2 algorithm with the provided
|
||||
/// <paramref name="password" />.
|
||||
/// This overload of the method generates a random salt value for added security.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
|
|
@ -283,7 +283,7 @@ namespace CapyKit.Helpers
|
|||
/// </returns>
|
||||
public static Password Pbkdf2(string password, int saltSize)
|
||||
{
|
||||
var salt = SecurityHelper.GetRandomBytes(saltSize);
|
||||
var salt = GetRandomBytes(saltSize);
|
||||
var pwd = new Password(password, salt, Password.Pbkdf2Algorithm);
|
||||
|
||||
return pwd;
|
||||
|
|
@ -345,7 +345,10 @@ namespace CapyKit.Helpers
|
|||
ValidCharacterCollection.Special);
|
||||
}
|
||||
|
||||
/// <summary> Gets a cryptographically strong random string using the character values found in <see cref="VALID_CHARACTERS"/>. </summary>
|
||||
/// <summary>
|
||||
/// Gets a cryptographically strong random string using the character values found in
|
||||
/// <see cref="VALID_CHARACTERS" />.
|
||||
/// </summary>
|
||||
/// <param name="length"> The length of the string to create. </param>
|
||||
/// <returns> The random string. </returns>
|
||||
public static string GetRandomString(int length, params ValidCharacterCollection[] validChars)
|
||||
|
|
@ -355,7 +358,7 @@ namespace CapyKit.Helpers
|
|||
new byte[length * 3]; // Overprovision the buffer so we can discard a small percentage.
|
||||
var validCharacters = GetValidCharacterComposition(validChars);
|
||||
var validByteUpperLimit =
|
||||
(256 / validCharacters.Length) * validCharacters.Length -
|
||||
256 / validCharacters.Length * validCharacters.Length -
|
||||
1; // Maintains equal distribution of valid characters.
|
||||
|
||||
using (var rng = RandomNumberGenerator.Create())
|
||||
|
|
@ -363,11 +366,11 @@ namespace CapyKit.Helpers
|
|||
while (buffer.Length < length)
|
||||
{
|
||||
rng.GetBytes(randomNumberBuffer);
|
||||
foreach (byte b in randomNumberBuffer)
|
||||
foreach (var b in randomNumberBuffer)
|
||||
{
|
||||
if (b <= validByteUpperLimit)
|
||||
{
|
||||
int index = b % validCharacters.Length;
|
||||
var index = b % validCharacters.Length;
|
||||
buffer.Append(validCharacters[index]);
|
||||
if (buffer.Length == length)
|
||||
{
|
||||
|
|
@ -405,7 +408,10 @@ namespace CapyKit.Helpers
|
|||
/// <summary>
|
||||
/// Static method that returns a valid character composition based on the given ValidCharacterCollection parameters.
|
||||
/// </summary>
|
||||
/// <param name="validCharacters">An array of ValidCharacterCollection enumeration values representing the desired character sets.</param>
|
||||
/// <param name="validCharacters">
|
||||
/// An array of ValidCharacterCollection enumeration values representing the desired
|
||||
/// character sets.
|
||||
/// </param>
|
||||
/// <returns>A string containing all the characters from the specified character sets.</returns>
|
||||
public static string GetValidCharacterComposition(params ValidCharacterCollection[] validCharacters)
|
||||
{
|
||||
|
|
@ -426,8 +432,6 @@ namespace CapyKit.Helpers
|
|||
case ValidCharacterCollection.Special:
|
||||
composition.Append(SecurityHelper.SPECIAL_CHARACTERS);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -480,6 +484,5 @@ namespace CapyKit.Helpers
|
|||
/// Indicates that special characters should be included in the random string.
|
||||
/// </summary>
|
||||
[EnumerationDescriptionAttribute(SecurityHelper.SPECIAL_CHARACTERS)]
|
||||
Special,
|
||||
}
|
||||
Special
|
||||
}
|
||||
|
|
@ -1,15 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace CapyKit.Helpers;
|
||||
|
||||
namespace CapyKit.Helpers
|
||||
{
|
||||
public static class SerializationHelper
|
||||
{
|
||||
#region Members
|
||||
|
|
@ -71,12 +63,17 @@ namespace CapyKit.Helpers
|
|||
}
|
||||
catch (JsonException ex)
|
||||
{
|
||||
CapyEventReporter.EmitEvent(EventLevel.Error, "JSON formatting error detected during deserialization of byte array for {0}.", args: new[] { typeof(T).Name });
|
||||
throw new FormatException(string.Format("JSON formatting error detected during deserialization of byte array for {0}.", typeof(T).Name), ex);
|
||||
CapyEventReporter.EmitEvent(EventLevel.Error,
|
||||
"JSON formatting error detected during deserialization of byte array for {0}.",
|
||||
args: new[] { typeof(T).Name });
|
||||
throw new FormatException(
|
||||
string.Format("JSON formatting error detected during deserialization of byte array for {0}.",
|
||||
typeof(T).Name), ex);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
CapyEventReporter.EmitEvent(EventLevel.Error, "Could not deserialize object of type {0}.", args: new[] { typeof(T).Name });
|
||||
CapyEventReporter.EmitEvent(EventLevel.Error, "Could not deserialize object of type {0}.",
|
||||
args: new[] { typeof(T).Name });
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
|
@ -91,10 +88,11 @@ namespace CapyKit.Helpers
|
|||
{
|
||||
return (T)Convert.ChangeType(str, typeof(T));
|
||||
}
|
||||
else if(string.IsNullOrWhiteSpace(str))
|
||||
|
||||
if (string.IsNullOrWhiteSpace(str))
|
||||
{
|
||||
CapyEventReporter.EmitEvent(EventLevel.Error, "Could not deserialize an empty string.");
|
||||
return default(T);
|
||||
return default;
|
||||
}
|
||||
|
||||
return JsonSerializer.Deserialize<T>(str);
|
||||
|
|
@ -102,4 +100,3 @@ namespace CapyKit.Helpers
|
|||
|
||||
#endregion Methods
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
namespace CapyKit.Helpers;
|
||||
|
||||
namespace CapyKit.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Static class containing helper methods for retrieving and setting application settings.
|
||||
/// </summary>
|
||||
|
|
@ -54,13 +48,13 @@ namespace CapyKit.Helpers
|
|||
/// <summary>
|
||||
/// Private delegate function that retrieves a setting with the given <c>key</c>.
|
||||
/// </summary>
|
||||
private static Func<string, object> accessor = (key) => default(object);
|
||||
private static Func<string, object> accessor = key => default;
|
||||
|
||||
/// <summary>
|
||||
/// Private delegate function that detects if a setting with a given <c>key</c> exists. Returns <see langword="true" />
|
||||
/// if the setting exists, <see langword="false" /> if not.
|
||||
/// </summary>
|
||||
private static Func<string, bool> detector = (key) => false;
|
||||
private static Func<string, bool> detector = key => false;
|
||||
|
||||
#endregion Members
|
||||
|
||||
|
|
@ -82,10 +76,10 @@ namespace CapyKit.Helpers
|
|||
return (T)result;
|
||||
}
|
||||
|
||||
return default(T);
|
||||
return default;
|
||||
}
|
||||
|
||||
return default(T);
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary> Sets the function used to retrieve application settings. </summary>
|
||||
|
|
@ -132,4 +126,3 @@ namespace CapyKit.Helpers
|
|||
|
||||
#endregion Methods
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,14 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlTypes;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace CapyKit;
|
||||
|
||||
namespace CapyKit
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a password with its hash, salt and algorithm used for encryption.
|
||||
/// </summary>
|
||||
|
|
@ -16,40 +9,7 @@ namespace CapyKit
|
|||
{
|
||||
#region Members
|
||||
|
||||
private static Lazy<Pbkdf2Algorithm> pbkdf2Algorithm = new Lazy<Pbkdf2Algorithm>(() => new Pbkdf2Algorithm());
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the hash of the password.
|
||||
/// </summary>
|
||||
public byte[] Hash { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the salt used for encryption.
|
||||
/// </summary>
|
||||
public byte[] Salt { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the algorithm used for password encryption.
|
||||
/// </summary>
|
||||
public IPasswordAlgorithm Algorithm { get; private set; }
|
||||
|
||||
#region Preconfigued Password Algorithms
|
||||
|
||||
/// <summary> Gets the preconfigured PBKDF2 algorithm. </summary>
|
||||
/// <value> The preconfigured PBKDF2 algorithm. </value>
|
||||
public static Pbkdf2Algorithm Pbkdf2Algorithm
|
||||
{
|
||||
get
|
||||
{
|
||||
return pbkdf2Algorithm.Value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
private static readonly Lazy<Pbkdf2Algorithm> pbkdf2Algorithm = new(() => new Pbkdf2Algorithm());
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
@ -57,7 +17,10 @@ namespace CapyKit
|
|||
/// <param name="password"> The password to be hashed. </param>
|
||||
/// <param name="salt"> The salt used for encryption. </param>
|
||||
/// <param name="algorithm"> The algorithm used for password encryption. </param>
|
||||
/// <param name="args"> A variable-length parameters list containing arguments to include for the <paramref name="algorithm"/>. </param>
|
||||
/// <param name="args">
|
||||
/// A variable-length parameters list containing arguments to include for the
|
||||
/// <paramref name="algorithm" />.
|
||||
/// </param>
|
||||
public Password(string password, byte[] salt, IPasswordAlgorithm algorithm, params object[] args)
|
||||
{
|
||||
// We know there will always be a salt, so we can prepend it to h
|
||||
|
|
@ -79,14 +42,50 @@ namespace CapyKit
|
|||
this.Algorithm = algorithm;
|
||||
}
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the hash of the password.
|
||||
/// </summary>
|
||||
public byte[] Hash { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the salt used for encryption.
|
||||
/// </summary>
|
||||
public byte[] Salt { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the algorithm used for password encryption.
|
||||
/// </summary>
|
||||
public IPasswordAlgorithm Algorithm { get; }
|
||||
|
||||
#region Preconfigued Password Algorithms
|
||||
|
||||
/// <summary> Gets the preconfigured PBKDF2 algorithm. </summary>
|
||||
/// <value> The preconfigured PBKDF2 algorithm. </value>
|
||||
public static Pbkdf2Algorithm Pbkdf2Algorithm
|
||||
{
|
||||
get { return Password.pbkdf2Algorithm.Value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if(obj == null) return false; // The object is null, and this object is not.
|
||||
if (obj == null)
|
||||
{
|
||||
return false; // The object is null, and this object is not.
|
||||
}
|
||||
|
||||
if(ReferenceEquals(this, obj)) return true; // The object is literally this object.
|
||||
if (ReferenceEquals(this, obj))
|
||||
{
|
||||
return true; // The object is literally this object.
|
||||
}
|
||||
|
||||
var objPassword = obj as Password;
|
||||
|
||||
|
|
@ -103,7 +102,8 @@ namespace CapyKit
|
|||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Hash: {0}, Salt: {1}, Algorithm: {2}", BitConverter.ToString(this.Hash), BitConverter.ToString(this.Salt), this.Algorithm?.AlgorithmName);
|
||||
return string.Format("Hash: {0}, Salt: {1}, Algorithm: {2}", BitConverter.ToString(this.Hash),
|
||||
BitConverter.ToString(this.Salt), this.Algorithm?.AlgorithmName);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
@ -180,31 +180,6 @@ namespace CapyKit
|
|||
/// </summary>
|
||||
public class Pbkdf2Algorithm : IPasswordAlgorithm
|
||||
{
|
||||
#region Members
|
||||
|
||||
/// <summary> (Immutable) The default length. </summary>
|
||||
/// <remarks> This member is immutable. </remarks>
|
||||
public const int LENGTH = 32;
|
||||
|
||||
/// <summary> The default number of iterations. </summary>
|
||||
/// <remarks> This member is immutable. </remarks>
|
||||
public const int ITERATIONS = 100000;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string AlgorithmName
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Pbkdf2";
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
/// <summary> Default constructor. </summary>
|
||||
|
|
@ -215,6 +190,18 @@ namespace CapyKit
|
|||
|
||||
#endregion
|
||||
|
||||
#region IPasswordAlgorithm Members
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <inheritdoc />
|
||||
public string AlgorithmName
|
||||
{
|
||||
get { return "Pbkdf2"; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary> Encrypts the given password using a PBKDF2 algorithm. </summary>
|
||||
|
|
@ -222,9 +209,15 @@ namespace CapyKit
|
|||
/// <param name="args">
|
||||
/// Additional arguments for the encryption process, specifically
|
||||
/// <list type="number">
|
||||
/// <item><c>salt</c></item>
|
||||
/// <item><c>length</c></item>
|
||||
/// <item><c>iterations</c></item>
|
||||
/// <item>
|
||||
/// <c>salt</c>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <c>length</c>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <c>iterations</c>
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </param>
|
||||
/// <returns> A byte array with the hashed <paramref name="password" />. </returns>
|
||||
|
|
@ -252,7 +245,7 @@ namespace CapyKit
|
|||
catch (Exception ex)
|
||||
{
|
||||
CapyEventReporter.EmitEvent(EventLevel.Error, "Could not convert the second parameter into an integer.");
|
||||
length = LENGTH;
|
||||
length = Pbkdf2Algorithm.LENGTH;
|
||||
}
|
||||
|
||||
var iterations = 0;
|
||||
|
|
@ -263,7 +256,7 @@ namespace CapyKit
|
|||
catch (Exception ex)
|
||||
{
|
||||
CapyEventReporter.EmitEvent(EventLevel.Error, "Could not convert the second parameter into an integer.");
|
||||
iterations = ITERATIONS;
|
||||
iterations = Pbkdf2Algorithm.ITERATIONS;
|
||||
}
|
||||
|
||||
var hash = new byte[0];
|
||||
|
|
@ -283,7 +276,20 @@ namespace CapyKit
|
|||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Members
|
||||
|
||||
/// <summary> (Immutable) The default length. </summary>
|
||||
/// <remarks> This member is immutable. </remarks>
|
||||
public const int LENGTH = 32;
|
||||
|
||||
/// <summary> The default number of iterations. </summary>
|
||||
/// <remarks> This member is immutable. </remarks>
|
||||
public const int ITERATIONS = 100000;
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
106
CapyKit/Pool.cs
106
CapyKit/Pool.cs
|
|
@ -1,13 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace CapyKit;
|
||||
|
||||
namespace CapyKit
|
||||
{
|
||||
/// <summary>
|
||||
/// A managed pool of resources. This class provides a thread-safe way to manage a collection of
|
||||
/// objects of type <typeparamref name="T" />.
|
||||
|
|
@ -77,7 +71,7 @@ namespace CapyKit
|
|||
/// <param name="poolSize"> The size of the pool. </param>
|
||||
private void FillPoolItemCollection(int poolSize)
|
||||
{
|
||||
FillPoolItemCollection(poolSize, () => default(T));
|
||||
FillPoolItemCollection(poolSize, () => default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -88,7 +82,7 @@ namespace CapyKit
|
|||
/// <param name="constructorSelector"> The constructor selector. </param>
|
||||
private void FillPoolItemCollection(int poolSize, Func<T> constructorSelector)
|
||||
{
|
||||
for (int i = 0; i < poolSize; i++)
|
||||
for (var i = 0; i < poolSize; i++)
|
||||
{
|
||||
this.poolItemCollection.Add(new PoolItem<T>(constructorSelector(), i));
|
||||
}
|
||||
|
|
@ -98,7 +92,7 @@ namespace CapyKit
|
|||
/// <param name="collection"> The <typeparamref name="T" /> collection. </param>
|
||||
private void FillPoolItemCollection(IEnumerable<T> collection)
|
||||
{
|
||||
int index = 0;
|
||||
var index = 0;
|
||||
foreach (var item in collection)
|
||||
{
|
||||
this.poolItemCollection.Add(new PoolItem<T>(item, index++));
|
||||
|
|
@ -116,7 +110,8 @@ namespace CapyKit
|
|||
var firstAvailableItem = this.poolItemCollection.First(item => !item.Locked);
|
||||
firstAvailableItem.SetLock();
|
||||
|
||||
CapyEventReporter.EmitEvent(EventLevel.Debug, "Accessed ppol and retrieved {0}", args: new[] { firstAvailableItem });
|
||||
CapyEventReporter.EmitEvent(EventLevel.Debug, "Accessed ppol and retrieved {0}",
|
||||
args: new[] { firstAvailableItem });
|
||||
|
||||
return firstAvailableItem;
|
||||
}
|
||||
|
|
@ -144,6 +139,35 @@ namespace CapyKit
|
|||
/// <typeparam name="T"> The type of the pooled item. </typeparam>
|
||||
public sealed class PoolItem<T>
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PoolItem{T}" /> class with the specified item and
|
||||
/// index.
|
||||
/// </summary>
|
||||
/// <param name="item"> The pooled item. </param>
|
||||
/// <param name="index"> The zero-based index of the pooled item. </param>
|
||||
internal PoolItem(T item, int index)
|
||||
{
|
||||
this.item = item;
|
||||
this.index = index;
|
||||
this.locked = false;
|
||||
this.typeName = typeof(T).Name;
|
||||
}
|
||||
|
||||
#endregion Constructors
|
||||
|
||||
#region Overrides
|
||||
|
||||
/// <summary> Returns a string that represents the current object and its lock state. </summary>
|
||||
/// <returns> A string that represents the current object and its lock state. </returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0} {1} ({2})", this.typeName, this.index, this.locked ? "Locked" : "Unlocked");
|
||||
}
|
||||
|
||||
#endregion Overrides
|
||||
|
||||
#region Members
|
||||
|
||||
/// <summary> The pooled item. </summary>
|
||||
|
|
@ -166,62 +190,32 @@ namespace CapyKit
|
|||
/// <value> The pooled resource. </value>
|
||||
public T Item
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.item;
|
||||
}
|
||||
get { return this.item; }
|
||||
}
|
||||
|
||||
/// <summary> Gets a value indicating whether this object is locked or not. </summary>
|
||||
/// <value> A value indicating whether this object is locked or not. </value>
|
||||
public bool Locked
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.locked;
|
||||
}
|
||||
get { return this.locked; }
|
||||
}
|
||||
|
||||
/// <summary> Gets the zero-based index of the pooled item. </summary>
|
||||
/// <value> The index. </value>
|
||||
public int Index
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.index;
|
||||
}
|
||||
get { return this.index; }
|
||||
}
|
||||
|
||||
/// <summary> Gets the name of the <see cref="Type" /> of the pooled item. </summary>
|
||||
/// <value> The name of the <see cref="Type" /> of the pooled item. </value>
|
||||
public string TypeName
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.typeName;
|
||||
}
|
||||
get { return this.typeName; }
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PoolItem{T}"/> class with the specified item and
|
||||
/// index.
|
||||
/// </summary>
|
||||
/// <param name="item"> The pooled item. </param>
|
||||
/// <param name="index"> The zero-based index of the pooled item. </param>
|
||||
internal PoolItem(T item, int index)
|
||||
{
|
||||
this.item = item;
|
||||
this.index = index;
|
||||
this.locked = false;
|
||||
this.typeName = typeof(T).Name;
|
||||
}
|
||||
|
||||
#endregion Constructors
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary> Sets the lock on the item indicating that it is in use. </summary>
|
||||
|
|
@ -234,7 +228,8 @@ namespace CapyKit
|
|||
{
|
||||
if (this.locked)
|
||||
{
|
||||
CapyEventReporter.EmitEvent(EventLevel.Error, "Lock requested for {0}, but the lock request failed.", args: new[] { this });
|
||||
CapyEventReporter.EmitEvent(EventLevel.Error, "Lock requested for {0}, but the lock request failed.",
|
||||
args: new[] { this });
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -249,23 +244,12 @@ namespace CapyKit
|
|||
{
|
||||
if (!this.locked)
|
||||
{
|
||||
CapyEventReporter.EmitEvent(EventLevel.Error, "Lock release requested for {0}, but the lock was already released.", args: new[] { this } );
|
||||
CapyEventReporter.EmitEvent(EventLevel.Error,
|
||||
"Lock release requested for {0}, but the lock was already released.", args: new[] { this });
|
||||
}
|
||||
|
||||
this.locked = false;
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
|
||||
#region Overrides
|
||||
|
||||
/// <summary> Returns a string that represents the current object and its lock state. </summary>
|
||||
/// <returns> A string that represents the current object and its lock state. </returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0} {1} ({2})", this.typeName, this.index, this.locked ? "Locked" : "Unlocked");
|
||||
}
|
||||
|
||||
#endregion Overrides
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
namespace CapyKit;
|
||||
|
||||
namespace CapyKit
|
||||
{
|
||||
/// <summary>
|
||||
/// A object comparer that can accept a lambda expression to compare properties.
|
||||
/// </summary>
|
||||
|
|
@ -15,7 +9,6 @@ namespace CapyKit
|
|||
/// using System;
|
||||
/// using System.Collections.Generic;
|
||||
/// using System.Linq;
|
||||
///
|
||||
/// class Program
|
||||
/// {
|
||||
/// static void Main(string[] args)
|
||||
|
|
@ -25,17 +18,14 @@ namespace CapyKit
|
|||
/// new Person { Name = "Alice", Age = 30 }, new Person { Name = "Bob", Age = 30 }, new
|
||||
/// Person { Name = "Charlie", Age = 35 }
|
||||
/// };
|
||||
///
|
||||
/// var comparer = new PropertyComparer<Person, int>(p => p.Age);
|
||||
/// var distinctPeople = people.Distinct(comparer).ToList();
|
||||
///
|
||||
/// foreach (var person in distinctPeople)
|
||||
/// {
|
||||
/// Console.WriteLine($"{person.Name} - {person.Age}");
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// class Person
|
||||
/// {
|
||||
/// public string Name { get; set; }
|
||||
|
|
@ -45,7 +35,7 @@ namespace CapyKit
|
|||
public class PropertyComparer<T, U> : IEqualityComparer<T>
|
||||
{
|
||||
/// <summary> The expression to retrieve the property. </summary>
|
||||
private Func<T, U> expression;
|
||||
private readonly Func<T, U> expression;
|
||||
|
||||
/// <summary> Constructor. </summary>
|
||||
/// <param name="expression"> The expression. </param>
|
||||
|
|
@ -54,6 +44,8 @@ namespace CapyKit
|
|||
this.expression = expression;
|
||||
}
|
||||
|
||||
#region IEqualityComparer<T> Members
|
||||
|
||||
/// <summary> Determines whether the specified properties are equal. </summary>
|
||||
/// <param name="x"> The first object of type <typeparamref name="T" /> to compare. </param>
|
||||
/// <param name="y"> The second object of type <typeparamref name="T" /> to compare. </param>
|
||||
|
|
@ -63,39 +55,39 @@ namespace CapyKit
|
|||
/// </returns>
|
||||
public bool Equals(T x, T y)
|
||||
{
|
||||
var left = expression.Invoke(x);
|
||||
var right = expression.Invoke(y);
|
||||
var left = this.expression.Invoke(x);
|
||||
var right = this.expression.Invoke(y);
|
||||
|
||||
if (left == null && right == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (left == null ^ right == null)
|
||||
|
||||
if ((left == null) ^ (right == null))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
return left.Equals(right);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Returns a hash code for the specified object. </summary>
|
||||
/// <param name="obj">
|
||||
/// The <see cref="T:System.Object" /> for which a hash code is to be returned.
|
||||
/// </param>
|
||||
/// <returns> A hash code for the specified object. </returns>
|
||||
///
|
||||
/// ### <exception cref="T:System.ArgumentNullException">
|
||||
/// ###
|
||||
/// <exception cref="T:System.ArgumentNullException">
|
||||
/// The type of <paramref name="obj" /> is a reference type and
|
||||
/// <paramref name="obj" /> is
|
||||
/// <see langword="null" />.
|
||||
/// </exception>
|
||||
public int GetHashCode(T obj)
|
||||
{
|
||||
var property = expression(obj);
|
||||
var property = this.expression(obj);
|
||||
|
||||
return (property == null) ? 0 : property.GetHashCode();
|
||||
}
|
||||
return property == null ? 0 : property.GetHashCode();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue