From 520bc2543de0047220988508b9d837a60e9d0468 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sun, 27 Aug 2017 23:41:03 +0200 Subject: [PATCH] split up autocrypt operations class into package --- .../fsck/k9/autocrypt/AutocryptHeader.java | 31 ++++ .../k9/autocrypt/AutocryptHeaderParser.java | 97 +++++++++++ .../k9/autocrypt/AutocryptOperations.java | 45 ++++++ .../fsck/k9/crypto/AutocryptOperations.java | 150 ------------------ .../k9/ui/crypto/MessageCryptoHelper.java | 4 +- .../AutocryptHeaderParserTest.java} | 22 +-- 6 files changed, 186 insertions(+), 163 deletions(-) create mode 100644 k9mail/src/main/java/com/fsck/k9/autocrypt/AutocryptHeader.java create mode 100644 k9mail/src/main/java/com/fsck/k9/autocrypt/AutocryptHeaderParser.java create mode 100644 k9mail/src/main/java/com/fsck/k9/autocrypt/AutocryptOperations.java delete mode 100644 k9mail/src/main/java/com/fsck/k9/crypto/AutocryptOperations.java rename k9mail/src/test/java/com/fsck/k9/{crypto/AutocryptOperationsTest.java => autocrypt/AutocryptHeaderParserTest.java} (80%) diff --git a/k9mail/src/main/java/com/fsck/k9/autocrypt/AutocryptHeader.java b/k9mail/src/main/java/com/fsck/k9/autocrypt/AutocryptHeader.java new file mode 100644 index 000000000..17a984799 --- /dev/null +++ b/k9mail/src/main/java/com/fsck/k9/autocrypt/AutocryptHeader.java @@ -0,0 +1,31 @@ +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 parameters; + final boolean isPreferEncryptMutual; + + AutocryptHeader(Map parameters, String addr, byte[] keyData, boolean isPreferEncryptMutual) { + this.parameters = parameters; + this.addr = addr; + this.keyData = keyData; + this.isPreferEncryptMutual = isPreferEncryptMutual; + } +} diff --git a/k9mail/src/main/java/com/fsck/k9/autocrypt/AutocryptHeaderParser.java b/k9mail/src/main/java/com/fsck/k9/autocrypt/AutocryptHeaderParser.java new file mode 100644 index 000000000..f42e83d38 --- /dev/null +++ b/k9mail/src/main/java/com/fsck/k9/autocrypt/AutocryptHeaderParser.java @@ -0,0 +1,97 @@ +package com.fsck.k9.autocrypt; + + +import java.util.ArrayList; +import java.util.Map; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import com.fsck.k9.mail.Message; +import com.fsck.k9.mail.internet.MimeUtility; +import okio.ByteString; +import timber.log.Timber; + + +class AutocryptHeaderParser { + private static final AutocryptHeaderParser INSTANCE = new AutocryptHeaderParser(); + + + public static AutocryptHeaderParser getInstance() { + return INSTANCE; + } + + private AutocryptHeaderParser() { } + + + @Nullable + AutocryptHeader getValidAutocryptHeader(Message currentMessage) { + String[] headers = currentMessage.getHeader(AutocryptHeader.AUTOCRYPT_HEADER); + ArrayList autocryptHeaders = parseAllAutocryptHeaders(headers); + + boolean isSingleValidHeader = autocryptHeaders.size() == 1; + return isSingleValidHeader ? autocryptHeaders.get(0) : null; + } + + @Nullable + private AutocryptHeader parseAutocryptHeader(String headerValue) { + Map parameters = MimeUtility.getAllHeaderParameters(headerValue); + + 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(AutocryptHeader.AUTOCRYPT_PARAM_KEY_DATA); + if (base64KeyData == null) { + Timber.e("autocrypt: missing key parameter"); + return null; + } + + ByteString byteString = ByteString.decodeBase64(base64KeyData); + if (byteString == null) { + Timber.e("autocrypt: error parsing base64 data"); + return null; + } + + 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(AutocryptHeader.AUTOCRYPT_PARAM_PREFER_ENCRYPT); + if (AutocryptHeader.AUTOCRYPT_PREFER_ENCRYPT_MUTUAL.equalsIgnoreCase(preferEncrypt)) { + isPreferEncryptMutual = true; + } + + if (hasCriticalParameters(parameters)) { + return null; + } + + return new AutocryptHeader(parameters, to, byteString.toByteArray(), isPreferEncryptMutual); + } + + private boolean hasCriticalParameters(Map parameters) { + for (String parameterName : parameters.keySet()) { + if (parameterName != null && !parameterName.startsWith("_")) { + return true; + } + } + return false; + } + + @NonNull + private ArrayList parseAllAutocryptHeaders(String[] headers) { + ArrayList autocryptHeaders = new ArrayList<>(); + for (String header : headers) { + AutocryptHeader autocryptHeader = parseAutocryptHeader(header); + if (autocryptHeader != null) { + autocryptHeaders.add(autocryptHeader); + } + } + return autocryptHeaders; + } +} diff --git a/k9mail/src/main/java/com/fsck/k9/autocrypt/AutocryptOperations.java b/k9mail/src/main/java/com/fsck/k9/autocrypt/AutocryptOperations.java new file mode 100644 index 000000000..6cdc6baa5 --- /dev/null +++ b/k9mail/src/main/java/com/fsck/k9/autocrypt/AutocryptOperations.java @@ -0,0 +1,45 @@ +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; + } +} diff --git a/k9mail/src/main/java/com/fsck/k9/crypto/AutocryptOperations.java b/k9mail/src/main/java/com/fsck/k9/crypto/AutocryptOperations.java deleted file mode 100644 index 54e3afd07..000000000 --- a/k9mail/src/main/java/com/fsck/k9/crypto/AutocryptOperations.java +++ /dev/null @@ -1,150 +0,0 @@ -package com.fsck.k9.crypto; - - -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"; - - 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 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); - ArrayList autocryptHeaders = parseAllAutocryptHeaders(headers); - - boolean isSingleValidHeader = autocryptHeaders.size() == 1; - return isSingleValidHeader ? autocryptHeaders.get(0) : null; - } - - @NonNull - private ArrayList parseAllAutocryptHeaders(String[] headers) { - ArrayList 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 parameters = MimeUtility.getAllHeaderParameters(headerValue); - - String type = parameters.remove(AUTOCRYPT_PARAM_TYPE); - if (type != null && !type.equals(AUTOCRYPT_TYPE_1)) { - Timber.e("autocrypt: unsupported type parameter %s", type); - return null; - } - - String base64KeyData = parameters.remove(AUTOCRYPT_PARAM_KEY_DATA); - if (base64KeyData == null) { - Timber.e("autocrypt: missing key parameter"); - return null; - } - - ByteString byteString = ByteString.decodeBase64(base64KeyData); - if (byteString == null) { - Timber.e("autocrypt: error parsing base64 data"); - return null; - } - - String to = parameters.remove(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)) { - isPreferEncryptMutual = true; - } - - if (hasCriticalParameters(parameters)) { - return null; - } - - return new AutocryptHeader(parameters, to, byteString.toByteArray(), isPreferEncryptMutual); - } - - private boolean hasCriticalParameters(Map parameters) { - for (String parameterName : parameters.keySet()) { - if (parameterName != null && !parameterName.startsWith("_")) { - return true; - } - } - return false; - } - - public boolean hasAutocryptHeader(Message currentMessage) { - return currentMessage.getHeader(AUTOCRYPT_HEADER).length > 0; - } - - @VisibleForTesting - class AutocryptHeader { - final byte[] keyData; - final String addr; - final Map parameters; - final boolean isPreferEncryptMutual; - - private AutocryptHeader(Map parameters, String addr, byte[] keyData, boolean isPreferEncryptMutual) { - this.parameters = parameters; - this.addr = addr; - this.keyData = keyData; - this.isPreferEncryptMutual = isPreferEncryptMutual; - } - } -} diff --git a/k9mail/src/main/java/com/fsck/k9/ui/crypto/MessageCryptoHelper.java b/k9mail/src/main/java/com/fsck/k9/ui/crypto/MessageCryptoHelper.java index 1afe63b5e..05f587aab 100644 --- a/k9mail/src/main/java/com/fsck/k9/ui/crypto/MessageCryptoHelper.java +++ b/k9mail/src/main/java/com/fsck/k9/ui/crypto/MessageCryptoHelper.java @@ -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; diff --git a/k9mail/src/test/java/com/fsck/k9/crypto/AutocryptOperationsTest.java b/k9mail/src/test/java/com/fsck/k9/autocrypt/AutocryptHeaderParserTest.java similarity index 80% rename from k9mail/src/test/java/com/fsck/k9/crypto/AutocryptOperationsTest.java rename to k9mail/src/test/java/com/fsck/k9/autocrypt/AutocryptHeaderParserTest.java index e9e11981b..fc1f0fc88 100644 --- a/k9mail/src/test/java/com/fsck/k9/crypto/AutocryptOperationsTest.java +++ b/k9mail/src/test/java/com/fsck/k9/autocrypt/AutocryptHeaderParserTest.java @@ -1,4 +1,4 @@ -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);