#nullable enable using Bit.Core.Auth.Enums; using Bit.Core.Auth.Models.Data; using Bit.Core.Context; using Bit.Core.Entities; using Bit.Core.Enums; using Bit.Core.Exceptions; using Bit.Core.KeyManagement.Commands; using Bit.Core.KeyManagement.Models.Data; using Bit.Core.KeyManagement.Repositories; using Bit.Core.Services; using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture.Attributes; using NSubstitute; using NSubstitute.ReturnsExtensions; using Xunit; namespace Bit.Core.Test.KeyManagement.Commands; [SutProviderCustomize] public class RegenerateUserAsymmetricKeysCommandTests { [Theory] [BitAutoData] public async Task RegenerateKeysAsync_NoCurrentContext_NotFoundException( SutProvider sutProvider, UserAsymmetricKeys userAsymmetricKeys) { sutProvider.GetDependency().UserId.ReturnsNullForAnyArgs(); var usersOrganizationAccounts = new List(); var designatedEmergencyAccess = new List(); await Assert.ThrowsAsync(() => sutProvider.Sut.RegenerateKeysAsync(userAsymmetricKeys, usersOrganizationAccounts, designatedEmergencyAccess)); } [Theory] [BitAutoData] public async Task RegenerateKeysAsync_UserHasNoSharedAccess_Success( SutProvider sutProvider, UserAsymmetricKeys userAsymmetricKeys) { sutProvider.GetDependency().UserId.ReturnsForAnyArgs(userAsymmetricKeys.UserId); var usersOrganizationAccounts = new List(); var designatedEmergencyAccess = new List(); await sutProvider.Sut.RegenerateKeysAsync(userAsymmetricKeys, usersOrganizationAccounts, designatedEmergencyAccess); await sutProvider.GetDependency() .Received(1) .RegenerateUserAsymmetricKeysAsync(Arg.Is(userAsymmetricKeys)); await sutProvider.GetDependency() .Received(1) .PushSyncSettingsAsync(Arg.Is(userAsymmetricKeys.UserId)); } [Theory] [BitAutoData(false, false, true)] [BitAutoData(false, true, false)] [BitAutoData(false, true, true)] [BitAutoData(true, false, false)] [BitAutoData(true, false, true)] [BitAutoData(true, true, false)] [BitAutoData(true, true, true)] public async Task RegenerateKeysAsync_UserIdMisMatch_NotFoundException( bool userAsymmetricKeysMismatch, bool orgMismatch, bool emergencyAccessMismatch, SutProvider sutProvider, UserAsymmetricKeys userAsymmetricKeys, ICollection usersOrganizationAccounts, ICollection designatedEmergencyAccess) { sutProvider.GetDependency().UserId .ReturnsForAnyArgs(userAsymmetricKeysMismatch ? new Guid() : userAsymmetricKeys.UserId); if (!orgMismatch) { usersOrganizationAccounts = SetupOrganizationUserAccounts(userAsymmetricKeys.UserId, usersOrganizationAccounts); } if (!emergencyAccessMismatch) { designatedEmergencyAccess = SetupEmergencyAccess(userAsymmetricKeys.UserId, designatedEmergencyAccess); } await Assert.ThrowsAsync(() => sutProvider.Sut.RegenerateKeysAsync(userAsymmetricKeys, usersOrganizationAccounts, designatedEmergencyAccess)); await sutProvider.GetDependency() .ReceivedWithAnyArgs(0) .RegenerateUserAsymmetricKeysAsync(Arg.Any()); await sutProvider.GetDependency() .ReceivedWithAnyArgs(0) .PushSyncSettingsAsync(Arg.Any()); } [Theory] [BitAutoData(OrganizationUserStatusType.Confirmed)] [BitAutoData(OrganizationUserStatusType.Revoked)] public async Task RegenerateKeysAsync_UserInOrganizations_BadRequestException( OrganizationUserStatusType organizationUserStatus, SutProvider sutProvider, UserAsymmetricKeys userAsymmetricKeys, ICollection usersOrganizationAccounts) { sutProvider.GetDependency().UserId.ReturnsForAnyArgs(userAsymmetricKeys.UserId); usersOrganizationAccounts = CreateInOrganizationAccounts(userAsymmetricKeys.UserId, organizationUserStatus, usersOrganizationAccounts); var designatedEmergencyAccess = new List(); await Assert.ThrowsAsync(() => sutProvider.Sut.RegenerateKeysAsync(userAsymmetricKeys, usersOrganizationAccounts, designatedEmergencyAccess)); await sutProvider.GetDependency() .ReceivedWithAnyArgs(0) .RegenerateUserAsymmetricKeysAsync(Arg.Any()); await sutProvider.GetDependency() .ReceivedWithAnyArgs(0) .PushSyncSettingsAsync(Arg.Any()); } [Theory] [BitAutoData(EmergencyAccessStatusType.Confirmed)] [BitAutoData(EmergencyAccessStatusType.RecoveryApproved)] [BitAutoData(EmergencyAccessStatusType.RecoveryInitiated)] public async Task RegenerateKeysAsync_UserHasDesignatedEmergencyAccess_BadRequestException( EmergencyAccessStatusType statusType, SutProvider sutProvider, UserAsymmetricKeys userAsymmetricKeys, ICollection designatedEmergencyAccess) { sutProvider.GetDependency().UserId.ReturnsForAnyArgs(userAsymmetricKeys.UserId); designatedEmergencyAccess = CreateDesignatedEmergencyAccess(userAsymmetricKeys.UserId, statusType, designatedEmergencyAccess); var usersOrganizationAccounts = new List(); await Assert.ThrowsAsync(() => sutProvider.Sut.RegenerateKeysAsync(userAsymmetricKeys, usersOrganizationAccounts, designatedEmergencyAccess)); await sutProvider.GetDependency() .ReceivedWithAnyArgs(0) .RegenerateUserAsymmetricKeysAsync(Arg.Any()); await sutProvider.GetDependency() .ReceivedWithAnyArgs(0) .PushSyncSettingsAsync(Arg.Any()); } private static ICollection CreateInOrganizationAccounts(Guid userId, OrganizationUserStatusType organizationUserStatus, ICollection organizationUserAccounts) { foreach (var organizationUserAccount in organizationUserAccounts) { organizationUserAccount.UserId = userId; organizationUserAccount.Status = organizationUserStatus; } return organizationUserAccounts; } private static ICollection CreateDesignatedEmergencyAccess(Guid userId, EmergencyAccessStatusType status, ICollection designatedEmergencyAccess) { foreach (var designated in designatedEmergencyAccess) { designated.GranteeId = userId; designated.Status = status; } return designatedEmergencyAccess; } private static ICollection SetupOrganizationUserAccounts(Guid userId, ICollection organizationUserAccounts) { foreach (var organizationUserAccount in organizationUserAccounts) { organizationUserAccount.UserId = userId; } return organizationUserAccounts; } private static ICollection SetupEmergencyAccess(Guid userId, ICollection emergencyAccessDetails) { foreach (var emergencyAccessDetail in emergencyAccessDetails) { emergencyAccessDetail.GranteeId = userId; } return emergencyAccessDetails; } }