diff --git a/test/Core.Test/KeyManagement/Commands/SetAccountKeysForUserCommandTests.cs b/test/Core.Test/KeyManagement/Commands/SetAccountKeysForUserCommandTests.cs new file mode 100644 index 0000000000..df8976ffbf --- /dev/null +++ b/test/Core.Test/KeyManagement/Commands/SetAccountKeysForUserCommandTests.cs @@ -0,0 +1,140 @@ +using Bit.Core.Entities; +using Bit.Core.KeyManagement.Commands; +using Bit.Core.KeyManagement.Entities; +using Bit.Core.KeyManagement.Enums; +using Bit.Core.KeyManagement.Models.Api.Request; +using Bit.Core.KeyManagement.Repositories; +using Bit.Core.Repositories; +using Bit.Test.Common.AutoFixture.Attributes; +using NSubstitute; +using NSubstitute.ReturnsExtensions; +using Xunit; + +namespace Bit.Core.Test.KeyManagement.Commands; + +public class SetAccountKeysForUserCommandTests +{ + [Theory] + [BitAutoData] + public async Task SetAccountKeysForUserAsync_UserNotFound_ThrowsArgumentExceptionAsync( + Guid userId, + AccountKeysRequestModel accountKeys) + { + var command = new SetAccountKeysForUserCommand(); + var userRepository = Substitute.For(); + var userSignatureKeyPairRepository = Substitute.For(); + + userRepository.GetByIdAsync(userId).ReturnsNullForAnyArgs(); + + var exception = await Assert.ThrowsAsync(() => + command.SetAccountKeysForUserAsync(userId, accountKeys, + userRepository, + userSignatureKeyPairRepository)); + + Assert.Equal("userId", exception.ParamName); + Assert.Contains("User not found", exception.Message); + } + + [Theory] + [BitAutoData] + public async Task SetAccountKeysForUserAsync_WithV1Keys_UpdatesUserCorrectlyAsync( + User user, + AccountKeysRequestModel accountKeys) + { + accountKeys.PublicKeyEncryptionKeyPair = null; + accountKeys.SignatureKeyPair = null; + accountKeys.SecurityState = null; + + // Clear any signature-related properties set by autofixture + user.SignedPublicKey = null; + user.SecurityState = null; + user.SecurityVersion = null; + + var command = new SetAccountKeysForUserCommand(); + var userRepository = Substitute.For(); + var userSignatureKeyPairRepository = Substitute.For(); + + userRepository.GetByIdAsync(user.Id).Returns(user); + + await command.SetAccountKeysForUserAsync(user.Id, accountKeys, + userRepository, + userSignatureKeyPairRepository); + + Assert.Equal(accountKeys.UserKeyEncryptedAccountPrivateKey, user.PrivateKey); + Assert.Equal(accountKeys.AccountPublicKey, user.PublicKey); + Assert.Null(user.SignedPublicKey); + Assert.Null(user.SecurityState); + Assert.Null(user.SecurityVersion); + + await userRepository + .Received(1) + .ReplaceAsync(Arg.Is(u => u.Id == user.Id)); + + await userSignatureKeyPairRepository + .DidNotReceiveWithAnyArgs() + .UpsertAsync(Arg.Any()); + } + + [Theory] + [BitAutoData] + public async Task SetAccountKeysForUserAsync_WithV2Keys_UpdatesUserAndCreatesSignatureKeyPairAsync( + User user) + { + var publicKeyEncryptionKeyPair = new PublicKeyEncryptionKeyPairRequestModel + { + WrappedPrivateKey = "wrappedPrivateKey", + PublicKey = "publicKey", + SignedPublicKey = "signedPublicKey" + }; + + var signatureKeyPair = new SignatureKeyPairRequestModel + { + SignatureAlgorithm = "ed25519", + WrappedSigningKey = "wrappedSigningKey", + VerifyingKey = "verifyingKey" + }; + + var securityState = new SecurityStateModel + { + SecurityState = "state", + SecurityVersion = 1 + }; + + var accountKeys = new AccountKeysRequestModel + { + UserKeyEncryptedAccountPrivateKey = "userKeyEncryptedPrivateKey", + AccountPublicKey = "accountPublicKey", + PublicKeyEncryptionKeyPair = publicKeyEncryptionKeyPair, + SignatureKeyPair = signatureKeyPair, + SecurityState = securityState + }; + + var command = new SetAccountKeysForUserCommand(); + var userRepository = Substitute.For(); + var userSignatureKeyPairRepository = Substitute.For(); + + userRepository.GetByIdAsync(user.Id).Returns(user); + + await command.SetAccountKeysForUserAsync(user.Id, accountKeys, + userRepository, + userSignatureKeyPairRepository); + + Assert.Equal(publicKeyEncryptionKeyPair.WrappedPrivateKey, user.PrivateKey); + Assert.Equal(publicKeyEncryptionKeyPair.PublicKey, user.PublicKey); + Assert.Equal(publicKeyEncryptionKeyPair.SignedPublicKey, user.SignedPublicKey); + Assert.Equal(securityState.SecurityState, user.SecurityState); + Assert.Equal(securityState.SecurityVersion, user.SecurityVersion); + + await userRepository + .Received(1) + .ReplaceAsync(Arg.Is(u => u.Id == user.Id)); + + await userSignatureKeyPairRepository + .Received(1) + .UpsertAsync(Arg.Is(pair => + pair.UserId == user.Id && + pair.SignatureAlgorithm == SignatureAlgorithm.Ed25519 && + pair.SigningKey == signatureKeyPair.WrappedSigningKey && + pair.VerifyingKey == signatureKeyPair.VerifyingKey)); + } +}