Compare commits

...

23 Commits

Author SHA1 Message Date
amacocian 1c7d3a2be2 Adjust project descriptions (#12)
* Adjust package description
2022-01-02 16:54:15 +02:00
amacocian 0a30872781 Introduce .netcore extensions (#11)
* Introduce .netcore extensions
Implement ArgumentNullException for .net6 and c#10

* Update pipelines to install .netcore 6

* Update test projects to .net 6.0
2022-01-02 00:10:49 +02:00
Alexandru Macocian 7eed1ca466 Unify namespace naming 2021-11-15 22:21:46 +01:00
Alexandru Macocian b6cc64fd51 Update dependencies 2021-11-15 22:08:24 +01:00
Alexandru Macocian c8bfaffb42 Fix namespaces 2021-11-15 22:04:18 +01:00
Alexandru Macocian bf163251dd Password hashing implementation 2021-11-15 21:52:39 +01:00
Alexandru Macocian c0b5734b71 Add extensions to simplify CVLoggerFactory usage 2021-11-01 16:18:10 +01:00
Alexandru Macocian 2944d9887e Update dependencies 2021-10-02 07:45:42 +02:00
amacocian 57925151fa Update dependencies (#10)
Fix code style
2021-09-16 13:56:05 +02:00
amacocian d20e5bd308 Fix CV extension (#9) 2021-08-18 16:34:54 +02:00
amacocian c9d1ba8773 Merge pull request #8 from AlexMacocian/alexmacocian/extend-cryptorngprovider
Extend CryptoRngProvider api
2021-07-15 16:33:28 +03:00
Alexandru Macocian ce3cac9fa2 Extend CryptoRngProvider api 2021-07-15 16:32:40 +03:00
amacocian a2d23ed716 Merge pull request #7 from AlexMacocian/alexmacocian/rngprovider-securestring
Implementation of SecureString and CryptoRngProvider
2021-07-15 16:19:32 +03:00
Alexandru Macocian 7660893087 Remove UTs expecting exception 2021-07-15 16:15:17 +03:00
Alexandru Macocian 68ec8f983d Implementation of SecureString and CryptoRngProvider 2021-07-15 16:11:05 +03:00
amacocian 1711dd2ec2 Merge pull request #6 from AlexMacocian/alexmacocian/serialization-extensions
Serialize and Deserialize extensions
2021-07-15 12:46:48 +03:00
Alexandru Macocian 3b67e45e64 Bump version 2021-07-15 12:41:47 +03:00
Alexandru Macocian 22fa8eccf7 Serialize and Deserialize extensions 2021-07-15 12:41:18 +03:00
amacocian 9609b2912c Merge pull request #5 from AlexMacocian/alexmacocian/security-package
SystemExtensions Security
2021-07-14 12:22:53 +03:00
Alexandru Macocian a2e99cb263 SystemExtensions Security 2021-07-14 12:17:31 +03:00
amacocian f9088a5aef Merge pull request #4 from AlexMacocian/alexmacocian/move-logger-resolver
Move logger resolver to System.Logging
2021-07-10 13:06:35 +03:00
Alexandru Macocian d67ee95916 Fix UTs 2021-07-10 13:02:54 +03:00
Alexandru Macocian 8bfb8f1757 Move logger resolver to System.Logging
Nit fixes
2021-07-10 13:01:47 +03:00
58 changed files with 1877 additions and 263 deletions
+20 -1
View File
@@ -21,6 +21,7 @@ jobs:
Test_Project_Path: SystemExtensions.Tests\SystemExtensions.NetStandard.Tests.csproj
DI_Test_Project_Path: SystemExtensions.DependencyInjection.Tests\SystemExtensions.NetStandard.DependencyInjection.Tests.csproj
Source_Project_Path: SystemExtensions.NetStandard\SystemExtensions.NetStandard.csproj
Core_Project_Path: SystemExtensions.NetCore\SystemExtensions.NetCore.csproj
Actions_Allow_Unsecure_Commands: true
steps:
@@ -32,7 +33,7 @@ jobs:
- name: Install .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: '5.0.202'
dotnet-version: '6.0.x'
- name: Setup MSBuild.exe
uses: microsoft/setup-msbuild@v1.0.1
@@ -45,17 +46,35 @@ jobs:
- name: Build SystemExtensions.NetStandard project
run: dotnet build SystemExtensions.NetStandard -c $env:Configuration
- name: Build SystemExtensions.NetCore project
run: dotnet build SystemExtensions.NetCore -c $env:Configuration
- name: Build SystemExtensions.NetStandard.DependencyInjection project
run: dotnet build SystemExtensions.NetStandard.DependencyInjection -c $env:Configuration
- name: Build SystemExtensions.NetStandard.Security project
run: dotnet build SystemExtensions.NetStandard.Security -c $env:Configuration
- name: Push SystemExtensions.NetStandard nuget package
uses: brandedoutcast/publish-nuget@v2.5.5
with:
PROJECT_FILE_PATH: SystemExtensions.NetStandard\SystemExtensions.NetStandard.csproj
NUGET_KEY: ${{secrets.NUGET_API_KEY}}
- name: Push SystemExtensions.NetCore nuget package
uses: brandedoutcast/publish-nuget@v2.5.5
with:
PROJECT_FILE_PATH: SystemExtensions.NetCore\SystemExtensions.NetCore.csproj
NUGET_KEY: ${{secrets.NUGET_API_KEY}}
- name: Push SystemExtensions.NetStandard.DependencyInjection nuget package
uses: brandedoutcast/publish-nuget@v2.5.5
with:
PROJECT_FILE_PATH: SystemExtensions.NetStandard.DependencyInjection\SystemExtensions.NetStandard.DependencyInjection.csproj
NUGET_KEY: ${{secrets.NUGET_API_KEY}}
- name: Push SystemExtensions.NetStandard.Security nuget package
uses: brandedoutcast/publish-nuget@v2.5.5
with:
PROJECT_FILE_PATH: SystemExtensions.NetStandard.Security\SystemExtensions.NetStandard.Security.csproj
NUGET_KEY: ${{secrets.NUGET_API_KEY}}
+5 -1
View File
@@ -22,6 +22,7 @@ jobs:
Solution_Path: SystemExtensions.sln
Test_Project_Path: SystemExtensions.Tests\SystemExtensions.NetStandard.Tests.csproj
DI_Test_Project_Path: SystemExtensions.DependencyInjection.Tests\SystemExtensions.NetStandard.DependencyInjection.Tests.csproj
Sec_Test_Project_Path: SystemExtensions.NetStandard.Security.Tests\SystemExtensions.NetStandard.Security.Tests.csproj
Source_Project_Path: SystemExtensions.NetStandard\SystemExtensions.NetStandard.csproj
Actions_Allow_Unsecure_Commands: true
@@ -34,7 +35,7 @@ jobs:
- name: Install .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: '5.0.202'
dotnet-version: '6.0.x'
- name: Setup MSBuild.exe
uses: microsoft/setup-msbuild@v1.0.1
@@ -45,6 +46,9 @@ jobs:
- name: Execute DI Unit Tests
run: dotnet test $env:DI_Test_Project_Path
- name: Execute Security Unit Tests
run: dotnet test $env:Sec_Test_Project_Path
- name: Restore Project
run: msbuild $env:Solution_Path /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=$env:RuntimeIdentifier
env:
@@ -3,6 +3,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System;
using System.Configuration;
using System.Extensions.Configuration;
namespace SystemExtensions.DependencyInjection.Tests.Configuration
{
@@ -4,7 +4,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System;
using System.Logging;
using System.Windows.Extensions.Logging;
namespace SystemExtensions.DependencyInjection.Tests.Logging
{
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
@@ -0,0 +1,22 @@
using System.Runtime.CompilerServices;
namespace System.Core.Extensions;
public static class ObjectExtensions
{
public static T ThrowIfNull<T>([ValidatedNotNull] this T obj, [CallerArgumentExpression("obj")] string? paramName = null)
where T : class
{
if (obj is null)
{
throw new ArgumentNullException(paramName);
}
return obj;
}
[AttributeUsage(AttributeTargets.Parameter)]
sealed class ValidatedNotNullAttribute : Attribute
{
}
}
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Nullable>enable</Nullable>
<RootNamespace>System</RootNamespace>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<Version>1.0.1</Version>
<Authors>Alexandru Macocian</Authors>
<RepositoryUrl>https://github.com/AlexMacocian/SystemExtensions</RepositoryUrl>
<Description>Extensions for the System namespace</Description>
</PropertyGroup>
<ItemGroup>
<None Include="../LICENSE">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
</ItemGroup>
</Project>
@@ -1,4 +1,5 @@
using Slim.Resolvers;
using System.Extensions.Configuration;
namespace System.Configuration
{
@@ -1,6 +1,6 @@
using System.Extensions;
using System.Configuration;
namespace System.Configuration
namespace System.Extensions.Configuration
{
public sealed class UpdateableOptionsWrapper<T> : IUpdateableOptions<T>
where T : class
@@ -104,6 +104,23 @@ namespace System.Extensions
return serviceManager;
}
/// <summary>
/// Register a <see cref="ILoggerFactory"/> with a <see cref="CVLoggerProvider"/>.
/// </summary>
/// <param name="serviceManager"></param>
/// <returns></returns>
public static IServiceManager RegisterCVLoggerFactory(this IServiceManager serviceManager)
{
serviceManager.RegisterScoped<ILoggerFactory, LoggerFactory>(sp =>
{
LoggerFactory loggerFactory = new();
loggerFactory.AddProvider(new CVLoggerProvider(sp.GetService<ILogsWriter>()));
return loggerFactory;
});
return serviceManager;
}
public static IServiceManager RegisterLoggerFactory(this IServiceManager serviceManager, Func<Slim.IServiceProvider, ILoggerFactory> loggerFactory)
{
serviceManager.ThrowIfNull(nameof(serviceManager));
@@ -7,7 +7,7 @@ namespace System.Logging
public sealed class CVLoggerProvider : ICVLoggerProvider
{
private readonly ILogsWriter logsManager;
private CorrelationVector correlationVector;
private readonly CorrelationVector correlationVector;
public CVLoggerProvider(ILogsWriter logsWriter)
{
@@ -28,11 +28,6 @@ namespace System.Logging
public ILogger CreateLogger(string categoryName)
{
if (this.correlationVector is not null)
{
this.correlationVector = CorrelationVector.Extend(this.correlationVector.ToString());
}
return new CVLogger(categoryName, this);
}
@@ -2,7 +2,7 @@
using Slim.Resolvers;
using System.Linq;
namespace System.Windows.Extensions.Logging
namespace System.Logging
{
public sealed class LoggerResolver : IDependencyResolver
{
@@ -25,7 +25,7 @@ namespace System.Windows.Extensions.Logging
}
else if (type == typeof(ILogger))
{
return ResolveLogger(serviceProvider, type);
return ResolveLogger(serviceProvider);
}
else
{
@@ -41,7 +41,7 @@ namespace System.Windows.Extensions.Logging
return createLoggerMethod.MakeGenericMethod(categoryTypes.First()).Invoke(null, new object[] { loggerFactory });
}
private static object ResolveLogger(Slim.IServiceProvider serviceProvider, Type type)
private static object ResolveLogger(Slim.IServiceProvider serviceProvider)
{
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
return loggerFactory.CreateLogger(string.Empty);
@@ -6,9 +6,10 @@
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<LangVersion>latest</LangVersion>
<Version>1.1.0</Version>
<Version>1.1.7</Version>
<Authors>Alexandru Macocian</Authors>
<RepositoryUrl>https://github.com/AlexMacocian/SystemExtensions</RepositoryUrl>
<Description>Extensions for the Slim Dependency Injection engine</Description>
</PropertyGroup>
<ItemGroup>
@@ -20,9 +21,9 @@
<ItemGroup>
<PackageReference Include="Microsoft.CorrelationVector" Version="1.0.42" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
<PackageReference Include="Slim" Version="1.5.1" />
<PackageReference Include="SystemExtensions.NetStandard" Version="1.3.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
<PackageReference Include="Slim" Version="1.6.0" />
<PackageReference Include="SystemExtensions.NetStandard" Version="1.3.1" />
</ItemGroup>
</Project>
@@ -0,0 +1,105 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Security.Encryption;
using System.Text;
using System.Threading.Tasks;
namespace SystemExtensions.NetStandard.Security.Tests
{
[TestClass]
public class AesEncrypterTests
{
private ISymmetricEncrypter symmetricEncrypter;
private string keyString;
private byte[] keyBytes;
private byte[] ivBytes;
private string ivString;
private string toEncryptString;
private byte[] toEncryptBytes;
[TestInitialize]
public void TestInitialize()
{
this.symmetricEncrypter = new AesEncrypter();
this.keyBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2 };
this.keyString = Convert.ToBase64String(this.keyBytes);
this.ivBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6 };
this.ivString = Convert.ToBase64String(this.ivBytes);
this.toEncryptBytes = Encoding.UTF8.GetBytes("toEncrypt");
this.toEncryptString = Convert.ToBase64String(this.toEncryptBytes);
}
[TestMethod]
public async Task EncryptDecryptStringWithStringKeyStringIv()
{
var encrypted = await this.symmetricEncrypter.Encrypt(this.keyString, this.ivString, this.toEncryptString).ConfigureAwait(false);
var decrypted = await this.symmetricEncrypter.Decrypt(this.keyString, this.ivString, encrypted).ConfigureAwait(false);
this.toEncryptString.Should().Be(decrypted);
}
[TestMethod]
public async Task EncryptDecryptStringWithByteKeyByteIv()
{
var encrypted = await this.symmetricEncrypter.Encrypt(this.keyBytes, this.ivBytes, this.toEncryptString).ConfigureAwait(false);
var decrypted = await this.symmetricEncrypter.Decrypt(this.keyBytes, this.ivBytes, encrypted).ConfigureAwait(false);
this.toEncryptString.Should().Be(decrypted);
}
[TestMethod]
public async Task EncryptDecryptByteWithStringKeyStringIv()
{
var encrypted = await this.symmetricEncrypter.Encrypt(this.keyString, this.ivString, this.toEncryptBytes).ConfigureAwait(false);
var decrypted = await this.symmetricEncrypter.Decrypt(this.keyString, this.ivString, encrypted).ConfigureAwait(false);
this.toEncryptBytes.Should().BeEquivalentTo(decrypted);
}
[TestMethod]
public async Task EncryptDecryptByteWithByteKeyByteIv()
{
var encrypted = await this.symmetricEncrypter.Encrypt(this.keyBytes, this.ivBytes, this.toEncryptBytes).ConfigureAwait(false);
var decrypted = await this.symmetricEncrypter.Decrypt(this.keyBytes, this.ivBytes, encrypted).ConfigureAwait(false);
this.toEncryptBytes.Should().BeEquivalentTo(decrypted);
}
[TestMethod]
public async Task EncryptDecryptStreamWithStringKeyStringIv()
{
var encrypted = await this.symmetricEncrypter.Encrypt(this.keyString, this.ivString, new MemoryStream(this.toEncryptBytes)).ConfigureAwait(false);
encrypted.Position = 0;
var decrypted = await this.symmetricEncrypter.Decrypt(this.keyString, this.ivString, encrypted).ConfigureAwait(false);
this.toEncryptBytes.Should().BeEquivalentTo(((MemoryStream)decrypted).ToArray());
}
[TestMethod]
public async Task EncryptDecryptStreamWithByteKeyByteIv()
{
var encrypted = await this.symmetricEncrypter.Encrypt(this.keyBytes, this.ivBytes, new MemoryStream(this.toEncryptBytes)).ConfigureAwait(false);
encrypted.Position = 0;
var decrypted = await this.symmetricEncrypter.Decrypt(this.keyBytes, this.ivBytes, encrypted).ConfigureAwait(false);
this.toEncryptBytes.Should().BeEquivalentTo(((MemoryStream)decrypted).ToArray());
}
[TestMethod]
public void GetEncryptionStreamReturnsCryptoStream()
{
var encryptionStream = this.symmetricEncrypter.GetEncryptionStream(this.keyBytes, this.ivBytes, new MemoryStream());
encryptionStream.Should().BeAssignableTo<CryptoStream>();
}
[TestMethod]
public void GetDecryptionStreamReturnsCryptoStream()
{
var encryptionStream = this.symmetricEncrypter.GetDecryptionStream(this.keyBytes, this.ivBytes, new MemoryStream());
encryptionStream.Should().BeAssignableTo<CryptoStream>();
}
}
}
@@ -0,0 +1,55 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;
using System.Security.Rng;
namespace SystemExtensions.NetStandard.Security.Tests
{
[TestClass]
public class CryptoRngProviderTests
{
private CryptoRngProvider cryptoRngProvider;
[TestInitialize]
public void TestInitialize()
{
this.cryptoRngProvider = new CryptoRngProvider();
}
[TestMethod]
public void GetBytes_ShouldSetValues()
{
var bytes = new byte[100];
this.cryptoRngProvider.GetBytes(bytes);
bytes.All(b => b == 0).Should().BeFalse();
}
[TestMethod]
public void GetNonZeroBytes_ShouldSetNonZeroValues()
{
var bytes = new byte[100];
this.cryptoRngProvider.GetNonZeroBytes(bytes);
bytes.All(b => b != 0).Should().BeTrue();
}
[TestMethod]
public void GetBytes_ShouldReturnBytes()
{
var bytes = this.cryptoRngProvider.GetBytes(10);
bytes.Length.Should().Be(10);
}
[TestMethod]
public void GetNonZeroBytes_ShouldReturnBytes()
{
var bytes = this.cryptoRngProvider.GetNonZeroBytes(10);
bytes.Length.Should().Be(10);
}
}
}
@@ -0,0 +1,261 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Security.Hashing;
using System.Threading.Tasks;
namespace SystemExtensions.NetStandard.Security.Tests
{
[TestClass]
public sealed class Rfc2898DeriveBytesPasswordHashingServiceTests
{
private const int TooShortHashLength = 31;
private const int DesiredHashLength = 32;
private const int Iterations = 10000;
private const int TooLittleIterations = 1000;
private readonly Rfc2898DeriveBytesPasswordHashingService rfc2898DeriveBytesPasswordHashingService = new();
private byte[] tooShortSaltBytes;
private string tooShortSaltString;
private byte[] incorrectSaltBytes;
private string incorrectSaltString;
private byte[] saltBytes;
private string saltString;
private byte[] passwordBytes;
private string passwordString;
private byte[] incorrectPasswordBytes;
private string incorrectPasswordString;
[TestInitialize]
public void TestInitialize()
{
this.tooShortSaltBytes = new byte[16];
this.tooShortSaltString = Convert.ToBase64String(this.tooShortSaltBytes);
this.saltBytes = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 };
this.incorrectSaltBytes = new byte[32];
this.incorrectSaltString = Convert.ToBase64String(this.incorrectSaltBytes);
this.saltString = Convert.ToBase64String(this.saltBytes);
this.passwordBytes = new byte[] { 5, 1, 2, 34, 35, 123, 4, 23, 1, 235, 32, 234 };
this.passwordString = Convert.ToBase64String(this.passwordBytes);
this.incorrectPasswordBytes = new byte[] { 14, 123, 23, 4, 2, 1, 23, 25 };
this.incorrectPasswordString = Convert.ToBase64String(this.incorrectPasswordBytes);
}
[TestMethod]
public void PasswordNull_HashBytes_Throws_ArgumentNullException()
{
var action = new Func<Task<byte[]>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(null, this.saltBytes, DesiredHashLength, Iterations));
action.Should().Throw<ArgumentNullException>();
}
[TestMethod]
public void PasswordNull_HashString_Throws_ArgumentNullException()
{
var action = new Func<Task<string>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(null, this.saltString, DesiredHashLength, Iterations));
action.Should().Throw<ArgumentNullException>();
}
[TestMethod]
public void SaltNull_HashBytes_Throws_ArgumentNullException()
{
var action = new Func<Task<byte[]>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, null, DesiredHashLength, Iterations));
action.Should().Throw<ArgumentNullException>();
}
[TestMethod]
public void SaltNull_HashString_Throws_ArgumentNullException()
{
var action = new Func<Task<string>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, null, DesiredHashLength, Iterations));
action.Should().Throw<ArgumentNullException>();
}
[TestMethod]
public void HashLengthTooSmall_HashBytes_Throws_InvalidOperationException()
{
var action = new Func<Task<byte[]>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, TooShortHashLength, Iterations));
action.Should().Throw<InvalidOperationException>();
}
[TestMethod]
public void HashLengthTooSmall_HashString_Throws_InvalidOperationException()
{
var action = new Func<Task<string>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, TooShortHashLength, Iterations));
action.Should().Throw<InvalidOperationException>();
}
[TestMethod]
public void TooLittleIterations_HashBytes_Throws_InvalidOperationException()
{
var action = new Func<Task<byte[]>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, DesiredHashLength, TooLittleIterations));
action.Should().Throw<InvalidOperationException>();
}
[TestMethod]
public void TooLittleIterations_HashString_Throws_InvalidOperationException()
{
var action = new Func<Task<string>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, DesiredHashLength, TooLittleIterations));
action.Should().Throw<InvalidOperationException>();
}
[TestMethod]
public void TooShortSalt_HashBytes_Throws_InvalidOperationException()
{
var action = new Func<Task<byte[]>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.tooShortSaltBytes, DesiredHashLength, TooLittleIterations));
action.Should().Throw<InvalidOperationException>();
}
[TestMethod]
public void TooShortSalt_HashString_Throws_InvalidOperationException()
{
var action = new Func<Task<string>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.tooShortSaltString, DesiredHashLength, TooLittleIterations));
action.Should().Throw<InvalidOperationException>();
}
[TestMethod]
public void PasswordNull_VerifyBytes_Throws_ArgumentNullException()
{
var action = new Func<Task<bool>>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(null, this.incorrectPasswordBytes, this.saltBytes, Iterations));
action.Should().Throw<ArgumentNullException>();
}
[TestMethod]
public void PasswordNull_VerifyString_Throws_ArgumentNullException()
{
var action = new Func<Task<bool>>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(null, this.incorrectPasswordString, this.saltString, Iterations));
action.Should().Throw<ArgumentNullException>();
}
[TestMethod]
public void HashNull_VerifyBytes_Throws_ArgumentNullException()
{
var action = new Func<Task<bool>>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordBytes, null, this.saltBytes, Iterations));
action.Should().Throw<ArgumentNullException>();
}
[TestMethod]
public void HashNull_VerifyString_Throws_ArgumentNullException()
{
var action = new Func<Task<bool>>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordString, null, this.saltString, Iterations));
action.Should().Throw<ArgumentNullException>();
}
[TestMethod]
public void SaltNull_VerifyBytes_Throws_ArgumentNullException()
{
var action = new Func<Task<bool>>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordBytes, this.incorrectPasswordBytes, null, Iterations));
action.Should().Throw<ArgumentNullException>();
}
[TestMethod]
public void SaltNull_VerifyString_Throws_ArgumentNullException()
{
var action = new Func<Task<bool>>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordString, this.incorrectPasswordString, null, Iterations));
action.Should().Throw<ArgumentNullException>();
}
[TestMethod]
public void TooLittleIterations_VerifyBytes_Throws_InvalidOperationException()
{
var action = new Func<Task<bool>>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordBytes, this.incorrectPasswordBytes, this.saltBytes, TooLittleIterations));
action.Should().Throw<InvalidOperationException>();
}
[TestMethod]
public void TooLittleIterations_VerifyString_Throws_InvalidOperationException()
{
var action = new Func<Task<bool>>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordString, this.incorrectPasswordString, this.saltString, TooLittleIterations));
action.Should().Throw<InvalidOperationException>();
}
[TestMethod]
public async Task HashBytes_ReturnsHashedBytes()
{
var hashedBytes = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, DesiredHashLength, Iterations);
hashedBytes.Should().NotBeNull();
hashedBytes.Should().HaveCount(DesiredHashLength);
}
[TestMethod]
public async Task HashString_ReturnsHashedString()
{
var hashedString = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, DesiredHashLength, Iterations);
hashedString.Should().NotBeNull();
var hashedBytes = Convert.FromBase64String(hashedString);
hashedBytes.Should().HaveCount(DesiredHashLength);
}
[TestMethod]
public async Task VerifyBytes_CorrectPassword_ReturnsTrue()
{
var hashedBytes = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, DesiredHashLength, Iterations);
var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedBytes, this.passwordBytes, this.saltBytes, Iterations);
result.Should().BeTrue();
}
[TestMethod]
public async Task VerifyString_CorrectPassword_ReturnsTrue()
{
var hashedString = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, DesiredHashLength, Iterations);
var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedString, this.passwordString, this.saltString, Iterations);
result.Should().BeTrue();
}
[TestMethod]
public async Task VerifyBytes_IncorrectPassword_ReturnsFalse()
{
var hashedBytes = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, DesiredHashLength, Iterations);
var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedBytes, this.incorrectPasswordBytes, this.saltBytes, Iterations);
result.Should().BeFalse();
}
[TestMethod]
public async Task VerifyString_IncorrectPassword_ReturnsFalse()
{
var hashedString = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, DesiredHashLength, Iterations);
var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedString, this.incorrectPasswordString, this.saltString, Iterations);
result.Should().BeFalse();
}
[TestMethod]
public async Task VerifyBytes_IncorrectSalt_ReturnsFalse()
{
var hashedBytes = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, DesiredHashLength, Iterations);
var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedBytes, this.passwordBytes, this.incorrectSaltBytes, Iterations);
result.Should().BeFalse();
}
[TestMethod]
public async Task VerifyString_IncorrectSalt_ReturnsFalse()
{
var hashedString = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, DesiredHashLength, Iterations);
var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedString, this.passwordString, this.incorrectSaltString, Iterations);
result.Should().BeFalse();
}
[TestMethod]
public async Task VerifyBytes_IncorrectIterations_ReturnsFalse()
{
var hashedBytes = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, DesiredHashLength, Iterations);
var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedBytes, this.passwordBytes, this.saltBytes, Iterations + 1);
result.Should().BeFalse();
}
[TestMethod]
public async Task VerifyString_IncorrectIterations_ReturnsFalse()
{
var hashedString = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, DesiredHashLength, Iterations);
var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedString, this.passwordString, this.saltString, Iterations + 1);
result.Should().BeFalse();
}
}
}
@@ -0,0 +1,122 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Security.Encryption;
namespace SystemExtensions.NetStandard.Security.Tests
{
[TestClass]
public class SecureStringTests
{
[TestMethod]
public void SecureString_NewSecureString_ReturnsValue()
{
var str = new SecureString("hello");
str.Value.Should().Be("hello");
}
[TestMethod]
public void SecureStringEmpty_AreEqual()
{
var str = SecureString.Empty;
str.Should().Be(SecureString.Empty);
}
[TestMethod]
public void SecureStringEmpty_Equals_StringEmpty()
{
var ss = SecureString.Empty;
var s = string.Empty;
ss.Should().Be(s);
}
[TestMethod]
public void SecureString_Equals_OtherSecureString()
{
var ss1 = new SecureString("Hello");
var ss2 = new SecureString("Hello");
ss1.Equals(ss2).Should().BeTrue();
}
[TestMethod]
[DataRow("hello", "hello", true)]
[DataRow("hello", "henlo", false)]
public void SecureString_EqualOperator_OtherSecureString(string str1, string str2, bool isEqual)
{
var ss1 = new SecureString(str1);
var ss2 = new SecureString(str2);
(ss1 == ss2).Should().Be(isEqual);
}
[TestMethod]
[DataRow("hello", "hello", false)]
[DataRow("hello", "henlo", true)]
public void SecureString_DifferentOperator_OtherSecureString(string str1, string str2, bool isDifferent)
{
var ss1 = new SecureString(str1);
var ss2 = new SecureString(str2);
(ss1 != ss2).Should().Be(isDifferent);
}
[TestMethod]
[DataRow("hello", "hello", true)]
[DataRow("hello", "henlo", false)]
public void SecureString_EqualOperator_String(string str1, string str2, bool isEqual)
{
var ss1 = new SecureString(str1);
(ss1 == str2).Should().Be(isEqual);
}
[TestMethod]
[DataRow("hello", "hello", false)]
[DataRow("hello", "henlo", true)]
public void SecureString_DifferentOperator_String(string str1, string str2, bool isDifferent)
{
var ss1 = new SecureString(str1);
(ss1 != str2).Should().Be(isDifferent);
}
[TestMethod]
public void SecureString_PlusOperator_SecureString()
{
var ss1 = new SecureString("Hello ");
var ss2 = new SecureString("World");
(ss1 + ss2).Should().Be("Hello World");
}
[TestMethod]
public void SecureString_PlusOperator_String()
{
var ss1 = new SecureString("Hello ");
var ss2 = "World";
(ss1 + ss2).Should().Be("Hello World");
}
[TestMethod]
public void SecureString_PlusOperator_Char()
{
var ss1 = new SecureString("Hello ");
var c = 'W';
(ss1 + c).Should().Be("Hello W");
}
[TestMethod]
public void SecureString_WithOptionalEntropy_Matches()
{
SecureString.AddOptionalEntropy(new byte[] { 10, 20, 25, 34, 56, 12, 10, 81, 200, 155, 123, 144, 123, 192, 122, 1 });
var ss1 = new SecureString("Hello");
var ss2 = new SecureString("Hello");
ss1.Should().Be(ss2);
}
}
}
@@ -0,0 +1,48 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.IO;
using System.Security.Hashing;
using System.Text;
using System.Threading.Tasks;
namespace SystemExtensions.NetStandard.Security.Tests
{
[TestClass]
public sealed class Sha256HashingServiceTests
{
private readonly IHashingService hashingService = new Sha256HashingService();
private string toHashtString;
private byte[] toHashtBytes;
private Stream toHashStream;
[TestInitialize]
public void TestInitialize()
{
this.toHashtBytes = Encoding.UTF8.GetBytes("toEncrypt");
this.toHashtString = Convert.ToBase64String(this.toHashtBytes);
this.toHashStream = new MemoryStream(this.toHashtBytes);
}
[TestMethod]
public async Task HashString()
{
var hash = await this.hashingService.Hash(this.toHashtString).ConfigureAwait(false);
hash.Should().BeOfType<string>();
}
[TestMethod]
public async Task HashBytes()
{
var hash = await this.hashingService.Hash(this.toHashtBytes).ConfigureAwait(false);
hash.Should().BeOfType<byte[]>();
}
[TestMethod]
public async Task HashStream()
{
var hash = await this.hashingService.Hash(this.toHashStream).ConfigureAwait(false);
hash.Should().BeAssignableTo<Stream>();
}
}
}
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="5.10.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.3" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.3" />
<PackageReference Include="coverlet.collector" Version="3.0.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SystemExtensions.NetStandard.Security\SystemExtensions.NetStandard.Security.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,214 @@
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Threading.Tasks;
using System.Security.Utilities;
namespace System.Security.Encryption
{
public sealed class AesEncrypter : ISymmetricEncrypter
{
public async Task<string> Decrypt(string key, string iv, string value)
{
using var valueStream = BytesToStream(StringToBytes(value));
using var decryptedStream = await DecryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false);
return StreamToString(decryptedStream);
}
public async Task<string> Decrypt(byte[] key, byte[] iv, string value)
{
using var valueStream = BytesToStream(StringToBytes(value));
using var decryptedStream = await DecryptInternal(key, iv, valueStream).ConfigureAwait(false);
return StreamToString(decryptedStream);
}
public async Task<byte[]> Decrypt(string key, string iv, byte[] value)
{
using var valueStream = BytesToStream(value);
using var decryptedStream = await DecryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false);
return StreamToBytes(decryptedStream);
}
public async Task<byte[]> Decrypt(byte[] key, byte[] iv, byte[] value)
{
using var valueStream = BytesToStream(value);
using var decryptedStream = await DecryptInternal(key, iv, valueStream).ConfigureAwait(false);
return StreamToBytes(decryptedStream);
}
public async Task<Stream> Decrypt(string key, string iv, Stream value)
{
return await DecryptInternal(StringToBytes(key), StringToBytes(iv), value).ConfigureAwait(false);
}
public async Task<Stream> Decrypt(byte[] key, byte[] iv, Stream value)
{
return await DecryptInternal(key, iv, value).ConfigureAwait(false);
}
public async Task<string> Encrypt(string key, string iv, string value)
{
using var valueStream = BytesToStream(StringToBytes(value));
using var encryptedStream = await EncryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false);
return StreamToString(encryptedStream);
}
public async Task<string> Encrypt(byte[] key, byte[] iv, string value)
{
using var valueStream = BytesToStream(StringToBytes(value));
using var encryptedStream = await EncryptInternal(key, iv, valueStream).ConfigureAwait(false);
return StreamToString(encryptedStream);
}
public async Task<byte[]> Encrypt(string key, string iv, byte[] value)
{
using var valueStream = BytesToStream(value);
using var encryptedStream = await EncryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false);
return StreamToBytes(encryptedStream);
}
public async Task<byte[]> Encrypt(byte[] key, byte[] iv, byte[] value)
{
using var valueStream = BytesToStream(value);
using var encryptedStream = await EncryptInternal(key, iv, valueStream).ConfigureAwait(false);
return StreamToBytes(encryptedStream);
}
public async Task<Stream> Encrypt(string key, string iv, Stream value)
{
return value is null
? throw new ArgumentNullException(nameof(value))
: await EncryptInternal(StringToBytes(key), StringToBytes(iv), value).ConfigureAwait(false);
}
public async Task<Stream> Encrypt(byte[] key, byte[] iv, Stream value)
{
return value is null
? throw new ArgumentNullException(nameof(value))
: await EncryptInternal(key, iv, value).ConfigureAwait(false);
}
public Stream GetEncryptionStream(string key, string iv, Stream outStream)
{
return GetEncryptionStreamInternal(StringToBytes(key), StringToBytes(iv), outStream);
}
public Stream GetEncryptionStream(byte[] key, byte[] iv, Stream outStream)
{
return GetEncryptionStreamInternal(key, iv, outStream);
}
public Stream GetDecryptionStream(string key, string iv, Stream inStream)
{
return GetDecryptionStreamInternal(StringToBytes(key), StringToBytes(iv), inStream);
}
public Stream GetDecryptionStream(byte[] key, byte[] iv, Stream inStream)
{
return GetDecryptionStreamInternal(key, iv, inStream);
}
private static byte[] StreamToBytes(Stream value)
{
value.Position = 0;
var buffer = new byte[1024];
using var ms = new MemoryStream();
var read = -1;
do
{
read = value.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, read);
} while (read > 0);
return ms.ToArray();
}
private static string StreamToString(Stream value)
{
return Convert.ToBase64String(StreamToBytes(value));
}
private static byte[] StringToBytes(string value)
{
return Convert.FromBase64String(value);
}
private static Stream BytesToStream(byte[] value)
{
return new MemoryStream(value);
}
private static async Task<Stream> EncryptInternal(byte[] key, byte[] iv, Stream toEncryptStream)
{
if (key.Length < 32)
{
throw new ArgumentException($"{nameof(key)} must be at least 32 bytes");
}
if (iv.Length < 16)
{
throw new ArgumentException($"{nameof(iv)} must be at least 16 bytes");
}
key = key.Take(32).ToArray();
iv = iv.Take(16).ToArray();
var encryptedMemoryStream = new MemoryStream();
using var cryptoStream = GetEncryptionStreamInternal(key, iv, encryptedMemoryStream);
await toEncryptStream.CopyToAsync(cryptoStream).ConfigureAwait(false);
if (!cryptoStream.HasFlushedFinalBlock)
{
cryptoStream.FlushFinalBlock();
}
encryptedMemoryStream.Position = 0;
return encryptedMemoryStream;
}
private static async Task<Stream> DecryptInternal(byte[] key, byte[] iv, Stream toDecryptStream)
{
if (key.Length < 32)
{
throw new ArgumentException($"{nameof(key)} must be at least 32 bytes");
}
if (iv.Length < 16)
{
throw new ArgumentException($"{nameof(iv)} must be at least 16 bytes");
}
key = key.Take(32).ToArray();
iv = iv.Take(16).ToArray();
var decryptedMemoryStream = new MemoryStream();
using var cryptoStream = GetDecryptionStreamInternal(key, iv, toDecryptStream);
await cryptoStream.CopyToAsync(decryptedMemoryStream).ConfigureAwait(false);
if (!cryptoStream.HasFlushedFinalBlock)
{
cryptoStream.FlushFinalBlock();
}
decryptedMemoryStream.Position = 0;
return decryptedMemoryStream;
}
private static CryptoStream GetEncryptionStreamInternal(byte[] key, byte[] iv, Stream encryptedStream)
{
using var aes = Aes.Create();
aes.Padding = PaddingMode.PKCS7;
var crypto = aes.CreateEncryptor(key, iv);
var cryptoStream = new NotClosingCryptoStream(encryptedStream, crypto, CryptoStreamMode.Write);
return cryptoStream;
}
private static CryptoStream GetDecryptionStreamInternal(byte[] key, byte[] iv, Stream encryptedStream)
{
using var aes = Aes.Create();
aes.Padding = PaddingMode.PKCS7;
var crypto = aes.CreateDecryptor(key, iv);
var cryptoStream = new NotClosingCryptoStream(encryptedStream, crypto, CryptoStreamMode.Read);
return cryptoStream;
}
}
}
@@ -0,0 +1,25 @@
using System.IO;
using System.Threading.Tasks;
namespace System.Security.Encryption
{
public interface ISymmetricEncrypter
{
Stream GetEncryptionStream(string key, string iv, Stream outStream);
Stream GetEncryptionStream(byte[] key, byte[] iv, Stream outStream);
Stream GetDecryptionStream(string key, string iv, Stream inStream);
Stream GetDecryptionStream(byte[] key, byte[] iv, Stream inStream);
Task<string> Encrypt(string key, string iv, string value);
Task<string> Encrypt(byte[] key, byte[] iv, string value);
Task<byte[]> Encrypt(string key, string iv, byte[] value);
Task<byte[]> Encrypt(byte[] key, byte[] iv, byte[] value);
Task<Stream> Encrypt(string key, string iv, Stream value);
Task<Stream> Encrypt(byte[] key, byte[] iv, Stream value);
Task<string> Decrypt(string key, string iv, string value);
Task<string> Decrypt(byte[] key, byte[] iv, string value);
Task<byte[]> Decrypt(string key, string iv, byte[] value);
Task<byte[]> Decrypt(byte[] key, byte[] iv, byte[] value);
Task<Stream> Decrypt(string key, string iv, Stream value);
Task<Stream> Decrypt(byte[] key, byte[] iv, Stream value);
}
}
@@ -0,0 +1,102 @@
using System.Security.Cryptography;
using System.Text;
namespace System.Security.Encryption
{
public sealed class SecureString
{
private static byte[] optionalEntropy;
private byte[] encryptedValue;
public string Value {
get => this.encryptedValue is not null ? Encoding.UTF8.GetString(ProtectedData.Unprotect(this.encryptedValue, optionalEntropy, DataProtectionScope.CurrentUser)) : null;
private set => this.encryptedValue = ProtectedData.Protect(Encoding.UTF8.GetBytes(value), optionalEntropy, DataProtectionScope.CurrentUser);
}
public SecureString(string value)
{
this.Value = value;
}
public override bool Equals(object obj)
{
if (obj is string)
{
return this == (obj as string);
}
else if (obj is SecureString)
{
return this == (obj as SecureString);
}
else
{
return base.Equals(obj);
}
}
public override int GetHashCode()
{
return this.Value.GetHashCode();
}
public override string ToString()
{
return this.Value;
}
public static readonly SecureString Empty = new(string.Empty);
public static implicit operator string(SecureString ss) => ss is null ? string.Empty : ss.Value;
public static implicit operator SecureString(string s) => new(s);
public static SecureString operator +(SecureString ss1, SecureString ss2)
{
if (ss1 is null)
{
throw new ArgumentNullException(nameof(ss1));
}
if (ss2 is null)
{
throw new ArgumentNullException(nameof(ss2));
}
return new SecureString(ss1.Value + ss2.Value);
}
public static SecureString operator +(SecureString ss1, string s2)
{
if (ss1 is null)
{
throw new ArgumentNullException(nameof(ss1));
}
return new SecureString(ss1.Value + s2);
}
public static SecureString operator +(SecureString ss1, char c)
{
if (ss1 is null)
{
throw new ArgumentNullException(nameof(ss1));
}
return new SecureString(ss1.Value + c);
}
public static bool operator ==(SecureString ss1, SecureString ss2)
{
return ss1?.Value == ss2?.Value;
}
public static bool operator !=(SecureString ss1, SecureString ss2)
{
return !(ss1 == ss2);
}
public static bool operator ==(SecureString ss1, string s2)
{
return ss1?.Value == s2;
}
public static bool operator !=(SecureString ss1, string s2)
{
return !(ss1?.Value == s2);
}
public static void AddOptionalEntropy(byte[] entropy)
{
optionalEntropy = entropy;
}
}
}
@@ -0,0 +1,12 @@
using System.IO;
using System.Threading.Tasks;
namespace System.Security.Hashing
{
public interface IHashingService
{
Task<string> Hash(string raw);
Task<byte[]> Hash(byte[] raw);
Task<Stream> Hash(Stream raw);
}
}
@@ -0,0 +1,47 @@
using System.Threading.Tasks;
namespace System.Security.Hashing
{
public interface IPasswordHashingService
{
/// <summary>
/// Hash provided raw password and return the hashed value.
/// </summary>
/// <param name="raw">Base64 encoded password.</param>
/// <param name="salt">Base64 encoded salt to be used for hashing.</param>
/// <param name="length">Length of the resulting hash.</param>
/// <param name="iterations">Number of hashing iterations to be performed.</param>
/// <remarks>
/// The length of the hash will vary due to the base64 encoding of the resulting hash.
/// </remarks>
/// <returns>Base64 encoded hashed password.</returns>
Task<string> Hash(string raw, string salt, int length, int iterations);
/// <summary>
/// Hash provided raw password and return the hashed value.
/// </summary>
/// <param name="raw">Password to be hashed.</param>
/// <param name="salt">Salt to be used for hashing.</param>
/// <param name="length">Length of the resulting hash.</param>
/// <param name="iterations">Number of hashing iterations to be performed.</param>
/// <returns>Hashed password.</returns>
Task<byte[]> Hash(byte[] raw, byte[] salt, int length, int iterations);
/// <summary>
/// Verify provided password against a hashed password.
/// </summary>
/// <param name="hash">Base64 encoding of the previously hashed password.</param>
/// <param name="password">Base64 encoding of the password to be verified.</param>
/// <param name="salt">Salt used to hash the previous password.</param>
/// <param name="iterations">Number of iterations used to hash the previous password.</param>
/// <returns>Returns true if password matches the previously hashed password. Otherwise returns false.</returns>
Task<bool> VerifyPassword(string hash, string password, string salt, int iterations);
/// <summary>
/// Verify provided password against a hashed password.
/// </summary>
/// <param name="hash">Previously hashed password.</param>
/// <param name="password">Password to be verified.</param>
/// <param name="salt">Salt used to hash the previous password.</param>
/// <param name="iterations">Number of iterations used to hash the previous password.</param>
/// <returns>Returns true if password matches the previously hashed password. Otherwise returns false.</returns>
Task<bool> VerifyPassword(byte[] hash, byte[] password, byte[] salt, int iterations);
}
}
@@ -0,0 +1,101 @@
using System.Security.Cryptography;
using System.Threading.Tasks;
namespace System.Security.Hashing
{
public sealed class Rfc2898DeriveBytesPasswordHashingService : IPasswordHashingService
{
private const int MinimumIterations = 10000;
private const int MinimumHashLength = 32;
public Rfc2898DeriveBytesPasswordHashingService()
{
}
public async Task<string> Hash(string raw, string salt, int length, int iterations)
{
this.ValidateHashArguments(raw, salt, length, iterations);
var rawBytes = Convert.FromBase64String(raw);
var saltBytes = Convert.FromBase64String(salt);
var hashBytes = await this.HashInternal(rawBytes, saltBytes, length, iterations);
return Convert.ToBase64String(hashBytes);
}
public Task<byte[]> Hash(byte[] raw, byte[] salt, int length, int iterations)
{
this.ValidateHashArguments(raw, salt, length, iterations);
return this.HashInternal(raw, salt, length, iterations);
}
public Task<bool> VerifyPassword(string hash, string password, string salt, int iterations)
{
this.ValidateVerifyArguments(hash, password, salt, iterations);
var hashBytes = Convert.FromBase64String(hash);
var saltBytes = Convert.FromBase64String(salt);
var passwordBytes = Convert.FromBase64String(password);
return this.VerifyPasswordInternal(hashBytes, passwordBytes, saltBytes, iterations);
}
public Task<bool> VerifyPassword(byte[] hash, byte[] password, byte[] salt, int iterations)
{
this.ValidateVerifyArguments(hash, password, salt, iterations);
return this.VerifyPasswordInternal(hash, password, salt, iterations);
}
private void ValidateHashArguments(object raw, object salt, int length, int iterations)
{
_ = raw ?? throw new ArgumentNullException(nameof(raw));
_ = salt ?? throw new ArgumentNullException(nameof(salt));
if (iterations < MinimumIterations)
{
throw new InvalidOperationException($"Unable to perform secure hash. Iteration count must be over {MinimumIterations}");
}
if (length < MinimumHashLength)
{
throw new InvalidOperationException($"Unable to perform secure hash. Hash length must be over {MinimumHashLength}");
}
}
private void ValidateVerifyArguments(object hash, object password, object salt, int iterations)
{
_ = hash ?? throw new ArgumentNullException(nameof(hash));
_ = salt ?? throw new ArgumentNullException(nameof(salt));
_ = password ?? throw new ArgumentNullException(nameof(password));
if (iterations < MinimumIterations)
{
throw new InvalidOperationException($"Unable to verify hash. Iteration count must be over {MinimumIterations}");
}
}
private Task<byte[]> HashInternal(byte[] raw, byte[] salt, int length, int iterations)
{
using var pbkdf2 = new Rfc2898DeriveBytes(raw, salt, iterations);
var hash = pbkdf2.GetBytes(length);
return Task.FromResult(hash);
}
private Task<bool> VerifyPasswordInternal(byte[] hash, byte[] password, byte[] salt, int iterations)
{
using var pbkdf2 = new Rfc2898DeriveBytes(password, salt, iterations);
var hashToVerify = pbkdf2.GetBytes(hash.Length);
var lengthToVerify = Math.Max(hash.Length, hashToVerify.Length);
var match = true;
if (lengthToVerify <= 0)
{
return Task.FromResult(false);
}
for(var i = 0; i < lengthToVerify; i++)
{
if (i < hash.Length && i < hashToVerify.Length)
{
if (hashToVerify[i].Equals(hash[i]) is false)
{
match = false;
}
}
}
return Task.FromResult(match && hash.Length.Equals(hashToVerify.Length));
}
}
}
@@ -0,0 +1,62 @@
using System.IO;
using System.Security.Cryptography;
using System.Threading.Tasks;
namespace System.Security.Hashing
{
public sealed class Sha256HashingService : IHashingService
{
public async Task<string> Hash(string raw)
{
using var rawStream = BytesToStream(StringToBytes(raw));
using var hashedStream = await HashInternal(rawStream).ConfigureAwait(false);
return StreamToString(hashedStream);
}
public async Task<byte[]> Hash(byte[] raw)
{
using var rawStream = BytesToStream(raw);
using var hashedStream = await HashInternal(rawStream).ConfigureAwait(false);
return StreamToBytes(hashedStream);
}
public async Task<Stream> Hash(Stream raw)
{
return await HashInternal(raw);
}
private static byte[] StreamToBytes(Stream value)
{
value.Position = 0;
var buffer = new byte[1024];
using var ms = new MemoryStream();
var read = -1;
do
{
read = value.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, read);
} while (read > 0);
return ms.ToArray();
}
private static string StreamToString(Stream value)
{
return Convert.ToBase64String(StreamToBytes(value));
}
private static byte[] StringToBytes(string value)
{
return Convert.FromBase64String(value);
}
private static Stream BytesToStream(byte[] value)
{
return new MemoryStream(value);
}
private static async Task<Stream> HashInternal(Stream raw)
{
if (raw is null)
{
throw new ArgumentNullException(nameof(raw));
}
using var sha256 = SHA256.Create();
return await Task.Run(() => new MemoryStream(sha256.ComputeHash(raw)));
}
}
}
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Macocian Alexandru Victor
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -0,0 +1,59 @@
using System.Security.Cryptography;
namespace System.Security.Rng
{
public sealed class CryptoRngProvider : ICryptoRngProvider, IDisposable
{
private readonly RNGCryptoServiceProvider rngProvider;
private bool disposedValue;
public CryptoRngProvider()
{
this.rngProvider = new RNGCryptoServiceProvider();
}
public CryptoRngProvider(CspParameters cspParams)
{
this.rngProvider = new RNGCryptoServiceProvider(cspParams);
}
public void GetBytes(byte[] data)
{
this.rngProvider.GetBytes(data);
}
public void GetNonZeroBytes(byte[] data)
{
this.rngProvider.GetNonZeroBytes(data);
}
public byte[] GetBytes(int byteCount)
{
var bytes = new byte[byteCount];
this.GetBytes(bytes);
return bytes;
}
public byte[] GetNonZeroBytes(int byteCount)
{
var bytes = new byte[byteCount];
this.GetNonZeroBytes(bytes);
return bytes;
}
private void Dispose(bool disposing)
{
if (!this.disposedValue)
{
if (disposing)
{
this.rngProvider.Dispose();
}
this.disposedValue = true;
}
}
public void Dispose()
{
this.Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
}
@@ -0,0 +1,28 @@
namespace System.Security.Rng
{
public interface ICryptoRngProvider
{
/// <summary>
/// Populate provided array of bytes with cryptographically secure random bytes.
/// </summary>
/// <param name="data">Array of bytes to be populated.</param>
public void GetBytes(byte[] data);
/// <summary>
/// Return an array of cryptographically secure random bytes.
/// </summary>
/// <param name="byteCount">Length of the returned array.</param>
/// <returns>Array containing cryptographically secure random values.</returns>
public byte[] GetBytes(int byteCount);
/// <summary>
/// Populate provided array of bytes with cryptographically secure random non-zero bytes.
/// </summary>
/// <param name="data">Array of bytes to be populated.</param>
public void GetNonZeroBytes(byte[] data);
/// <summary>
/// Return an array of cryptographically secure random non-zero bytes.
/// </summary>
/// <param name="byteCount">Length of the returned array.</param>
/// <returns>Array containing cryptographically secure random non-zero values.</returns>
public byte[] GetNonZeroBytes(int byteCount);
}
}
@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<LangVersion>latest</LangVersion>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<RootNamespace>System</RootNamespace>
<Version>1.2.3</Version>
<Authors>Alexandru Macocian</Authors>
<RepositoryUrl>https://github.com/AlexMacocian/SystemExtensions</RepositoryUrl>
<Description>Security extensions for the System namespace</Description>
</PropertyGroup>
<ItemGroup>
<None Include="../LICENSE">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="5.0.0" />
</ItemGroup>
</Project>
@@ -0,0 +1,23 @@
using System.IO;
using System.Security.Cryptography;
namespace System.Security.Utilities
{
internal sealed class NotClosingCryptoStream : CryptoStream
{
public NotClosingCryptoStream(Stream stream, ICryptoTransform transform, CryptoStreamMode mode)
: base(stream, transform, mode)
{
}
protected override void Dispose(bool disposing)
{
if (!this.HasFlushedFinalBlock)
{
this.FlushFinalBlock();
}
base.Dispose(false);
}
}
}
@@ -60,7 +60,7 @@ namespace System.Collections.Generic
public void Add(T value)
{
count++;
AVLNode<T> newItem = new AVLNode<T>(value);
var newItem = new AVLNode<T>(value);
if (root == null)
{
root = newItem;
@@ -77,7 +77,7 @@ namespace System.Collections.Generic
/// <returns>True if the value is in the tree.</returns>
public bool Contains(T value)
{
AVLNode<T> node = Find(value, root);
var node = Find(value, root);
if (node == null)
{
return false;
@@ -105,12 +105,12 @@ namespace System.Collections.Generic
/// </summary>
public void Clear()
{
Queue<AVLNode<T>> queue = new Queue<AVLNode<T>>();
var queue = new Queue<AVLNode<T>>();
queue.Enqueue(root);
while (queue.Count > 0)
{
AVLNode<T> currentNode = queue.Dequeue();
var currentNode = queue.Dequeue();
if (currentNode.Left != null)
{
queue.Enqueue(currentNode.Left);
@@ -134,11 +134,11 @@ namespace System.Collections.Generic
/// <param name="arrayIndex">Starting index of the provided array.</param>
public void CopyTo(T[] array, int arrayIndex)
{
Queue<AVLNode<T>> queue = new Queue<AVLNode<T>>();
var queue = new Queue<AVLNode<T>>();
queue.Enqueue(root);
while (queue.Count > 0)
{
AVLNode<T> currentNode = queue.Dequeue();
var currentNode = queue.Dequeue();
array[arrayIndex++] = currentNode.Value;
if (currentNode.Left != null)
{
@@ -164,7 +164,7 @@ namespace System.Collections.Generic
/// <returns>Array containing the values contained in the tree.</returns>
public T[] ToArray()
{
T[] array = new T[count];
var array = new T[count];
CopyTo(array, 0);
return array;
}
@@ -191,7 +191,7 @@ namespace System.Collections.Generic
}
private AVLNode<T> BalanceTree(AVLNode<T> current)
{
int b_factor = BalanceFactor(current);
var b_factor = BalanceFactor(current);
if (b_factor > 1)
{
if (BalanceFactor(current.Left) > 0)
@@ -299,7 +299,9 @@ namespace System.Collections.Generic
return current;
}
else
{
return Find(target, current.Left);
}
}
else
{
@@ -308,7 +310,9 @@ namespace System.Collections.Generic
return current;
}
else
{
return Find(target, current.Right);
}
}
}
@@ -318,46 +322,46 @@ namespace System.Collections.Generic
}
private int GetHeight(AVLNode<T> current)
{
int height = 0;
var height = 0;
if (current != null)
{
int l = GetHeight(current.Left);
int r = GetHeight(current.Right);
int m = Max(l, r);
var l = GetHeight(current.Left);
var r = GetHeight(current.Right);
var m = Max(l, r);
height = m + 1;
}
return height;
}
private int BalanceFactor(AVLNode<T> current)
{
int l = GetHeight(current.Left);
int r = GetHeight(current.Right);
int b_factor = l - r;
var l = GetHeight(current.Left);
var r = GetHeight(current.Right);
var b_factor = l - r;
return b_factor;
}
private AVLNode<T> RotateRR(AVLNode<T> parent)
{
AVLNode<T> pivot = parent.Right;
var pivot = parent.Right;
parent.Right = pivot.Left;
pivot.Left = parent;
return pivot;
}
private AVLNode<T> RotateLL(AVLNode<T> parent)
{
AVLNode<T> pivot = parent.Left;
var pivot = parent.Left;
parent.Left = pivot.Right;
pivot.Right = parent;
return pivot;
}
private AVLNode<T> RotateLR(AVLNode<T> parent)
{
AVLNode<T> pivot = parent.Left;
var pivot = parent.Left;
parent.Left = RotateRR(pivot);
return RotateLL(parent);
}
private AVLNode<T> RotateRL(AVLNode<T> parent)
{
AVLNode<T> pivot = parent.Right;
var pivot = parent.Right;
parent.Right = RotateLL(pivot);
return RotateRR(parent);
}
@@ -367,12 +371,12 @@ namespace System.Collections.Generic
}
private IEnumerator<T> GetEnumerator(AVLNode<T> rootNode)
{
Queue<AVLNode<T>> queue = new Queue<AVLNode<T>>();
var queue = new Queue<AVLNode<T>>();
queue.Enqueue(rootNode);
while (queue.Count > 0)
{
AVLNode<T> currentNode = queue.Dequeue();
var currentNode = queue.Dequeue();
yield return currentNode.Value;
if (currentNode.Left != null)
{
@@ -88,7 +88,7 @@ namespace System.Collections.Generic
{
Capacity = 2 * Capacity;
}
int position = ++count;
var position = ++count;
for (; position > 1 && value.CompareTo(items[position / 2]) < 0; position /= 2)
{
items[position] = items[position / 2];
@@ -105,7 +105,7 @@ namespace System.Collections.Generic
{
throw new IndexOutOfRangeException("Heap is empty!");
}
T min = items[1];
var min = items[1];
items[1] = items[count--];
BubbleDown(1);
return min;
@@ -120,7 +120,7 @@ namespace System.Collections.Generic
{
throw new IndexOutOfRangeException("Heap is empty!");
}
T min = items[1];
var min = items[1];
return min;
}
/// <summary>
@@ -129,7 +129,7 @@ namespace System.Collections.Generic
/// <returns>Array with values sorted as in heap</returns>
public T[] ToArray()
{
T[] newArray = new T[count];
var newArray = new T[count];
Array.Copy(items, 1, newArray, 0, count);
return newArray;
}
@@ -168,7 +168,7 @@ namespace System.Collections.Generic
/// <returns>Enumerator that iterates over the heap.</returns>
public IEnumerator<T> GetEnumerator()
{
for (int i = 0; i < count; i++)
for (var i = 0; i < count; i++)
{
yield return items[i + 1];
}
@@ -181,7 +181,7 @@ namespace System.Collections.Generic
/// <param name="index">Index of element to bubble</param>
private void BubbleDown(int index)
{
T temp = items[index];
var temp = items[index];
int childIndex;
for (; 2 * index <= count; index = childIndex)
{
@@ -49,7 +49,7 @@
/// <param name="value">Value to be added.</param>
public void Add(T value)
{
FibonacciNode<T> node = new FibonacciNode<T>
var node = new FibonacciNode<T>
{
Value = value,
Marked = false,
@@ -77,7 +77,7 @@
/// <returns>Minimum value.</returns>
public T Remove()
{
FibonacciNode<T> currentRoot = root;
var currentRoot = root;
if (currentRoot != null)
{
root = RemoveMinimum(root);
@@ -96,7 +96,7 @@
/// <param name="value">New value to be assigned to the node.</param>
public void DecreaseKey(T oldValue, T value)
{
FibonacciNode<T> node = Find(root, oldValue);
var node = Find(root, oldValue);
root = DecreaseKey(root, node, value);
}
/// <summary>
@@ -129,7 +129,7 @@
{
return null;
}
T[] array = new T[count];
var array = new T[count];
if (count == 1)
{
array[0] = root.Value;
@@ -137,7 +137,7 @@
}
else
{
int index = 0;
var index = 0;
RecursiveFillArray(root, ref array, ref index);
return array;
}
@@ -160,7 +160,7 @@
/// <param name="index">Index of the next unintialized element in the array.</param>
private void RecursiveFillArray(FibonacciNode<T> currentNode, ref T[] array, ref int index)
{
FibonacciNode<T> oldNode = currentNode;
var oldNode = currentNode;
do
{
array[index] = currentNode.Value;
@@ -178,12 +178,12 @@
/// <param name="currentNode">Current node in the iteration.</param>
private IEnumerator<T> GetEnumerator(FibonacciNode<T> currentNode)
{
Queue<FibonacciNode<T>> queue = new Queue<FibonacciNode<T>>();
var queue = new Queue<FibonacciNode<T>>();
queue.Enqueue(currentNode);
while (queue.Count > 0)
{
currentNode = queue.Dequeue();
FibonacciNode<T> oldNode = currentNode;
var oldNode = currentNode;
do
{
yield return currentNode.Value;
@@ -204,7 +204,7 @@
{
if (node != null)
{
FibonacciNode<T> current = node;
var current = node;
do
{
Remove(current.Child);
@@ -234,12 +234,12 @@
}
if (node1.Value.CompareTo(node2.Value) > 0)
{
FibonacciNode<T> temp = node1;
var temp = node1;
node1 = node2;
node2 = temp;
}
FibonacciNode<T> node1Next = node1.Next;
FibonacciNode<T> node2Prev = node2.Previous;
var node1Next = node1.Next;
var node2Prev = node2.Previous;
node1.Next = node2;
node2.Previous = node1;
node1Next.Previous = node2Prev;
@@ -268,7 +268,7 @@
{
return;
}
FibonacciNode<T> current = node;
var current = node;
do
{
current.Marked = false;
@@ -299,12 +299,12 @@
return node;
}
FibonacciNode<T>[] trees = new FibonacciNode<T>[64];
var trees = new FibonacciNode<T>[64];
while (true)
{
if (trees[node.Degree] != null)
{
FibonacciNode<T> t = trees[node.Degree];
var t = trees[node.Degree];
if (t == node)
{
break;
@@ -344,8 +344,8 @@
}
node = node.Next;
}
FibonacciNode<T> min = node;
FibonacciNode<T> start = node;
var min = node;
var start = node;
do
{
if (node.Value.CompareTo(min.Value) < 0)
@@ -397,7 +397,7 @@
if (node.Value.CompareTo(node.Parent.Value) < 0)
{
root = Cut(root, node);
FibonacciNode<T> parent = node.Parent;
var parent = node.Parent;
node.Parent = null;
while (parent != null && parent.Marked)
{
@@ -429,7 +429,7 @@
/// <returns></returns>
private FibonacciNode<T> Find(FibonacciNode<T> root, T value)
{
FibonacciNode<T> node = root;
var node = root;
if (node == null)
{
return null;
@@ -440,7 +440,7 @@
{
return node;
}
FibonacciNode<T> ret = Find(node.Child, value);
var ret = Find(node.Child, value);
if (ret != null)
{
return ret;
@@ -50,7 +50,7 @@
random = new Random();
head = new NodeSet<T>(default, maxLevel);
end = head;
for (int i = 0; i <= maxLevel; i++)
for (var i = 0; i <= maxLevel; i++)
{
head.Next[i] = end;
}
@@ -64,8 +64,8 @@
/// <param name="item">Item to be added.</param>
public void Add(T item)
{
NodeSet<T> curNode = head;
int newLevel = 0;
var curNode = head;
var newLevel = 0;
while (random.Next(0, 2) > 0 && newLevel < maxLevel)
{
newLevel++;
@@ -74,7 +74,7 @@
{
level = newLevel;
}
NodeSet<T> newNode = new NodeSet<T>(item, newLevel);
var newNode = new NodeSet<T>(item, newLevel);
for (var i = 0; i <= newLevel; i++)
{
if (i > curNode.Level)
@@ -97,8 +97,8 @@
/// <returns>True if removal was successful.</returns>
public bool Remove(T item)
{
bool removed = false;
NodeSet<T> curNode = head;
var removed = false;
var curNode = head;
for (var i = 0; i <= maxLevel; i++)
{
if (i > curNode.Level)
@@ -134,7 +134,7 @@
/// </summary>
public void Clear()
{
for (int i = 0; i < maxLevel; i++)
for (var i = 0; i < maxLevel; i++)
{
head.Next[i] = end;
}
@@ -160,7 +160,7 @@
/// <param name="arrayIndex">Index to start insertion in the array.</param>
public void CopyTo(T[] array, int arrayIndex)
{
NodeSet<T> node = head.Next[0];
var node = head.Next[0];
while (node != end)
{
array[arrayIndex] = node.Key;
@@ -174,9 +174,9 @@
/// <returns>Array filled with elements from the collection.</returns>
public T[] ToArray()
{
T[] array = new T[count];
int index = 0;
NodeSet<T> curNode = head.Next[0];
var array = new T[count];
var index = 0;
var curNode = head.Next[0];
while (curNode != end)
{
array[index] = curNode.Key;
@@ -191,7 +191,7 @@
/// <returns></returns>
public IEnumerator<T> GetEnumerator()
{
NodeSet<T> curNode = head.Next[0];
var curNode = head.Next[0];
while (curNode != end)
{
yield return curNode.Key;
@@ -206,9 +206,9 @@
}
private NodeSet<T> Find(T key)
{
NodeSet<T> curNode = head;
var curNode = head;
for (int i = level; i >= 0; i--)
for (var i = level; i >= 0; i--)
{
while (curNode.Next[i] != end)
{
@@ -97,8 +97,8 @@
{
if (root != null)
{
T[] array = new T[count];
int index = 0;
var array = new T[count];
var index = 0;
ToArray(root, ref array, ref index);
return array;
}
@@ -221,7 +221,7 @@
{
if (node.Key.CompareTo(key) < 0)
{
Node<T> found = Find(node.Left, key);
var found = Find(node.Left, key);
if (found == null)
{
found = Find(node.Right, key);
@@ -230,7 +230,7 @@
}
else if (node.Key.CompareTo(key) > 0)
{
Node<T> found = Find(node.Right, key);
var found = Find(node.Right, key);
if (found == null)
{
found = Find(node.Left, key);
@@ -255,7 +255,7 @@
}
private IEnumerator<T> GetEnumerator(Node<T> currentNode)
{
Queue<Node<T>> queue = new Queue<Node<T>>();
var queue = new Queue<Node<T>>();
queue.Enqueue(currentNode);
while (queue.Count > 0)
{
@@ -6,10 +6,13 @@ namespace System.Extensions
{
public static byte[] ReadAllBytes(this Stream stream)
{
if (stream is null) throw new ArgumentNullException(nameof(stream));
if (stream is null)
{
throw new ArgumentNullException(nameof(stream));
}
var buffer = new byte[256];
using (MemoryStream ms = new MemoryStream())
using (var ms = new MemoryStream())
{
int read;
while ((read = stream.Read(buffer, 0, 256)) > 0)
@@ -22,7 +22,10 @@ namespace System.Extensions
public static ICollection<T> ClearAnd<T>(this ICollection<T> collection)
{
if (collection is null) throw new ArgumentNullException(nameof(collection));
if (collection is null)
{
throw new ArgumentNullException(nameof(collection));
}
collection.Clear();
return collection;
@@ -30,10 +33,17 @@ namespace System.Extensions
public static ICollection<T> AddRange<T>(this ICollection<T> collection, IEnumerable<T> values)
{
if (collection is null) throw new ArgumentNullException(nameof(collection));
if (values is null) throw new ArgumentNullException(nameof(values));
if (collection is null)
{
throw new ArgumentNullException(nameof(collection));
}
foreach(var item in values)
if (values is null)
{
throw new ArgumentNullException(nameof(values));
}
foreach (var item in values)
{
collection.Add(item);
}
@@ -43,8 +53,15 @@ namespace System.Extensions
public static int IndexOfWhere<T>(this ICollection<T> collection, Func<T, bool> selector)
{
if (collection is null) throw new ArgumentNullException(nameof(collection));
if (selector is null) throw new ArgumentNullException(nameof(selector));
if (collection is null)
{
throw new ArgumentNullException(nameof(collection));
}
if (selector is null)
{
throw new ArgumentNullException(nameof(selector));
}
var index = 0;
foreach (var item in collection)
@@ -1,7 +1,31 @@
namespace System.Extensions
using Newtonsoft.Json;
namespace System.Extensions
{
public static class ObjectExtensions
{
public static T Deserialize<T>(this string serialized)
where T : class
{
if (serialized.IsNullOrWhiteSpace())
{
throw new ArgumentException("Provided serialized string cannot be null or whitespace", nameof(serialized));
}
return JsonConvert.DeserializeObject<T>(serialized);
}
public static string Serialize<T>(this T obj)
where T : class
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
return JsonConvert.SerializeObject(obj);
}
public static T Cast<T>(this object obj)
{
return (T)obj;
@@ -19,7 +43,10 @@
public static T ThrowIfNull<T>([ValidatedNotNull] this T obj, string name) where T : class
{
if (obj is null) throw new ArgumentNullException(name);
if (obj is null)
{
throw new ArgumentNullException(name);
}
return obj;
}
@@ -40,8 +40,15 @@
}
public Optional<T> Do(Action<T> onSome, Action onNone)
{
if (onSome is null) throw new ArgumentNullException(nameof(onSome));
if (onNone is null) throw new ArgumentNullException(nameof(onNone));
if (onSome is null)
{
throw new ArgumentNullException(nameof(onSome));
}
if (onNone is null)
{
throw new ArgumentNullException(nameof(onNone));
}
if (this is Some)
{
@@ -67,8 +74,15 @@
}
public Optional<V> Switch<V>(Func<T, V> onSome, Func<V> onNone)
{
if (onSome is null) throw new ArgumentNullException($"{nameof(onSome)}");
if (onNone is null) throw new ArgumentNullException($"{nameof(onNone)}");
if (onSome is null)
{
throw new ArgumentNullException($"{nameof(onSome)}");
}
if (onNone is null)
{
throw new ArgumentNullException($"{nameof(onNone)}");
}
if (this is Some)
{
@@ -43,9 +43,15 @@
}
public Result<TSuccess, TFailure> Do(Action onSuccess, Action onFailure)
{
if (onSuccess is null) throw new ArgumentNullException(nameof(onSuccess));
if (onSuccess is null)
{
throw new ArgumentNullException(nameof(onSuccess));
}
if (onFailure is null) throw new ArgumentNullException(nameof(onFailure));
if (onFailure is null)
{
throw new ArgumentNullException(nameof(onFailure));
}
if (value is TSuccess)
{
@@ -71,9 +77,15 @@
}
public Result<TSuccess, TFailure> Do(Action<TSuccess> onSuccess, Action<TFailure> onFailure)
{
if (onSuccess is null) throw new ArgumentNullException(nameof(onSuccess));
if (onSuccess is null)
{
throw new ArgumentNullException(nameof(onSuccess));
}
if (onFailure is null) throw new ArgumentNullException(nameof(onFailure));
if (onFailure is null)
{
throw new ArgumentNullException(nameof(onFailure));
}
if (value is TSuccess success)
{
@@ -99,9 +111,15 @@
}
public T Switch<T>(Func<TSuccess, T> onSuccess, Func<TFailure, T> onFailure)
{
if (onSuccess is null) throw new ArgumentNullException(nameof(onSuccess));
if (onSuccess is null)
{
throw new ArgumentNullException(nameof(onSuccess));
}
if (onFailure is null) throw new ArgumentNullException(nameof(onFailure));
if (onFailure is null)
{
throw new ArgumentNullException(nameof(onFailure));
}
if (value is TSuccess success)
{
@@ -127,9 +145,15 @@
}
public Result<V, K> Switch<V, K>(Func<TSuccess, V> onSuccess, Func<TFailure, K> onFailure)
{
if (onSuccess is null) throw new ArgumentNullException(nameof(onSuccess));
if (onSuccess is null)
{
throw new ArgumentNullException(nameof(onSuccess));
}
if (onFailure is null) throw new ArgumentNullException(nameof(onFailure));
if (onFailure is null)
{
throw new ArgumentNullException(nameof(onFailure));
}
if (value is TSuccess success)
{
@@ -7,8 +7,15 @@ namespace System.Extensions
{
public static void DoWhileReading(this Stream stream, Action<int, byte[]> action, int bufferLength = 256)
{
if (stream is null) throw new ArgumentNullException(nameof(stream));
if (action is null) throw new ArgumentNullException(nameof(action));
if (stream is null)
{
throw new ArgumentNullException(nameof(stream));
}
if (action is null)
{
throw new ArgumentNullException(nameof(action));
}
var buffer = new byte[bufferLength];
var read = stream.Read(buffer, 0, bufferLength);
@@ -21,7 +28,10 @@ namespace System.Extensions
public static byte[] ReadBytes(this Stream stream, int count)
{
if (stream is null) throw new ArgumentNullException(nameof(stream));
if (stream is null)
{
throw new ArgumentNullException(nameof(stream));
}
var buffer = new byte[count];
stream.Read(buffer, 0, count);
@@ -30,9 +40,15 @@ namespace System.Extensions
public static Stream Rewind(this Stream stream)
{
if (stream is null) throw new ArgumentNullException(nameof(stream));
if (stream is null)
{
throw new ArgumentNullException(nameof(stream));
}
if (!stream.CanSeek) throw new InvalidOperationException("Stream doesn't support rewinding");
if (!stream.CanSeek)
{
throw new InvalidOperationException("Stream doesn't support rewinding");
}
stream.Seek(0, SeekOrigin.Begin);
return stream;
@@ -41,17 +57,19 @@ namespace System.Extensions
public static string ReadUntil(this StreamReader sr, string delim)
{
var sb = new StringBuilder();
bool found = false;
var found = false;
while (!found && !sr.EndOfStream)
{
for (int i = 0; i < delim.Length; i++)
for (var i = 0; i < delim.Length; i++)
{
char c = (char)sr.Read();
var c = (char)sr.Read();
sb.Append(c);
if (c != delim[i])
{
break;
}
if (i == delim.Length - 1)
{
@@ -44,13 +44,17 @@ namespace System.Extensions
public static async Task RunPeriodicAsync(this Action onTick, TimeSpan dueTime, TimeSpan interval, CancellationToken token)
{
if (dueTime > TimeSpan.Zero)
{
await Task.Delay(dueTime, token).ConfigureAwait(false);
}
while (!token.IsCancellationRequested)
{
onTick?.Invoke();
if (interval > TimeSpan.Zero)
{
await Task.Delay(interval, token).ConfigureAwait(false);
}
}
}
@@ -95,7 +99,7 @@ namespace System.Extensions
var oldContext = SynchronizationContext.Current;
var synch = new ExclusiveSynchronizationContext();
SynchronizationContext.SetSynchronizationContext(synch);
T ret = default(T);
var ret = default(T);
synch.Post(async _ =>
{
try
@@ -46,7 +46,10 @@ namespace System.Extensions
public TResult Finally(Action act)
{
if (act is null) throw new ArgumentNullException(nameof(act));
if (act is null)
{
throw new ArgumentNullException(nameof(act));
}
try
{
@@ -2,13 +2,15 @@
<PropertyGroup>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<LangVersion>latest</LangVersion>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<RootNamespace>System</RootNamespace>
<Version>1.3.0</Version>
<Version>1.3.2</Version>
<Authors>Alexandru Macocian</Authors>
<RepositoryUrl>https://github.com/AlexMacocian/SystemExtensions</RepositoryUrl>
<Description>Extensions for the System namespace</Description>
</PropertyGroup>
<ItemGroup>
@@ -18,4 +20,8 @@
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
</Project>
@@ -174,7 +174,7 @@ namespace System.Threading
threadpool = new List<WorkerThread>();
tasks = new PriorityQueue<QueueEntry>();
maxThreads = System.Environment.ProcessorCount;
for (int i = 0; i < maxThreads; i++)
for (var i = 0; i < maxThreads; i++)
{
this.CreateAndStartWorkerThread();
}
@@ -194,7 +194,7 @@ namespace System.Threading
threadpool = new List<WorkerThread>();
tasks = new PriorityQueue<QueueEntry>();
this.maxThreads = Math.Max(maxThreads, 1);
for (int i = 0; i < maxThreads; i++)
for (var i = 0; i < maxThreads; i++)
{
this.CreateAndStartWorkerThread();
}
@@ -216,23 +216,23 @@ namespace System.Threading
{
threadpool = new List<WorkerThread>();
tasks = new PriorityQueue<QueueEntry>();
for (int i = 0; i < lowest; i++)
for (var i = 0; i < lowest; i++)
{
this.CreateAndStartWorkerThread(ThreadPriority.Lowest);
}
for (int i = 0; i < belowNormal; i++)
for (var i = 0; i < belowNormal; i++)
{
this.CreateAndStartWorkerThread(ThreadPriority.BelowNormal);
}
for (int i = 0; i < normal; i++)
for (var i = 0; i < normal; i++)
{
this.CreateAndStartWorkerThread(ThreadPriority.Normal);
}
for (int i = 0; i < aboveNormal; i++)
for (var i = 0; i < aboveNormal; i++)
{
this.CreateAndStartWorkerThread(ThreadPriority.AboveNormal);
}
for (int i = 0; i < highest; i++)
for (var i = 0; i < highest; i++)
{
this.CreateAndStartWorkerThread(ThreadPriority.Highest);
}
@@ -247,7 +247,11 @@ namespace System.Threading
/// <param name="taskPriority">Priority of task. Affects its position into the queue.</param>
public void QueueUserWorkItem(WaitCallback waitCallback, object callbackState, TaskPriority taskPriority)
{
while (!Monitor.TryEnter(tasksLock)) ;
while (!Monitor.TryEnter(tasksLock))
{
;
}
tasks.Enqueue(new QueueEntry(taskPriority, waitCallback, callbackState));
Monitor.Exit(tasksLock);
}
@@ -307,7 +311,11 @@ namespace System.Threading
thisWorkerThread.Working = true;
QueueEntry task = null;
while (!Monitor.TryEnter(tasksLock)) ;
while (!Monitor.TryEnter(tasksLock))
{
;
}
if (tasks.Count > 0)
{
task = tasks.Dequeue();
@@ -316,7 +324,7 @@ namespace System.Threading
if (task != null)
{
System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.Name + " - Running task!");
WaitCallback waitCallback = task.WaitCallback;
var waitCallback = task.WaitCallback;
waitCallback.Invoke(task.Object);
}
thisWorkerThread.Working = false;
@@ -328,7 +336,7 @@ namespace System.Threading
/// </summary>
private void ObserverLoop()
{
Statistics statistics = new Statistics();
var statistics = new Statistics();
while (true)
{
//Observer operates on a 100ms loop. Due to the low priority of the thread itself, this loop will almost always take
@@ -346,7 +354,7 @@ namespace System.Threading
//This part of code updates the statistics of the threadpool.
if (statistics.Initialized)
{
double loopDuration = (DateTime.Now - statistics.LastUpdate).TotalMilliseconds;
var loopDuration = (DateTime.Now - statistics.LastUpdate).TotalMilliseconds;
if (statistics.LoopFrequency == 0)
{
statistics.LoopFrequency = loopDuration;
@@ -387,7 +395,7 @@ namespace System.Threading
if (tasks.Count > 0)
{
//If there are tasks pending, find a thread with priority under Normal and upgrade its priority.
Thread t = FindThreadWithLowPriority();
var t = FindThreadWithLowPriority();
if (t != null)
{
UpgradeThreadPriority(t);
@@ -396,7 +404,7 @@ namespace System.Threading
else
{
//If there are no tasks pending, find a thread with priority above Lowest and downgrade its priority.
Thread t = FindThreadWithAcceptablePriority();
var t = FindThreadWithAcceptablePriority();
if (t != null)
{
DowngradeThreadPriority(t);
@@ -423,7 +431,7 @@ namespace System.Threading
//If thread is currently working, notify it to close.
//Else, abort the thread.
//Reset counter to 0.
WorkerThread worker = threadpool[threadpool.Count - 1];
var worker = threadpool[threadpool.Count - 1];
if (worker.Working)
{
worker.Running = false;
@@ -444,7 +452,7 @@ namespace System.Threading
/// <returns>Thread with low priority.</returns>
private Thread FindThreadWithLowPriority()
{
foreach (WorkerThread t in threadpool)
foreach (var t in threadpool)
{
if (t.Thread.Priority == ThreadPriority.Lowest || t.Thread.Priority == ThreadPriority.BelowNormal)
{
@@ -459,7 +467,7 @@ namespace System.Threading
/// <returns>Thread with BelowNormal or Normal priority.</returns>
private Thread FindThreadWithAcceptablePriority()
{
foreach (WorkerThread t in threadpool)
foreach (var t in threadpool)
{
if (t.Thread.Priority == ThreadPriority.Normal || t.Thread.Priority == ThreadPriority.BelowNormal)
{
@@ -538,7 +546,7 @@ namespace System.Threading
this.observerCancellationTokenSource.Cancel();
this.observer.Join();
}
foreach (WorkerThread worker in threadpool)
foreach (var worker in threadpool)
{
worker.CancellationTokenSource.Cancel();
worker.Thread.Join();
@@ -20,7 +20,7 @@ namespace System.Collections.Tests
{
try
{
for (int i = 0; i < 100; i++)
for (var i = 0; i < 100; i++)
{
avlTree.Add(i * 20 - (50 + i));
}
@@ -38,7 +38,7 @@ namespace System.Collections.Tests
[TestMethod()]
public void ContainsTest()
{
for (int i = 0; i < 100; i++)
for (var i = 0; i < 100; i++)
{
avlTree.Add(i);
}
@@ -52,7 +52,7 @@ namespace System.Collections.Tests
[TestMethod()]
public void RemoveTest()
{
for (int i = 0; i < 100; i++)
for (var i = 0; i < 100; i++)
{
avlTree.Add(i);
}
@@ -68,7 +68,7 @@ namespace System.Collections.Tests
[TestMethod()]
public void ClearTest()
{
for (int i = 0; i < 100; i++)
for (var i = 0; i < 100; i++)
{
avlTree.Add(i);
}
@@ -82,24 +82,24 @@ namespace System.Collections.Tests
[TestMethod()]
public void CopyToTest()
{
for (int i = 0; i < 100; i++)
for (var i = 0; i < 100; i++)
{
avlTree.Add(i);
}
int[] array = new int[100];
var array = new int[100];
avlTree.CopyTo(array, 0);
}
[TestMethod()]
public void GetEnumeratorTest()
{
for (int i = 0; i < 100; i++)
for (var i = 0; i < 100; i++)
{
avlTree.Add(i);
}
int count = 0;
foreach(int value in avlTree)
var count = 0;
foreach(var value in avlTree)
{
count++;
System.Diagnostics.Debug.WriteLine(value);
@@ -114,34 +114,34 @@ namespace System.Collections.Tests
[TestMethod()]
public void ToArrayTest()
{
for (int i = 0; i < 100; i++)
for (var i = 0; i < 100; i++)
{
avlTree.Add(i);
}
int[] array = avlTree.ToArray();
var array = avlTree.ToArray();
}
[TestMethod()]
public void Serialize()
{
AVLTree<int> avlTree2 = new AVLTree<int>();
for (int i = 0; i < 100; i++)
var avlTree2 = new AVLTree<int>();
for (var i = 0; i < 100; i++)
{
avlTree.Add(i);
}
BinaryFormatter serializer = new BinaryFormatter();
string s = string.Empty;
var serializer = new BinaryFormatter();
var s = string.Empty;
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, avlTree);
stream.Position = 0;
avlTree2 = (AVLTree<int>)serializer.Deserialize(stream);
}
IEnumerator<int> avlTreeEnum = avlTree.GetEnumerator();
IEnumerator<int> avlTree2Enum = avlTree2.GetEnumerator();
var avlTreeEnum = avlTree.GetEnumerator();
var avlTree2Enum = avlTree2.GetEnumerator();
for(int i = 0; i < 100; i++)
for(var i = 0; i < 100; i++)
{
if(avlTreeEnum.Current != avlTree2Enum.Current)
{
@@ -31,7 +31,7 @@ namespace System.Collections.Tests
{
try
{
for (int i = 0; i < 100; i++)
for (var i = 0; i < 100; i++)
{
binaryHeap.Add(i * 20 - (50 + i));
}
@@ -52,7 +52,7 @@ namespace System.Collections.Tests
{
try
{
int tries = binaryHeap.Count;
var tries = binaryHeap.Count;
while (binaryHeap.Count > 0)
{
if (tries == 0)
@@ -72,7 +72,7 @@ namespace System.Collections.Tests
[TestMethod()]
public void MinMaxTest()
{
for (int i = 0; i < 1000; i++)
for (var i = 0; i < 1000; i++)
{
binaryHeap.Add(i);
}
@@ -85,7 +85,7 @@ namespace System.Collections.Tests
[TestMethod()]
public void ClearTest()
{
for (int i = 0; i < 100; i++)
for (var i = 0; i < 100; i++)
{
binaryHeap.Add(i);
}
@@ -99,12 +99,12 @@ namespace System.Collections.Tests
[TestMethod()]
public void ClearTest2()
{
for (int i = 100; i < 200; i++)
for (var i = 100; i < 200; i++)
{
binaryHeap.Add(i);
}
binaryHeap.Clear(false);
int[] array = binaryHeap.ToArray();
var array = binaryHeap.ToArray();
if (binaryHeap.Count > 0 || binaryHeap.Capacity == 10)
{
Assert.Fail();
@@ -133,11 +133,11 @@ namespace System.Collections.Tests
[TestMethod()]
public void ToArrayTest()
{
for(int i = 0; i < 1000; i++)
for(var i = 0; i < 1000; i++)
{
binaryHeap.Add(i);
}
int[] array = binaryHeap.ToArray();
var array = binaryHeap.ToArray();
if(array.Length != binaryHeap.Count)
{
Assert.Fail();
@@ -151,12 +151,12 @@ namespace System.Collections.Tests
[TestMethod()]
public void GetEnumeratorTest()
{
for (int i = 0; i < 1000; i++)
for (var i = 0; i < 1000; i++)
{
binaryHeap.Add(i);
}
int count = 0;
foreach(int value in binaryHeap)
var count = 0;
foreach(var value in binaryHeap)
{
System.Diagnostics.Debug.WriteLine(value);
count++;
@@ -173,22 +173,22 @@ namespace System.Collections.Tests
[TestMethod()]
public void Serialize()
{
BinaryHeap<int> binaryHeap2 = new BinaryHeap<int>();
for (int i = 0; i < 100; i++)
var binaryHeap2 = new BinaryHeap<int>();
for (var i = 0; i < 100; i++)
{
binaryHeap.Add(i);
}
BinaryFormatter serializer = new BinaryFormatter();
string s = string.Empty;
var serializer = new BinaryFormatter();
var s = string.Empty;
using (var stream = new MemoryStream()) {
serializer.Serialize(stream, binaryHeap);
stream.Position = 0;
binaryHeap2 = (BinaryHeap<int>)serializer.Deserialize(stream);
}
IEnumerator<int> binaryHeapEnum = binaryHeap.GetEnumerator();
IEnumerator<int> binaryHeapEnum2 = binaryHeap2.GetEnumerator();
var binaryHeapEnum = binaryHeap.GetEnumerator();
var binaryHeapEnum2 = binaryHeap2.GetEnumerator();
for (int i = 0; i < 100; i++)
for (var i = 0; i < 100; i++)
{
if (binaryHeapEnum.Current != binaryHeapEnum2.Current)
{
@@ -12,7 +12,7 @@ namespace System.Collections.Tests
[TestMethod()]
public void InsertTest()
{
for (int i = 0; i < 1000; i++)
for (var i = 0; i < 1000; i++)
{
fibonacciHeap.Add(i);
}
@@ -31,21 +31,21 @@ namespace System.Collections.Tests
[TestMethod()]
public void MergeTest()
{
FibonacciHeap<int> fibonacciHeap1 = new FibonacciHeap<int>();
FibonacciHeap<int> fibonacciHeap2 = new FibonacciHeap<int>();
var fibonacciHeap1 = new FibonacciHeap<int>();
var fibonacciHeap2 = new FibonacciHeap<int>();
for(int i = 0; i < 100; i++)
for(var i = 0; i < 100; i++)
{
fibonacciHeap1.Add(i);
}
for(int i = 100; i < 300; i++)
for(var i = 100; i < 300; i++)
{
fibonacciHeap2.Add(i);
}
fibonacciHeap1.Merge(fibonacciHeap2);
for(int i = 1; i < 300; i++)
for(var i = 1; i < 300; i++)
{
if (!fibonacciHeap1.Contains(i))
{
@@ -70,11 +70,11 @@ namespace System.Collections.Tests
{
Assert.Fail();
}
for (int i = 0; i < 1000; i++)
for (var i = 0; i < 1000; i++)
{
fibonacciHeap.Add(i);
}
for (int i = 0; i < 1000; i++)
for (var i = 0; i < 1000; i++)
{
if (fibonacciHeap.Remove() != i)
{
@@ -104,7 +104,7 @@ namespace System.Collections.Tests
[TestMethod()]
public void ContainsTest()
{
for(int i = 0; i < 10000; i++)
for(var i = 0; i < 10000; i++)
{
fibonacciHeap.Add(i);
}
@@ -117,7 +117,7 @@ namespace System.Collections.Tests
[TestMethod()]
public void ClearTest()
{
for(int i = 0; i < 10000; i++)
for(var i = 0; i < 10000; i++)
{
fibonacciHeap.Add(i);
}
@@ -132,14 +132,14 @@ namespace System.Collections.Tests
[TestMethod()]
public void ToArrayTest()
{
for(int i = 999; i >= 0; i--)
for(var i = 999; i >= 0; i--)
{
fibonacciHeap.Add(i);
}
fibonacciHeap.Remove();
int[] arr = fibonacciHeap.ToArray();
var arr = fibonacciHeap.ToArray();
for(int i = 1; i < 512; i++)
for(var i = 1; i < 512; i++)
{
if(arr[i - 1] != i)
{
@@ -151,14 +151,14 @@ namespace System.Collections.Tests
[TestMethod()]
public void GetEnumeratorTest()
{
for (int i = 999; i >= 0; i--)
for (var i = 999; i >= 0; i--)
{
fibonacciHeap.Add(i);
}
int count = 0;
var count = 0;
foreach(int value in fibonacciHeap)
foreach(var value in fibonacciHeap)
{
System.Diagnostics.Debug.WriteLine(value);
count++;
@@ -175,23 +175,23 @@ namespace System.Collections.Tests
[TestMethod()]
public void Serialize()
{
FibonacciHeap<int> fibonacciHeap2 = new FibonacciHeap<int>();
for (int i = 0; i < 100; i++)
var fibonacciHeap2 = new FibonacciHeap<int>();
for (var i = 0; i < 100; i++)
{
fibonacciHeap.Add(i);
}
BinaryFormatter serializer = new BinaryFormatter();
string s = string.Empty;
var serializer = new BinaryFormatter();
var s = string.Empty;
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, fibonacciHeap);
stream.Position = 0;
fibonacciHeap2 = (FibonacciHeap<int>)serializer.Deserialize(stream);
}
IEnumerator<int> enum1 = fibonacciHeap.GetEnumerator();
IEnumerator<int> enum2 = fibonacciHeap2.GetEnumerator();
var enum1 = fibonacciHeap.GetEnumerator();
var enum2 = fibonacciHeap2.GetEnumerator();
for (int i = 0; i < 100; i++)
for (var i = 0; i < 100; i++)
{
if (enum1.Current != enum2.Current)
{
@@ -29,7 +29,7 @@ namespace System.Collections.Tests
[TestMethod()]
public void EnqueueTest()
{
for(int i = 0; i < 100; i++)
for(var i = 0; i < 100; i++)
{
priorityQueue.Enqueue(i);
}
@@ -42,11 +42,11 @@ namespace System.Collections.Tests
[TestMethod()]
public void DequeueTest()
{
for(int i = 0; i < 100; i++)
for(var i = 0; i < 100; i++)
{
priorityQueue.Enqueue(i);
}
for(int i = 0; i < 100; i++)
for(var i = 0; i < 100; i++)
{
if(i != priorityQueue.Dequeue())
{
@@ -81,23 +81,23 @@ namespace System.Collections.Tests
[TestMethod()]
public void Serialize()
{
PriorityQueue<int> priorityQueue2 = new PriorityQueue<int>();
for (int i = 0; i < 100; i++)
var priorityQueue2 = new PriorityQueue<int>();
for (var i = 0; i < 100; i++)
{
priorityQueue.Enqueue(i);
}
BinaryFormatter serializer = new BinaryFormatter();
string s = string.Empty;
var serializer = new BinaryFormatter();
var s = string.Empty;
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, priorityQueue);
stream.Position = 0;
priorityQueue2 = (PriorityQueue<int>)serializer.Deserialize(stream);
}
IEnumerator<int> enum1 = priorityQueue.GetEnumerator();
IEnumerator<int> enum2 = priorityQueue2.GetEnumerator();
var enum1 = priorityQueue.GetEnumerator();
var enum2 = priorityQueue2.GetEnumerator();
for (int i = 0; i < 100; i++)
for (var i = 0; i < 100; i++)
{
if (enum1.Current != enum2.Current)
{
@@ -12,19 +12,19 @@ namespace System.Collections.Tests
[TestMethod()]
public void SkipListTest()
{
SkipList<int> skipList = new SkipList<int>();
var skipList = new SkipList<int>();
}
[TestMethod()]
public void SkipListTest2()
{
SkipList<int> skipList = new SkipList<int>(30);
var skipList = new SkipList<int>(30);
}
[TestMethod()]
public void AddTest()
{
for(int i = 0; i < 200; i++)
for(var i = 0; i < 200; i++)
{
skipList.Add(i);
}
@@ -33,7 +33,7 @@ namespace System.Collections.Tests
[TestMethod()]
public void ClearTest()
{
for (int i = 0; i < 200; i++)
for (var i = 0; i < 200; i++)
{
skipList.Add(i);
}
@@ -47,7 +47,7 @@ namespace System.Collections.Tests
[TestMethod()]
public void ContainsTest()
{
for (int i = 0; i < 200; i++)
for (var i = 0; i < 200; i++)
{
skipList.Add(i);
}
@@ -61,13 +61,13 @@ namespace System.Collections.Tests
[TestMethod()]
public void CopyToTest()
{
for (int i = 0; i < 200; i++)
for (var i = 0; i < 200; i++)
{
skipList.Add(i);
}
int[] array = new int[skipList.Count];
var array = new int[skipList.Count];
skipList.CopyTo(array, 0);
for (int i = 0; i < 200; i++)
for (var i = 0; i < 200; i++)
{
if(array[i] != i)
{
@@ -79,13 +79,13 @@ namespace System.Collections.Tests
[TestMethod()]
public void ToArrayTest()
{
for (int i = 0; i < 200; i++)
for (var i = 0; i < 200; i++)
{
skipList.Add(i);
}
int[] array = skipList.ToArray();
var array = skipList.ToArray();
for (int i = 0; i < 200; i++)
for (var i = 0; i < 200; i++)
{
if(array[i] != i)
{
@@ -97,12 +97,12 @@ namespace System.Collections.Tests
[TestMethod()]
public void GetEnumeratorTest()
{
for (int i = 0; i < 200; i++)
for (var i = 0; i < 200; i++)
{
skipList.Add(i);
}
foreach(int i in skipList)
foreach(var i in skipList)
{
System.Diagnostics.Debug.WriteLine(i);
}
@@ -111,7 +111,7 @@ namespace System.Collections.Tests
[TestMethod()]
public void RemoveTest()
{
for (int i = 0; i < 200; i++)
for (var i = 0; i < 200; i++)
{
skipList.Add(i);
}
@@ -126,23 +126,23 @@ namespace System.Collections.Tests
[Ignore("Binary serialization is obsolete and should not be used anymore")]
public void Serialize()
{
SkipList<int> skipList2 = new SkipList<int>();
for (int i = 0; i < 100; i++)
var skipList2 = new SkipList<int>();
for (var i = 0; i < 100; i++)
{
skipList.Add(i);
}
BinaryFormatter serializer = new BinaryFormatter();
string s = string.Empty;
var serializer = new BinaryFormatter();
var s = string.Empty;
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, skipList);
stream.Position = 0;
skipList2 = (SkipList<int>)serializer.Deserialize(stream);
}
IEnumerator<int> enum1 = skipList.GetEnumerator();
IEnumerator<int> enum2 = skipList2.GetEnumerator();
var enum1 = skipList.GetEnumerator();
var enum2 = skipList2.GetEnumerator();
for (int i = 0; i < 100; i++)
for (var i = 0; i < 100; i++)
{
if (enum1.Current != enum2.Current)
{
@@ -18,8 +18,8 @@ namespace System.Collections.Tests
[TestMethod()]
public void InsertTest()
{
Random random = new Random();
for(int i = 0; i < 1000; i++)
var random = new Random();
for(var i = 0; i < 1000; i++)
{
treap.Add(random.Next(0, 5000));
}
@@ -41,8 +41,8 @@ namespace System.Collections.Tests
[TestMethod()]
public void ClearTest()
{
Random random = new Random();
for (int i = 0; i < 100; i++)
var random = new Random();
for (var i = 0; i < 100; i++)
{
treap.Add(random.Next(0, 5000));
}
@@ -71,12 +71,12 @@ namespace System.Collections.Tests
[TestMethod()]
public void ToArrayTest()
{
for(int i = 0; i < 1000; i++)
for(var i = 0; i < 1000; i++)
{
treap.Add(i);
}
int[] arr = treap.ToArray();
for(int i = 0; i < 1000; i++)
var arr = treap.ToArray();
for(var i = 0; i < 1000; i++)
{
if(arr[i] != i)
{
@@ -88,13 +88,13 @@ namespace System.Collections.Tests
[TestMethod()]
public void GetEnumeratorTest()
{
for (int i = 0; i < 1000; i++)
for (var i = 0; i < 1000; i++)
{
treap.Add(i);
}
int count = 0;
foreach(int value in treap)
var count = 0;
foreach(var value in treap)
{
System.Diagnostics.Debug.WriteLine(value);
count++;
@@ -112,23 +112,23 @@ namespace System.Collections.Tests
[Ignore("Binary serialization is obsolete and should not be used anymore")]
public void Serialize()
{
Treap<int> treap2 = new Treap<int>();
for (int i = 0; i < 100; i++)
var treap2 = new Treap<int>();
for (var i = 0; i < 100; i++)
{
treap.Add(i);
}
BinaryFormatter serializer = new BinaryFormatter();
string s = string.Empty;
var serializer = new BinaryFormatter();
var s = string.Empty;
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, treap);
stream.Position = 0;
treap2 = (Treap<int>)serializer.Deserialize(stream);
}
IEnumerator<int> enum1 = treap.GetEnumerator();
IEnumerator<int> enum2 = treap2.GetEnumerator();
var enum1 = treap.GetEnumerator();
var enum2 = treap2.GetEnumerator();
for (int i = 0; i < 100; i++)
for (var i = 0; i < 100; i++)
{
if (enum1.Current != enum2.Current)
{
@@ -0,0 +1,42 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace System.Extensions.Tests;
[TestClass]
public class ObjectExtensionsTests
{
[TestMethod]
public void ThrowIfNull_NetCore_ThrowsWithCorrectName()
{
object obj = null;
try
{
System.Core.Extensions.ObjectExtensions.ThrowIfNull(obj);
}
catch (ArgumentNullException ex)
{
ex.ParamName.Should().Be("obj");
return;
}
Assert.Fail("Null object should throw");
}
[TestMethod]
public void ThrowIfNull_NetStandard_ThrowsWithCorrectName()
{
object obj = null;
try
{
ObjectExtensions.ThrowIfNull(obj, nameof(obj));
}
catch (ArgumentNullException ex)
{
ex.ParamName.Should().Be("obj");
return;
}
Assert.Fail("Null object should throw");
}
}
@@ -1,7 +1,5 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Http;
using System.IO;
using System.Net;
using System.Net.Http;
@@ -9,7 +7,7 @@ using System.Threading;
using System.Threading.Tasks;
using SystemExtensionsTests.Utils;
namespace SystemExtensionsTests.Http
namespace System.Http.Tests
{
[TestClass]
public class HttpClientTests
@@ -32,7 +30,7 @@ namespace SystemExtensionsTests.Http
[TestMethod]
public async Task HttpClientEmitsCorrectMessages()
{
int messagesEmitted = 0;
var messagesEmitted = 0;
this.httpClient.EventEmitted += (sender, message) =>
{
messagesEmitted++;
@@ -309,7 +307,7 @@ namespace SystemExtensionsTests.Http
this.handler.ResponseResolverAsync = async (request) =>
{
request.RequestUri.Should().Be(expectedUri);
for (int i = 0; i < 10; i++)
for (var i = 0; i < 10; i++)
{
await Task.Delay(100);
}
@@ -53,7 +53,7 @@ namespace System.Structures.BitStructures.Tests
[DataRow(int.MaxValue, int.MinValue)]
public void TestLowHigh(int low, int high)
{
Int64BitStruct int64 = new Int64BitStruct(low, high);
var int64 = new Int64BitStruct(low, high);
Int32BitStruct lowStruct = low;
Int32BitStruct highStruct = high;
Assert.IsTrue(int64.Low == lowStruct);
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
@@ -18,6 +18,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SystemExtensions.NetCore\SystemExtensions.NetCore.csproj" />
<ProjectReference Include="..\SystemExtensions.NetStandard\SystemExtensions.NetStandard.csproj" />
</ItemGroup>
@@ -49,7 +49,7 @@ namespace System.Threading.Tests
Thread.Sleep(100);
try
{
int x = threadPool.NumberOfThreads;
var x = threadPool.NumberOfThreads;
Assert.Fail();
}
catch(Exception e)
@@ -63,17 +63,17 @@ namespace System.Threading.Tests
{
threadPool.Dispose();
threadPool = new PriorityThreadPool();
for (int i = 0; i < 10; i++)
for (var i = 0; i < 10; i++)
{
threadPool.QueueUserWorkItem(o =>
{
for (int x = 0; x < 100; x++)
for (var x = 0; x < 100; x++)
{
System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.ManagedThreadId + " - " + x);
}
}, null);
}
for (int i = 0; i < 10; i++)
for (var i = 0; i < 10; i++)
{
System.Diagnostics.Debug.WriteLine("=====================================");
System.Diagnostics.Debug.WriteLine("Current threads in threadpool: " + threadPool.NumberOfThreads);
@@ -98,11 +98,11 @@ namespace System.Threading.Tests
{
Assert.Fail();
}
for (int i = 0; i < 10; i++)
for (var i = 0; i < 10; i++)
{
threadPool.QueueUserWorkItem(o =>
{
for (int x = 0; x < 100; x++)
for (var x = 0; x < 100; x++)
{
System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.ManagedThreadId + " - " + x);
}
@@ -126,11 +126,11 @@ namespace System.Threading.Tests
{
Assert.Fail();
}
for (int i = 0; i < 10; i++)
for (var i = 0; i < 10; i++)
{
threadPool.QueueUserWorkItem(o =>
{
for (int x = 0; x < 100; x++)
for (var x = 0; x < 100; x++)
{
switch (Thread.CurrentThread.Priority)
{
@@ -153,7 +153,7 @@ namespace System.Threading.Tests
}
}, null);
}
for (int i = 0; i < 50; i++)
for (var i = 0; i < 50; i++)
{
System.Diagnostics.Debug.WriteLine("=====================================");
System.Diagnostics.Debug.WriteLine("Current threads in threadpool: " + threadPool.NumberOfThreads);
@@ -168,9 +168,9 @@ namespace System.Threading.Tests
{
threadPool.Dispose();
threadPool = new PriorityThreadPool();
for (int i = 0; i < 1000; i++)
for (var i = 0; i < 1000; i++)
{
TaskPriority taskPriority = TaskPriority.Lowest;
var taskPriority = TaskPriority.Lowest;
if(i % 10 == 0)
{
taskPriority = TaskPriority.Highest;
+31 -2
View File
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31005.135
# Visual Studio Version 17
VisualStudioVersion = 17.0.31815.197
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemExtensions.NetStandard", "SystemExtensions.NetStandard\SystemExtensions.NetStandard.csproj", "{4CE9E55C-6016-4631-B8D4-4D763DD05F23}"
EndProject
@@ -14,6 +14,20 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemExtensions.NetStandar
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemExtensions.NetStandard.DependencyInjection.Tests", "SystemExtensions.DependencyInjection.Tests\SystemExtensions.NetStandard.DependencyInjection.Tests.csproj", "{1AFA1EEF-CEBA-4046-8466-C9B52979B7DA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemExtensions.NetStandard.Security", "SystemExtensions.NetStandard.Security\SystemExtensions.NetStandard.Security.csproj", "{BFC5BEE7-2569-45EA-9713-CDB32EED57AA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemExtensions.NetStandard.Security.Tests", "SystemExtensions.NetStandard.Security.Tests\SystemExtensions.NetStandard.Security.Tests.csproj", "{341ECE0F-A8DD-49A0-AE3D-B28D72E85130}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SystemExtensions.NetCore", "SystemExtensions.NetCore\SystemExtensions.NetCore.csproj", "{9E6EBBF0-671B-4941-A72B-2CA60C882038}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{BBA334F6-779A-4A45-8BF3-EA321D0D12CF}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{52962B0C-BB5F-4211-A70C-801D0A73CACC}"
ProjectSection(SolutionItems) = preProject
.github\workflows\cd.yaml = .github\workflows\cd.yaml
.github\workflows\ci.yaml = .github\workflows\ci.yaml
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -36,10 +50,25 @@ Global
{1AFA1EEF-CEBA-4046-8466-C9B52979B7DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1AFA1EEF-CEBA-4046-8466-C9B52979B7DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1AFA1EEF-CEBA-4046-8466-C9B52979B7DA}.Release|Any CPU.Build.0 = Release|Any CPU
{BFC5BEE7-2569-45EA-9713-CDB32EED57AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BFC5BEE7-2569-45EA-9713-CDB32EED57AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BFC5BEE7-2569-45EA-9713-CDB32EED57AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BFC5BEE7-2569-45EA-9713-CDB32EED57AA}.Release|Any CPU.Build.0 = Release|Any CPU
{341ECE0F-A8DD-49A0-AE3D-B28D72E85130}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{341ECE0F-A8DD-49A0-AE3D-B28D72E85130}.Debug|Any CPU.Build.0 = Debug|Any CPU
{341ECE0F-A8DD-49A0-AE3D-B28D72E85130}.Release|Any CPU.ActiveCfg = Release|Any CPU
{341ECE0F-A8DD-49A0-AE3D-B28D72E85130}.Release|Any CPU.Build.0 = Release|Any CPU
{9E6EBBF0-671B-4941-A72B-2CA60C882038}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9E6EBBF0-671B-4941-A72B-2CA60C882038}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9E6EBBF0-671B-4941-A72B-2CA60C882038}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9E6EBBF0-671B-4941-A72B-2CA60C882038}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{52962B0C-BB5F-4211-A70C-801D0A73CACC} = {BBA334F6-779A-4A45-8BF3-EA321D0D12CF}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BFA90E90-BD97-40AD-B19E-C723E504369A}
EndGlobalSection