Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b6f540bf authored by Vincent Breitmoser's avatar Vincent Breitmoser
Browse files

compose: apply transfer encoding *after* PGP/INLINE signing

parent 8a58398c
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -132,4 +132,8 @@ public class TextBody implements Body, SizeAware {

        return countingOutputStream.getCount();
    }

    public String getEncoding() {
        return mEncoding;
    }
}
+15 −5
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@ package com.fsck.k9.message;


import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import android.app.PendingIntent;
@@ -22,8 +23,10 @@ import com.fsck.k9.mail.internet.MimeHeader;
import com.fsck.k9.mail.internet.MimeMessage;
import com.fsck.k9.mail.internet.MimeMessageHelper;
import com.fsck.k9.mail.internet.MimeMultipart;
import com.fsck.k9.mail.internet.MimeUtility;
import com.fsck.k9.mail.internet.TextBody;
import com.fsck.k9.mailstore.BinaryMemoryBody;
import org.apache.commons.io.IOUtils;
import org.apache.james.mime4j.util.MimeUtil;
import org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.util.OpenPgpApi;
@@ -97,8 +100,8 @@ public class PgpMessageBuilder extends MessageBuilder {
                pgpApiIntent = buildOpenPgpApiIntent(shouldSign, shouldEncrypt, isPgpInlineMode);
            }

            PendingIntent returnedPendingIntent =
                    launchOpenPgpApiIntent(pgpApiIntent, shouldEncrypt || isPgpInlineMode, isPgpInlineMode);
            PendingIntent returnedPendingIntent = launchOpenPgpApiIntent(
                    pgpApiIntent, shouldEncrypt || isPgpInlineMode, shouldEncrypt || !isPgpInlineMode, isPgpInlineMode);
            if (returnedPendingIntent != null) {
                queueMessageBuildPendingIntent(returnedPendingIntent, REQUEST_USER_INTERACTION);
                return;
@@ -154,7 +157,7 @@ public class PgpMessageBuilder extends MessageBuilder {
    }

    private PendingIntent launchOpenPgpApiIntent(@NonNull Intent openPgpIntent,
            boolean captureOutputPart, boolean writeBodyContentOnly) throws MessagingException {
            boolean captureOutputPart, boolean capturedOutputPartIs7Bit, boolean writeBodyContentOnly) throws MessagingException {
        final MimeBodyPart bodyPart = currentProcessedMimeMessage.toBodyPart();
        String[] contentType = currentProcessedMimeMessage.getHeader(MimeHeader.HEADER_CONTENT_TYPE);
        if (contentType.length > 0) {
@@ -168,7 +171,8 @@ public class PgpMessageBuilder extends MessageBuilder {
        OutputStream outputStream = null;
        if (captureOutputPart) {
            try {
                pgpResultTempBody = new BinaryTempFileBody(MimeUtil.ENC_7BIT);
                pgpResultTempBody = new BinaryTempFileBody(
                        capturedOutputPartIs7Bit ? MimeUtil.ENC_7BIT : MimeUtil.ENC_8BIT);
                outputStream = pgpResultTempBody.getOutputStream();
            } catch (IOException e) {
                throw new MessagingException("could not allocate temp file for storage!", e);
@@ -214,7 +218,9 @@ public class PgpMessageBuilder extends MessageBuilder {
            public void writeTo(OutputStream os) throws IOException {
                try {
                    if (writeBodyContentOnly) {
                        bodyPart.getBody().writeTo(os);
                        Body body = bodyPart.getBody();
                        InputStream inputStream = body.getInputStream();
                        IOUtils.copy(inputStream, os);
                    } else {
                        bodyPart.writeTo(os);
                    }
@@ -298,6 +304,10 @@ public class PgpMessageBuilder extends MessageBuilder {
            throw new IllegalStateException("call to mimeBuildInlineMessage while pgp/inline isn't enabled!");
        }

        boolean isCleartextSignature = !cryptoStatus.isEncryptionEnabled();
        if (isCleartextSignature) {
            inlineBodyPart.setEncoding(MimeUtil.ENC_QUOTED_PRINTABLE);
        }
        MimeMessageHelper.setBody(currentProcessedMimeMessage, inlineBodyPart);
    }

+3 −1
Original line number Diff line number Diff line
package com.fsck.k9.message;


import android.text.TextUtils;
import android.util.Log;

import com.fsck.k9.K9;
import com.fsck.k9.mail.Body;
import com.fsck.k9.helper.HtmlConverter;
import com.fsck.k9.mail.Body;
import com.fsck.k9.mail.internet.TextBody;


class TextBodyBuilder {
    private boolean mIncludeQuotedText = true;
    private boolean mReplyAfterQuote = false;
+22 −10
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@ package com.fsck.k9.message;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
@@ -23,11 +24,15 @@ import com.fsck.k9.activity.misc.Attachment;
import com.fsck.k9.mail.Address;
import com.fsck.k9.mail.BodyPart;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.internet.BinaryTempFileBody;
import com.fsck.k9.mail.internet.MimeMessage;
import com.fsck.k9.mail.internet.MimeMultipart;
import com.fsck.k9.mail.internet.MimeUtility;
import com.fsck.k9.mail.internet.TextBody;
import com.fsck.k9.message.MessageBuilder.Callback;
import com.fsck.k9.view.RecipientSelectView.Recipient;
import org.apache.commons.io.IOUtils;
import org.apache.james.mime4j.util.MimeUtil;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -54,7 +59,7 @@ import static org.mockito.Mockito.when;
public class PgpMessageBuilderTest {
    public static final long TEST_SIGN_KEY_ID = 123L;
    public static final long TEST_SELF_ENCRYPT_KEY_ID = 234L;
    public static final String TEST_MESSAGE_TEXT = "message text";
    public static final String TEST_MESSAGE_TEXT = "message text with a ☭ CCCP symbol";


    private ComposeCryptoStatusBuilder cryptoStatusBuilder = createDefaultComposeCryptoStatusBuilder();
@@ -138,10 +143,11 @@ public class PgpMessageBuilderTest {
        Assert.assertEquals("multipart/signed must consist of two parts", 2, multipart.getCount());

        BodyPart contentBodyPart = multipart.getBodyPart(0);
        Assert.assertEquals("first part must be the text content",
        Assert.assertEquals("first part must have content type text/plain",
                "text/plain", MimeUtility.getHeaderParameter(contentBodyPart.getContentType(), null));
        assertContentOfBodyPartEquals("content must match the supplied detached signature",
                contentBodyPart, TEST_MESSAGE_TEXT);
        Assert.assertTrue("signed message body must be TextBody", contentBodyPart.getBody() instanceof TextBody);
        Assert.assertEquals(MimeUtil.ENC_QUOTED_PRINTABLE, ((TextBody) contentBodyPart.getBody()).getEncoding());
        assertContentOfBodyPartEquals("content must match the message text", contentBodyPart, TEST_MESSAGE_TEXT);

        BodyPart signatureBodyPart = multipart.getBodyPart(1);
        Assert.assertEquals("second part must be pgp signature",
@@ -279,14 +285,17 @@ public class PgpMessageBuilderTest {
        Assert.assertEquals("multipart/encrypted must consist of two parts", 2, multipart.getCount());

        BodyPart dummyBodyPart = multipart.getBodyPart(0);
        Assert.assertEquals("second part must be pgp encrypted dummy part",
        Assert.assertEquals("first part must be pgp encrypted dummy part",
                "application/pgp-encrypted", dummyBodyPart.getContentType());
        assertContentOfBodyPartEquals("content must match the supplied detached signature",
                dummyBodyPart, "Version: 1");

        BodyPart signatureBodyPart = multipart.getBodyPart(1);
        Assert.assertEquals("second part must be octet-stream",
                "application/octet-stream", signatureBodyPart.getContentType());
        BodyPart encryptedBodyPart = multipart.getBodyPart(1);
        Assert.assertEquals("second part must be octet-stream of encrypted data",
                "application/octet-stream", encryptedBodyPart.getContentType());
        Assert.assertTrue("message body must be BinaryTempFileBody",
                encryptedBodyPart.getBody() instanceof BinaryTempFileBody);
        Assert.assertEquals(MimeUtil.ENC_7BIT, ((BinaryTempFileBody) encryptedBodyPart.getBody()).getEncoding());
    }

    @Test
@@ -322,7 +331,9 @@ public class PgpMessageBuilderTest {
        verifyNoMoreInteractions(mockCallback);

        MimeMessage message = captor.getValue();
        Assert.assertEquals("message must be text/plain", "text/plain", message.getMimeType());
        Assert.assertEquals("text/plain", message.getMimeType());
        Assert.assertTrue("message body must be BinaryTempFileBody", message.getBody() instanceof BinaryTempFileBody);
        Assert.assertEquals(MimeUtil.ENC_7BIT, ((BinaryTempFileBody) message.getBody()).getEncoding());
    }

    @Test
@@ -417,7 +428,8 @@ public class PgpMessageBuilderTest {
    private static void assertContentOfBodyPartEquals(String reason, BodyPart signatureBodyPart, String expected) {
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            signatureBodyPart.getBody().writeTo(bos);
            InputStream inputStream = MimeUtility.decodeBody(signatureBodyPart.getBody());
            IOUtils.copy(inputStream, bos);
            Assert.assertEquals(reason, expected, new String(bos.toByteArray()));
        } catch (IOException | MessagingException e) {
            Assert.fail();