/// <summary>
        /// Parses the return data from the HIBP API into a list of PasswordHashEntry object for simplification purposes.
        /// </summary>
        /// <param name="passwordsRange">One long string containing multiple newline-seperated entries. The entries are semicolom seperated hash:occurences object, e.g. 00D4F6E8FA6EECAD2A3AA415EEC418D38EC:2</param>
        /// <returns>A list of parsed PasswordHashEntry objects, based on HIBP API return data.</returns>
        private List <PasswordHashEntry> ParsePasswordsRangeFromApi(string passwordsRange)
        {
            List <PasswordHashEntry> entries = null;

            if (!string.IsNullOrEmpty(passwordsRange))
            {
                entries = new List <PasswordHashEntry>();
            }

            // Split entries on NewLine character (\r\n).
            // PasswordsRange contains for example: 00D4F6E8FA6EECAD2A3AA415EEC418D38EC:2\r\n011053FD0102E94D6AE2F8B83D76FAF94F6:1
            foreach (var hashAndOccurences in passwordsRange.Split(new[] { Environment.NewLine }, StringSplitOptions.None))
            {
                string[] items = hashAndOccurences.Split(':');

                PasswordHashEntry passwordHashEntry = new PasswordHashEntry()
                {
                    Hash       = items[0],
                    Occurences = int.Parse(items[1])
                };

                entries.Add(passwordHashEntry);
            }

            return(entries);
        }
        /// <summary>
        /// Gets the amount of occurences based on hashed password and store it in a PasswordHashEntry.
        /// </summary>
        /// <param name="hashedPassword">SHA-1 hashed password.</param>
        /// <returns>Filled PasswordHashEntry with total amount of occurences.</returns>
        public async Task <PasswordHashEntry> GetPasswordOccurences(string hashedPassword)
        {
            PasswordHashEntry passwordHashEntry = null;

            try
            {
                string uriString = $"{baseUrl}/pwnedpassword/{hashedPassword}";
                Uri    uri       = new Uri(uriString);
                string content   = await GetJsonFromUri(uri);

                if (int.TryParse(content, out int occurences))
                {
                    passwordHashEntry = new PasswordHashEntry()
                    {
                        Hash       = hashedPassword,
                        Occurences = occurences
                    };
                }
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine($"HttpUtils: GetPasswordOccurences: Cannot get password occurences. Message: {e}");
            }

            return(passwordHashEntry);
        }
        private async Task <bool> PasswordIsSafe(string password)
        {
            bool   passwordIsSafe        = false;
            string sha1HashedPassword    = HashingHelper.Hash(password);
            var    hashedPasswordEntries = await _httpUtils.GetPasswordsByRange(sha1HashedPassword);

            int similarOccurences        = 0;
            PasswordHashEntry foundEntry = hashedPasswordEntries.Find(entry => entry.Hash.Equals(sha1HashedPassword));

            foreach (var passwordHashEntry in hashedPasswordEntries)
            {
                similarOccurences += passwordHashEntry.Occurences;
            }

            _logger.LogInformation($"Found {similarOccurences} hashes.");

            // The password is safe if it does not occur in the found hashes.
            if (foundEntry == null)
            {
                _logger.LogInformation($"No exact Hash match found.");

                passwordIsSafe = true;
            }
            else
            {
                _logger.LogInformation($"Found: {foundEntry.Hash} with {foundEntry.Occurences} occurences");
            }

            return(passwordIsSafe);
        }
        private void AddPasswordError(PasswordHashEntry passwordHashEntry)
        {
            var url = Url.Action("PasswordHelp", "Account");

            string passwordError = $"The chosen password is unsafe and has previously appeared {passwordHashEntry.Occurences} times in password breaches. Please choose a different one.";

            ModelState.AddModelError("passwordError", passwordError);
        }
        private async Task <PasswordHashEntry> GetPasswordHashEntryAsync(string password)
        {
            string            sha1HashedPassword = HashingHelper.Hash(password);
            PasswordHashEntry passwordHashEntry  = await _httpUtils.GetPasswordOccurences(sha1HashedPassword);

            if (passwordHashEntry != null)
            {
                _logger.LogInformation($"Found: {passwordHashEntry.Hash} with {passwordHashEntry.Occurences} occurences");
            }
            else if (passwordHashEntry == null)
            {
                _logger.LogInformation($"No exact Hash match found.");
            }

            return(passwordHashEntry);
        }
        public async Task <IActionResult> Register(RegisterViewModel model, string returnUrl = null)
        {
            ViewData["ReturnUrl"] = returnUrl;

            if (ModelState.IsValid)
            {
                var user = new ApplicationUser {
                    UserName = model.Email, Email = model.Email
                };
                PasswordHashEntry passwordHashEntry = await GetPasswordHashEntryAsync(model.Password);

                if (passwordHashEntry == null)
                {
                    var result = await _userManager.CreateAsync(user, model.Password);

                    if (result.Succeeded)
                    {
                        _logger.LogInformation("User created a new account with password.");

                        var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);

                        var callbackUrl = Url.EmailConfirmationLink(user.Id, code, Request.Scheme);
                        await _emailSender.SendEmailConfirmationAsync(model.Email, callbackUrl);

                        await _signInManager.SignInAsync(user, isPersistent : false);

                        _logger.LogInformation("User created a new account with password.");

                        return(RedirectToLocal(returnUrl));
                    }

                    AddErrors(result);
                }
                else
                {
                    AddPasswordError(passwordHashEntry);
                }
            }

            return(View(model));
        }