/// <inheritdoc /> public async Task PasswordResetAsync(Dto.PasswordResetAsync.RequestDto dto) { var user = await _db.Users.FirstOrDefaultAsync(x => x.Email == dto.Email && x.ExternalId == null); if (user == null) { throw new EntityNotFoundException(_l["Something went wrong... Please contact support."]); } var secondsPassed = DateTime.UtcNow.Subtract(user.ResetPasswordCreatedAt.GetValueOrDefault()).Seconds; var isMaxCountExceeded = user.ResetPasswordCount >= _appSettings.MaxResetPasswordCount; var isWaitingTimePassed = secondsPassed > _appSettings.ResetPasswordWaitingTime; if (isMaxCountExceeded && !isWaitingTimePassed) { var secondsToWait = _appSettings.ResetPasswordWaitingTime - secondsPassed; throw new TooManyResetPasswordAttemptsException(string.Format( _l["You must wait for {0} seconds before you try to reset password again."], secondsToWait)); } user.ResetPasswordCode = _passwordHelper.GenerateRandomString(30) + Guid.NewGuid(); user.ResetPasswordCount += 1; user.ResetPasswordCreatedAt = DateTime.UtcNow; // Prepare email template. await using var stream = _embedded .GetFileInfo($"Resources/EmailTemplates/{_lr["RESOURCE:Email_PasswordReset.html"]}") .CreateReadStream(); var encPasswordCode = HttpUtility.UrlEncode(user.ResetPasswordCode); var encEmail = HttpUtility.UrlEncode(user.Email); var emailBody = await new StreamReader(stream).ReadToEndAsync(); emailBody = emailBody.Replace("{{APP_NAME}}", _appSettings.Name); emailBody = emailBody.Replace("{{PASSWORD_RESET_CONFIRM_URL}}", $"{_appSettings.ResetPasswordUrl}?code={encPasswordCode}&email={encEmail}"); // Send an email. var emailSuccess = await _emailService.SendAsync(_appSettings.Email, _appSettings.EmailName, user.Email, _l["Reset your password"], emailBody, null); if (!emailSuccess) { throw new EmailNotSentException(_l["Sending of email failed."]); } await _db.SaveChangesAsync(); }