1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-01 16:12:49 -05:00

Transactionally safe user password and email change updates.

This commit is contained in:
Kyle Spearrin
2016-02-21 00:15:17 -05:00
parent 1da53f0ecc
commit 1b3acec905
5 changed files with 53 additions and 39 deletions

View File

@ -69,7 +69,7 @@ namespace Bit.Core.Services
{
throw new ApplicationException("Use register method to create a new user.");
}
await _userRepository.ReplaceAsync(user);
}
@ -128,50 +128,43 @@ namespace Bit.Core.Services
}
var existingUser = await _userRepository.GetByEmailAsync(newEmail);
if(existingUser != null)
if(existingUser != null && existingUser.Id != user.Id)
{
return IdentityResult.Failed(_identityErrorDescriber.DuplicateEmail(newEmail));
}
var result = await UpdatePasswordHash(user, newMasterPassword);
if(!result.Succeeded)
{
return result;
}
user.Email = newEmail;
user.MasterPassword = _passwordHasher.HashPassword(user, newMasterPassword);
user.SecurityStamp = Guid.NewGuid().ToString();
await _cipherRepository.DirtyCiphersAsync(user.Id);
await _userRepository.ReplaceAsync(user);
await _cipherRepository.UpdateDirtyCiphersAsync(ciphers);
// TODO: what if something fails? rollback?
await _cipherRepository.UpdateUserEmailPasswordAndCiphersAsync(user, ciphers);
return IdentityResult.Success;
}
public override Task<IdentityResult> ChangePasswordAsync(User user, string currentMasterPasswordHash, string newMasterPasswordHash)
public override Task<IdentityResult> ChangePasswordAsync(User user, string masterPassword, string newMasterPassword)
{
throw new NotImplementedException();
}
public async Task<IdentityResult> ChangePasswordAsync(User user, string currentMasterPasswordHash, string newMasterPasswordHash, IEnumerable<dynamic> ciphers)
public async Task<IdentityResult> ChangePasswordAsync(User user, string masterPassword, string newMasterPassword, IEnumerable<dynamic> ciphers)
{
if(user == null)
{
throw new ArgumentNullException(nameof(user));
}
if(await base.CheckPasswordAsync(user, currentMasterPasswordHash))
if(await base.CheckPasswordAsync(user, masterPassword))
{
var result = await UpdatePasswordHash(user, newMasterPasswordHash);
var result = await UpdatePasswordHash(user, newMasterPassword);
if(!result.Succeeded)
{
return result;
}
await _cipherRepository.DirtyCiphersAsync(user.Id);
await _userRepository.ReplaceAsync(user);
await _cipherRepository.UpdateDirtyCiphersAsync(ciphers);
// TODO: what if something fails? rollback?
await _cipherRepository.UpdateUserEmailPasswordAndCiphersAsync(user, ciphers);
return IdentityResult.Success;
}
@ -179,14 +172,14 @@ namespace Bit.Core.Services
return IdentityResult.Failed(_identityErrorDescriber.PasswordMismatch());
}
public async Task<IdentityResult> RefreshSecurityStampAsync(User user, string masterPasswordHash)
public async Task<IdentityResult> RefreshSecurityStampAsync(User user, string masterPassword)
{
if(user == null)
{
throw new ArgumentNullException(nameof(user));
}
if(await base.CheckPasswordAsync(user, masterPasswordHash))
if(await base.CheckPasswordAsync(user, masterPassword))
{
var result = await base.UpdateSecurityStampAsync(user);
if(!result.Succeeded)