Merge branch 'fix/2848_allow-downloading-pgp/mime-message-attachments' into 'develop'

Fixes downloading of the pgp/mime message attachments

See merge request android/mail/proton-mail-android!1055
This commit is contained in:
Maciej Surmacz 2022-04-15 15:27:56 +00:00
commit de39dad5ff
5 changed files with 168 additions and 38 deletions

View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 2022 Proton Technologies AG
*
* This file is part of ProtonMail.
*
* ProtonMail is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonMail is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonMail. If not, see https://www.gnu.org/licenses/.
*/
package ch.protonmail.android.attachments
import ch.protonmail.android.crypto.AddressCrypto
import ch.protonmail.android.data.local.model.Attachment
import javax.inject.Inject
class ExtractAttachmentByteArray @Inject constructor(
private val attachmentsRepository: AttachmentsRepository
) {
suspend operator fun invoke(attachment: Attachment, addressCrypto: AddressCrypto): ByteArray? {
return attachment.mimeData ?: attachmentsRepository.getAttachmentDataOrNull(
addressCrypto,
requireNotNull(attachment.attachmentId),
requireNotNull(attachment.keyPackets)
)
}
}

View File

@ -57,7 +57,7 @@ class HandleSingleAttachment @Inject constructor(
private val databaseProvider: DatabaseProvider,
private val attachmentsHelper: AttachmentsHelper,
private val clearingServiceHelper: AttachmentClearingServiceHelper,
private val attachmentsRepository: AttachmentsRepository
private val extractAttachmentByteArray: ExtractAttachmentByteArray
) {
private val attachmentMetadataDao: AttachmentMetadataDao
@ -153,17 +153,13 @@ class HandleSingleAttachment @Inject constructor(
crypto: AddressCrypto,
mimeType: String?
): Uri? {
val decryptedByteArray = attachmentsRepository.getAttachmentDataOrNull(
crypto,
requireNotNull(attachment.attachmentId),
requireNotNull(attachment.keyPackets)
)
return decryptedByteArray?.inputStream()?.let {
attachmentsHelper.saveAttachmentInMediaStore(
context.contentResolver, filename, mimeType, it
)
}
return extractAttachmentByteArray(attachment, crypto)
?.inputStream()
?.let {
attachmentsHelper.saveAttachmentInMediaStore(
context.contentResolver, filename, mimeType, it
)
}
}
private suspend fun downloadAttachmentBeforeQ(
@ -172,24 +168,18 @@ class HandleSingleAttachment @Inject constructor(
crypto: AddressCrypto,
mimeType: String?
): Uri? {
val decryptedByteArray = attachmentsRepository.getAttachmentDataOrNull(
crypto,
requireNotNull(attachment.attachmentId),
requireNotNull(attachment.keyPackets)
)
return decryptedByteArray?.let { bytes ->
val file = saveBytesToFile(filename, bytes)
val result = awaitUriFromMediaScanned(
context,
file,
mimeType
)
val uri = result.second
Timber.v("Stored file: $filename path: ${result.first} uri: $uri")
uri
}
return extractAttachmentByteArray(attachment, crypto)
?.let { bytes ->
val file = saveBytesToFile(filename, bytes)
val result = awaitUriFromMediaScanned(
context,
file,
mimeType
)
val uri = result.second
Timber.v("Stored file: $filename path: ${result.first} uri: $uri")
uri
}
}
private fun saveBytesToFile(filename: String, bytes: ByteArray): File {

View File

@ -0,0 +1,78 @@
/*
* Copyright (c) 2022 Proton Technologies AG
*
* This file is part of ProtonMail.
*
* ProtonMail is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonMail is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonMail. If not, see https://www.gnu.org/licenses/.
*/
package ch.protonmail.android.attachments
import ch.protonmail.android.crypto.AddressCrypto
import ch.protonmail.android.testdata.AttachmentTestData
import io.mockk.called
import io.mockk.coEvery
import io.mockk.mockk
import io.mockk.verify
import kotlinx.coroutines.test.runBlockingTest
import org.junit.Test
import kotlin.test.assertSame
internal class ExtractAttachmentByteArrayTest {
private val addressCryptoMock = mockk<AddressCrypto>()
private val attachmentsRepositoryMock = mockk<AttachmentsRepository>()
private val extractAttachmentByteArray = ExtractAttachmentByteArray(
attachmentsRepositoryMock
)
@Test
fun `should return the in memory mime data when it is present`() = runBlockingTest {
// given
val expectedAttachmentBytes = AttachmentTestData.WITH_MIME_DATA.mimeData
// when
val actualAttachmentBytes = extractAttachmentByteArray(
AttachmentTestData.WITH_MIME_DATA,
addressCryptoMock
)
// then
assertSame(expectedAttachmentBytes, actualAttachmentBytes)
verify { addressCryptoMock wasNot called }
verify { attachmentsRepositoryMock wasNot called }
}
@Test
fun `should get attachment byte array through repository when in memory mime data not present`() = runBlockingTest {
// given
val expectedAttachmentBytes = ByteArray(42)
coEvery {
attachmentsRepositoryMock.getAttachmentDataOrNull(
addressCryptoMock,
AttachmentTestData.ID,
AttachmentTestData.KEY_PACKETS
)
} returns expectedAttachmentBytes
// when
val actualAttachmentBytes = extractAttachmentByteArray(
AttachmentTestData.WITHOUT_MIME_DATA,
addressCryptoMock
)
// then
assertSame(expectedAttachmentBytes, actualAttachmentBytes)
}
}

View File

@ -48,10 +48,10 @@ class HandleSingleAttachmentTest : ArchTest {
private val context: Context = mockk()
private val userManager: UserManager = mockk()
private val databaseProvider: DatabaseProvider = mockk()
private val attachmentsRepository: AttachmentsRepository = mockk()
private val clearingServiceHelper: AttachmentClearingServiceHelper = mockk()
private val attachmentsHelper: AttachmentsHelper = mockk()
private val testMimeType = "image/jpeg"
private val extractAttachmentByteArray: ExtractAttachmentByteArray = mockk()
val useCase = HandleSingleAttachment(
context,
@ -59,7 +59,7 @@ class HandleSingleAttachmentTest : ArchTest {
databaseProvider,
attachmentsHelper,
clearingServiceHelper,
attachmentsRepository
extractAttachmentByteArray
)
@BeforeTest
@ -101,9 +101,7 @@ class HandleSingleAttachmentTest : ArchTest {
every { keyPackets } returns testKeyPackets
}
coEvery {
attachmentsRepository.getAttachmentDataOrNull(
crypto, testAttachmentId, testKeyPackets
)
extractAttachmentByteArray(attachment, crypto)
} returns testBytePackets
val expected = ListenableWorker.Result.failure()
@ -112,9 +110,7 @@ class HandleSingleAttachmentTest : ArchTest {
// then
coVerify(exactly = 3) {
attachmentsRepository.getAttachmentDataOrNull(
crypto, testAttachmentId, testKeyPackets
)
extractAttachmentByteArray(attachment, crypto)
}
assertEquals(expected, result)
}

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2022 Proton Technologies AG
*
* This file is part of ProtonMail.
*
* ProtonMail is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonMail is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonMail. If not, see https://www.gnu.org/licenses/.
*/
package ch.protonmail.android.testdata
import ch.protonmail.android.data.local.model.Attachment
object AttachmentTestData {
const val ID = "attachmentId"
const val KEY_PACKETS = "keyPackets"
val WITH_MIME_DATA = Attachment(attachmentId = ID, mimeData = ByteArray(10), keyPackets = KEY_PACKETS)
val WITHOUT_MIME_DATA = Attachment(attachmentId = ID, mimeData = null, keyPackets = KEY_PACKETS)
}