mirror of
https://github.com/bitwarden/server
synced 2026-01-18 00:13:19 +00:00
[PM-27884][PM-27886][PM-27885] - Add Cipher Archives (#6578)
* add Archives column to ciphers table * add archives column * update cipher archive/unarchive and cipher deatils query * add migrations * add missing migrations * fixes * update tests. cleanup * syntax fix * fix sql syntax * fix sql * fix CreateWithCollections * fix sql * fix migration file * fix migration * add go * add missing go * fix migrations * add missing proc * fix migrations * implement claude suggestions * fix test * update cipher service and tests * updates to soft delete * update UserCipherDetailsQuery and migration * update migration * update archive ciphers command to allow org ciphers to be archived * updates to archivedDate * revert change to UserCipherDetails * updates to migration and procs * remove archivedDate from Cipher_CreateWithCollections * remove trailing comma * fix syntax errors * fix migration * add double quotes around datetime * fix syntax error * remove archivedDate from cipher entity * re-add ArchivedDate into cipher * fix migration * do not set Cipher.ArchivedDate in CipherRepository * re-add ArchivedDate until removed from the db * set defaults * change to CREATE OR ALTER * fix migration * fix migration file * quote datetime * fix existing archiveAsync test. add additional test * quote datetime * update migration * do not wrap datetime in quotes * do not wrap datetime in quotes * fix migration * clean up archives and archivedDate from procs * fix UserCipherDetailsQuery * fix setting date in JSON_MODIFY * prefer cast over convert * fix cipher response model * re-add ArchivedDate * add new keyword * remove ArchivedDate from entity * use custom parameters for CipherDetails_CreateWithCollections * remove reference to archivedDate * add missing param * add missing param * fix params * fix cipher repository * fix migration file * update request/response models * update migration * remove Archives from Cipher_CreateWithCollections * revert last change * clean up * remove comment * remove column in migration * change language in drop * wrap in brackets * put drop column in separate migration * remove archivedDate column * re-add archivedDate * add refresh module * bump migration name * fix proc and migration * do not require edit permission for archiving ciphers * do not require edit permission for unarchiving ciphers
This commit is contained in:
@@ -1207,10 +1207,110 @@ public class CipherRepositoryTests
|
||||
// Act
|
||||
await sutRepository.ArchiveAsync(new List<Guid> { cipher.Id }, user.Id);
|
||||
|
||||
// Assert
|
||||
var archivedCipher = await sutRepository.GetByIdAsync(cipher.Id, user.Id);
|
||||
Assert.NotNull(archivedCipher);
|
||||
Assert.NotNull(archivedCipher.ArchivedDate);
|
||||
// Assert – per-user view should show an archive date
|
||||
var archivedCipherForUser = await sutRepository.GetByIdAsync(cipher.Id, user.Id);
|
||||
Assert.NotNull(archivedCipherForUser);
|
||||
Assert.NotNull(archivedCipherForUser.ArchivedDate);
|
||||
}
|
||||
|
||||
[DatabaseTheory, DatabaseData]
|
||||
public async Task ArchiveAsync_IsPerUserForSharedCipher(
|
||||
ICipherRepository cipherRepository,
|
||||
IUserRepository userRepository,
|
||||
IOrganizationRepository organizationRepository,
|
||||
IOrganizationUserRepository organizationUserRepository,
|
||||
ICollectionRepository collectionRepository,
|
||||
ICollectionCipherRepository collectionCipherRepository)
|
||||
{
|
||||
// Arrange: two users in the same org, both with access to the same cipher
|
||||
var user1 = await userRepository.CreateAsync(new User
|
||||
{
|
||||
Name = "Test User 1",
|
||||
Email = $"test+{Guid.NewGuid()}@email.com",
|
||||
ApiKey = "TEST",
|
||||
SecurityStamp = "stamp",
|
||||
});
|
||||
|
||||
var user2 = await userRepository.CreateAsync(new User
|
||||
{
|
||||
Name = "Test User 2",
|
||||
Email = $"test+{Guid.NewGuid()}@email.com",
|
||||
ApiKey = "TEST",
|
||||
SecurityStamp = "stamp",
|
||||
});
|
||||
|
||||
var org = await organizationRepository.CreateAsync(new Organization
|
||||
{
|
||||
Name = "Test Organization",
|
||||
BillingEmail = user1.Email,
|
||||
Plan = "Test",
|
||||
});
|
||||
|
||||
var orgUser1 = await organizationUserRepository.CreateAsync(new OrganizationUser
|
||||
{
|
||||
UserId = user1.Id,
|
||||
OrganizationId = org.Id,
|
||||
Status = OrganizationUserStatusType.Confirmed,
|
||||
Type = OrganizationUserType.Owner,
|
||||
});
|
||||
|
||||
var orgUser2 = await organizationUserRepository.CreateAsync(new OrganizationUser
|
||||
{
|
||||
UserId = user2.Id,
|
||||
OrganizationId = org.Id,
|
||||
Status = OrganizationUserStatusType.Confirmed,
|
||||
Type = OrganizationUserType.User,
|
||||
});
|
||||
|
||||
var sharedCollection = await collectionRepository.CreateAsync(new Collection
|
||||
{
|
||||
Name = "Shared Collection",
|
||||
OrganizationId = org.Id,
|
||||
});
|
||||
|
||||
var cipher = await cipherRepository.CreateAsync(new Cipher
|
||||
{
|
||||
Type = CipherType.Login,
|
||||
OrganizationId = org.Id,
|
||||
Data = "",
|
||||
});
|
||||
|
||||
await collectionCipherRepository.UpdateCollectionsForAdminAsync(
|
||||
cipher.Id,
|
||||
org.Id,
|
||||
new List<Guid> { sharedCollection.Id });
|
||||
|
||||
// Give both org users access to the shared collection
|
||||
await collectionRepository.UpdateUsersAsync(sharedCollection.Id, new List<CollectionAccessSelection>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Id = orgUser1.Id,
|
||||
HidePasswords = false,
|
||||
ReadOnly = false,
|
||||
Manage = true,
|
||||
},
|
||||
new()
|
||||
{
|
||||
Id = orgUser2.Id,
|
||||
HidePasswords = false,
|
||||
ReadOnly = false,
|
||||
Manage = true,
|
||||
},
|
||||
});
|
||||
|
||||
// Act: user1 archives the shared cipher
|
||||
await cipherRepository.ArchiveAsync(new List<Guid> { cipher.Id }, user1.Id);
|
||||
|
||||
// Assert: user1 sees it as archived
|
||||
var cipherForUser1 = await cipherRepository.GetByIdAsync(cipher.Id, user1.Id);
|
||||
Assert.NotNull(cipherForUser1);
|
||||
Assert.NotNull(cipherForUser1.ArchivedDate);
|
||||
|
||||
// Assert: user2 still sees it as *not* archived
|
||||
var cipherForUser2 = await cipherRepository.GetByIdAsync(cipher.Id, user2.Id);
|
||||
Assert.NotNull(cipherForUser2);
|
||||
Assert.Null(cipherForUser2.ArchivedDate);
|
||||
}
|
||||
|
||||
[DatabaseTheory, DatabaseData]
|
||||
|
||||
Reference in New Issue
Block a user