2016-07-02 09:01:47 +03:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using Bit.App.Abstractions;
|
|
|
|
|
using Plugin.Settings.Abstractions;
|
2016-10-15 08:18:12 +03:00
|
|
|
|
using PCLCrypto;
|
2016-07-02 09:01:47 +03:00
|
|
|
|
|
|
|
|
|
namespace Bit.App.Services
|
|
|
|
|
{
|
|
|
|
|
public class PasswordGenerationService : IPasswordGenerationService
|
|
|
|
|
{
|
|
|
|
|
private readonly ISettings _settings;
|
|
|
|
|
|
|
|
|
|
public PasswordGenerationService(ISettings settings)
|
|
|
|
|
{
|
|
|
|
|
_settings = settings;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-15 08:01:00 +03:00
|
|
|
|
public string GeneratePassword(
|
|
|
|
|
int? length = null,
|
|
|
|
|
bool? uppercase = null,
|
|
|
|
|
bool? lowercase = null,
|
|
|
|
|
bool? numbers = null,
|
|
|
|
|
bool? special = null,
|
|
|
|
|
bool? ambiguous = null,
|
|
|
|
|
int? minUppercase = null,
|
|
|
|
|
int? minLowercase = null,
|
|
|
|
|
int? minNumbers = null,
|
|
|
|
|
int? minSpecial = null)
|
2016-07-02 09:01:47 +03:00
|
|
|
|
{
|
2016-07-15 08:01:00 +03:00
|
|
|
|
int minUppercaseValue = minUppercase.GetValueOrDefault(1),
|
|
|
|
|
minLowercaseValue = minLowercase.GetValueOrDefault(1),
|
|
|
|
|
minNumbersValue = minNumbers.GetValueOrDefault(_settings.GetValueOrDefault(Constants.PasswordGeneratorMinNumbers, 1)),
|
|
|
|
|
minSpecialValue = minSpecial.GetValueOrDefault(_settings.GetValueOrDefault(Constants.PasswordGeneratorMinSpecial, 1)),
|
|
|
|
|
lengthValue = length.GetValueOrDefault(_settings.GetValueOrDefault(Constants.PasswordGeneratorLength, 10));
|
|
|
|
|
|
|
|
|
|
bool uppercaseValue = uppercase.GetValueOrDefault(_settings.GetValueOrDefault(Constants.PasswordGeneratorUppercase, true)),
|
|
|
|
|
lowercaseValue = lowercase.GetValueOrDefault(_settings.GetValueOrDefault(Constants.PasswordGeneratorLowercase, true)),
|
|
|
|
|
numbersValue = numbers.GetValueOrDefault(_settings.GetValueOrDefault(Constants.PasswordGeneratorNumbers, true)),
|
|
|
|
|
specialValue = special.GetValueOrDefault(_settings.GetValueOrDefault(Constants.PasswordGeneratorSpecial, true)),
|
|
|
|
|
ambiguousValue = ambiguous.GetValueOrDefault(_settings.GetValueOrDefault(Constants.PasswordGeneratorAmbiguous, false));
|
2016-07-02 09:01:47 +03:00
|
|
|
|
|
|
|
|
|
// Sanitize
|
2016-07-15 08:01:00 +03:00
|
|
|
|
if(uppercaseValue && minUppercaseValue < 0)
|
2016-07-02 09:01:47 +03:00
|
|
|
|
{
|
2016-07-15 08:01:00 +03:00
|
|
|
|
minUppercaseValue = 1;
|
2016-07-02 09:01:47 +03:00
|
|
|
|
}
|
2016-07-15 08:01:00 +03:00
|
|
|
|
if(lowercaseValue && minLowercaseValue < 0)
|
2016-07-02 09:01:47 +03:00
|
|
|
|
{
|
2016-07-15 08:01:00 +03:00
|
|
|
|
minLowercaseValue = 1;
|
2016-07-02 09:01:47 +03:00
|
|
|
|
}
|
2016-07-15 08:01:00 +03:00
|
|
|
|
if(numbersValue && minNumbersValue < 0)
|
2016-07-02 09:01:47 +03:00
|
|
|
|
{
|
2016-07-15 08:01:00 +03:00
|
|
|
|
minNumbersValue = 1;
|
2016-07-02 09:01:47 +03:00
|
|
|
|
}
|
2016-07-15 08:01:00 +03:00
|
|
|
|
if(specialValue && minSpecialValue < 0)
|
2016-07-02 09:01:47 +03:00
|
|
|
|
{
|
2016-07-15 08:01:00 +03:00
|
|
|
|
minSpecialValue = 1;
|
2016-07-02 09:01:47 +03:00
|
|
|
|
}
|
|
|
|
|
|
2016-07-15 08:01:00 +03:00
|
|
|
|
if(lengthValue < 1)
|
2016-07-02 09:01:47 +03:00
|
|
|
|
{
|
2016-07-15 08:01:00 +03:00
|
|
|
|
lengthValue = 10;
|
2016-07-02 09:01:47 +03:00
|
|
|
|
}
|
2016-07-15 08:01:00 +03:00
|
|
|
|
var minLength = minUppercaseValue + minLowercaseValue + minNumbersValue + minSpecialValue;
|
|
|
|
|
if(lengthValue < minLength)
|
2016-07-02 09:01:47 +03:00
|
|
|
|
{
|
2016-07-15 08:01:00 +03:00
|
|
|
|
lengthValue = minLength;
|
2016-07-02 09:01:47 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var positionsBuilder = new StringBuilder();
|
2016-07-15 08:01:00 +03:00
|
|
|
|
if(lowercaseValue && minLowercaseValue > 0)
|
2016-07-02 09:01:47 +03:00
|
|
|
|
{
|
2016-07-15 08:01:00 +03:00
|
|
|
|
for(int i = 0; i < minLowercaseValue; i++)
|
2016-07-02 09:01:47 +03:00
|
|
|
|
{
|
|
|
|
|
positionsBuilder.Append("l");
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-07-15 08:01:00 +03:00
|
|
|
|
if(uppercaseValue && minUppercaseValue > 0)
|
2016-07-02 09:01:47 +03:00
|
|
|
|
{
|
2016-07-15 08:01:00 +03:00
|
|
|
|
for(int i = 0; i < minUppercaseValue; i++)
|
2016-07-02 09:01:47 +03:00
|
|
|
|
{
|
|
|
|
|
positionsBuilder.Append("u");
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-07-15 08:01:00 +03:00
|
|
|
|
if(numbersValue && minNumbersValue > 0)
|
2016-07-02 09:01:47 +03:00
|
|
|
|
{
|
2016-07-15 08:01:00 +03:00
|
|
|
|
for(int i = 0; i < minNumbersValue; i++)
|
2016-07-02 09:01:47 +03:00
|
|
|
|
{
|
|
|
|
|
positionsBuilder.Append("n");
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-07-15 08:01:00 +03:00
|
|
|
|
if(specialValue && minSpecialValue > 0)
|
2016-07-02 09:01:47 +03:00
|
|
|
|
{
|
2016-07-15 08:01:00 +03:00
|
|
|
|
for(int i = 0; i < minSpecialValue; i++)
|
2016-07-02 09:01:47 +03:00
|
|
|
|
{
|
|
|
|
|
positionsBuilder.Append("s");
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-07-15 08:01:00 +03:00
|
|
|
|
while(positionsBuilder.Length < lengthValue)
|
2016-07-02 09:01:47 +03:00
|
|
|
|
{
|
|
|
|
|
positionsBuilder.Append("a");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Shuffle
|
2016-10-15 08:18:12 +03:00
|
|
|
|
var positions = positionsBuilder.ToString().ToCharArray().OrderBy(a => Next(int.MaxValue)).ToArray();
|
2016-07-02 09:01:47 +03:00
|
|
|
|
|
|
|
|
|
// Build out other character sets
|
|
|
|
|
var allCharSet = string.Empty;
|
|
|
|
|
|
|
|
|
|
var lowercaseCharSet = "abcdefghijkmnopqrstuvwxyz";
|
2016-07-15 08:01:00 +03:00
|
|
|
|
if(ambiguousValue)
|
2016-07-02 09:01:47 +03:00
|
|
|
|
{
|
|
|
|
|
lowercaseCharSet = string.Concat(lowercaseCharSet, "l");
|
|
|
|
|
}
|
2016-07-15 08:01:00 +03:00
|
|
|
|
if(lowercaseValue)
|
2016-07-02 09:01:47 +03:00
|
|
|
|
{
|
|
|
|
|
allCharSet = string.Concat(allCharSet, lowercaseCharSet);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var uppercaseCharSet = "ABCDEFGHIJKLMNPQRSTUVWXYZ";
|
2016-07-15 08:01:00 +03:00
|
|
|
|
if(ambiguousValue)
|
2016-07-02 09:01:47 +03:00
|
|
|
|
{
|
|
|
|
|
uppercaseCharSet = string.Concat(uppercaseCharSet, "O");
|
|
|
|
|
}
|
2016-07-15 08:01:00 +03:00
|
|
|
|
if(uppercaseValue)
|
2016-07-02 09:01:47 +03:00
|
|
|
|
{
|
|
|
|
|
allCharSet = string.Concat(allCharSet, uppercaseCharSet);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var numberCharSet = "23456789";
|
2016-07-15 08:01:00 +03:00
|
|
|
|
if(ambiguousValue)
|
2016-07-02 09:01:47 +03:00
|
|
|
|
{
|
|
|
|
|
numberCharSet = string.Concat(numberCharSet, "01");
|
|
|
|
|
}
|
2016-07-15 08:01:00 +03:00
|
|
|
|
if(numbersValue)
|
2016-07-02 09:01:47 +03:00
|
|
|
|
{
|
|
|
|
|
allCharSet = string.Concat(allCharSet, numberCharSet);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var specialCharSet = "!@#$%^&*";
|
2016-07-15 08:01:00 +03:00
|
|
|
|
if(specialValue)
|
2016-07-02 09:01:47 +03:00
|
|
|
|
{
|
|
|
|
|
allCharSet = string.Concat(allCharSet, specialCharSet);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var password = new StringBuilder();
|
2016-07-15 08:01:00 +03:00
|
|
|
|
for(var i = 0; i < lengthValue; i++)
|
2016-07-02 09:01:47 +03:00
|
|
|
|
{
|
|
|
|
|
string positionChars = string.Empty;
|
|
|
|
|
switch(positions[i])
|
|
|
|
|
{
|
|
|
|
|
case 'l':
|
|
|
|
|
positionChars = lowercaseCharSet;
|
|
|
|
|
break;
|
|
|
|
|
case 'u':
|
|
|
|
|
positionChars = uppercaseCharSet;
|
|
|
|
|
break;
|
|
|
|
|
case 'n':
|
|
|
|
|
positionChars = numberCharSet;
|
|
|
|
|
break;
|
|
|
|
|
case 's':
|
|
|
|
|
positionChars = specialCharSet;
|
|
|
|
|
break;
|
|
|
|
|
case 'a':
|
|
|
|
|
positionChars = allCharSet;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-15 08:18:12 +03:00
|
|
|
|
var randomCharIndex = Next(positionChars.Length - 1);
|
2016-07-02 09:01:47 +03:00
|
|
|
|
password.Append(positionChars[randomCharIndex]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return password.ToString();
|
|
|
|
|
}
|
2016-10-15 08:18:12 +03:00
|
|
|
|
|
|
|
|
|
private int Next(int maxValue)
|
|
|
|
|
{
|
|
|
|
|
if(maxValue == 0)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (int)(WinRTCrypto.CryptographicBuffer.GenerateRandomNumber() % maxValue);
|
|
|
|
|
}
|
2016-07-02 09:01:47 +03:00
|
|
|
|
}
|
|
|
|
|
}
|