Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

638 Feature Request: password generator with options #664

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/dev/impl/DevToys/DevToys.csproj
Expand Up @@ -32,6 +32,7 @@
<Compile Include="Core\Threading\AsyncLazy.cs" />
<Compile Include="Helpers\Base64Helper.cs" />
<Compile Include="Helpers\CertificateHelper.cs" />
<Compile Include="Helpers\CryptoRandomGenerator.cs" />
<Compile Include="Helpers\JsonYaml\Core\BooleanYamlTypeResolver.cs" />
<Compile Include="Helpers\StorageFileHelper.cs" />
<Compile Include="Helpers\ImageHelper.cs" />
Expand Down Expand Up @@ -144,6 +145,8 @@
<Compile Include="ViewModels\Tools\Generators\GeneratorsGroupToolProvider.cs" />
<Compile Include="ViewModels\Tools\Generators\LoremIpsumGenerator\LoremIpsumGeneratorToolProvider.cs" />
<Compile Include="ViewModels\Tools\Generators\LoremIpsumGenerator\LoremIpsumGeneratorToolViewModel.cs" />
<Compile Include="ViewModels\Tools\Generators\PasswordGenerator\PasswordGeneratorToolProvider.cs" />
<Compile Include="ViewModels\Tools\Generators\PasswordGenerator\PasswordGeneratorToolViewModel.cs" />
<Compile Include="ViewModels\Tools\Graphic\ColorBlindnessSimulator\ColorBlindnessSimulatorToolProvider.cs" />
<Compile Include="ViewModels\Tools\Graphic\ColorBlindnessSimulator\ColorBlindnessSimulatorToolViewModel.cs" />
<Compile Include="ViewModels\Tools\Graphic\ColorPicker\ColorPickerToolProvider.cs" />
Expand Down Expand Up @@ -214,6 +217,9 @@
<Compile Include="Views\Tools\Generators\CheckSumGenerator\CheckSumGeneratorToolPage.xaml.cs">
<DependentUpon>CheckSumGeneratorToolPage.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Tools\Generators\PasswordGenerator\PasswordGeneratorPage.xaml.cs">
<DependentUpon>PasswordGeneratorPage.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Tools\Graphic\ColorBlindnessSimulator\ColorBlindnessSimulatorToolPage.xaml.cs">
<DependentUpon>ColorBlindnessSimulatorToolPage.xaml</DependentUpon>
</Compile>
Expand Down Expand Up @@ -597,6 +603,10 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\Tools\Generators\PasswordGenerator\PasswordGeneratorPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Tools\Graphic\ColorPicker\ColorPickerToolPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
Expand Down
226 changes: 226 additions & 0 deletions src/dev/impl/DevToys/Helpers/CryptoRandomGenerator.cs
@@ -0,0 +1,226 @@
#nullable enable

using System;
using System.Security.Cryptography;

namespace DevToys.Helpers
{
/// <summary>
/// A class that mimics the standard Random class in the .NET Framework - but uses a random number generator internally.
/// Taken from IdentityModel (ref.: https://github.com/IdentityModel/IdentityModel/ )
/// Taken from PasswordGenerator (ref.: https://github.com/Darkseal/PasswordGenerator/blob/master/CryptoRandom.cs )
/// </summary>
internal sealed class CryptoRandom : Random
{
private static readonly RandomNumberGenerator Rng = RandomNumberGenerator.Create();
private readonly byte[] _uint32Buffer = new byte[4];

/// <summary>
/// Output format for unique IDs
/// </summary>
public enum OutputFormat
{
/// <summary>
/// URL-safe Base64
/// </summary>
Base64Url,
/// <summary>
/// Base64
/// </summary>
Base64,
/// <summary>
/// Hex
/// </summary>
Hex
}

/// <summary>
/// Creates a random key byte array.
/// </summary>
/// <param name="length">The length.</param>
/// <returns></returns>
public static byte[] CreateRandomKey(int length)
{
byte[] bytes = new byte[length];
Rng.GetBytes(bytes);

return bytes;
}

/// <summary>
/// Creates a URL safe unique identifier.
/// </summary>
/// <param name="length">The length.</param>
/// <param name="format">The output format</param>
/// <returns></returns>
public static string CreateUniqueId(int length = 32, OutputFormat format = OutputFormat.Base64Url)
{
byte[] bytes = CreateRandomKey(length);

return format switch
{
OutputFormat.Base64Url => Base64Url.Encode(bytes),
OutputFormat.Base64 => Convert.ToBase64String(bytes),
OutputFormat.Hex => BitConverter.ToString(bytes).Replace("-", ""),
_ => throw new ArgumentException("Invalid output format", nameof(format))
};
}

/// <summary>
/// Initializes a new instance of the <see cref="CryptoRandom"/> class.
/// </summary>
public CryptoRandom() { }

/// <summary>
/// Initializes a new instance of the <see cref="CryptoRandom"/> class.
/// </summary>
/// <param name="ignoredSeed">seed (ignored)</param>
public CryptoRandom(int ignoredSeed) { }

/// <summary>
/// Returns a nonnegative random number.
/// </summary>
/// <returns>
/// A 32-bit signed integer greater than or equal to zero and less than <see cref="F:System.Int32.MaxValue"/>.
/// </returns>
public override int Next()
{
Rng.GetBytes(_uint32Buffer);
return BitConverter.ToInt32(_uint32Buffer, 0) & 0x7FFFFFFF;
}

/// <summary>
/// Returns a nonnegative random number less than the specified maximum.
/// </summary>
/// <param name="maxValue">The exclusive upper bound of the random number to be generated. <paramref name="maxValue"/> must be greater than or equal to zero.</param>
/// <returns>
/// A 32-bit signed integer greater than or equal to zero, and less than <paramref name="maxValue"/>; that is, the range of return values ordinarily includes zero but not <paramref name="maxValue"/>. However, if <paramref name="maxValue"/> equals zero, <paramref name="maxValue"/> is returned.
/// </returns>
/// <exception cref="T:System.ArgumentOutOfRangeException">
/// <paramref name="maxValue"/> is less than zero.
/// </exception>
public override int Next(int maxValue)
{
if (maxValue < 0)
{
throw new ArgumentOutOfRangeException(nameof(maxValue));
}

return Next(0, maxValue);
}

/// <summary>
/// Returns a random number within a specified range.
/// </summary>
/// <param name="minValue">The inclusive lower bound of the random number returned.</param>
/// <param name="maxValue">The exclusive upper bound of the random number returned. <paramref name="maxValue"/> must be greater than or equal to <paramref name="minValue"/>.</param>
/// <returns>
/// A 32-bit signed integer greater than or equal to <paramref name="minValue"/> and less than <paramref name="maxValue"/>; that is, the range of return values includes <paramref name="minValue"/> but not <paramref name="maxValue"/>. If <paramref name="minValue"/> equals <paramref name="maxValue"/>, <paramref name="minValue"/> is returned.
/// </returns>
/// <exception cref="T:System.ArgumentOutOfRangeException">
/// <paramref name="minValue"/> is greater than <paramref name="maxValue"/>.
/// </exception>
public override int Next(int minValue, int maxValue)
{
if (minValue > maxValue)
{
throw new ArgumentOutOfRangeException(nameof(minValue));
}

if (minValue == maxValue)
{
return minValue;
}

long diff = maxValue - minValue;

while (true)
{
Rng.GetBytes(_uint32Buffer);
UInt32 rand = BitConverter.ToUInt32(_uint32Buffer, 0);

long max = (1 + (long)UInt32.MaxValue);
long remainder = max % diff;
if (rand < max - remainder)
{
return (Int32)(minValue + (rand % diff));
}
}
}

/// <summary>
/// Returns a random number between 0.0 and 1.0.
/// </summary>
/// <returns>
/// A double-precision floating point number greater than or equal to 0.0, and less than 1.0.
/// </returns>
public override double NextDouble()
{
Rng.GetBytes(_uint32Buffer);
uint rand = BitConverter.ToUInt32(_uint32Buffer, 0);
return rand / (1.0 + uint.MaxValue);
}

/// <summary>
/// Fills the elements of a specified array of bytes with random numbers.
/// </summary>
/// <param name="buffer">An array of bytes to contain random numbers.</param>
/// <exception cref="T:System.ArgumentNullException">
/// <paramref name="buffer"/> is null.
/// </exception>
public override void NextBytes(byte[] buffer)
{
if (buffer == null)
{
throw new ArgumentNullException(nameof(buffer));
}

Rng.GetBytes(buffer);
}
}

/// <summary>
/// Base64Url encoder/decoder
/// </summary>
public static class Base64Url
{
/// <summary>
/// Encodes the specified byte array.
/// </summary>
/// <param name="arg">The argument.</param>
/// <returns></returns>
public static string Encode(byte[] arg)
{
string? s = Convert.ToBase64String(arg); // Standard base64 encoder

s = s.Split('=')[0]; // Remove any trailing '='s
s = s.Replace('+', '-'); // 62nd char of encoding
s = s.Replace('/', '_'); // 63rd char of encoding

return s;
}

/// <summary>
/// Decodes the specified string.
/// </summary>
/// <param name="arg">The argument.</param>
/// <returns></returns>
/// <exception cref="System.Exception">Illegal base64url string!</exception>
public static byte[] Decode(string arg)
{
string s = arg;
s = s.Replace('-', '+'); // 62nd char of encoding
s = s.Replace('_', '/'); // 63rd char of encoding

switch (s.Length % 4) // Pad with trailing '='s
{
case 0: break; // No pad chars in this case
case 2: s += "=="; break; // Two pad chars
case 3: s += "="; break; // One pad char
default: throw new Exception("Illegal base64url string!");
}

return Convert.FromBase64String(s); // Standard base64 decoder
}
}
}
106 changes: 106 additions & 0 deletions src/dev/impl/DevToys/LanguageManager.cs
Expand Up @@ -45,6 +45,7 @@ public partial class LanguageManager : ObservableObject
private readonly MainPageStrings _mainpage = new MainPageStrings();
private readonly MarkdownPreviewStrings _markdownpreview = new MarkdownPreviewStrings();
private readonly NumberBaseConverterStrings _numberbaseconverter = new NumberBaseConverterStrings();
private readonly PasswordGeneratorStrings _passwordgenerator = new PasswordGeneratorStrings();
private readonly PngJpgCompressorStrings _pngjpgcompressor = new PngJpgCompressorStrings();
private readonly RegExStrings _regex = new RegExStrings();
private readonly SearchResultStrings _searchresult = new SearchResultStrings();
Expand Down Expand Up @@ -174,6 +175,11 @@ public partial class LanguageManager : ObservableObject
/// </summary>
public NumberBaseConverterStrings NumberBaseConverter => _numberbaseconverter;

/// <summary>
/// Gets the <see cref="PasswordGeneratorStrings"/>.
/// </summary>
public PasswordGeneratorStrings PasswordGenerator => _passwordgenerator;

/// <summary>
/// Gets the <see cref="PngJpgCompressorStrings"/>.
/// </summary>
Expand Down Expand Up @@ -2295,6 +2301,106 @@ public string GetFormattedValueOverflow(string? param0)
public string IncompatibleBaseDictionaryError => _resources.GetString("IncompatibleBaseDictionaryError");
}

public class PasswordGeneratorStrings : ObservableObject
{
private readonly ResourceLoader _resources = ResourceLoader.GetForViewIndependentUse("PasswordGenerator");

/// <summary>
/// Gets the resource AccessibleName.
/// </summary>
public string AccessibleName => _resources.GetString("AccessibleName");

/// <summary>
/// Gets the resource Configuration.
/// </summary>
public string Configuration => _resources.GetString("Configuration");

/// <summary>
/// Gets the resource MenuDisplayName.
/// </summary>
public string MenuDisplayName => _resources.GetString("MenuDisplayName");

/// <summary>
/// Gets the resource Generate.
/// </summary>
public string Generate => _resources.GetString("Generate");

/// <summary>
/// Gets the resource GenerateButton.
/// </summary>
public string GenerateButton => _resources.GetString("GenerateButton");

/// <summary>
/// Gets the resource Passwords.
/// </summary>
public string Passwords => _resources.GetString("Passwords");

/// <summary>
/// Gets the resource MultiplySymbol.
/// </summary>
public string MultiplySymbol => _resources.GetString("MultiplySymbol");

/// <summary>
/// Gets the resource NumberOfPasswordsToGenerate_AutomationProperties_Name.
/// </summary>
public string NumberOfPasswordsToGenerate_AutomationProperties_Name => _resources.GetString("NumberOfPasswordsToGenerate_AutomationProperties_Name");

/// <summary>
/// Gets the resource Uppercase.
/// </summary>
public string Uppercase => _resources.GetString("Uppercase");

/// <summary>
/// Gets the resource Description.
/// </summary>
public string Description => _resources.GetString("Description");

/// <summary>
/// Gets the resource Digits.
/// </summary>
public string Digits => _resources.GetString("Digits");

/// <summary>
/// Gets the resource Lowercase.
/// </summary>
public string Lowercase => _resources.GetString("Lowercase");

/// <summary>
/// Gets the resource SpecialCharacters.
/// </summary>
public string SpecialCharacters => _resources.GetString("SpecialCharacters");

/// <summary>
/// Gets the resource Length.
/// </summary>
public string Length => _resources.GetString("Length");

/// <summary>
/// Gets the resource SearchDisplayName.
/// </summary>
public string SearchDisplayName => _resources.GetString("SearchDisplayName");

/// <summary>
/// Gets the resource SearchKeywords.
/// </summary>
public string SearchKeywords => _resources.GetString("SearchKeywords");

/// <summary>
/// Gets the resource LowercaseDescription.
/// </summary>
public string LowercaseDescription => _resources.GetString("LowercaseDescription");

/// <summary>
/// Gets the resource SpecialCharactersDescription.
/// </summary>
public string SpecialCharactersDescription => _resources.GetString("SpecialCharactersDescription");

/// <summary>
/// Gets the resource UppercaseDescription.
/// </summary>
public string UppercaseDescription => _resources.GetString("UppercaseDescription");
}

public class PngJpgCompressorStrings : ObservableObject
{
private readonly ResourceLoader _resources = ResourceLoader.GetForViewIndependentUse("PngJpgCompressor");
Expand Down