public async Task GenerateTokenAndEmail(string username, string recoveryUrl) { string trimmedUsername = username.Trim(); var user = await _userRepository.GetByUsernameAsync(trimmedUsername); if (user == null) { _logger.LogInformation($"Username '{trimmedUsername}' doesn't exist so can't create a recovery token."); throw new GraException($"User '{trimmedUsername}' not found."); } if (string.IsNullOrEmpty(user.Email)) { _logger.LogInformation($"User {user.Id} doesn't have an email address configured so cannot send a recovery token."); throw new GraException($"User '{trimmedUsername}' doesn't have an email address configured."); } // clear any existing tokens var existingRequests = await _recoveryTokenRepository.GetByUserIdAsync(user.Id); _logger.LogInformation($"Found {existingRequests.Count()} existing recovery tokens for user {user.Id}."); foreach (var request in existingRequests) { await _recoveryTokenRepository.RemoveSaveAsync(-1, request.Id); } string tokenString = _tokenGenerator.Generate().ToUpper().Trim(); // insert new token var token = await _recoveryTokenRepository.AddSaveAsync(-1, new RecoveryToken { Token = tokenString.ToLower(), UserId = user.Id }); _logger.LogInformation($"Inserted token for user {user.Id}."); var site = await _siteRepository.GetByIdAsync(GetCurrentSiteId()); string subject = $"{site.Name} password recovery"; string mailBody = $"{site.Name} has received a request for a password recovery." + "\n\rAccess the password recovery page in order to set a new password:"******"\n\r {recoveryUrl}?username={trimmedUsername}&token={tokenString}" + $"\n\r\n\rIf that link does not work work, please visit:" + $"\n\r {recoveryUrl}" + $"\n\rand enter the following:" + $"\n\r Username: {trimmedUsername}" + $"\n\r Token: {tokenString}"; string htmlBody = $"<p>{site.Name} has received a request for a password recovery.</p>" + "<p>Access the " + $"<a href=\"{recoveryUrl}?username={trimmedUsername}&token={tokenString}\">" + "password recovery page</a> in order to set a new password.</p>" + "<p>If that link does not work, please visit: " + $"<a href=\"{recoveryUrl}\">{recoveryUrl}</a> " + "and enter the following:<ul>" + $"<li>Username:{trimmedUsername}</li>" + $"<li>Token: {tokenString}</li></ul></p>"; await _emailService.Send(user.Id, subject, mailBody, htmlBody); }
public async Task <Models.ServiceResult> GenerateTokenAndEmail(string username, string recoveryUrl) { string trimmedUsername = username.Trim(); var user = await _userRepository.GetByUsernameAsync(trimmedUsername); if (user == null) { _logger.LogInformation("Username {Username} doesn't exist so can't create a recovery token.", trimmedUsername); return(new Models.ServiceResult { Status = Models.ServiceResultStatus.Error, Message = Annotations.Validate.Username, Arguments = new[] { trimmedUsername } }); } if (string.IsNullOrEmpty(user.Email)) { _logger.LogInformation("User {Username} ({UserId}) doesn't have an email address configured so cannot send a recovery token.", user?.Username, user?.Id); return(new Models.ServiceResult { Status = Models.ServiceResultStatus.Error, Message = Annotations.Validate.EmailConfigured, Arguments = new[] { trimmedUsername } }); } // clear any existing tokens var existingRequests = await _recoveryTokenRepository.GetByUserIdAsync(user.Id); foreach (var request in existingRequests) { await _recoveryTokenRepository.RemoveSaveAsync(-1, request.Id); } string tokenString = _tokenGenerator.Generate().ToUpperInvariant().Trim(); // insert new token await _recoveryTokenRepository.AddSaveAsync(-1, new RecoveryToken { Token = tokenString.ToLowerInvariant(), UserId = user.Id }); _logger.LogInformation("Cleared {Existing} existing recovery tokens and inserted a new one for {Username} ({UserId})", existingRequests.Count(), user?.Username, user.Id); var site = await _siteRepository.GetByIdAsync(GetCurrentSiteId()); string subject = $"{site.Name} password recovery"; string mailBody = $"{site.Name} has received a request for a password recovery." + "\n\rAccess the password recovery page in order to set a new password:"******"\n\r {recoveryUrl}?username={trimmedUsername}&token={tokenString}" + $"\n\r\n\rIf that link does not work work, please visit:" + $"\n\r {recoveryUrl}" + $"\n\rand enter the following:" + $"\n\r Username: {trimmedUsername}" + $"\n\r Token: {tokenString}"; string htmlBody = $"<p>{site.Name} has received a request for a password recovery.</p>" + "<p>Access the " + $"<a href=\"{recoveryUrl}?username={trimmedUsername}&token={tokenString}\">" + "password recovery page</a> in order to set a new password.</p>" + "<p>If that link does not work, please visit: " + $"<a href=\"{recoveryUrl}\">{recoveryUrl}</a> " + "and enter the following:<ul>" + $"<li>Username:{trimmedUsername}</li>" + $"<li>Token: {tokenString}</li></ul></p>"; await _emailService.Send(user.Id, subject, mailBody, htmlBody); return(new Models.ServiceResult(Models.ServiceResultStatus.Success)); }
public async Task <Models.ServiceResult> GenerateTokenAndEmail(string username, string recoveryUrl) { string trimmedUsername = username.Trim(); var user = await _userRepository.GetByUsernameAsync(trimmedUsername); if (user == null) { _logger.LogInformation("Username {Username} doesn't exist so can't create a recovery token.", trimmedUsername); return(new Models.ServiceResult { Status = Models.ServiceResultStatus.Error, Message = Annotations.Validate.Username, Arguments = new[] { trimmedUsername } }); } if (string.IsNullOrEmpty(user.Email)) { _logger.LogInformation("User {Username} ({UserId}) doesn't have an email address configured so cannot send a recovery token.", user?.Username, user?.Id); return(new Models.ServiceResult { Status = Models.ServiceResultStatus.Error, Message = Annotations.Validate.EmailConfigured, Arguments = new[] { trimmedUsername } }); } // clear any existing tokens var existingRequests = await _recoveryTokenRepository.GetByUserIdAsync(user.Id); foreach (var request in existingRequests) { await _recoveryTokenRepository.RemoveSaveAsync(-1, request.Id); } string tokenString = _tokenGenerator.Generate().ToUpperInvariant().Trim(); // insert new token await _recoveryTokenRepository.AddSaveAsync(-1, new RecoveryToken { Token = tokenString.ToLowerInvariant(), UserId = user.Id }); _logger.LogInformation("Cleared {Existing} existing recovery tokens and inserted a new one for {Username} ({UserId})", existingRequests.Count(), user?.Username, user.Id); var site = await _siteLookupService.GetByIdAsync(GetCurrentSiteId()); var directEmailDetails = new DirectEmailDetails(site.Name) { DirectEmailSystemId = "PasswordRecovery", LanguageId = await _languageService .GetLanguageIdAsync(CultureInfo.CurrentUICulture.Name), SendingUserId = await _userRepository.GetSystemUserId(), ToUserId = user.Id }; directEmailDetails.Tags.Add("RecoveryLink", $"{recoveryUrl}?username={trimmedUsername}&token={tokenString}"); directEmailDetails.Tags.Add("RecoveryBaseLink", recoveryUrl); directEmailDetails.Tags.Add("Username", trimmedUsername); directEmailDetails.Tags.Add("Token", tokenString); var siteLink = await _siteLookupService.GetSiteLinkAsync(site.Id); directEmailDetails.Tags.Add("Sitelink", siteLink.AbsoluteUri); var result = new Models.ServiceResult(); try { var history = await _emailService.SendDirectAsync(directEmailDetails); result.Status = history?.Successful == true ? Models.ServiceResultStatus.Success : Models.ServiceResultStatus.Error; } catch (GraException ex) { if (ex?.InnerException is MimeKit.ParseException) { result.Status = Models.ServiceResultStatus.Error; result.Message = Annotations.Validate.AssociatedEmailAddressInvalid; result.Arguments = new[] { username }; } } return(result); }