mirror of
https://github.com/bitwarden/mobile
synced 2025-12-05 23:53:33 +00:00
[PM-1402] Refactor PasswordGenerationService alongside PolicyService (#2443)
* PM-1402 Refactor pass generation service alongside policyservice * PM-1402 Refactor PasswordGenerationService and PolicyService to have a simpler code and more specific to each class * PM-1402 Fix format * PM-1402 Moved policy consts from PolicyService to Policy * PM-1402 fix crash due to lack of null checking * PM-1402 fix format * PM-1402 removed GetValueOrDefault() given that it was not needed and was changing the behavior
This commit is contained in:
committed by
GitHub
parent
f24b82f345
commit
1c8328f62d
@@ -121,9 +121,8 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
var ssoToken = response.Token;
|
var ssoToken = response.Token;
|
||||||
|
|
||||||
|
var passwordOptions = PasswordGenerationOptions.CreateDefault
|
||||||
var passwordOptions = new PasswordGenerationOptions(true);
|
.WithLength(64);
|
||||||
passwordOptions.Length = 64;
|
|
||||||
|
|
||||||
var codeVerifier = await _passwordGenerationService.GeneratePasswordAsync(passwordOptions);
|
var codeVerifier = await _passwordGenerationService.GeneratePasswordAsync(passwordOptions);
|
||||||
var codeVerifierHash = await _cryptoFunctionService.HashAsync(codeVerifier, CryptoHashAlgorithm.Sha256);
|
var codeVerifierHash = await _cryptoFunctionService.HashAsync(codeVerifier, CryptoHashAlgorithm.Sha256);
|
||||||
|
|||||||
@@ -827,7 +827,7 @@ namespace Bit.App.Pages
|
|||||||
private void SetOptions()
|
private void SetOptions()
|
||||||
{
|
{
|
||||||
_options.AllowAmbiguousChar = AllowAmbiguousChars;
|
_options.AllowAmbiguousChar = AllowAmbiguousChars;
|
||||||
_options.Type = PasswordTypeSelectedIndex == 1 ? "passphrase" : "password";
|
_options.Type = PasswordTypeSelectedIndex == 1 ? PasswordGenerationOptions.TYPE_PASSPHRASE : PasswordGenerationOptions.TYPE_PASSWORD;
|
||||||
_options.MinNumber = MinNumber;
|
_options.MinNumber = MinNumber;
|
||||||
_options.MinSpecial = MinSpecial;
|
_options.MinSpecial = MinSpecial;
|
||||||
_options.Special = Special;
|
_options.Special = Special;
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ namespace Bit.App.Pages
|
|||||||
{
|
{
|
||||||
// if we have a vault timeout policy, we need to filter the timeout options
|
// if we have a vault timeout policy, we need to filter the timeout options
|
||||||
_vaultTimeoutPolicy = (await _policyService.GetAll(PolicyType.MaximumVaultTimeout)).First();
|
_vaultTimeoutPolicy = (await _policyService.GetAll(PolicyType.MaximumVaultTimeout)).First();
|
||||||
var policyMinutes = _policyService.GetPolicyInt(_vaultTimeoutPolicy, PolicyService.TIMEOUT_POLICY_MINUTES);
|
var policyMinutes = _vaultTimeoutPolicy.GetInt(Policy.MINUTES_KEY);
|
||||||
_vaultTimeoutOptions = _vaultTimeoutOptions.Where(t =>
|
_vaultTimeoutOptions = _vaultTimeoutOptions.Where(t =>
|
||||||
t.Value <= policyMinutes &&
|
t.Value <= policyMinutes &&
|
||||||
(t.Value > 0 || t.Value == CustomVaultTimeoutValue) &&
|
(t.Value > 0 || t.Value == CustomVaultTimeoutValue) &&
|
||||||
@@ -302,7 +302,7 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
if (_vaultTimeoutPolicy != null)
|
if (_vaultTimeoutPolicy != null)
|
||||||
{
|
{
|
||||||
var maximumTimeout = _policyService.GetPolicyInt(_vaultTimeoutPolicy, PolicyService.TIMEOUT_POLICY_MINUTES);
|
var maximumTimeout = _vaultTimeoutPolicy.GetInt(Policy.MINUTES_KEY);
|
||||||
|
|
||||||
if (newTimeout > maximumTimeout)
|
if (newTimeout > maximumTimeout)
|
||||||
{
|
{
|
||||||
@@ -382,7 +382,7 @@ namespace Bit.App.Pages
|
|||||||
public async Task VaultTimeoutActionAsync()
|
public async Task VaultTimeoutActionAsync()
|
||||||
{
|
{
|
||||||
if (_vaultTimeoutPolicy != null &&
|
if (_vaultTimeoutPolicy != null &&
|
||||||
!string.IsNullOrEmpty(_policyService.GetPolicyString(_vaultTimeoutPolicy, PolicyService.TIMEOUT_POLICY_ACTION)))
|
!string.IsNullOrEmpty(_vaultTimeoutPolicy.GetString(Policy.MINUTES_KEY)))
|
||||||
{
|
{
|
||||||
// do nothing if we have a policy set
|
// do nothing if we have a policy set
|
||||||
return;
|
return;
|
||||||
@@ -610,8 +610,8 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
if (_vaultTimeoutPolicy != null)
|
if (_vaultTimeoutPolicy != null)
|
||||||
{
|
{
|
||||||
var policyMinutes = _policyService.GetPolicyInt(_vaultTimeoutPolicy, PolicyService.TIMEOUT_POLICY_MINUTES);
|
var policyMinutes = _vaultTimeoutPolicy.GetInt(Policy.MINUTES_KEY);
|
||||||
var policyAction = _policyService.GetPolicyString(_vaultTimeoutPolicy, PolicyService.TIMEOUT_POLICY_ACTION);
|
var policyAction = _vaultTimeoutPolicy.GetString(Policy.ACTION_KEY);
|
||||||
|
|
||||||
if (policyMinutes.HasValue || !string.IsNullOrWhiteSpace(policyAction))
|
if (policyMinutes.HasValue || !string.IsNullOrWhiteSpace(policyAction))
|
||||||
{
|
{
|
||||||
@@ -625,14 +625,14 @@ namespace Bit.App.Pages
|
|||||||
else if (!policyMinutes.HasValue && !string.IsNullOrWhiteSpace(policyAction))
|
else if (!policyMinutes.HasValue && !string.IsNullOrWhiteSpace(policyAction))
|
||||||
{
|
{
|
||||||
policyAlert = string.Format(AppResources.VaultTimeoutActionPolicyInEffect,
|
policyAlert = string.Format(AppResources.VaultTimeoutActionPolicyInEffect,
|
||||||
policyAction == PolicyService.TIMEOUT_POLICY_ACTION_LOCK ? AppResources.Lock : AppResources.LogOut);
|
policyAction == Policy.ACTION_LOCK ? AppResources.Lock : AppResources.LogOut);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
policyAlert = string.Format(AppResources.VaultTimeoutPolicyWithActionInEffect,
|
policyAlert = string.Format(AppResources.VaultTimeoutPolicyWithActionInEffect,
|
||||||
Math.Floor((float)policyMinutes / 60),
|
Math.Floor((float)policyMinutes / 60),
|
||||||
policyMinutes % 60,
|
policyMinutes % 60,
|
||||||
policyAction == PolicyService.TIMEOUT_POLICY_ACTION_LOCK ? AppResources.Lock : AppResources.LogOut);
|
policyAction == Policy.ACTION_LOCK ? AppResources.Lock : AppResources.LogOut);
|
||||||
}
|
}
|
||||||
securityItems.Insert(0, new SettingsPageListItem
|
securityItems.Insert(0, new SettingsPageListItem
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ namespace Bit.Core.Abstractions
|
|||||||
Task<string> GeneratePasswordAsync(PasswordGenerationOptions options);
|
Task<string> GeneratePasswordAsync(PasswordGenerationOptions options);
|
||||||
Task<List<GeneratedPasswordHistory>> GetHistoryAsync();
|
Task<List<GeneratedPasswordHistory>> GetHistoryAsync();
|
||||||
Task<(PasswordGenerationOptions, PasswordGeneratorPolicyOptions)> GetOptionsAsync();
|
Task<(PasswordGenerationOptions, PasswordGeneratorPolicyOptions)> GetOptionsAsync();
|
||||||
Task<(PasswordGenerationOptions, PasswordGeneratorPolicyOptions)>
|
|
||||||
EnforcePasswordGeneratorPoliciesOnOptionsAsync(PasswordGenerationOptions options);
|
|
||||||
Result PasswordStrength(string password, List<string> userInputs = null);
|
Result PasswordStrength(string password, List<string> userInputs = null);
|
||||||
Task SaveOptionsAsync(PasswordGenerationOptions options);
|
Task SaveOptionsAsync(PasswordGenerationOptions options);
|
||||||
void NormalizeOptions(PasswordGenerationOptions options, PasswordGeneratorPolicyOptions enforcedPolicyOptions);
|
void NormalizeOptions(PasswordGenerationOptions options, PasswordGeneratorPolicyOptions enforcedPolicyOptions);
|
||||||
|
|||||||
@@ -19,8 +19,7 @@ namespace Bit.Core.Abstractions
|
|||||||
Tuple<ResetPasswordPolicyOptions, bool> GetResetPasswordPolicyOptions(IEnumerable<Policy> policies,
|
Tuple<ResetPasswordPolicyOptions, bool> GetResetPasswordPolicyOptions(IEnumerable<Policy> policies,
|
||||||
string orgId);
|
string orgId);
|
||||||
Task<bool> PolicyAppliesToUser(PolicyType policyType, Func<Policy, bool> policyFilter = null, string userId = null);
|
Task<bool> PolicyAppliesToUser(PolicyType policyType, Func<Policy, bool> policyFilter = null, string userId = null);
|
||||||
int? GetPolicyInt(Policy policy, string key);
|
|
||||||
string GetPolicyString(Policy policy, string key);
|
|
||||||
Task<bool> ShouldShowVaultFilterAsync();
|
Task<bool> ShouldShowVaultFilterAsync();
|
||||||
|
Task<PasswordGeneratorPolicyOptions> GetPasswordGeneratorPolicyOptionsAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,29 +2,29 @@
|
|||||||
{
|
{
|
||||||
public class PasswordGenerationOptions
|
public class PasswordGenerationOptions
|
||||||
{
|
{
|
||||||
public PasswordGenerationOptions() { }
|
public const string TYPE_PASSWORD = "password";
|
||||||
|
public const string TYPE_PASSPHRASE = "passphrase";
|
||||||
|
|
||||||
public PasswordGenerationOptions(bool defaultOptions)
|
public static PasswordGenerationOptions CreateDefault => new PasswordGenerationOptions
|
||||||
{
|
{
|
||||||
if (defaultOptions)
|
Length = 14,
|
||||||
{
|
AllowAmbiguousChar = true,
|
||||||
Length = 14;
|
Number = true,
|
||||||
AllowAmbiguousChar = true;
|
MinNumber = 1,
|
||||||
Number = true;
|
Uppercase = true,
|
||||||
MinNumber = 1;
|
MinUppercase = 0,
|
||||||
Uppercase = true;
|
Lowercase = true,
|
||||||
MinUppercase = 0;
|
MinLowercase = 0,
|
||||||
Lowercase = true;
|
Special = false,
|
||||||
MinLowercase = 0;
|
MinSpecial = 1,
|
||||||
Special = false;
|
Type = TYPE_PASSWORD,
|
||||||
MinSpecial = 1;
|
NumWords = 3,
|
||||||
Type = "password";
|
WordSeparator = "-",
|
||||||
NumWords = 3;
|
Capitalize = false,
|
||||||
WordSeparator = "-";
|
IncludeNumber = false
|
||||||
Capitalize = false;
|
};
|
||||||
IncludeNumber = false;
|
|
||||||
}
|
public PasswordGenerationOptions() { }
|
||||||
}
|
|
||||||
|
|
||||||
public int? Length { get; set; }
|
public int? Length { get; set; }
|
||||||
public bool? AllowAmbiguousChar { get; set; }
|
public bool? AllowAmbiguousChar { get; set; }
|
||||||
@@ -42,6 +42,12 @@
|
|||||||
public bool? Capitalize { get; set; }
|
public bool? Capitalize { get; set; }
|
||||||
public bool? IncludeNumber { get; set; }
|
public bool? IncludeNumber { get; set; }
|
||||||
|
|
||||||
|
public PasswordGenerationOptions WithLength(int? length)
|
||||||
|
{
|
||||||
|
Length = length;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public void Merge(PasswordGenerationOptions defaults)
|
public void Merge(PasswordGenerationOptions defaults)
|
||||||
{
|
{
|
||||||
Length = Length ?? defaults.Length;
|
Length = Length ?? defaults.Length;
|
||||||
@@ -60,5 +66,75 @@
|
|||||||
Capitalize = Capitalize ?? defaults.Capitalize;
|
Capitalize = Capitalize ?? defaults.Capitalize;
|
||||||
IncludeNumber = IncludeNumber ?? defaults.IncludeNumber;
|
IncludeNumber = IncludeNumber ?? defaults.IncludeNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void EnforcePolicy(PasswordGeneratorPolicyOptions enforcedPolicyOptions)
|
||||||
|
{
|
||||||
|
if (enforcedPolicyOptions is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Length < enforcedPolicyOptions.MinLength)
|
||||||
|
{
|
||||||
|
Length = enforcedPolicyOptions.MinLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enforcedPolicyOptions.UseUppercase)
|
||||||
|
{
|
||||||
|
Uppercase = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enforcedPolicyOptions.UseLowercase)
|
||||||
|
{
|
||||||
|
Lowercase = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enforcedPolicyOptions.UseNumbers)
|
||||||
|
{
|
||||||
|
Number = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MinNumber < enforcedPolicyOptions.NumberCount)
|
||||||
|
{
|
||||||
|
MinNumber = enforcedPolicyOptions.NumberCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enforcedPolicyOptions.UseSpecial)
|
||||||
|
{
|
||||||
|
Special = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MinSpecial < enforcedPolicyOptions.SpecialCount)
|
||||||
|
{
|
||||||
|
MinSpecial = enforcedPolicyOptions.SpecialCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must normalize these fields because the receiving call expects all options to pass the current rules
|
||||||
|
if (MinSpecial + MinNumber > Length)
|
||||||
|
{
|
||||||
|
MinSpecial = Length - MinNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NumWords < enforcedPolicyOptions.MinNumberOfWords)
|
||||||
|
{
|
||||||
|
NumWords = enforcedPolicyOptions.MinNumberOfWords;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enforcedPolicyOptions.Capitalize)
|
||||||
|
{
|
||||||
|
Capitalize = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enforcedPolicyOptions.IncludeNumber)
|
||||||
|
{
|
||||||
|
IncludeNumber = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force default type if password/passphrase selected via policy
|
||||||
|
if (enforcedPolicyOptions.DefaultType == TYPE_PASSWORD || enforcedPolicyOptions.DefaultType == TYPE_PASSPHRASE)
|
||||||
|
{
|
||||||
|
Type = enforcedPolicyOptions.DefaultType;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,11 @@ namespace Bit.Core.Models.Domain
|
|||||||
{
|
{
|
||||||
public class Policy : Domain
|
public class Policy : Domain
|
||||||
{
|
{
|
||||||
|
public const string MINUTES_KEY = "minutes";
|
||||||
|
public const string ACTION_KEY = "action";
|
||||||
|
public const string ACTION_LOCK = "lock";
|
||||||
|
public const string ACTION_LOGOUT = "logOut";
|
||||||
|
|
||||||
public Policy() { }
|
public Policy() { }
|
||||||
|
|
||||||
public Policy(PolicyData obj)
|
public Policy(PolicyData obj)
|
||||||
@@ -22,5 +27,32 @@ namespace Bit.Core.Models.Domain
|
|||||||
public PolicyType Type { get; set; }
|
public PolicyType Type { get; set; }
|
||||||
public Dictionary<string, object> Data { get; set; }
|
public Dictionary<string, object> Data { get; set; }
|
||||||
public bool Enabled { get; set; }
|
public bool Enabled { get; set; }
|
||||||
|
|
||||||
|
public int? GetInt(string key)
|
||||||
|
{
|
||||||
|
if (Data.TryGetValue(key, out var val) && val != null)
|
||||||
|
{
|
||||||
|
return (int)(long)val;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool? GetBool(string key)
|
||||||
|
{
|
||||||
|
if (Data.TryGetValue(key, out var val) && val != null)
|
||||||
|
{
|
||||||
|
return (bool)val;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetString(string key)
|
||||||
|
{
|
||||||
|
if (Data.TryGetValue(key, out var val))
|
||||||
|
{
|
||||||
|
return (string)val;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -605,7 +605,7 @@ namespace Bit.Core.Services
|
|||||||
var generatedFingerprintPhrase = await _cryptoService.GetFingerprintAsync(email, keyPair.Item1);
|
var generatedFingerprintPhrase = await _cryptoService.GetFingerprintAsync(email, keyPair.Item1);
|
||||||
var fingerprintPhrase = string.Join("-", generatedFingerprintPhrase);
|
var fingerprintPhrase = string.Join("-", generatedFingerprintPhrase);
|
||||||
var publicB64 = Convert.ToBase64String(keyPair.Item1);
|
var publicB64 = Convert.ToBase64String(keyPair.Item1);
|
||||||
var accessCode = await _passwordGenerationService.GeneratePasswordAsync(new PasswordGenerationOptions(true) { Length = 25 });
|
var accessCode = await _passwordGenerationService.GeneratePasswordAsync(PasswordGenerationOptions.CreateDefault.WithLength(25));
|
||||||
var passwordlessCreateLoginRequest = new PasswordlessCreateLoginRequest(email, publicB64, deviceId, accessCode, AuthRequestType.AuthenticateAndUnlock, fingerprintPhrase);
|
var passwordlessCreateLoginRequest = new PasswordlessCreateLoginRequest(email, publicB64, deviceId, accessCode, AuthRequestType.AuthenticateAndUnlock, fingerprintPhrase);
|
||||||
var response = await _apiService.PostCreateRequestAsync(passwordlessCreateLoginRequest);
|
var response = await _apiService.PostCreateRequestAsync(passwordlessCreateLoginRequest);
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ using System.Text.RegularExpressions;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Enums;
|
|
||||||
using Bit.Core.Models.Domain;
|
using Bit.Core.Models.Domain;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Zxcvbn;
|
using Zxcvbn;
|
||||||
@@ -15,17 +14,17 @@ namespace Bit.Core.Services
|
|||||||
{
|
{
|
||||||
public class PasswordGenerationService : IPasswordGenerationService
|
public class PasswordGenerationService : IPasswordGenerationService
|
||||||
{
|
{
|
||||||
private const int MaxPasswordsInHistory = 100;
|
private const int MAX_PASSWORDS_IN_HISTORY = 100;
|
||||||
private const string LowercaseCharSet = "abcdefghijkmnopqrstuvwxyz";
|
private const string LOWERCASE_CHAR_SET = "abcdefghijkmnopqrstuvwxyz";
|
||||||
private const string UppercaseCharSet = "ABCDEFGHJKLMNPQRSTUVWXYZ";
|
private const string UPPERCASE_CHAR_SET = "ABCDEFGHJKLMNPQRSTUVWXYZ";
|
||||||
private const string NumberCharSet = "23456789";
|
private const string NUMER_CHAR_SET = "23456789";
|
||||||
private const string SpecialCharSet = "!@#$%^&*";
|
private const string SPECIAL_CHAR_SET = "!@#$%^&*";
|
||||||
|
|
||||||
private readonly ICryptoService _cryptoService;
|
private readonly ICryptoService _cryptoService;
|
||||||
private readonly IStateService _stateService;
|
private readonly IStateService _stateService;
|
||||||
private readonly ICryptoFunctionService _cryptoFunctionService;
|
private readonly ICryptoFunctionService _cryptoFunctionService;
|
||||||
private readonly IPolicyService _policyService;
|
private readonly IPolicyService _policyService;
|
||||||
private PasswordGenerationOptions _defaultOptions = new PasswordGenerationOptions(true);
|
private PasswordGenerationOptions _defaultOptions = PasswordGenerationOptions.CreateDefault;
|
||||||
private PasswordGenerationOptions _optionsCache;
|
private PasswordGenerationOptions _optionsCache;
|
||||||
private List<GeneratedPasswordHistory> _history;
|
private List<GeneratedPasswordHistory> _history;
|
||||||
|
|
||||||
@@ -45,7 +44,7 @@ namespace Bit.Core.Services
|
|||||||
{
|
{
|
||||||
// Overload defaults with given options
|
// Overload defaults with given options
|
||||||
options.Merge(_defaultOptions);
|
options.Merge(_defaultOptions);
|
||||||
if (options.Type == "passphrase")
|
if (options.Type == PasswordGenerationOptions.TYPE_PASSPHRASE)
|
||||||
{
|
{
|
||||||
return await GeneratePassphraseAsync(options);
|
return await GeneratePassphraseAsync(options);
|
||||||
}
|
}
|
||||||
@@ -54,30 +53,30 @@ namespace Bit.Core.Services
|
|||||||
SanitizePasswordLength(options, true);
|
SanitizePasswordLength(options, true);
|
||||||
|
|
||||||
var positionsBuilder = new StringBuilder();
|
var positionsBuilder = new StringBuilder();
|
||||||
if (options.Lowercase.GetValueOrDefault() && options.MinLowercase.GetValueOrDefault() > 0)
|
if (options.Lowercase.GetValueOrDefault() && options.MinLowercase > 0)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < options.MinLowercase.GetValueOrDefault(); i++)
|
for (int i = 0; i < options.MinLowercase; i++)
|
||||||
{
|
{
|
||||||
positionsBuilder.Append("l");
|
positionsBuilder.Append("l");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (options.Uppercase.GetValueOrDefault() && options.MinUppercase.GetValueOrDefault() > 0)
|
if (options.Uppercase.GetValueOrDefault() && options.MinUppercase > 0)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < options.MinUppercase.GetValueOrDefault(); i++)
|
for (int i = 0; i < options.MinUppercase; i++)
|
||||||
{
|
{
|
||||||
positionsBuilder.Append("u");
|
positionsBuilder.Append("u");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (options.Number.GetValueOrDefault() && options.MinNumber.GetValueOrDefault() > 0)
|
if (options.Number.GetValueOrDefault() && options.MinNumber > 0)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < options.MinNumber.GetValueOrDefault(); i++)
|
for (int i = 0; i < options.MinNumber; i++)
|
||||||
{
|
{
|
||||||
positionsBuilder.Append("n");
|
positionsBuilder.Append("n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (options.Special.GetValueOrDefault() && options.MinSpecial.GetValueOrDefault() > 0)
|
if (options.Special.GetValueOrDefault() && options.MinSpecial > 0)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < options.MinSpecial.GetValueOrDefault(); i++)
|
for (int i = 0; i < options.MinSpecial; i++)
|
||||||
{
|
{
|
||||||
positionsBuilder.Append("s");
|
positionsBuilder.Append("s");
|
||||||
}
|
}
|
||||||
@@ -92,68 +91,68 @@ namespace Bit.Core.Services
|
|||||||
.OrderBy(a => _cryptoFunctionService.RandomNumber()).ToArray();
|
.OrderBy(a => _cryptoFunctionService.RandomNumber()).ToArray();
|
||||||
|
|
||||||
// Build out other character sets
|
// Build out other character sets
|
||||||
var allCharSet = string.Empty;
|
var allCharSet = new StringBuilder();
|
||||||
var lowercaseCharSet = LowercaseCharSet;
|
|
||||||
|
var lowercaseCharSet = LOWERCASE_CHAR_SET;
|
||||||
if (options.AllowAmbiguousChar.GetValueOrDefault())
|
if (options.AllowAmbiguousChar.GetValueOrDefault())
|
||||||
{
|
{
|
||||||
lowercaseCharSet = string.Concat(lowercaseCharSet, "l");
|
lowercaseCharSet = string.Concat(lowercaseCharSet, "l");
|
||||||
}
|
}
|
||||||
if (options.Lowercase.GetValueOrDefault())
|
if (options.Lowercase.GetValueOrDefault())
|
||||||
{
|
{
|
||||||
allCharSet = string.Concat(allCharSet, lowercaseCharSet);
|
allCharSet.Append(lowercaseCharSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
var uppercaseCharSet = UppercaseCharSet;
|
var uppercaseCharSet = UPPERCASE_CHAR_SET;
|
||||||
if (options.AllowAmbiguousChar.GetValueOrDefault())
|
if (options.AllowAmbiguousChar.GetValueOrDefault())
|
||||||
{
|
{
|
||||||
uppercaseCharSet = string.Concat(uppercaseCharSet, "IO");
|
uppercaseCharSet = string.Concat(uppercaseCharSet, "IO");
|
||||||
}
|
}
|
||||||
if (options.Uppercase.GetValueOrDefault())
|
if (options.Uppercase.GetValueOrDefault())
|
||||||
{
|
{
|
||||||
allCharSet = string.Concat(allCharSet, uppercaseCharSet);
|
allCharSet.Append(uppercaseCharSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
var numberCharSet = NumberCharSet;
|
var numberCharSet = NUMER_CHAR_SET;
|
||||||
if (options.AllowAmbiguousChar.GetValueOrDefault())
|
if (options.AllowAmbiguousChar.GetValueOrDefault())
|
||||||
{
|
{
|
||||||
numberCharSet = string.Concat(numberCharSet, "01");
|
numberCharSet = string.Concat(numberCharSet, "01");
|
||||||
}
|
}
|
||||||
if (options.Number.GetValueOrDefault())
|
if (options.Number.GetValueOrDefault())
|
||||||
{
|
{
|
||||||
allCharSet = string.Concat(allCharSet, numberCharSet);
|
allCharSet.Append(numberCharSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
var specialCharSet = SpecialCharSet;
|
|
||||||
if (options.Special.GetValueOrDefault())
|
if (options.Special.GetValueOrDefault())
|
||||||
{
|
{
|
||||||
allCharSet = string.Concat(allCharSet, specialCharSet);
|
allCharSet.Append(SPECIAL_CHAR_SET);
|
||||||
}
|
}
|
||||||
|
|
||||||
var password = new StringBuilder();
|
var password = new StringBuilder();
|
||||||
for (var i = 0; i < options.Length.GetValueOrDefault(); i++)
|
for (var i = 0; i < options.Length.GetValueOrDefault(); i++)
|
||||||
{
|
{
|
||||||
var positionChars = string.Empty;
|
var charSetOnCurrentPosition = string.Empty;
|
||||||
switch (positions[i])
|
switch (positions[i])
|
||||||
{
|
{
|
||||||
case 'l':
|
case 'l':
|
||||||
positionChars = lowercaseCharSet;
|
charSetOnCurrentPosition = lowercaseCharSet;
|
||||||
break;
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
positionChars = uppercaseCharSet;
|
charSetOnCurrentPosition = uppercaseCharSet;
|
||||||
break;
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
positionChars = numberCharSet;
|
charSetOnCurrentPosition = numberCharSet;
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
positionChars = specialCharSet;
|
charSetOnCurrentPosition = SPECIAL_CHAR_SET;
|
||||||
break;
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
positionChars = allCharSet;
|
charSetOnCurrentPosition = allCharSet.ToString();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
var randomCharIndex = await _cryptoService.RandomNumberAsync(0, positionChars.Length - 1);
|
var randomCharIndex = await _cryptoService.RandomNumberAsync(0, charSetOnCurrentPosition.Length - 1);
|
||||||
password.Append(positionChars[randomCharIndex]);
|
password.Append(charSetOnCurrentPosition[randomCharIndex]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return password.ToString();
|
return password.ToString();
|
||||||
@@ -168,7 +167,7 @@ namespace Bit.Core.Services
|
|||||||
public async Task<string> GeneratePassphraseAsync(PasswordGenerationOptions options)
|
public async Task<string> GeneratePassphraseAsync(PasswordGenerationOptions options)
|
||||||
{
|
{
|
||||||
options.Merge(_defaultOptions);
|
options.Merge(_defaultOptions);
|
||||||
if (options.NumWords.GetValueOrDefault() <= 2)
|
if (options.NumWords <= 2)
|
||||||
{
|
{
|
||||||
options.NumWords = _defaultOptions.NumWords;
|
options.NumWords = _defaultOptions.NumWords;
|
||||||
}
|
}
|
||||||
@@ -221,179 +220,10 @@ namespace Bit.Core.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var (enforcedOptions, enforcedPolicyOptions) = await EnforcePasswordGeneratorPoliciesOnOptionsAsync(
|
var policyOptions = await _policyService.GetPasswordGeneratorPolicyOptionsAsync();
|
||||||
_optionsCache);
|
_optionsCache.EnforcePolicy(policyOptions);
|
||||||
_optionsCache = enforcedOptions;
|
|
||||||
return (_optionsCache, enforcedPolicyOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<(PasswordGenerationOptions, PasswordGeneratorPolicyOptions)>
|
return (_optionsCache, policyOptions ?? new PasswordGeneratorPolicyOptions());
|
||||||
EnforcePasswordGeneratorPoliciesOnOptionsAsync(PasswordGenerationOptions options)
|
|
||||||
{
|
|
||||||
var enforcedPolicyOptions = await GetPasswordGeneratorPolicyOptions();
|
|
||||||
if (enforcedPolicyOptions != null)
|
|
||||||
{
|
|
||||||
if (options.Length < enforcedPolicyOptions.MinLength)
|
|
||||||
{
|
|
||||||
options.Length = enforcedPolicyOptions.MinLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enforcedPolicyOptions.UseUppercase)
|
|
||||||
{
|
|
||||||
options.Uppercase = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enforcedPolicyOptions.UseLowercase)
|
|
||||||
{
|
|
||||||
options.Lowercase = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enforcedPolicyOptions.UseNumbers)
|
|
||||||
{
|
|
||||||
options.Number = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.MinNumber < enforcedPolicyOptions.NumberCount)
|
|
||||||
{
|
|
||||||
options.MinNumber = enforcedPolicyOptions.NumberCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enforcedPolicyOptions.UseSpecial)
|
|
||||||
{
|
|
||||||
options.Special = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.MinSpecial < enforcedPolicyOptions.SpecialCount)
|
|
||||||
{
|
|
||||||
options.MinSpecial = enforcedPolicyOptions.SpecialCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Must normalize these fields because the receiving call expects all options to pass the current rules
|
|
||||||
if (options.MinSpecial + options.MinNumber > options.Length)
|
|
||||||
{
|
|
||||||
options.MinSpecial = options.Length - options.MinNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.NumWords < enforcedPolicyOptions.MinNumberOfWords)
|
|
||||||
{
|
|
||||||
options.NumWords = enforcedPolicyOptions.MinNumberOfWords;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enforcedPolicyOptions.Capitalize)
|
|
||||||
{
|
|
||||||
options.Capitalize = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enforcedPolicyOptions.IncludeNumber)
|
|
||||||
{
|
|
||||||
options.IncludeNumber = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Force default type if password/passphrase selected via policy
|
|
||||||
if (enforcedPolicyOptions.DefaultType == "password" || enforcedPolicyOptions.DefaultType == "passphrase")
|
|
||||||
{
|
|
||||||
options.Type = enforcedPolicyOptions.DefaultType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// UI layer expects an instantiated object to prevent more explicit null checks
|
|
||||||
enforcedPolicyOptions = new PasswordGeneratorPolicyOptions();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (options, enforcedPolicyOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<PasswordGeneratorPolicyOptions> GetPasswordGeneratorPolicyOptions()
|
|
||||||
{
|
|
||||||
var policies = await _policyService.GetAll(PolicyType.PasswordGenerator);
|
|
||||||
PasswordGeneratorPolicyOptions enforcedOptions = null;
|
|
||||||
|
|
||||||
if (policies == null || !policies.Any())
|
|
||||||
{
|
|
||||||
return enforcedOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var currentPolicy in policies)
|
|
||||||
{
|
|
||||||
if (!currentPolicy.Enabled || currentPolicy.Data == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enforcedOptions == null)
|
|
||||||
{
|
|
||||||
enforcedOptions = new PasswordGeneratorPolicyOptions();
|
|
||||||
}
|
|
||||||
|
|
||||||
var defaultType = GetPolicyString(currentPolicy, "defaultType");
|
|
||||||
if (defaultType != null && enforcedOptions.DefaultType != "password")
|
|
||||||
{
|
|
||||||
enforcedOptions.DefaultType = defaultType;
|
|
||||||
}
|
|
||||||
|
|
||||||
var minLength = GetPolicyInt(currentPolicy, "minLength");
|
|
||||||
if (minLength != null && (int)(long)minLength > enforcedOptions.MinLength)
|
|
||||||
{
|
|
||||||
enforcedOptions.MinLength = (int)(long)minLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
var useUpper = GetPolicyBool(currentPolicy, "useUpper");
|
|
||||||
if (useUpper != null && (bool)useUpper)
|
|
||||||
{
|
|
||||||
enforcedOptions.UseUppercase = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var useLower = GetPolicyBool(currentPolicy, "useLower");
|
|
||||||
if (useLower != null && (bool)useLower)
|
|
||||||
{
|
|
||||||
enforcedOptions.UseLowercase = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var useNumbers = GetPolicyBool(currentPolicy, "useNumbers");
|
|
||||||
if (useNumbers != null && (bool)useNumbers)
|
|
||||||
{
|
|
||||||
enforcedOptions.UseNumbers = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var minNumbers = GetPolicyInt(currentPolicy, "minNumbers");
|
|
||||||
if (minNumbers != null && (int)(long)minNumbers > enforcedOptions.NumberCount)
|
|
||||||
{
|
|
||||||
enforcedOptions.NumberCount = (int)(long)minNumbers;
|
|
||||||
}
|
|
||||||
|
|
||||||
var useSpecial = GetPolicyBool(currentPolicy, "useSpecial");
|
|
||||||
if (useSpecial != null && (bool)useSpecial)
|
|
||||||
{
|
|
||||||
enforcedOptions.UseSpecial = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var minSpecial = GetPolicyInt(currentPolicy, "minSpecial");
|
|
||||||
if (minSpecial != null && (int)(long)minSpecial > enforcedOptions.SpecialCount)
|
|
||||||
{
|
|
||||||
enforcedOptions.SpecialCount = (int)(long)minSpecial;
|
|
||||||
}
|
|
||||||
|
|
||||||
var minNumberWords = GetPolicyInt(currentPolicy, "minNumberWords");
|
|
||||||
if (minNumberWords != null && (int)(long)minNumberWords > enforcedOptions.MinNumberOfWords)
|
|
||||||
{
|
|
||||||
enforcedOptions.MinNumberOfWords = (int)(long)minNumberWords;
|
|
||||||
}
|
|
||||||
|
|
||||||
var capitalize = GetPolicyBool(currentPolicy, "capitalize");
|
|
||||||
if (capitalize != null && (bool)capitalize)
|
|
||||||
{
|
|
||||||
enforcedOptions.Capitalize = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var includeNumber = GetPolicyBool(currentPolicy, "includeNumber");
|
|
||||||
if (includeNumber != null && (bool)includeNumber)
|
|
||||||
{
|
|
||||||
enforcedOptions.IncludeNumber = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return enforcedOptions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<string> GetPasswordStrengthUserInput(string email)
|
public List<string> GetPasswordStrengthUserInput(string email)
|
||||||
@@ -409,45 +239,6 @@ namespace Bit.Core.Services
|
|||||||
return new List<string>(data);
|
return new List<string>(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int? GetPolicyInt(Policy policy, string key)
|
|
||||||
{
|
|
||||||
if (policy.Data.ContainsKey(key))
|
|
||||||
{
|
|
||||||
var value = policy.Data[key];
|
|
||||||
if (value != null)
|
|
||||||
{
|
|
||||||
return (int)(long)value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool? GetPolicyBool(Policy policy, string key)
|
|
||||||
{
|
|
||||||
if (policy.Data.ContainsKey(key))
|
|
||||||
{
|
|
||||||
var value = policy.Data[key];
|
|
||||||
if (value != null)
|
|
||||||
{
|
|
||||||
return (bool)value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetPolicyString(Policy policy, string key)
|
|
||||||
{
|
|
||||||
if (policy.Data.ContainsKey(key))
|
|
||||||
{
|
|
||||||
var value = policy.Data[key];
|
|
||||||
if (value != null)
|
|
||||||
{
|
|
||||||
return (string)value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task SaveOptionsAsync(PasswordGenerationOptions options)
|
public async Task SaveOptionsAsync(PasswordGenerationOptions options)
|
||||||
{
|
{
|
||||||
await _stateService.SetPasswordGenerationOptionsAsync(options);
|
await _stateService.SetPasswordGenerationOptionsAsync(options);
|
||||||
@@ -485,7 +276,7 @@ namespace Bit.Core.Services
|
|||||||
token.ThrowIfCancellationRequested();
|
token.ThrowIfCancellationRequested();
|
||||||
currentHistory.Insert(0, new GeneratedPasswordHistory { Password = password, Date = DateTime.UtcNow });
|
currentHistory.Insert(0, new GeneratedPasswordHistory { Password = password, Date = DateTime.UtcNow });
|
||||||
// Remove old items.
|
// Remove old items.
|
||||||
if (currentHistory.Count > MaxPasswordsInHistory)
|
if (currentHistory.Count > MAX_PASSWORDS_IN_HISTORY)
|
||||||
{
|
{
|
||||||
currentHistory.RemoveAt(currentHistory.Count - 1);
|
currentHistory.RemoveAt(currentHistory.Count - 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,11 +17,6 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
private IEnumerable<Policy> _policyCache;
|
private IEnumerable<Policy> _policyCache;
|
||||||
|
|
||||||
public const string TIMEOUT_POLICY_MINUTES = "minutes";
|
|
||||||
public const string TIMEOUT_POLICY_ACTION = "action";
|
|
||||||
public const string TIMEOUT_POLICY_ACTION_LOCK = "lock";
|
|
||||||
public const string TIMEOUT_POLICY_ACTION_LOGOUT = "logOut";
|
|
||||||
|
|
||||||
public PolicyService(
|
public PolicyService(
|
||||||
IStateService stateService,
|
IStateService stateService,
|
||||||
IOrganizationService organizationService)
|
IOrganizationService organizationService)
|
||||||
@@ -51,10 +46,8 @@ namespace Bit.Core.Services
|
|||||||
{
|
{
|
||||||
return _policyCache.Where(p => p.Type == type).ToList();
|
return _policyCache.Where(p => p.Type == type).ToList();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
return _policyCache;
|
||||||
return _policyCache;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Replace(Dictionary<string, PolicyData> policies, string userId = null)
|
public async Task Replace(Dictionary<string, PolicyData> policies, string userId = null)
|
||||||
@@ -77,7 +70,7 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
public async Task UpdateVaultTimeoutFromPolicyAsync(Policy policy, string userId = null)
|
public async Task UpdateVaultTimeoutFromPolicyAsync(Policy policy, string userId = null)
|
||||||
{
|
{
|
||||||
var policyTimeout = GetPolicyInt(policy, PolicyService.TIMEOUT_POLICY_MINUTES);
|
var policyTimeout = policy.GetInt(Policy.MINUTES_KEY);
|
||||||
if (policyTimeout != null)
|
if (policyTimeout != null)
|
||||||
{
|
{
|
||||||
var vaultTimeout = await _stateService.GetVaultTimeoutAsync(userId);
|
var vaultTimeout = await _stateService.GetVaultTimeoutAsync(userId);
|
||||||
@@ -92,11 +85,11 @@ namespace Bit.Core.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var policyAction = GetPolicyString(policy, PolicyService.TIMEOUT_POLICY_ACTION);
|
var policyAction = policy.GetString(Policy.ACTION_KEY);
|
||||||
if (!string.IsNullOrEmpty(policyAction))
|
if (!string.IsNullOrEmpty(policyAction))
|
||||||
{
|
{
|
||||||
var vaultTimeoutAction = await _stateService.GetVaultTimeoutActionAsync(userId);
|
var vaultTimeoutAction = await _stateService.GetVaultTimeoutActionAsync(userId);
|
||||||
var action = policyAction == PolicyService.TIMEOUT_POLICY_ACTION_LOCK ? VaultTimeoutAction.Lock : VaultTimeoutAction.Logout;
|
var action = policyAction == Policy.ACTION_LOCK ? VaultTimeoutAction.Lock : VaultTimeoutAction.Logout;
|
||||||
if (vaultTimeoutAction != action)
|
if (vaultTimeoutAction != action)
|
||||||
{
|
{
|
||||||
await _stateService.SetVaultTimeoutActionAsync(action, userId);
|
await _stateService.SetVaultTimeoutActionAsync(action, userId);
|
||||||
@@ -107,71 +100,63 @@ namespace Bit.Core.Services
|
|||||||
public async Task<MasterPasswordPolicyOptions> GetMasterPasswordPolicyOptions(
|
public async Task<MasterPasswordPolicyOptions> GetMasterPasswordPolicyOptions(
|
||||||
IEnumerable<Policy> policies = null, string userId = null)
|
IEnumerable<Policy> policies = null, string userId = null)
|
||||||
{
|
{
|
||||||
MasterPasswordPolicyOptions enforcedOptions = null;
|
|
||||||
|
|
||||||
if (policies == null)
|
if (policies == null)
|
||||||
{
|
{
|
||||||
policies = await GetAll(PolicyType.MasterPassword, userId);
|
policies = await GetAll(PolicyType.MasterPassword, userId);
|
||||||
|
if (policies == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
policies = policies.Where(p => p.Type == PolicyType.MasterPassword);
|
policies = policies.Where(p => p.Type == PolicyType.MasterPassword);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (policies == null || !policies.Any())
|
policies = policies.Where(p => p.Enabled && p.Data != null);
|
||||||
|
|
||||||
|
if (!policies.Any())
|
||||||
{
|
{
|
||||||
return enforcedOptions;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var enforcedOptions = new MasterPasswordPolicyOptions();
|
||||||
|
|
||||||
foreach (var currentPolicy in policies)
|
foreach (var currentPolicy in policies)
|
||||||
{
|
{
|
||||||
if (!currentPolicy.Enabled || currentPolicy.Data == null)
|
var minComplexity = currentPolicy.GetInt("minComplexity");
|
||||||
|
if (minComplexity > enforcedOptions.MinComplexity)
|
||||||
{
|
{
|
||||||
continue;
|
enforcedOptions.MinComplexity = minComplexity.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enforcedOptions == null)
|
var minLength = currentPolicy.GetInt("minLength");
|
||||||
|
if (minLength > enforcedOptions.MinLength)
|
||||||
{
|
{
|
||||||
enforcedOptions = new MasterPasswordPolicyOptions();
|
enforcedOptions.MinLength = minLength.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
var minComplexity = GetPolicyInt(currentPolicy, "minComplexity");
|
if (currentPolicy.GetBool("requireUpper") == true)
|
||||||
if (minComplexity != null && (int)(long)minComplexity > enforcedOptions.MinComplexity)
|
|
||||||
{
|
|
||||||
enforcedOptions.MinComplexity = (int)(long)minComplexity;
|
|
||||||
}
|
|
||||||
|
|
||||||
var minLength = GetPolicyInt(currentPolicy, "minLength");
|
|
||||||
if (minLength != null && (int)(long)minLength > enforcedOptions.MinLength)
|
|
||||||
{
|
|
||||||
enforcedOptions.MinLength = (int)(long)minLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
var requireUpper = GetPolicyBool(currentPolicy, "requireUpper");
|
|
||||||
if (requireUpper == true)
|
|
||||||
{
|
{
|
||||||
enforcedOptions.RequireUpper = true;
|
enforcedOptions.RequireUpper = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var requireLower = GetPolicyBool(currentPolicy, "requireLower");
|
if (currentPolicy.GetBool("requireLower") == true)
|
||||||
if (requireLower == true)
|
|
||||||
{
|
{
|
||||||
enforcedOptions.RequireLower = true;
|
enforcedOptions.RequireLower = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var requireNumbers = GetPolicyBool(currentPolicy, "requireNumbers");
|
if (currentPolicy.GetBool("requireNumbers") == true)
|
||||||
if (requireNumbers == true)
|
|
||||||
{
|
{
|
||||||
enforcedOptions.RequireNumbers = true;
|
enforcedOptions.RequireNumbers = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var requireSpecial = GetPolicyBool(currentPolicy, "requireSpecial");
|
if (currentPolicy.GetBool("requireSpecial") == true)
|
||||||
if (requireSpecial == true)
|
|
||||||
{
|
{
|
||||||
enforcedOptions.RequireSpecial = true;
|
enforcedOptions.RequireSpecial = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var enforceOnLogin = GetPolicyBool(currentPolicy, "enforceOnLogin");
|
var enforceOnLogin = currentPolicy.GetBool("enforceOnLogin");
|
||||||
if (enforceOnLogin == true)
|
if (enforceOnLogin == true)
|
||||||
{
|
{
|
||||||
enforcedOptions.EnforceOnLogin = true;
|
enforcedOptions.EnforceOnLogin = true;
|
||||||
@@ -234,7 +219,7 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
var policy = policies.FirstOrDefault(p =>
|
var policy = policies.FirstOrDefault(p =>
|
||||||
p.OrganizationId == orgId && p.Type == PolicyType.ResetPassword && p.Enabled);
|
p.OrganizationId == orgId && p.Type == PolicyType.ResetPassword && p.Enabled);
|
||||||
resetPasswordPolicyOptions.AutoEnrollEnabled = GetPolicyBool(policy, "autoEnrollEnabled") ?? false;
|
resetPasswordPolicyOptions.AutoEnrollEnabled = policy.GetBool("autoEnrollEnabled") ?? false;
|
||||||
|
|
||||||
return new Tuple<ResetPasswordPolicyOptions, bool>(resetPasswordPolicyOptions, policy != null);
|
return new Tuple<ResetPasswordPolicyOptions, bool>(resetPasswordPolicyOptions, policy != null);
|
||||||
}
|
}
|
||||||
@@ -280,23 +265,6 @@ namespace Bit.Core.Services
|
|||||||
return organization.isExemptFromPolicies;
|
return organization.isExemptFromPolicies;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int? GetPolicyInt(Policy policy, string key)
|
|
||||||
{
|
|
||||||
if (policy.Data.ContainsKey(key))
|
|
||||||
{
|
|
||||||
var value = policy.Data[key];
|
|
||||||
if (value != null)
|
|
||||||
{
|
|
||||||
return (int)(long)value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetPolicyString(Policy policy, string key) =>
|
|
||||||
policy.Data.TryGetValue(key, out var val) ? val as string : null;
|
|
||||||
|
|
||||||
|
|
||||||
public async Task<bool> ShouldShowVaultFilterAsync()
|
public async Task<bool> ShouldShowVaultFilterAsync()
|
||||||
{
|
{
|
||||||
var personalOwnershipPolicyApplies = await PolicyAppliesToUser(PolicyType.PersonalOwnership);
|
var personalOwnershipPolicyApplies = await PolicyAppliesToUser(PolicyType.PersonalOwnership);
|
||||||
@@ -309,19 +277,86 @@ namespace Bit.Core.Services
|
|||||||
return organizations?.Any() ?? false;
|
return organizations?.Any() ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool? GetPolicyBool(Policy policy, string key)
|
public async Task<PasswordGeneratorPolicyOptions> GetPasswordGeneratorPolicyOptionsAsync()
|
||||||
{
|
{
|
||||||
if (policy.Data.ContainsKey(key))
|
var policies = await GetAll(PolicyType.PasswordGenerator);
|
||||||
|
if (policies == null)
|
||||||
{
|
{
|
||||||
var value = policy.Data[key];
|
return null;
|
||||||
if (value != null)
|
}
|
||||||
|
|
||||||
|
var actualPolicies = policies.Where(p => p.Enabled && p.Data != null);
|
||||||
|
if (!actualPolicies.Any())
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var enforcedOptions = new PasswordGeneratorPolicyOptions();
|
||||||
|
|
||||||
|
foreach (var currentPolicy in actualPolicies)
|
||||||
|
{
|
||||||
|
var defaultType = currentPolicy.GetString("defaultType");
|
||||||
|
if (defaultType != null && enforcedOptions.DefaultType != PasswordGenerationOptions.TYPE_PASSWORD)
|
||||||
{
|
{
|
||||||
return (bool)value;
|
enforcedOptions.DefaultType = defaultType;
|
||||||
|
}
|
||||||
|
|
||||||
|
var minLength = currentPolicy.GetInt("minLength");
|
||||||
|
if (minLength > enforcedOptions.MinLength)
|
||||||
|
{
|
||||||
|
enforcedOptions.MinLength = minLength.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentPolicy.GetBool("useUpper") == true)
|
||||||
|
{
|
||||||
|
enforcedOptions.UseUppercase = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentPolicy.GetBool("useLower") == true)
|
||||||
|
{
|
||||||
|
enforcedOptions.UseLowercase = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentPolicy.GetBool("useNumbers") == true)
|
||||||
|
{
|
||||||
|
enforcedOptions.UseNumbers = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var minNumbers = currentPolicy.GetInt("minNumbers");
|
||||||
|
if (minNumbers > enforcedOptions.NumberCount)
|
||||||
|
{
|
||||||
|
enforcedOptions.NumberCount = minNumbers.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentPolicy.GetBool("useSpecial") == true)
|
||||||
|
{
|
||||||
|
enforcedOptions.UseSpecial = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var minSpecial = currentPolicy.GetInt("minSpecial");
|
||||||
|
if (minSpecial > enforcedOptions.SpecialCount)
|
||||||
|
{
|
||||||
|
enforcedOptions.SpecialCount = minSpecial.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
var minNumberWords = currentPolicy.GetInt("minNumberWords");
|
||||||
|
if (minNumberWords > enforcedOptions.MinNumberOfWords)
|
||||||
|
{
|
||||||
|
enforcedOptions.MinNumberOfWords = minNumberWords.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentPolicy.GetBool("capitalize") == true)
|
||||||
|
{
|
||||||
|
enforcedOptions.Capitalize = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentPolicy.GetBool("includeNumber") == true)
|
||||||
|
{
|
||||||
|
enforcedOptions.IncludeNumber = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
|
return enforcedOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
|
using Bit.Core.Models.Domain;
|
||||||
|
|
||||||
namespace Bit.Core.Services
|
namespace Bit.Core.Services
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -75,8 +75,7 @@ namespace Bit.Core.Utilities
|
|||||||
messagingService.Send("logout", extras);
|
messagingService.Send("logout", extras);
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
});
|
});
|
||||||
var passwordGenerationService = new PasswordGenerationService(cryptoService, stateService,
|
var passwordGenerationService = new PasswordGenerationService(cryptoService, stateService, cryptoFunctionService, policyService);
|
||||||
cryptoFunctionService, policyService);
|
|
||||||
var totpService = new TotpService(cryptoFunctionService);
|
var totpService = new TotpService(cryptoFunctionService);
|
||||||
var authService = new AuthService(cryptoService, cryptoFunctionService, apiService, stateService,
|
var authService = new AuthService(cryptoService, cryptoFunctionService, apiService, stateService,
|
||||||
tokenService, appIdService, i18nService, platformUtilsService, messagingService, vaultTimeoutService,
|
tokenService, appIdService, i18nService, platformUtilsService, messagingService, vaultTimeoutService,
|
||||||
|
|||||||
Reference in New Issue
Block a user