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

Commit 520bc254 authored by Vincent Breitmoser's avatar Vincent Breitmoser
Browse files

split up autocrypt operations class into package

parent 05361adf
Loading
Loading
Loading
Loading
+31 −0
Original line number Diff line number Diff line
package com.fsck.k9.autocrypt;


import java.util.Map;


class AutocryptHeader {
    static final String AUTOCRYPT_HEADER = "Autocrypt";

    static final String AUTOCRYPT_PARAM_TO = "addr";
    static final String AUTOCRYPT_PARAM_KEY_DATA = "keydata";

    static final String AUTOCRYPT_PARAM_TYPE = "type";
    static final String AUTOCRYPT_TYPE_1 = "1";

    static final String AUTOCRYPT_PARAM_PREFER_ENCRYPT = "prefer-encrypt";
    static final String AUTOCRYPT_PREFER_ENCRYPT_MUTUAL = "mutual";


    final byte[] keyData;
    final String addr;
    final Map<String,String> parameters;
    final boolean isPreferEncryptMutual;

    AutocryptHeader(Map<String, String> parameters, String addr, byte[] keyData, boolean isPreferEncryptMutual) {
        this.parameters = parameters;
        this.addr = addr;
        this.keyData = keyData;
        this.isPreferEncryptMutual = isPreferEncryptMutual;
    }
}
+97 −0
Original line number Diff line number Diff line
package com.fsck.k9.crypto;
package com.fsck.k9.autocrypt;


import java.util.ArrayList;
import java.util.Date;
import java.util.Map;

import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;

import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.internet.MimeUtility;
import okio.ByteString;
import org.openintents.openpgp.AutocryptPeerUpdate;
import org.openintents.openpgp.util.OpenPgpApi;
import timber.log.Timber;


public class AutocryptOperations {
    private static final String AUTOCRYPT_HEADER = "Autocrypt";
class AutocryptHeaderParser {
    private static final AutocryptHeaderParser INSTANCE = new AutocryptHeaderParser();

    private static final String AUTOCRYPT_PARAM_TO = "addr";
    private static final String AUTOCRYPT_PARAM_KEY_DATA = "keydata";

    private static final String AUTOCRYPT_PARAM_TYPE = "type";
    private static final String AUTOCRYPT_TYPE_1 = "1";

    private static final String AUTOCRYPT_PARAM_PREFER_ENCRYPT = "prefer-encrypt";
    private static final String AUTOCRYPT_PREFER_ENCRYPT_MUTUAL = "mutual";


    public AutocryptOperations() {
    public static AutocryptHeaderParser getInstance() {
        return INSTANCE;
    }

    private AutocryptHeaderParser() { }

    public boolean addAutocryptPeerUpdateToIntentIfPresent(Message currentMessage, Intent intent) {
        AutocryptHeader autocryptHeader = getValidAutocryptHeader(currentMessage);
        if (autocryptHeader == null) {
            return false;
        }

        String messageFromAddress = currentMessage.getFrom()[0].getAddress();
        if (!autocryptHeader.addr.equalsIgnoreCase(messageFromAddress)) {
            return false;
        }

        Date messageDate = currentMessage.getSentDate();
        Date internalDate = currentMessage.getInternalDate();
        Date effectiveDate = messageDate.before(internalDate) ? messageDate : internalDate;

        AutocryptPeerUpdate data = AutocryptPeerUpdate.create(
                autocryptHeader.keyData, effectiveDate, autocryptHeader.isPreferEncryptMutual);
        intent.putExtra(OpenPgpApi.EXTRA_AUTOCRYPT_PEER_ID, messageFromAddress);
        intent.putExtra(OpenPgpApi.EXTRA_AUTOCRYPT_PEER_UPDATE, data);
        return true;
    }

    @Nullable
    @VisibleForTesting
    AutocryptHeader getValidAutocryptHeader(Message currentMessage) {
        String[] headers = currentMessage.getHeader(AUTOCRYPT_HEADER);
        String[] headers = currentMessage.getHeader(AutocryptHeader.AUTOCRYPT_HEADER);
        ArrayList<AutocryptHeader> autocryptHeaders = parseAllAutocryptHeaders(headers);

        boolean isSingleValidHeader = autocryptHeaders.size() == 1;
        return isSingleValidHeader ? autocryptHeaders.get(0) : null;
    }

    @NonNull
    private ArrayList<AutocryptHeader> parseAllAutocryptHeaders(String[] headers) {
        ArrayList<AutocryptHeader> autocryptHeaders = new ArrayList<>();
        for (String header : headers) {
            AutocryptHeader autocryptHeader = parseAutocryptHeader(header);
            if (autocryptHeader != null) {
                autocryptHeaders.add(autocryptHeader);
            }
        }
        return autocryptHeaders;
    }

    @Nullable
    private AutocryptHeader parseAutocryptHeader(String headerValue) {
        Map<String,String> parameters = MimeUtility.getAllHeaderParameters(headerValue);

        String type = parameters.remove(AUTOCRYPT_PARAM_TYPE);
        if (type != null && !type.equals(AUTOCRYPT_TYPE_1)) {
        String type = parameters.remove(AutocryptHeader.AUTOCRYPT_PARAM_TYPE);
        if (type != null && !type.equals(AutocryptHeader.AUTOCRYPT_TYPE_1)) {
            Timber.e("autocrypt: unsupported type parameter %s", type);
            return null;
        }

        String base64KeyData = parameters.remove(AUTOCRYPT_PARAM_KEY_DATA);
        String base64KeyData = parameters.remove(AutocryptHeader.AUTOCRYPT_PARAM_KEY_DATA);
        if (base64KeyData == null) {
            Timber.e("autocrypt: missing key parameter");
            return null;
@@ -101,15 +55,15 @@ public class AutocryptOperations {
            return null;
        }

        String to = parameters.remove(AUTOCRYPT_PARAM_TO);
        String to = parameters.remove(AutocryptHeader.AUTOCRYPT_PARAM_TO);
        if (to == null) {
            Timber.e("autocrypt: no to header!");
            return null;
        }

        boolean isPreferEncryptMutual = false;
        String preferEncrypt = parameters.remove(AUTOCRYPT_PARAM_PREFER_ENCRYPT);
        if (AUTOCRYPT_PREFER_ENCRYPT_MUTUAL.equalsIgnoreCase(preferEncrypt)) {
        String preferEncrypt = parameters.remove(AutocryptHeader.AUTOCRYPT_PARAM_PREFER_ENCRYPT);
        if (AutocryptHeader.AUTOCRYPT_PREFER_ENCRYPT_MUTUAL.equalsIgnoreCase(preferEncrypt)) {
            isPreferEncryptMutual = true;
        }

@@ -129,22 +83,15 @@ public class AutocryptOperations {
        return false;
    }

    public boolean hasAutocryptHeader(Message currentMessage) {
        return currentMessage.getHeader(AUTOCRYPT_HEADER).length > 0;
    @NonNull
    private ArrayList<AutocryptHeader> parseAllAutocryptHeaders(String[] headers) {
        ArrayList<AutocryptHeader> autocryptHeaders = new ArrayList<>();
        for (String header : headers) {
            AutocryptHeader autocryptHeader = parseAutocryptHeader(header);
            if (autocryptHeader != null) {
                autocryptHeaders.add(autocryptHeader);
            }

    @VisibleForTesting
    class AutocryptHeader {
        final byte[] keyData;
        final String addr;
        final Map<String,String> parameters;
        final boolean isPreferEncryptMutual;

        private AutocryptHeader(Map<String, String> parameters, String addr, byte[] keyData, boolean isPreferEncryptMutual) {
            this.parameters = parameters;
            this.addr = addr;
            this.keyData = keyData;
            this.isPreferEncryptMutual = isPreferEncryptMutual;
        }
        return autocryptHeaders;
    }
}
+45 −0
Original line number Diff line number Diff line
package com.fsck.k9.autocrypt;


import java.util.Date;

import android.content.Intent;

import com.fsck.k9.mail.Message;
import org.openintents.openpgp.AutocryptPeerUpdate;
import org.openintents.openpgp.util.OpenPgpApi;


public class AutocryptOperations {
    private final AutocryptHeaderParser autocryptHeaderParser;

    public AutocryptOperations() {
        this.autocryptHeaderParser = AutocryptHeaderParser.getInstance();
    }

    public boolean addAutocryptPeerUpdateToIntentIfPresent(Message currentMessage, Intent intent) {
        AutocryptHeader autocryptHeader = autocryptHeaderParser.getValidAutocryptHeader(currentMessage);
        if (autocryptHeader == null) {
            return false;
        }

        String messageFromAddress = currentMessage.getFrom()[0].getAddress();
        if (!autocryptHeader.addr.equalsIgnoreCase(messageFromAddress)) {
            return false;
        }

        Date messageDate = currentMessage.getSentDate();
        Date internalDate = currentMessage.getInternalDate();
        Date effectiveDate = messageDate.before(internalDate) ? messageDate : internalDate;

        AutocryptPeerUpdate data = AutocryptPeerUpdate.create(
                autocryptHeader.keyData, effectiveDate, autocryptHeader.isPreferEncryptMutual);
        intent.putExtra(OpenPgpApi.EXTRA_AUTOCRYPT_PEER_ID, messageFromAddress);
        intent.putExtra(OpenPgpApi.EXTRA_AUTOCRYPT_PEER_UPDATE, data);
        return true;
    }

    public boolean hasAutocryptHeader(Message currentMessage) {
        return currentMessage.getHeader(AutocryptHeader.AUTOCRYPT_HEADER).length > 0;
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ import android.support.annotation.Nullable;
import android.support.annotation.WorkerThread;

import com.fsck.k9.K9;
import com.fsck.k9.crypto.AutocryptOperations;
import com.fsck.k9.autocrypt.AutocryptOperations;
import com.fsck.k9.crypto.MessageDecryptVerifier;
import com.fsck.k9.mail.Address;
import com.fsck.k9.mail.Body;
@@ -94,7 +94,7 @@ public class MessageCryptoHelper {
        this.context = context.getApplicationContext();

        if (!K9.isOpenPgpProviderConfigured()) {
            throw new IllegalStateException("MessageCryptoHelper must only be called with a openpgp provider!");
            throw new IllegalStateException("MessageCryptoHelper must only be called with a OpenPGP provider!");
        }

        this.openPgpApiFactory = openPgpApiFactory;
+11 −11
Original line number Diff line number Diff line
package com.fsck.k9.crypto;
package com.fsck.k9.autocrypt;


import java.io.FileInputStream;
@@ -6,7 +6,6 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

import com.fsck.k9.crypto.AutocryptOperations.AutocryptHeader;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.internet.BinaryTempFileBody;
import com.fsck.k9.mail.internet.MimeMessage;
@@ -24,8 +23,9 @@ import static org.junit.Assert.assertNull;

@RunWith(RobolectricTestRunner.class)
@Config(manifest = Config.NONE, sdk = 21)
public class AutocryptOperationsTest {
    AutocryptOperations autocryptOperations = new AutocryptOperations();
@SuppressWarnings("WeakerAccess")
public class AutocryptHeaderParserTest {
    AutocryptHeaderParser autocryptHeaderParser = AutocryptHeaderParser.getInstance();

    @Before
    public void setUp() throws Exception {
@@ -38,7 +38,7 @@ public class AutocryptOperationsTest {
    public void getValidAutocryptHeader__withNoHeader__shouldReturnNull() throws Exception {
        MimeMessage message = parseFromResource("autocrypt/no_autocrypt.eml");

        AutocryptHeader autocryptHeader = autocryptOperations.getValidAutocryptHeader(message);
        AutocryptHeader autocryptHeader = autocryptHeaderParser.getValidAutocryptHeader(message);

        assertNull(autocryptHeader);
    }
@@ -47,7 +47,7 @@ public class AutocryptOperationsTest {
    public void getValidAutocryptHeader__withBrokenBase64__shouldReturnNull() throws Exception {
        MimeMessage message = parseFromResource("autocrypt/rsa2048-broken-base64.eml");

        AutocryptHeader autocryptHeader = autocryptOperations.getValidAutocryptHeader(message);
        AutocryptHeader autocryptHeader = autocryptHeaderParser.getValidAutocryptHeader(message);

        assertNull(autocryptHeader);
    }
@@ -56,7 +56,7 @@ public class AutocryptOperationsTest {
    public void getValidAutocryptHeader__withSimpleAutocrypt() throws Exception {
        MimeMessage message = parseFromResource("autocrypt/rsa2048-simple.eml");

        AutocryptHeader autocryptHeader = autocryptOperations.getValidAutocryptHeader(message);
        AutocryptHeader autocryptHeader = autocryptHeaderParser.getValidAutocryptHeader(message);

        assertNotNull(autocryptHeader);
        assertEquals("alice@testsuite.autocrypt.org", autocryptHeader.addr);
@@ -68,7 +68,7 @@ public class AutocryptOperationsTest {
    public void getValidAutocryptHeader__withExplicitType() throws Exception {
        MimeMessage message = parseFromResource("autocrypt/rsa2048-explicit-type.eml");

        AutocryptHeader autocryptHeader = autocryptOperations.getValidAutocryptHeader(message);
        AutocryptHeader autocryptHeader = autocryptHeaderParser.getValidAutocryptHeader(message);

        assertNotNull(autocryptHeader);
        assertEquals("alice@testsuite.autocrypt.org", autocryptHeader.addr);
@@ -79,7 +79,7 @@ public class AutocryptOperationsTest {
    public void getValidAutocryptHeader__withUnknownType__shouldReturnNull() throws Exception {
        MimeMessage message = parseFromResource("autocrypt/unknown-type.eml");

        AutocryptHeader autocryptHeader = autocryptOperations.getValidAutocryptHeader(message);
        AutocryptHeader autocryptHeader = autocryptHeaderParser.getValidAutocryptHeader(message);

        assertNull(autocryptHeader);
    }
@@ -88,7 +88,7 @@ public class AutocryptOperationsTest {
    public void getValidAutocryptHeader__withUnknownCriticalHeader__shouldReturnNull() throws Exception {
        MimeMessage message = parseFromResource("autocrypt/rsa2048-unknown-critical.eml");

        AutocryptHeader autocryptHeader = autocryptOperations.getValidAutocryptHeader(message);
        AutocryptHeader autocryptHeader = autocryptHeaderParser.getValidAutocryptHeader(message);

        assertNull(autocryptHeader);
    }
@@ -97,7 +97,7 @@ public class AutocryptOperationsTest {
    public void getValidAutocryptHeader__withUnknownNonCriticalHeader() throws Exception {
        MimeMessage message = parseFromResource("autocrypt/rsa2048-unknown-non-critical.eml");

        AutocryptHeader autocryptHeader = autocryptOperations.getValidAutocryptHeader(message);
        AutocryptHeader autocryptHeader = autocryptHeaderParser.getValidAutocryptHeader(message);

        assertNotNull(autocryptHeader);
        assertEquals("alice@testsuite.autocrypt.org", autocryptHeader.addr);
Loading