diff --git a/src/Api/Vault/Controllers/CiphersController.cs b/src/Api/Vault/Controllers/CiphersController.cs index 0983225f84..c200810156 100644 --- a/src/Api/Vault/Controllers/CiphersController.cs +++ b/src/Api/Vault/Controllers/CiphersController.cs @@ -1422,11 +1422,9 @@ public class CiphersController : Controller throw new NotFoundException(); } - // Extract lastKnownRevisionDate from form data if present - DateTime? lastKnownRevisionDate = GetLastKnownRevisionDateFromForm(); await Request.GetFileAsync(async (stream) => { - await _cipherService.UploadFileForExistingAttachmentAsync(stream, cipher, attachmentData, lastKnownRevisionDate); + await _cipherService.UploadFileForExistingAttachmentAsync(stream, cipher, attachmentData); }); } @@ -1525,13 +1523,10 @@ public class CiphersController : Controller throw new NotFoundException(); } - // Extract lastKnownRevisionDate from form data if present - DateTime? lastKnownRevisionDate = GetLastKnownRevisionDateFromForm(); - await Request.GetFileAsync(async (stream, fileName, key) => { await _cipherService.CreateAttachmentShareAsync(cipher, stream, fileName, key, - Request.ContentLength.GetValueOrDefault(0), attachmentId, organizationId, lastKnownRevisionDate); + Request.ContentLength.GetValueOrDefault(0), attachmentId, organizationId); }); } diff --git a/src/Core/Vault/Services/ICipherService.cs b/src/Core/Vault/Services/ICipherService.cs index 110d4b6ea4..765dae30c1 100644 --- a/src/Core/Vault/Services/ICipherService.cs +++ b/src/Core/Vault/Services/ICipherService.cs @@ -17,7 +17,7 @@ public interface ICipherService Task CreateAttachmentAsync(Cipher cipher, Stream stream, string fileName, string key, long requestLength, Guid savingUserId, bool orgAdmin = false, DateTime? lastKnownRevisionDate = null); Task CreateAttachmentShareAsync(Cipher cipher, Stream stream, string fileName, string key, long requestLength, - string attachmentId, Guid organizationShareId, DateTime? lastKnownRevisionDate = null); + string attachmentId, Guid organizationShareId); Task DeleteAsync(CipherDetails cipherDetails, Guid deletingUserId, bool orgAdmin = false); Task DeleteManyAsync(IEnumerable cipherIds, Guid deletingUserId, Guid? organizationId = null, bool orgAdmin = false); Task DeleteAttachmentAsync(Cipher cipher, string attachmentId, Guid deletingUserId, bool orgAdmin = false); @@ -34,7 +34,7 @@ public interface ICipherService Task SoftDeleteManyAsync(IEnumerable cipherIds, Guid deletingUserId, Guid? organizationId = null, bool orgAdmin = false); Task RestoreAsync(CipherDetails cipherDetails, Guid restoringUserId, bool orgAdmin = false); Task> RestoreManyAsync(IEnumerable cipherIds, Guid restoringUserId, Guid? organizationId = null, bool orgAdmin = false); - Task UploadFileForExistingAttachmentAsync(Stream stream, Cipher cipher, CipherAttachment.MetaData attachmentId, DateTime? lastKnownRevisionDate = null); + Task UploadFileForExistingAttachmentAsync(Stream stream, Cipher cipher, CipherAttachment.MetaData attachmentId); Task GetAttachmentDownloadDataAsync(Cipher cipher, string attachmentId); Task ValidateCipherAttachmentFile(Cipher cipher, CipherAttachment.MetaData attachmentData); Task ValidateBulkCollectionAssignmentAsync(IEnumerable collectionIds, IEnumerable cipherIds, Guid userId); diff --git a/src/Core/Vault/Services/Implementations/CipherService.cs b/src/Core/Vault/Services/Implementations/CipherService.cs index 4e980f66b6..cbf4ec81e3 100644 --- a/src/Core/Vault/Services/Implementations/CipherService.cs +++ b/src/Core/Vault/Services/Implementations/CipherService.cs @@ -183,9 +183,8 @@ public class CipherService : ICipherService } } - public async Task UploadFileForExistingAttachmentAsync(Stream stream, Cipher cipher, CipherAttachment.MetaData attachment, DateTime? lastKnownRevisionDate = null) + public async Task UploadFileForExistingAttachmentAsync(Stream stream, Cipher cipher, CipherAttachment.MetaData attachment) { - ValidateCipherLastKnownRevisionDate(cipher, lastKnownRevisionDate); if (attachment == null) { throw new BadRequestException("Cipher attachment does not exist"); @@ -290,11 +289,10 @@ public class CipherService : ICipherService } public async Task CreateAttachmentShareAsync(Cipher cipher, Stream stream, string fileName, string key, - long requestLength, string attachmentId, Guid organizationId, DateTime? lastKnownRevisionDate = null) + long requestLength, string attachmentId, Guid organizationId) { try { - ValidateCipherLastKnownRevisionDate(cipher, lastKnownRevisionDate); if (requestLength < 1) { throw new BadRequestException("No data to attach."); diff --git a/test/Core.Test/Vault/Services/CipherServiceTests.cs b/test/Core.Test/Vault/Services/CipherServiceTests.cs index fb53c41bad..c5eecb8f34 100644 --- a/test/Core.Test/Vault/Services/CipherServiceTests.cs +++ b/test/Core.Test/Vault/Services/CipherServiceTests.cs @@ -225,130 +225,6 @@ public class CipherServiceTests Assert.NotNull(result.uploadUrl); } - [Theory, BitAutoData] - public async Task UploadFileForExistingAttachmentAsync_WrongRevisionDate_Throws(SutProvider sutProvider, - Cipher cipher) - { - var lastKnownRevisionDate = cipher.RevisionDate.AddDays(-1); - var stream = new MemoryStream(); - var attachment = new CipherAttachment.MetaData - { - AttachmentId = "test-attachment-id", - Size = 100, - FileName = "test.txt", - Key = "test-key" - }; - - var exception = await Assert.ThrowsAsync( - () => sutProvider.Sut.UploadFileForExistingAttachmentAsync(stream, cipher, attachment, lastKnownRevisionDate)); - Assert.Contains("out of date", exception.Message); - } - - [Theory] - [BitAutoData("")] - [BitAutoData("Correct Time")] - public async Task UploadFileForExistingAttachmentAsync_CorrectRevisionDate_DoesNotThrow(string revisionDateString, - SutProvider sutProvider, CipherDetails cipher) - { - var lastKnownRevisionDate = string.IsNullOrEmpty(revisionDateString) ? (DateTime?)null : cipher.RevisionDate; - var stream = new MemoryStream(new byte[100]); - var attachmentId = "test-attachment-id"; - var attachment = new CipherAttachment.MetaData - { - AttachmentId = attachmentId, - Size = 100, - FileName = "test.txt", - Key = "test-key" - }; - - // Set the attachment on the cipher so ValidateCipherAttachmentFile can find it - cipher.SetAttachments(new Dictionary - { - [attachmentId] = attachment - }); - - sutProvider.GetDependency() - .UploadNewAttachmentAsync(stream, cipher, attachment) - .Returns(Task.CompletedTask); - - sutProvider.GetDependency() - .ValidateFileAsync(cipher, attachment, Arg.Any()) - .Returns((true, 100L)); - - sutProvider.GetDependency() - .UpdateAttachmentAsync(Arg.Any()) - .Returns(Task.CompletedTask); - - await sutProvider.Sut.UploadFileForExistingAttachmentAsync(stream, cipher, attachment, lastKnownRevisionDate); - - await sutProvider.GetDependency().Received(1) - .UploadNewAttachmentAsync(stream, cipher, attachment); - } - - [Theory, BitAutoData] - public async Task CreateAttachmentShareAsync_WrongRevisionDate_Throws(SutProvider sutProvider, - Cipher cipher, Guid organizationId) - { - var lastKnownRevisionDate = cipher.RevisionDate.AddDays(-1); - var stream = new MemoryStream(); - var fileName = "test.txt"; - var key = "test-key"; - var attachmentId = "attachment-id"; - - var exception = await Assert.ThrowsAsync( - () => sutProvider.Sut.CreateAttachmentShareAsync(cipher, stream, fileName, key, 100, attachmentId, organizationId, lastKnownRevisionDate)); - Assert.Contains("out of date", exception.Message); - } - - [Theory] - [BitAutoData("")] - [BitAutoData("Correct Time")] - public async Task CreateAttachmentShareAsync_CorrectRevisionDate_DoesNotThrow(string revisionDateString, - SutProvider sutProvider, CipherDetails cipher, Guid organizationId) - { - var lastKnownRevisionDate = string.IsNullOrEmpty(revisionDateString) ? (DateTime?)null : cipher.RevisionDate; - var stream = new MemoryStream(new byte[100]); - var fileName = "test.txt"; - var key = "test-key"; - var attachmentId = "attachment-id"; - - // Setup cipher with existing attachment (no TempMetadata) - cipher.OrganizationId = null; - cipher.SetAttachments(new Dictionary - { - [attachmentId] = new CipherAttachment.MetaData - { - AttachmentId = attachmentId, - Size = 100, - FileName = "existing.txt", - Key = "existing-key" - } - }); - - // Mock organization - var organization = new Organization - { - Id = organizationId, - MaxStorageGb = 1 - }; - sutProvider.GetDependency() - .GetByIdAsync(organizationId) - .Returns(organization); - - sutProvider.GetDependency() - .UploadShareAttachmentAsync(stream, cipher.Id, organizationId, Arg.Any()) - .Returns(Task.CompletedTask); - - sutProvider.GetDependency() - .UpdateAttachmentAsync(Arg.Any()) - .Returns(Task.CompletedTask); - - await sutProvider.Sut.CreateAttachmentShareAsync(cipher, stream, fileName, key, 100, attachmentId, organizationId, lastKnownRevisionDate); - - await sutProvider.GetDependency().Received(1) - .UploadShareAttachmentAsync(stream, cipher.Id, organizationId, Arg.Any()); - } - [Theory] [BitAutoData] public async Task SaveDetailsAsync_PersonalVault_WithOrganizationDataOwnershipPolicyEnabled_Throws(