/// <summary> /// Calculates the strength of the given <paramref name="password"/> and /// fires the <c>ScoreUpdated</c> event if the calculation succeeded. /// The function protects against too frequent updates by cancelling /// calculations that are still running while a new calculation was already /// started. It is therefore safe to call this method in quick succession. /// </summary> /// <param name="password"></param> private void CalculateResult(string password) { // The provided password will sometimes be null when the dialog was // closed before our calc thread got a chance to do its thing, so // we need to handle this case here. if (password == null) { return; } // This will avoid updating the UI too often on quick password input for (int i = 0; i < 10; i++) { Thread.Sleep(5); if (_cts.IsCancellationRequested) { return; } } // Now we should be good to calculate PasswordStrengthResult result = new PasswordStrengthResult(); result.PasswordLength = password.Length; if (result.PasswordLength > PW_MIN_LENGTH) { result.StrengthPoints = result.PasswordLength; } else { result.StrengthPoints = (int)(result.PasswordLength / 2); } for (int i = 0; i < password.Length; i++) { char c = password[i]; // Uppercase if (c >= 65 && c <= 90) { if (!result.UppercaseUsed) { result.StrengthPoints += 2; result.UppercaseUsed = true; } } // Lowercase else if (c >= 97 && c <= 122) { if (!result.LowercaseUsed) { result.LowercaseUsed = true; } } // Digit else if (c >= 48 && c <= 57) { if (!result.DigitsUsed) { result.StrengthPoints += 2; result.DigitsUsed = true; } } // Symbol else { if (!result.SymbolsUsed) { result.StrengthPoints += 2; result.SymbolsUsed = true; } } if (result.AllCharClassesUsed) { break; // No need to look any further } if (_cts.IsCancellationRequested) { return; } } if (result.StrengthPoints < STRENGTH_POINTS_MIN_MEDIUM) { result.Rating = PasswordRating.POOR; } else if (result.StrengthPoints < STRENGTH_POINTS_MIN_GOOD) { result.Rating = PasswordRating.MEDIUM; } else { result.Rating = PasswordRating.GOOD; } // Last chance to detect cancellation if (_cts.IsCancellationRequested) { return; } // Fire score updated event ScoreUpdated?.Invoke(this, new ScoreUpdatedEventArgs(result)); }
public ScoreUpdatedEventArgs(PasswordStrengthResult passwordScore) { Score = passwordScore; }