public async Task <ActionResult <IActionResult> > ForgotPassword(string email) { if (String.IsNullOrWhiteSpace(email)) { return(BadRequest()); } if (_context.Users.Any(e => e.Email == email)) { ResetTokenModel model = new ResetTokenModel { Email = email, Expires = DateTime.UtcNow.AddHours(24), IsTokenUsed = false }; // Generate reset token byte[] resetTokenBytes; new RNGCryptoServiceProvider().GetBytes(resetTokenBytes = new byte[16]); model.Token = Convert.ToBase64String(resetTokenBytes); //TODO: send reset email or whatever string message = "Hi! To reset your password you need to open the following link within 24h: \n\n https://wanderer.app/passwordReset?token=" + model.Token; _context.ResetTokens.Add(model.HashToken()); await _context.SaveChangesAsync(); return(Ok()); } return(NotFound()); }
public async Task <ActionResult <UserModel> > ResetPassword(int id, string resetToken, string newPassword) { if (!_context.ResetTokens.Any(e => e.Id == id)) { return(NotFound()); } ResetTokenModel tokenModel = _context.ResetTokens.First(e => e.Id == id); if (DateTime.Now - tokenModel.Expires > TimeSpan.Zero || tokenModel.IsTokenUsed) { throw new UnauthorizedAccessException(); } byte[] hashBytes = Convert.FromBase64String(tokenModel.Token); /* Get the salt */ byte[] salt = new byte[16]; Array.Copy(hashBytes, 0, salt, 0, 16); /* Compute the hash on the password the user entered */ var pbkdf2 = new Rfc2898DeriveBytes(resetToken, salt, 10000); byte[] hash = pbkdf2.GetBytes(100); /* Compare the results */ for (int i = 0; i < 20; i++) { if (hashBytes[i + 16] != hash[i]) { throw new UnauthorizedAccessException(); } } // So the token exists, is not expired or used, and matches. Time to change the password. if (String.IsNullOrWhiteSpace(newPassword)) { return(BadRequest()); } UserModel user = _context.Users.First(it => it.Email == tokenModel.Email); user.Password = newPassword; user.HashPassword(); _context.Users.Update(user); tokenModel.IsTokenUsed = true; _context.ResetTokens.Update(tokenModel); await _context.SaveChangesAsync(); return(user.WithoutPassword()); }
public static ResetTokenModel HashToken(this ResetTokenModel resetToken) { byte[] salt; new RNGCryptoServiceProvider().GetBytes(salt = new byte[16]); var pbkdf2 = new Rfc2898DeriveBytes(resetToken.Token, salt, 10000); byte[] hash = pbkdf2.GetBytes(20); byte[] hashBytes = new byte[36]; Array.Copy(salt, 0, hashBytes, 0, 16); Array.Copy(hash, 0, hashBytes, 16, 20); resetToken.Token = Convert.ToBase64String(hashBytes); return(resetToken); }