1
0
mirror of https://github.com/bitwarden/mobile synced 2026-02-14 07:13:18 +00:00

PM-115 Fix attachment encryption on new cipher item encryption model

This commit is contained in:
Federico Maccaroni
2023-06-01 17:49:58 +03:00
parent d8a64f0f75
commit 0fed85140b
5 changed files with 38 additions and 15 deletions

View File

@@ -123,7 +123,7 @@ namespace Bit.App.Pages
{
await _deviceActionService.ShowLoadingAsync(AppResources.Saving);
_cipherDomain = await _cipherService.SaveAttachmentRawWithServerAsync(
_cipherDomain, FileName, FileData);
_cipherDomain, Cipher, FileName, FileData);
Cipher = await _cipherDomain.DecryptAsync();
await _deviceActionService.HideLoadingAsync();
_platformUtilsService.ShowToast("success", null, AppResources.AttachementAdded);

View File

@@ -27,7 +27,7 @@ namespace Bit.Core.Abstractions
Task<Cipher> GetAsync(string id);
Task<CipherView> GetLastUsedForUrlAsync(string url);
Task ReplaceAsync(Dictionary<string, CipherData> ciphers);
Task<Cipher> SaveAttachmentRawWithServerAsync(Cipher cipher, string filename, byte[] data);
Task<Cipher> SaveAttachmentRawWithServerAsync(Cipher cipher, CipherView cipherView, string filename, byte[] data);
Task SaveCollectionsWithServerAsync(Cipher cipher);
Task SaveNeverDomainAsync(string domain);
Task SaveWithServerAsync(Cipher cipher);

View File

@@ -597,11 +597,12 @@ namespace Bit.Core.Services
await UpsertAsync(data);
}
public async Task<Cipher> SaveAttachmentRawWithServerAsync(Cipher cipher, string filename, byte[] data)
public async Task<Cipher> SaveAttachmentRawWithServerAsync(Cipher cipher, CipherView cipherView, string filename, byte[] data)
{
var orgKey = await _cryptoService.GetOrgKeyAsync(cipher.OrganizationId);
var encFileName = await _cryptoService.EncryptAsync(filename, orgKey);
var (attachmentKey, orgEncAttachmentKey) = await _cryptoService.MakeEncKeyAsync(orgKey);
var key = await UpdateCipherAndGetCipherKeyAsync(cipher, cipherView, orgKey);
var encFileName = await _cryptoService.EncryptAsync(filename, key);
var (attachmentKey, encAttachmentKey) = await _cryptoService.MakeEncKeyAsync(key);
var encFileData = await _cryptoService.EncryptToBytesAsync(data, attachmentKey);
CipherResponse response;
@@ -609,7 +610,7 @@ namespace Bit.Core.Services
{
var request = new AttachmentRequest
{
Key = orgEncAttachmentKey.EncryptedString,
Key = encAttachmentKey.EncryptedString,
FileName = encFileName.EncryptedString,
FileSize = encFileData.Buffer.Length,
};
@@ -621,7 +622,7 @@ namespace Bit.Core.Services
}
catch (ApiException e) when (e.Error.StatusCode == System.Net.HttpStatusCode.NotFound || e.Error.StatusCode == System.Net.HttpStatusCode.MethodNotAllowed)
{
response = await LegacyServerAttachmentFileUploadAsync(cipher.Id, encFileName, encFileData, orgEncAttachmentKey);
response = await LegacyServerAttachmentFileUploadAsync(cipher.Id, encFileName, encFileData, encAttachmentKey);
}
var userId = await _stateService.GetActiveUserIdAsync();

View File

@@ -1,6 +1,8 @@
using System;
using System.Text;
using AutoFixture;
using Bit.Core.Models.Domain;
using Bit.Core.Models.View;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
@@ -26,16 +28,36 @@ namespace Bit.Core.Test.AutoFixture
}
}
internal class UserCipherView : ICustomization
{
public void Customize(IFixture fixture)
{
byte[] getRandomBytes(int size)
{
Random random = new Random();
byte[] bytes = new byte[size];
random.NextBytes(bytes);
return bytes;
};
fixture.Customize<CipherView>(composer => composer
.Without(c => c.OrganizationId)
.Without(c => c.Attachments)
.With(c => c.Key, new SymmetricCryptoKey(getRandomBytes(32), Enums.EncryptionType.AesCbc128_HmacSha256_B64)));
}
}
internal class UserCipherAutoDataAttribute : CustomAutoDataAttribute
{
public UserCipherAutoDataAttribute() : base(new SutProviderCustomization(),
new UserCipher())
new UserCipher(), new UserCipherView())
{ }
}
internal class InlineUserCipherAutoDataAttribute : InlineCustomAutoDataAttribute
{
public InlineUserCipherAutoDataAttribute(params object[] values) : base(new[] { typeof(SutProviderCustomization),
typeof(UserCipher) }, values)
typeof(UserCipher), typeof(UserCipherView) }, values)
{ }
}

View File

@@ -22,7 +22,7 @@ namespace Bit.Core.Test.Services
{
[Theory, UserCipherAutoData]
public async Task SaveWithServerAsync_PrefersFileUploadService(SutProvider<CipherService> sutProvider,
Cipher cipher, string fileName, EncByteArray data, AttachmentUploadDataResponse uploadDataResponse, EncString encKey)
Cipher cipher, CipherView cipherView, string fileName, EncByteArray data, AttachmentUploadDataResponse uploadDataResponse, EncString encKey)
{
var encFileName = new EncString(fileName);
sutProvider.GetDependency<ICryptoService>().EncryptAsync(fileName, Arg.Any<SymmetricCryptoKey>())
@@ -33,7 +33,7 @@ namespace Bit.Core.Test.Services
sutProvider.GetDependency<IApiService>().PostCipherAttachmentAsync(cipher.Id, Arg.Any<AttachmentRequest>())
.Returns(uploadDataResponse);
await sutProvider.Sut.SaveAttachmentRawWithServerAsync(cipher, fileName, data.Buffer);
await sutProvider.Sut.SaveAttachmentRawWithServerAsync(cipher, cipherView, fileName, data.Buffer);
await sutProvider.GetDependency<IFileUploadService>().Received(1)
.UploadCipherAttachmentFileAsync(uploadDataResponse, encFileName, data);
@@ -43,7 +43,7 @@ namespace Bit.Core.Test.Services
[InlineUserCipherAutoData(HttpStatusCode.NotFound)]
[InlineUserCipherAutoData(HttpStatusCode.MethodNotAllowed)]
public async Task SaveWithServerAsync_FallsBackToLegacyFormData(HttpStatusCode statusCode,
SutProvider<CipherService> sutProvider, Cipher cipher, string fileName, EncByteArray data,
SutProvider<CipherService> sutProvider, Cipher cipher, CipherView cipherView, string fileName, EncByteArray data,
CipherResponse response, EncString encKey)
{
sutProvider.GetDependency<ICryptoService>().EncryptAsync(fileName, Arg.Any<SymmetricCryptoKey>())
@@ -56,7 +56,7 @@ namespace Bit.Core.Test.Services
sutProvider.GetDependency<IApiService>().PostCipherAttachmentLegacyAsync(cipher.Id, Arg.Any<MultipartFormDataContent>())
.Returns(response);
await sutProvider.Sut.SaveAttachmentRawWithServerAsync(cipher, fileName, data.Buffer);
await sutProvider.Sut.SaveAttachmentRawWithServerAsync(cipher, cipherView, fileName, data.Buffer);
await sutProvider.GetDependency<IApiService>().Received(1)
.PostCipherAttachmentLegacyAsync(cipher.Id, Arg.Any<MultipartFormDataContent>());
@@ -64,7 +64,7 @@ namespace Bit.Core.Test.Services
[Theory, UserCipherAutoData]
public async Task SaveWithServerAsync_ThrowsOnBadRequestApiException(SutProvider<CipherService> sutProvider,
Cipher cipher, string fileName, EncByteArray data, EncString encKey)
Cipher cipher, CipherView cipherView, string fileName, EncByteArray data, EncString encKey)
{
sutProvider.GetDependency<ICryptoService>().EncryptAsync(fileName, Arg.Any<SymmetricCryptoKey>())
.Returns(new EncString(fileName));
@@ -77,7 +77,7 @@ namespace Bit.Core.Test.Services
.Throws(expectedException);
var actualException = await Assert.ThrowsAsync<ApiException>(async () =>
await sutProvider.Sut.SaveAttachmentRawWithServerAsync(cipher, fileName, data.Buffer));
await sutProvider.Sut.SaveAttachmentRawWithServerAsync(cipher, cipherView, fileName, data.Buffer));
Assert.Equal(expectedException.Error.StatusCode, actualException.Error.StatusCode);
}