mirror of
https://github.com/bitwarden/server
synced 2025-12-06 00:03:34 +00:00
when ciphers are soft deleted, complete any associated security tasks (#6492)
This commit is contained in:
@@ -2286,6 +2286,63 @@ public class CipherServiceTests
|
||||
.PushSyncCiphersAsync(deletingUserId);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SoftDeleteAsync_CallsMarkAsCompleteByCipherIds(
|
||||
Guid deletingUserId, CipherDetails cipherDetails, SutProvider<CipherService> sutProvider)
|
||||
{
|
||||
cipherDetails.UserId = deletingUserId;
|
||||
cipherDetails.OrganizationId = null;
|
||||
cipherDetails.DeletedDate = null;
|
||||
|
||||
sutProvider.GetDependency<IUserService>()
|
||||
.GetUserByIdAsync(deletingUserId)
|
||||
.Returns(new User
|
||||
{
|
||||
Id = deletingUserId,
|
||||
});
|
||||
|
||||
await sutProvider.Sut.SoftDeleteAsync(cipherDetails, deletingUserId);
|
||||
|
||||
await sutProvider.GetDependency<ISecurityTaskRepository>()
|
||||
.Received(1)
|
||||
.MarkAsCompleteByCipherIds(Arg.Is<IEnumerable<Guid>>(ids =>
|
||||
ids.Count() == 1 && ids.First() == cipherDetails.Id));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SoftDeleteManyAsync_CallsMarkAsCompleteByCipherIds(
|
||||
Guid deletingUserId, List<CipherDetails> ciphers, SutProvider<CipherService> sutProvider)
|
||||
{
|
||||
var cipherIds = ciphers.Select(c => c.Id).ToArray();
|
||||
|
||||
foreach (var cipher in ciphers)
|
||||
{
|
||||
cipher.UserId = deletingUserId;
|
||||
cipher.OrganizationId = null;
|
||||
cipher.Edit = true;
|
||||
cipher.DeletedDate = null;
|
||||
}
|
||||
|
||||
sutProvider.GetDependency<IUserService>()
|
||||
.GetUserByIdAsync(deletingUserId)
|
||||
.Returns(new User
|
||||
{
|
||||
Id = deletingUserId,
|
||||
});
|
||||
sutProvider.GetDependency<ICipherRepository>()
|
||||
.GetManyByUserIdAsync(deletingUserId)
|
||||
.Returns(ciphers);
|
||||
|
||||
await sutProvider.Sut.SoftDeleteManyAsync(cipherIds, deletingUserId, null, false);
|
||||
|
||||
await sutProvider.GetDependency<ISecurityTaskRepository>()
|
||||
.Received(1)
|
||||
.MarkAsCompleteByCipherIds(Arg.Is<IEnumerable<Guid>>(ids =>
|
||||
ids.Count() == cipherIds.Length && ids.All(id => cipherIds.Contains(id))));
|
||||
}
|
||||
|
||||
private async Task AssertNoActionsAsync(SutProvider<CipherService> sutProvider)
|
||||
{
|
||||
await sutProvider.GetDependency<ICipherRepository>().DidNotReceiveWithAnyArgs().GetManyOrganizationDetailsByOrganizationIdAsync(default);
|
||||
|
||||
@@ -345,4 +345,110 @@ public class SecurityTaskRepositoryTests
|
||||
Assert.Equal(0, metrics.CompletedTasks);
|
||||
Assert.Equal(0, metrics.TotalTasks);
|
||||
}
|
||||
|
||||
[DatabaseTheory, DatabaseData]
|
||||
public async Task MarkAsCompleteByCipherIds_MarksPendingTasksAsCompleted(
|
||||
IOrganizationRepository organizationRepository,
|
||||
ICipherRepository cipherRepository,
|
||||
ISecurityTaskRepository securityTaskRepository)
|
||||
{
|
||||
var organization = await organizationRepository.CreateAsync(new Organization
|
||||
{
|
||||
Name = "Test Org",
|
||||
PlanType = PlanType.EnterpriseAnnually,
|
||||
Plan = "Test Plan",
|
||||
BillingEmail = "billing@email.com"
|
||||
});
|
||||
|
||||
var cipher1 = await cipherRepository.CreateAsync(new Cipher
|
||||
{
|
||||
Type = CipherType.Login,
|
||||
OrganizationId = organization.Id,
|
||||
Data = "",
|
||||
});
|
||||
|
||||
var cipher2 = await cipherRepository.CreateAsync(new Cipher
|
||||
{
|
||||
Type = CipherType.Login,
|
||||
OrganizationId = organization.Id,
|
||||
Data = "",
|
||||
});
|
||||
|
||||
var task1 = await securityTaskRepository.CreateAsync(new SecurityTask
|
||||
{
|
||||
OrganizationId = organization.Id,
|
||||
CipherId = cipher1.Id,
|
||||
Status = SecurityTaskStatus.Pending,
|
||||
Type = SecurityTaskType.UpdateAtRiskCredential,
|
||||
});
|
||||
|
||||
var task2 = await securityTaskRepository.CreateAsync(new SecurityTask
|
||||
{
|
||||
OrganizationId = organization.Id,
|
||||
CipherId = cipher2.Id,
|
||||
Status = SecurityTaskStatus.Pending,
|
||||
Type = SecurityTaskType.UpdateAtRiskCredential,
|
||||
});
|
||||
|
||||
await securityTaskRepository.MarkAsCompleteByCipherIds([cipher1.Id, cipher2.Id]);
|
||||
|
||||
var updatedTask1 = await securityTaskRepository.GetByIdAsync(task1.Id);
|
||||
var updatedTask2 = await securityTaskRepository.GetByIdAsync(task2.Id);
|
||||
|
||||
Assert.Equal(SecurityTaskStatus.Completed, updatedTask1.Status);
|
||||
Assert.Equal(SecurityTaskStatus.Completed, updatedTask2.Status);
|
||||
}
|
||||
|
||||
[DatabaseTheory, DatabaseData]
|
||||
public async Task MarkAsCompleteByCipherIds_OnlyUpdatesSpecifiedCiphers(
|
||||
IOrganizationRepository organizationRepository,
|
||||
ICipherRepository cipherRepository,
|
||||
ISecurityTaskRepository securityTaskRepository)
|
||||
{
|
||||
var organization = await organizationRepository.CreateAsync(new Organization
|
||||
{
|
||||
Name = "Test Org",
|
||||
PlanType = PlanType.EnterpriseAnnually,
|
||||
Plan = "Test Plan",
|
||||
BillingEmail = "billing@email.com"
|
||||
});
|
||||
|
||||
var cipher1 = await cipherRepository.CreateAsync(new Cipher
|
||||
{
|
||||
Type = CipherType.Login,
|
||||
OrganizationId = organization.Id,
|
||||
Data = "",
|
||||
});
|
||||
|
||||
var cipher2 = await cipherRepository.CreateAsync(new Cipher
|
||||
{
|
||||
Type = CipherType.Login,
|
||||
OrganizationId = organization.Id,
|
||||
Data = "",
|
||||
});
|
||||
|
||||
var taskToUpdate = await securityTaskRepository.CreateAsync(new SecurityTask
|
||||
{
|
||||
OrganizationId = organization.Id,
|
||||
CipherId = cipher1.Id,
|
||||
Status = SecurityTaskStatus.Pending,
|
||||
Type = SecurityTaskType.UpdateAtRiskCredential,
|
||||
});
|
||||
|
||||
var taskToKeep = await securityTaskRepository.CreateAsync(new SecurityTask
|
||||
{
|
||||
OrganizationId = organization.Id,
|
||||
CipherId = cipher2.Id,
|
||||
Status = SecurityTaskStatus.Pending,
|
||||
Type = SecurityTaskType.UpdateAtRiskCredential,
|
||||
});
|
||||
|
||||
await securityTaskRepository.MarkAsCompleteByCipherIds([cipher1.Id]);
|
||||
|
||||
var updatedTask = await securityTaskRepository.GetByIdAsync(taskToUpdate.Id);
|
||||
var unchangedTask = await securityTaskRepository.GetByIdAsync(taskToKeep.Id);
|
||||
|
||||
Assert.Equal(SecurityTaskStatus.Completed, updatedTask.Status);
|
||||
Assert.Equal(SecurityTaskStatus.Pending, unchangedTask.Status);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user