Merge pull request #2763 from k9mail/improve-crypto-structure-detection
Improve crypto structure detection
This commit is contained in:
commit
e266547bfc
14 changed files with 469 additions and 269 deletions
|
@ -162,6 +162,11 @@ public class MessageExtractor {
|
|||
Alternative alternative = new Alternative(text, html);
|
||||
outputViewableParts.add(alternative);
|
||||
}
|
||||
} else if (isSameMimeType(part.getMimeType(), "multipart/signed")) {
|
||||
if (multipart.getCount() > 0) {
|
||||
BodyPart bodyPart = multipart.getBodyPart(0);
|
||||
findViewablesAndAttachments(bodyPart, outputViewableParts, outputNonViewableParts);
|
||||
}
|
||||
} else {
|
||||
// For all other multipart parts we recurse to grab all viewable children.
|
||||
for (Part bodyPart : multipart.getBodyParts()) {
|
||||
|
|
|
@ -30,10 +30,10 @@ public class MimeBodyPart extends BodyPart {
|
|||
this(body, null);
|
||||
}
|
||||
|
||||
public MimeBodyPart(Body body, String mimeType) throws MessagingException {
|
||||
public MimeBodyPart(Body body, String contentType) throws MessagingException {
|
||||
mHeader = new MimeHeader();
|
||||
if (mimeType != null) {
|
||||
addHeader(MimeHeader.HEADER_CONTENT_TYPE, mimeType);
|
||||
if (contentType != null) {
|
||||
addHeader(MimeHeader.HEADER_CONTENT_TYPE, contentType);
|
||||
}
|
||||
MimeMessageHelper.setBody(this, body);
|
||||
}
|
||||
|
|
|
@ -81,6 +81,7 @@ public class MessageLoaderHelper {
|
|||
private LoaderManager loaderManager;
|
||||
@Nullable // make this explicitly nullable, make sure to cancel/ignore any operation if this is null
|
||||
private MessageLoaderCallbacks callback;
|
||||
private final boolean processSignedOnly;
|
||||
|
||||
|
||||
// transient state
|
||||
|
@ -100,6 +101,8 @@ public class MessageLoaderHelper {
|
|||
this.loaderManager = loaderManager;
|
||||
this.fragmentManager = fragmentManager;
|
||||
this.callback = callback;
|
||||
|
||||
processSignedOnly = K9.getOpenPgpSupportSignOnly();
|
||||
}
|
||||
|
||||
|
||||
|
@ -276,7 +279,7 @@ public class MessageLoaderHelper {
|
|||
retainCryptoHelperFragment.setData(messageCryptoHelper);
|
||||
}
|
||||
messageCryptoHelper.asyncStartOrResumeProcessingMessage(
|
||||
localMessage, messageCryptoCallback, cachedDecryptionResult);
|
||||
localMessage, messageCryptoCallback, cachedDecryptionResult, processSignedOnly);
|
||||
}
|
||||
|
||||
private void cancelAndClearCryptoOperation() {
|
||||
|
|
|
@ -18,6 +18,7 @@ import com.fsck.k9.mail.Multipart;
|
|||
import com.fsck.k9.mail.Part;
|
||||
import com.fsck.k9.mail.internet.MessageExtractor;
|
||||
import com.fsck.k9.mail.internet.MimeBodyPart;
|
||||
import com.fsck.k9.mail.internet.MimeMultipart;
|
||||
import com.fsck.k9.mail.internet.MimeUtility;
|
||||
import com.fsck.k9.mailstore.CryptoResultAnnotation;
|
||||
import com.fsck.k9.ui.crypto.MessageCryptoAnnotations;
|
||||
|
@ -25,7 +26,7 @@ import com.fsck.k9.ui.crypto.MessageCryptoAnnotations;
|
|||
import static com.fsck.k9.mail.internet.MimeUtility.isSameMimeType;
|
||||
|
||||
|
||||
public class MessageDecryptVerifier {
|
||||
public class MessageCryptoStructureDetector {
|
||||
private static final String MULTIPART_ENCRYPTED = "multipart/encrypted";
|
||||
private static final String MULTIPART_SIGNED = "multipart/signed";
|
||||
private static final String PROTOCOL_PARAMETER = "protocol";
|
||||
|
@ -109,7 +110,7 @@ public class MessageDecryptVerifier {
|
|||
return null;
|
||||
}
|
||||
|
||||
public static List<Part> findEncryptedParts(Part startPart) {
|
||||
public static List<Part> findMultipartEncryptedParts(Part startPart) {
|
||||
List<Part> encryptedParts = new ArrayList<>();
|
||||
Stack<Part> partsToCheck = new Stack<>();
|
||||
partsToCheck.push(startPart);
|
||||
|
@ -135,7 +136,7 @@ public class MessageDecryptVerifier {
|
|||
return encryptedParts;
|
||||
}
|
||||
|
||||
public static List<Part> findSignedParts(Part startPart, MessageCryptoAnnotations messageCryptoAnnotations) {
|
||||
public static List<Part> findMultipartSignedParts(Part startPart, MessageCryptoAnnotations messageCryptoAnnotations) {
|
||||
List<Part> signedParts = new ArrayList<>();
|
||||
Stack<Part> partsToCheck = new Stack<>();
|
||||
partsToCheck.push(startPart);
|
||||
|
@ -214,24 +215,59 @@ public class MessageDecryptVerifier {
|
|||
}
|
||||
|
||||
private static boolean isPartMultipartSigned(Part part) {
|
||||
return isSameMimeType(part.getMimeType(), MULTIPART_SIGNED);
|
||||
if (!isSameMimeType(part.getMimeType(), MULTIPART_SIGNED)) {
|
||||
return false;
|
||||
}
|
||||
if (! (part.getBody() instanceof MimeMultipart)) {
|
||||
return false;
|
||||
}
|
||||
MimeMultipart mimeMultipart = (MimeMultipart) part.getBody();
|
||||
if (mimeMultipart.getCount() != 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String protocolParameter = MimeUtility.getHeaderParameter(part.getContentType(), PROTOCOL_PARAMETER);
|
||||
|
||||
boolean dataUnavailable = protocolParameter == null && mimeMultipart.getBodyPart(0).getBody() == null;
|
||||
boolean protocolMatches = isSameMimeType(protocolParameter, mimeMultipart.getBodyPart(1).getMimeType());
|
||||
return dataUnavailable || protocolMatches;
|
||||
}
|
||||
|
||||
private static boolean isPartMultipartEncrypted(Part part) {
|
||||
return isSameMimeType(part.getMimeType(), MULTIPART_ENCRYPTED);
|
||||
if (!isSameMimeType(part.getMimeType(), MULTIPART_ENCRYPTED)) {
|
||||
return false;
|
||||
}
|
||||
if (! (part.getBody() instanceof MimeMultipart)) {
|
||||
return false;
|
||||
}
|
||||
MimeMultipart mimeMultipart = (MimeMultipart) part.getBody();
|
||||
if (mimeMultipart.getCount() != 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String protocolParameter = MimeUtility.getHeaderParameter(part.getContentType(), PROTOCOL_PARAMETER);
|
||||
|
||||
boolean dataUnavailable = protocolParameter == null && mimeMultipart.getBodyPart(1).getBody() == null;
|
||||
boolean protocolMatches = isSameMimeType(protocolParameter, mimeMultipart.getBodyPart(0).getMimeType());
|
||||
return dataUnavailable || protocolMatches;
|
||||
}
|
||||
|
||||
// TODO also guess by mime-type of contained part?
|
||||
public static boolean isPgpMimeEncryptedOrSignedPart(Part part) {
|
||||
String contentType = part.getContentType();
|
||||
String protocolParameter = MimeUtility.getHeaderParameter(contentType, PROTOCOL_PARAMETER);
|
||||
public static boolean isMultipartEncryptedOpenPgpProtocol(Part part) {
|
||||
if (!isSameMimeType(part.getMimeType(), MULTIPART_ENCRYPTED)) {
|
||||
throw new IllegalArgumentException("Part is not multipart/encrypted!");
|
||||
}
|
||||
|
||||
boolean isPgpEncrypted = isSameMimeType(part.getMimeType(), MULTIPART_ENCRYPTED) &&
|
||||
APPLICATION_PGP_ENCRYPTED.equalsIgnoreCase(protocolParameter);
|
||||
boolean isPgpSigned = isSameMimeType(part.getMimeType(), MULTIPART_SIGNED) &&
|
||||
APPLICATION_PGP_SIGNATURE.equalsIgnoreCase(protocolParameter);
|
||||
String protocolParameter = MimeUtility.getHeaderParameter(part.getContentType(), PROTOCOL_PARAMETER);
|
||||
return APPLICATION_PGP_ENCRYPTED.equalsIgnoreCase(protocolParameter);
|
||||
}
|
||||
|
||||
return isPgpEncrypted || isPgpSigned;
|
||||
public static boolean isMultipartSignedOpenPgpProtocol(Part part) {
|
||||
if (!isSameMimeType(part.getMimeType(), MULTIPART_SIGNED)) {
|
||||
throw new IllegalArgumentException("Part is not multipart/signed!");
|
||||
}
|
||||
|
||||
String protocolParameter = MimeUtility.getHeaderParameter(part.getContentType(), PROTOCOL_PARAMETER);
|
||||
return APPLICATION_PGP_SIGNATURE.equalsIgnoreCase(protocolParameter);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
|
@ -28,6 +28,7 @@ import com.fsck.k9.message.html.HtmlProcessor;
|
|||
import com.fsck.k9.ui.crypto.MessageCryptoAnnotations;
|
||||
import com.fsck.k9.ui.crypto.MessageCryptoSplitter;
|
||||
import com.fsck.k9.ui.crypto.MessageCryptoSplitter.CryptoMessageParts;
|
||||
import org.openintents.openpgp.util.OpenPgpUtils;
|
||||
import timber.log.Timber;
|
||||
|
||||
import static com.fsck.k9.mail.internet.MimeUtility.getHeaderParameter;
|
||||
|
@ -227,7 +228,7 @@ public class MessageViewInfoExtractor {
|
|||
Part part = ((Textual)viewable).getPart();
|
||||
addHtmlDivider(html, part, prependDivider);
|
||||
|
||||
String t = MessageExtractor.getTextFromPart(part);
|
||||
String t = getTextFromPart(part);
|
||||
if (t == null) {
|
||||
t = "";
|
||||
} else if (viewable instanceof Flowed) {
|
||||
|
@ -264,7 +265,7 @@ public class MessageViewInfoExtractor {
|
|||
Part part = ((Textual)viewable).getPart();
|
||||
addTextDivider(text, part, prependDivider);
|
||||
|
||||
String t = MessageExtractor.getTextFromPart(part);
|
||||
String t = getTextFromPart(part);
|
||||
if (t == null) {
|
||||
t = "";
|
||||
} else if (viewable instanceof Html) {
|
||||
|
@ -315,6 +316,17 @@ public class MessageViewInfoExtractor {
|
|||
}
|
||||
}
|
||||
|
||||
private String getTextFromPart(Part part) {
|
||||
String textFromPart = MessageExtractor.getTextFromPart(part);
|
||||
|
||||
String extractedClearsignedMessage = OpenPgpUtils.extractClearsignedMessage(textFromPart);
|
||||
if (extractedClearsignedMessage != null) {
|
||||
textFromPart = extractedClearsignedMessage;
|
||||
}
|
||||
|
||||
return textFromPart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the message part.
|
||||
*
|
||||
|
@ -504,7 +516,7 @@ public class MessageViewInfoExtractor {
|
|||
public final String text;
|
||||
public final String html;
|
||||
|
||||
public ViewableExtractedText(String text, String html) {
|
||||
ViewableExtractedText(String text, String html) {
|
||||
this.text = text;
|
||||
this.html = html;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package com.fsck.k9.message;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.fsck.k9.crypto.MessageDecryptVerifier;
|
||||
import com.fsck.k9.crypto.MessageCryptoStructureDetector;
|
||||
import com.fsck.k9.mail.Message;
|
||||
import com.fsck.k9.mail.Part;
|
||||
|
||||
|
@ -14,7 +14,7 @@ public class ComposePgpEnableByDefaultDecider {
|
|||
}
|
||||
|
||||
private boolean messageIsEncrypted(Message localMessage) {
|
||||
List<Part> encryptedParts = MessageDecryptVerifier.findEncryptedParts(localMessage);
|
||||
List<Part> encryptedParts = MessageCryptoStructureDetector.findMultipartEncryptedParts(localMessage);
|
||||
return !encryptedParts.isEmpty();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package com.fsck.k9.message;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.fsck.k9.crypto.MessageDecryptVerifier;
|
||||
import com.fsck.k9.crypto.MessageCryptoStructureDetector;
|
||||
import com.fsck.k9.mail.Message;
|
||||
import com.fsck.k9.mail.Part;
|
||||
|
||||
|
@ -15,7 +15,7 @@ public class ComposePgpInlineDecider {
|
|||
}
|
||||
|
||||
private boolean messageHasPgpInlineParts(Message localMessage) {
|
||||
List<Part> inlineParts = MessageDecryptVerifier.findPgpInlineParts(localMessage);
|
||||
List<Part> inlineParts = MessageCryptoStructureDetector.findPgpInlineParts(localMessage);
|
||||
return !inlineParts.isEmpty();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package com.fsck.k9.message.extractors;
|
|||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import com.fsck.k9.crypto.MessageDecryptVerifier;
|
||||
import com.fsck.k9.crypto.MessageCryptoStructureDetector;
|
||||
import com.fsck.k9.mail.Body;
|
||||
import com.fsck.k9.mail.BodyPart;
|
||||
import com.fsck.k9.mail.Message;
|
||||
|
@ -31,7 +31,7 @@ class EncryptionDetector {
|
|||
|
||||
private boolean containsInlinePgpEncryptedText(Message message) {
|
||||
Part textPart = textPartFinder.findFirstTextPart(message);
|
||||
return MessageDecryptVerifier.isPartPgpInlineEncrypted(textPart);
|
||||
return MessageCryptoStructureDetector.isPartPgpInlineEncrypted(textPart);
|
||||
}
|
||||
|
||||
private boolean containsPartWithMimeType(Part part, String... wantedMimeTypes) {
|
||||
|
|
|
@ -19,7 +19,7 @@ import android.support.annotation.WorkerThread;
|
|||
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.autocrypt.AutocryptOperations;
|
||||
import com.fsck.k9.crypto.MessageDecryptVerifier;
|
||||
import com.fsck.k9.crypto.MessageCryptoStructureDetector;
|
||||
import com.fsck.k9.mail.Address;
|
||||
import com.fsck.k9.mail.Body;
|
||||
import com.fsck.k9.mail.BodyPart;
|
||||
|
@ -52,7 +52,6 @@ import org.openintents.openpgp.util.OpenPgpApi.OpenPgpDataSink;
|
|||
import org.openintents.openpgp.util.OpenPgpApi.OpenPgpDataSource;
|
||||
import org.openintents.openpgp.util.OpenPgpServiceConnection;
|
||||
import org.openintents.openpgp.util.OpenPgpServiceConnection.OnBound;
|
||||
import org.openintents.openpgp.util.OpenPgpUtils;
|
||||
import timber.log.Timber;
|
||||
|
||||
|
||||
|
@ -84,6 +83,7 @@ public class MessageCryptoHelper {
|
|||
private State state;
|
||||
private CancelableBackgroundOperation cancelableBackgroundOperation;
|
||||
private boolean isCancelled;
|
||||
private boolean processSignedOnly;
|
||||
|
||||
private OpenPgpApi openPgpApi;
|
||||
private OpenPgpServiceConnection openPgpServiceConnection;
|
||||
|
@ -108,7 +108,7 @@ public class MessageCryptoHelper {
|
|||
}
|
||||
|
||||
public void asyncStartOrResumeProcessingMessage(Message message, MessageCryptoCallback callback,
|
||||
OpenPgpDecryptionResult cachedDecryptionResult) {
|
||||
OpenPgpDecryptionResult cachedDecryptionResult, boolean processSignedOnly) {
|
||||
if (this.currentMessage != null) {
|
||||
reattachCallback(message, callback);
|
||||
return;
|
||||
|
@ -119,21 +119,72 @@ public class MessageCryptoHelper {
|
|||
this.currentMessage = message;
|
||||
this.cachedDecryptionResult = cachedDecryptionResult;
|
||||
this.callback = callback;
|
||||
this.processSignedOnly = processSignedOnly;
|
||||
|
||||
nextStep();
|
||||
}
|
||||
|
||||
private void findPartsForEncryptionPass() {
|
||||
List<Part> encryptedParts = MessageDecryptVerifier.findEncryptedParts(currentMessage);
|
||||
processFoundEncryptedParts(encryptedParts);
|
||||
private void findPartsForMultipartEncryptionPass() {
|
||||
List<Part> encryptedParts = MessageCryptoStructureDetector.findMultipartEncryptedParts(currentMessage);
|
||||
for (Part part : encryptedParts) {
|
||||
if (!MessageHelper.isCompletePartAvailable(part)) {
|
||||
addErrorAnnotation(part, CryptoError.OPENPGP_ENCRYPTED_BUT_INCOMPLETE, MessageHelper.createEmptyPart());
|
||||
continue;
|
||||
}
|
||||
if (MessageCryptoStructureDetector.isMultipartEncryptedOpenPgpProtocol(part)) {
|
||||
CryptoPart cryptoPart = new CryptoPart(CryptoPartType.PGP_ENCRYPTED, part);
|
||||
partsToProcess.add(cryptoPart);
|
||||
continue;
|
||||
}
|
||||
addErrorAnnotation(part, CryptoError.ENCRYPTED_BUT_UNSUPPORTED, MessageHelper.createEmptyPart());
|
||||
}
|
||||
}
|
||||
|
||||
private void findPartsForSignaturePass() {
|
||||
List<Part> signedParts = MessageDecryptVerifier.findSignedParts(currentMessage, messageAnnotations);
|
||||
processFoundSignedParts(signedParts);
|
||||
private void findPartsForMultipartSignaturePass() {
|
||||
List<Part> signedParts = MessageCryptoStructureDetector
|
||||
.findMultipartSignedParts(currentMessage, messageAnnotations);
|
||||
for (Part part : signedParts) {
|
||||
if (!processSignedOnly) {
|
||||
boolean isEncapsulatedSignature =
|
||||
messageAnnotations.findKeyForAnnotationWithReplacementPart(part) != null;
|
||||
if (!isEncapsulatedSignature) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!MessageHelper.isCompletePartAvailable(part)) {
|
||||
MimeBodyPart replacementPart = getMultipartSignedContentPartIfAvailable(part);
|
||||
addErrorAnnotation(part, CryptoError.OPENPGP_SIGNED_BUT_INCOMPLETE, replacementPart);
|
||||
continue;
|
||||
}
|
||||
if (MessageCryptoStructureDetector.isMultipartSignedOpenPgpProtocol(part)) {
|
||||
CryptoPart cryptoPart = new CryptoPart(CryptoPartType.PGP_SIGNED, part);
|
||||
partsToProcess.add(cryptoPart);
|
||||
continue;
|
||||
}
|
||||
MimeBodyPart replacementPart = getMultipartSignedContentPartIfAvailable(part);
|
||||
addErrorAnnotation(part, CryptoError.SIGNED_BUT_UNSUPPORTED, replacementPart);
|
||||
}
|
||||
}
|
||||
|
||||
List<Part> inlineParts = MessageDecryptVerifier.findPgpInlineParts(currentMessage);
|
||||
processFoundInlinePgpParts(inlineParts);
|
||||
private void findPartsForPgpInlinePass() {
|
||||
List<Part> inlineParts = MessageCryptoStructureDetector.findPgpInlineParts(currentMessage);
|
||||
for (Part part : inlineParts) {
|
||||
if (!processSignedOnly && !MessageCryptoStructureDetector.isPartPgpInlineEncrypted(part)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!currentMessage.getFlags().contains(Flag.X_DOWNLOADED_FULL)) {
|
||||
if (MessageCryptoStructureDetector.isPartPgpInlineEncrypted(part)) {
|
||||
addErrorAnnotation(part, CryptoError.OPENPGP_ENCRYPTED_BUT_INCOMPLETE, NO_REPLACEMENT_PART);
|
||||
} else {
|
||||
addErrorAnnotation(part, CryptoError.OPENPGP_SIGNED_BUT_INCOMPLETE, NO_REPLACEMENT_PART);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
CryptoPart cryptoPart = new CryptoPart(CryptoPartType.PGP_INLINE, part);
|
||||
partsToProcess.add(cryptoPart);
|
||||
}
|
||||
}
|
||||
|
||||
private void findPartsForAutocryptPass() {
|
||||
|
@ -148,60 +199,11 @@ public class MessageCryptoHelper {
|
|||
}
|
||||
}
|
||||
|
||||
private void processFoundEncryptedParts(List<Part> foundParts) {
|
||||
for (Part part : foundParts) {
|
||||
if (!MessageHelper.isCompletePartAvailable(part)) {
|
||||
addErrorAnnotation(part, CryptoError.OPENPGP_ENCRYPTED_BUT_INCOMPLETE, MessageHelper.createEmptyPart());
|
||||
continue;
|
||||
}
|
||||
if (MessageDecryptVerifier.isPgpMimeEncryptedOrSignedPart(part)) {
|
||||
CryptoPart cryptoPart = new CryptoPart(CryptoPartType.PGP_ENCRYPTED, part);
|
||||
partsToProcess.add(cryptoPart);
|
||||
continue;
|
||||
}
|
||||
addErrorAnnotation(part, CryptoError.ENCRYPTED_BUT_UNSUPPORTED, MessageHelper.createEmptyPart());
|
||||
}
|
||||
}
|
||||
|
||||
private void processFoundSignedParts(List<Part> foundParts) {
|
||||
for (Part part : foundParts) {
|
||||
if (!MessageHelper.isCompletePartAvailable(part)) {
|
||||
MimeBodyPart replacementPart = getMultipartSignedContentPartIfAvailable(part);
|
||||
addErrorAnnotation(part, CryptoError.OPENPGP_SIGNED_BUT_INCOMPLETE, replacementPart);
|
||||
continue;
|
||||
}
|
||||
if (MessageDecryptVerifier.isPgpMimeEncryptedOrSignedPart(part)) {
|
||||
CryptoPart cryptoPart = new CryptoPart(CryptoPartType.PGP_SIGNED, part);
|
||||
partsToProcess.add(cryptoPart);
|
||||
continue;
|
||||
}
|
||||
MimeBodyPart replacementPart = getMultipartSignedContentPartIfAvailable(part);
|
||||
addErrorAnnotation(part, CryptoError.SIGNED_BUT_UNSUPPORTED, replacementPart);
|
||||
}
|
||||
}
|
||||
|
||||
private void addErrorAnnotation(Part part, CryptoError error, MimeBodyPart replacementPart) {
|
||||
CryptoResultAnnotation annotation = CryptoResultAnnotation.createErrorAnnotation(error, replacementPart);
|
||||
messageAnnotations.put(part, annotation);
|
||||
}
|
||||
|
||||
private void processFoundInlinePgpParts(List<Part> foundParts) {
|
||||
for (Part part : foundParts) {
|
||||
if (!currentMessage.getFlags().contains(Flag.X_DOWNLOADED_FULL)) {
|
||||
if (MessageDecryptVerifier.isPartPgpInlineEncrypted(part)) {
|
||||
addErrorAnnotation(part, CryptoError.OPENPGP_ENCRYPTED_BUT_INCOMPLETE, NO_REPLACEMENT_PART);
|
||||
} else {
|
||||
MimeBodyPart replacementPart = extractClearsignedTextReplacementPart(part);
|
||||
addErrorAnnotation(part, CryptoError.OPENPGP_SIGNED_BUT_INCOMPLETE, replacementPart);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
CryptoPart cryptoPart = new CryptoPart(CryptoPartType.PGP_INLINE, part);
|
||||
partsToProcess.add(cryptoPart);
|
||||
}
|
||||
}
|
||||
|
||||
private void nextStep() {
|
||||
if (isCancelled) {
|
||||
return;
|
||||
|
@ -396,7 +398,7 @@ public class MessageCryptoHelper {
|
|||
private void callAsyncDetachedVerify(Intent intent) throws IOException, MessagingException {
|
||||
OpenPgpDataSource dataSource = getDataSourceForSignedData(currentCryptoPart.part);
|
||||
|
||||
byte[] signatureData = MessageDecryptVerifier.getSignatureData(currentCryptoPart.part);
|
||||
byte[] signatureData = MessageCryptoStructureDetector.getSignatureData(currentCryptoPart.part);
|
||||
intent.putExtra(OpenPgpApi.EXTRA_DETACHED_SIGNATURE, signatureData);
|
||||
|
||||
openPgpApi.executeApiAsync(intent, dataSource, new IOpenPgpSinkResultCallback<Void>() {
|
||||
|
@ -645,17 +647,19 @@ public class MessageCryptoHelper {
|
|||
case START: {
|
||||
state = State.ENCRYPTION;
|
||||
|
||||
findPartsForEncryptionPass();
|
||||
findPartsForMultipartEncryptionPass();
|
||||
return;
|
||||
}
|
||||
|
||||
case ENCRYPTION: {
|
||||
state = State.SIGNATURES;
|
||||
state = State.SIGNATURES_AND_INLINE;
|
||||
|
||||
findPartsForSignaturePass();
|
||||
findPartsForMultipartSignaturePass();
|
||||
findPartsForPgpInlinePass();
|
||||
return;
|
||||
}
|
||||
case SIGNATURES: {
|
||||
|
||||
case SIGNATURES_AND_INLINE: {
|
||||
state = State.AUTOCRYPT;
|
||||
|
||||
findPartsForAutocryptPass();
|
||||
|
@ -780,22 +784,7 @@ public class MessageCryptoHelper {
|
|||
return replacementPart;
|
||||
}
|
||||
|
||||
private static MimeBodyPart extractClearsignedTextReplacementPart(Part part) {
|
||||
try {
|
||||
String clearsignedText = MessageExtractor.getTextFromPart(part);
|
||||
String replacementText = OpenPgpUtils.extractClearsignedMessage(clearsignedText);
|
||||
if (replacementText == null) {
|
||||
Timber.e("failed to extract clearsigned text for replacement part");
|
||||
return NO_REPLACEMENT_PART;
|
||||
}
|
||||
return new MimeBodyPart(new TextBody(replacementText), "text/plain");
|
||||
} catch (MessagingException e) {
|
||||
Timber.e(e, "failed to create clearsigned text replacement part");
|
||||
return NO_REPLACEMENT_PART;
|
||||
}
|
||||
}
|
||||
|
||||
private enum State {
|
||||
START, ENCRYPTION, SIGNATURES, AUTOCRYPT, FINISHED
|
||||
START, ENCRYPTION, SIGNATURES_AND_INLINE, AUTOCRYPT, FINISHED
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import java.util.List;
|
|||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.fsck.k9.crypto.MessageDecryptVerifier;
|
||||
import com.fsck.k9.crypto.MessageCryptoStructureDetector;
|
||||
import com.fsck.k9.mail.Message;
|
||||
import com.fsck.k9.mail.Part;
|
||||
import com.fsck.k9.mailstore.CryptoResultAnnotation;
|
||||
|
@ -21,7 +21,7 @@ public class MessageCryptoSplitter {
|
|||
@Nullable
|
||||
public static CryptoMessageParts split(@NonNull Message message, @Nullable MessageCryptoAnnotations annotations) {
|
||||
ArrayList<Part> extraParts = new ArrayList<>();
|
||||
Part primaryPart = MessageDecryptVerifier.findPrimaryEncryptedOrSignedPart(message, extraParts);
|
||||
Part primaryPart = MessageCryptoStructureDetector.findPrimaryEncryptedOrSignedPart(message, extraParts);
|
||||
if (primaryPart == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -7,20 +7,19 @@ import java.util.List;
|
|||
import com.fsck.k9.K9RobolectricTestRunner;
|
||||
import com.fsck.k9.mail.BodyPart;
|
||||
import com.fsck.k9.mail.Message;
|
||||
import com.fsck.k9.mail.MessagingException;
|
||||
import com.fsck.k9.mail.Multipart;
|
||||
import com.fsck.k9.mail.Part;
|
||||
import com.fsck.k9.mail.internet.MimeBodyPart;
|
||||
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.TextBody;
|
||||
import com.fsck.k9.ui.crypto.MessageCryptoAnnotations;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import static com.fsck.k9.message.TestMessageConstructionUtils.bodypart;
|
||||
import static com.fsck.k9.message.TestMessageConstructionUtils.messageFromBody;
|
||||
import static com.fsck.k9.message.TestMessageConstructionUtils.multipart;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
@ -29,13 +28,12 @@ import static org.junit.Assert.assertTrue;
|
|||
import static org.mockito.Mockito.mock;
|
||||
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
@RunWith(K9RobolectricTestRunner.class)
|
||||
@Config(manifest = Config.NONE)
|
||||
public class MessageDecryptVerifierTest {
|
||||
private static final String MIME_TYPE_MULTIPART_ENCRYPTED = "multipart/encrypted";
|
||||
private MessageCryptoAnnotations messageCryptoAnnotations = mock(MessageCryptoAnnotations.class);
|
||||
private static final String PROTCOL_PGP_ENCRYPTED = "application/pgp-encrypted";
|
||||
private static final String PGP_INLINE_DATA = "" +
|
||||
public class MessageCryptoStructureDetectorTest {
|
||||
MessageCryptoAnnotations messageCryptoAnnotations = mock(MessageCryptoAnnotations.class);
|
||||
static final String PGP_INLINE_DATA = "" +
|
||||
"-----BEGIN PGP MESSAGE-----\n" +
|
||||
"Header: Value\n" +
|
||||
"\n" +
|
||||
|
@ -49,7 +47,7 @@ public class MessageDecryptVerifierTest {
|
|||
Message message = new MimeMessage();
|
||||
MimeMessageHelper.setBody(message, new TextBody(PGP_INLINE_DATA));
|
||||
|
||||
Part cryptoPart = MessageDecryptVerifier.findPrimaryEncryptedOrSignedPart(message, outputExtraParts);
|
||||
Part cryptoPart = MessageCryptoStructureDetector.findPrimaryEncryptedOrSignedPart(message, outputExtraParts);
|
||||
|
||||
assertSame(message, cryptoPart);
|
||||
}
|
||||
|
@ -60,12 +58,12 @@ public class MessageDecryptVerifierTest {
|
|||
BodyPart pgpInlinePart = bodypart("text/plain", PGP_INLINE_DATA);
|
||||
Message message = messageFromBody(
|
||||
multipart("alternative",
|
||||
pgpInlinePart,
|
||||
pgpInlinePart,
|
||||
bodypart("text/html")
|
||||
)
|
||||
);
|
||||
|
||||
Part cryptoPart = MessageDecryptVerifier.findPrimaryEncryptedOrSignedPart(message, outputExtraParts);
|
||||
Part cryptoPart = MessageCryptoStructureDetector.findPrimaryEncryptedOrSignedPart(message, outputExtraParts);
|
||||
|
||||
assertSame(pgpInlinePart, cryptoPart);
|
||||
}
|
||||
|
@ -81,7 +79,7 @@ public class MessageDecryptVerifierTest {
|
|||
)
|
||||
);
|
||||
|
||||
Part cryptoPart = MessageDecryptVerifier.findPrimaryEncryptedOrSignedPart(message, outputExtraParts);
|
||||
Part cryptoPart = MessageCryptoStructureDetector.findPrimaryEncryptedOrSignedPart(message, outputExtraParts);
|
||||
|
||||
assertSame(pgpInlinePart, cryptoPart);
|
||||
}
|
||||
|
@ -101,7 +99,7 @@ public class MessageDecryptVerifierTest {
|
|||
)
|
||||
);
|
||||
|
||||
Part cryptoPart = MessageDecryptVerifier.findPrimaryEncryptedOrSignedPart(message, outputExtraParts);
|
||||
Part cryptoPart = MessageCryptoStructureDetector.findPrimaryEncryptedOrSignedPart(message, outputExtraParts);
|
||||
|
||||
assertSame(pgpInlinePart, cryptoPart);
|
||||
}
|
||||
|
@ -113,7 +111,7 @@ public class MessageDecryptVerifierTest {
|
|||
multipart("alternative")
|
||||
);
|
||||
|
||||
Part cryptoPart = MessageDecryptVerifier.findPrimaryEncryptedOrSignedPart(message, outputExtraParts);
|
||||
Part cryptoPart = MessageCryptoStructureDetector.findPrimaryEncryptedOrSignedPart(message, outputExtraParts);
|
||||
|
||||
assertNull(cryptoPart);
|
||||
}
|
||||
|
@ -125,7 +123,7 @@ public class MessageDecryptVerifierTest {
|
|||
multipart("mixed")
|
||||
);
|
||||
|
||||
Part cryptoPart = MessageDecryptVerifier.findPrimaryEncryptedOrSignedPart(message, outputExtraParts);
|
||||
Part cryptoPart = MessageCryptoStructureDetector.findPrimaryEncryptedOrSignedPart(message, outputExtraParts);
|
||||
|
||||
assertNull(cryptoPart);
|
||||
}
|
||||
|
@ -140,7 +138,7 @@ public class MessageDecryptVerifierTest {
|
|||
)
|
||||
);
|
||||
|
||||
Part cryptoPart = MessageDecryptVerifier.findPrimaryEncryptedOrSignedPart(message, outputExtraParts);
|
||||
Part cryptoPart = MessageCryptoStructureDetector.findPrimaryEncryptedOrSignedPart(message, outputExtraParts);
|
||||
|
||||
assertNull(cryptoPart);
|
||||
}
|
||||
|
@ -149,7 +147,7 @@ public class MessageDecryptVerifierTest {
|
|||
public void findEncryptedPartsShouldReturnEmptyListForEmptyMessage() throws Exception {
|
||||
MimeMessage emptyMessage = new MimeMessage();
|
||||
|
||||
List<Part> encryptedParts = MessageDecryptVerifier.findEncryptedParts(emptyMessage);
|
||||
List<Part> encryptedParts = MessageCryptoStructureDetector.findMultipartEncryptedParts(emptyMessage);
|
||||
|
||||
assertEquals(0, encryptedParts.size());
|
||||
}
|
||||
|
@ -159,56 +157,42 @@ public class MessageDecryptVerifierTest {
|
|||
MimeMessage message = new MimeMessage();
|
||||
message.setBody(new TextBody("message text"));
|
||||
|
||||
List<Part> encryptedParts = MessageDecryptVerifier.findEncryptedParts(message);
|
||||
List<Part> encryptedParts = MessageCryptoStructureDetector.findMultipartEncryptedParts(message);
|
||||
|
||||
assertEquals(0, encryptedParts.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findEncryptedPartsShouldReturnEmptyEncryptedPart() throws Exception {
|
||||
MimeMessage message = new MimeMessage();
|
||||
MimeMultipart multipartEncrypted = MimeMultipart.newInstance();
|
||||
multipartEncrypted.setSubType("encrypted");
|
||||
MimeMessageHelper.setBody(message, multipartEncrypted);
|
||||
setContentTypeWithProtocol(message, MIME_TYPE_MULTIPART_ENCRYPTED, PROTCOL_PGP_ENCRYPTED);
|
||||
public void findEncrypted__withMultipartEncrypted__shouldReturnRoot() throws Exception {
|
||||
Message message = messageFromBody(
|
||||
multipart("encrypted", "protocol=\"application/pgp-encrypted\"",
|
||||
bodypart("application/pgp-encrypted"),
|
||||
bodypart("application/octet-stream")
|
||||
)
|
||||
);
|
||||
|
||||
List<Part> encryptedParts = MessageDecryptVerifier.findEncryptedParts(message);
|
||||
List<Part> encryptedParts = MessageCryptoStructureDetector.findMultipartEncryptedParts(message);
|
||||
|
||||
assertEquals(1, encryptedParts.size());
|
||||
assertSame(message, encryptedParts.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findEncryptedPartsShouldReturnMultipleEncryptedParts() throws Exception {
|
||||
MimeMessage message = new MimeMessage();
|
||||
MimeMultipart multipartMixed = MimeMultipart.newInstance();
|
||||
multipartMixed.setSubType("mixed");
|
||||
MimeMessageHelper.setBody(message, multipartMixed);
|
||||
public void findEncrypted__withBadProtocol__shouldReturnEmpty() throws Exception {
|
||||
Message message = messageFromBody(
|
||||
multipart("encrypted", "protocol=\"application/not-pgp-encrypted\"",
|
||||
bodypart("application/pgp-encrypted"),
|
||||
bodypart("application/octet-stream", "content")
|
||||
)
|
||||
);
|
||||
|
||||
MimeMultipart multipartEncryptedOne = MimeMultipart.newInstance();
|
||||
multipartEncryptedOne.setSubType("encrypted");
|
||||
MimeBodyPart bodyPartOne = new MimeBodyPart(multipartEncryptedOne);
|
||||
setContentTypeWithProtocol(bodyPartOne, MIME_TYPE_MULTIPART_ENCRYPTED, PROTCOL_PGP_ENCRYPTED);
|
||||
multipartMixed.addBodyPart(bodyPartOne);
|
||||
List<Part> encryptedParts = MessageCryptoStructureDetector.findMultipartEncryptedParts(message);
|
||||
|
||||
MimeBodyPart bodyPartTwo = new MimeBodyPart(null, "text/plain");
|
||||
multipartMixed.addBodyPart(bodyPartTwo);
|
||||
|
||||
MimeMultipart multipartEncryptedThree = MimeMultipart.newInstance();
|
||||
multipartEncryptedThree.setSubType("encrypted");
|
||||
MimeBodyPart bodyPartThree = new MimeBodyPart(multipartEncryptedThree);
|
||||
setContentTypeWithProtocol(bodyPartThree, MIME_TYPE_MULTIPART_ENCRYPTED, PROTCOL_PGP_ENCRYPTED);
|
||||
multipartMixed.addBodyPart(bodyPartThree);
|
||||
|
||||
List<Part> encryptedParts = MessageDecryptVerifier.findEncryptedParts(message);
|
||||
|
||||
assertEquals(2, encryptedParts.size());
|
||||
assertSame(bodyPartOne, encryptedParts.get(0));
|
||||
assertSame(bodyPartThree, encryptedParts.get(1));
|
||||
assertTrue(encryptedParts.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findEncrypted__withMultipartEncrypted__shouldReturnRoot() throws Exception {
|
||||
public void findEncrypted__withBadProtocolAndNoBody__shouldReturnRoot() throws Exception {
|
||||
Message message = messageFromBody(
|
||||
multipart("encrypted",
|
||||
bodypart("application/pgp-encrypted"),
|
||||
|
@ -216,24 +200,64 @@ public class MessageDecryptVerifierTest {
|
|||
)
|
||||
);
|
||||
|
||||
List<Part> encryptedParts = MessageDecryptVerifier.findEncryptedParts(message);
|
||||
List<Part> encryptedParts = MessageCryptoStructureDetector.findMultipartEncryptedParts(message);
|
||||
|
||||
assertEquals(1, encryptedParts.size());
|
||||
assertSame(message, encryptedParts.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findEncrypted__withEmptyProtocol__shouldReturnEmpty() throws Exception {
|
||||
Message message = messageFromBody(
|
||||
multipart("encrypted",
|
||||
bodypart("application/pgp-encrypted"),
|
||||
bodypart("application/octet-stream", "content")
|
||||
)
|
||||
);
|
||||
|
||||
List<Part> encryptedParts = MessageCryptoStructureDetector.findMultipartEncryptedParts(message);
|
||||
|
||||
assertTrue(encryptedParts.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findEncrypted__withMissingEncryptedBody__shouldReturnEmpty() throws Exception {
|
||||
Message message = messageFromBody(
|
||||
multipart("encrypted", "protocol=\"application/pgp-encrypted\"",
|
||||
bodypart("application/pgp-encrypted")
|
||||
)
|
||||
);
|
||||
|
||||
List<Part> encryptedParts = MessageCryptoStructureDetector.findMultipartEncryptedParts(message);
|
||||
|
||||
assertTrue(encryptedParts.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findEncrypted__withBadStructure__shouldReturnEmpty() throws Exception {
|
||||
Message message = messageFromBody(
|
||||
multipart("encrypted", "protocol=\"application/pgp-encrypted\"",
|
||||
bodypart("application/octet-stream")
|
||||
)
|
||||
);
|
||||
|
||||
List<Part> encryptedParts = MessageCryptoStructureDetector.findMultipartEncryptedParts(message);
|
||||
|
||||
assertTrue(encryptedParts.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findEncrypted__withMultipartMixedSubEncrypted__shouldReturnRoot() throws Exception {
|
||||
Message message = messageFromBody(
|
||||
multipart("mixed",
|
||||
multipart("encrypted",
|
||||
multipart("encrypted", "protocol=\"application/pgp-encrypted\"",
|
||||
bodypart("application/pgp-encrypted"),
|
||||
bodypart("application/octet-stream")
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
List<Part> encryptedParts = MessageDecryptVerifier.findEncryptedParts(message);
|
||||
List<Part> encryptedParts = MessageCryptoStructureDetector.findMultipartEncryptedParts(message);
|
||||
|
||||
assertEquals(1, encryptedParts.size());
|
||||
assertSame(getPart(message, 0), encryptedParts.get(0));
|
||||
|
@ -244,18 +268,18 @@ public class MessageDecryptVerifierTest {
|
|||
throws Exception {
|
||||
Message message = messageFromBody(
|
||||
multipart("mixed",
|
||||
multipart("encrypted",
|
||||
multipart("encrypted", "protocol=\"application/pgp-encrypted\"",
|
||||
bodypart("application/pgp-encrypted"),
|
||||
bodypart("application/octet-stream")
|
||||
),
|
||||
multipart("encrypted",
|
||||
multipart("encrypted", "protocol=\"application/pgp-encrypted\"",
|
||||
bodypart("application/pgp-encrypted"),
|
||||
bodypart("application/octet-stream")
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
List<Part> encryptedParts = MessageDecryptVerifier.findEncryptedParts(message);
|
||||
List<Part> encryptedParts = MessageCryptoStructureDetector.findMultipartEncryptedParts(message);
|
||||
|
||||
assertEquals(2, encryptedParts.size());
|
||||
assertSame(getPart(message, 0), encryptedParts.get(0));
|
||||
|
@ -267,14 +291,14 @@ public class MessageDecryptVerifierTest {
|
|||
Message message = messageFromBody(
|
||||
multipart("mixed",
|
||||
bodypart("text/plain"),
|
||||
multipart("encrypted",
|
||||
multipart("encrypted", "protocol=\"application/pgp-encrypted\"",
|
||||
bodypart("application/pgp-encrypted"),
|
||||
bodypart("application/octet-stream")
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
List<Part> encryptedParts = MessageDecryptVerifier.findEncryptedParts(message);
|
||||
List<Part> encryptedParts = MessageCryptoStructureDetector.findMultipartEncryptedParts(message);
|
||||
|
||||
assertEquals(1, encryptedParts.size());
|
||||
assertSame(getPart(message, 1), encryptedParts.get(0));
|
||||
|
@ -284,7 +308,7 @@ public class MessageDecryptVerifierTest {
|
|||
public void findEncrypted__withMultipartMixedSubEncryptedAndText__shouldReturnEncrypted() throws Exception {
|
||||
Message message = messageFromBody(
|
||||
multipart("mixed",
|
||||
multipart("encrypted",
|
||||
multipart("encrypted", "protocol=\"application/pgp-encrypted\"",
|
||||
bodypart("application/pgp-encrypted"),
|
||||
bodypart("application/octet-stream")
|
||||
),
|
||||
|
@ -292,7 +316,7 @@ public class MessageDecryptVerifierTest {
|
|||
)
|
||||
);
|
||||
|
||||
List<Part> encryptedParts = MessageDecryptVerifier.findEncryptedParts(message);
|
||||
List<Part> encryptedParts = MessageCryptoStructureDetector.findMultipartEncryptedParts(message);
|
||||
|
||||
assertEquals(1, encryptedParts.size());
|
||||
assertSame(getPart(message, 0), encryptedParts.get(0));
|
||||
|
@ -301,22 +325,83 @@ public class MessageDecryptVerifierTest {
|
|||
@Test
|
||||
public void findSigned__withSimpleMultipartSigned__shouldReturnRoot() throws Exception {
|
||||
Message message = messageFromBody(
|
||||
multipart("signed",
|
||||
multipart("signed", "protocol=\"application/pgp-signature\"",
|
||||
bodypart("text/plain"),
|
||||
bodypart("application/pgp-signature")
|
||||
)
|
||||
);
|
||||
|
||||
List<Part> signedParts = MessageDecryptVerifier.findSignedParts(message, messageCryptoAnnotations);
|
||||
List<Part> signedParts = MessageCryptoStructureDetector
|
||||
.findMultipartSignedParts(message, messageCryptoAnnotations);
|
||||
|
||||
assertEquals(1, signedParts.size());
|
||||
assertSame(message, signedParts.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findSigned__withComplexMultipartSigned__shouldReturnRoot() throws Exception {
|
||||
public void findSigned__withNoProtocolAndNoBody__shouldReturnRoot() throws Exception {
|
||||
Message message = messageFromBody(
|
||||
multipart("signed",
|
||||
bodypart("text/plain"),
|
||||
bodypart("application/pgp-signature")
|
||||
)
|
||||
);
|
||||
|
||||
List<Part> signedParts = MessageCryptoStructureDetector
|
||||
.findMultipartSignedParts(message, messageCryptoAnnotations);
|
||||
|
||||
assertEquals(1, signedParts.size());
|
||||
assertSame(message, signedParts.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findSigned__withBadProtocol__shouldReturnNothing() throws Exception {
|
||||
Message message = messageFromBody(
|
||||
multipart("signed", "protocol=\"application/not-pgp-signature\"",
|
||||
bodypart("text/plain", "content"),
|
||||
bodypart("application/pgp-signature")
|
||||
)
|
||||
);
|
||||
|
||||
List<Part> signedParts = MessageCryptoStructureDetector
|
||||
.findMultipartSignedParts(message, messageCryptoAnnotations);
|
||||
|
||||
assertTrue(signedParts.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findSigned__withEmptyProtocol__shouldReturnRoot() throws Exception {
|
||||
Message message = messageFromBody(
|
||||
multipart("signed",
|
||||
bodypart("text/plain", "content"),
|
||||
bodypart("application/pgp-signature")
|
||||
)
|
||||
);
|
||||
|
||||
List<Part> signedParts = MessageCryptoStructureDetector
|
||||
.findMultipartSignedParts(message, messageCryptoAnnotations);
|
||||
|
||||
assertTrue(signedParts.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findSigned__withMissingSignature__shouldReturnEmpty() throws Exception {
|
||||
Message message = messageFromBody(
|
||||
multipart("signed", "protocol=\"application/pgp-signature\"",
|
||||
bodypart("text/plain")
|
||||
)
|
||||
);
|
||||
|
||||
List<Part> signedParts = MessageCryptoStructureDetector
|
||||
.findMultipartSignedParts(message, messageCryptoAnnotations);
|
||||
|
||||
assertTrue(signedParts.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findSigned__withComplexMultipartSigned__shouldReturnRoot() throws Exception {
|
||||
Message message = messageFromBody(
|
||||
multipart("signed", "protocol=\"application/pgp-signature\"",
|
||||
multipart("mixed",
|
||||
bodypart("text/plain"),
|
||||
bodypart("application/pdf")
|
||||
|
@ -325,7 +410,8 @@ public class MessageDecryptVerifierTest {
|
|||
)
|
||||
);
|
||||
|
||||
List<Part> signedParts = MessageDecryptVerifier.findSignedParts(message, messageCryptoAnnotations);
|
||||
List<Part> signedParts = MessageCryptoStructureDetector
|
||||
.findMultipartSignedParts(message, messageCryptoAnnotations);
|
||||
|
||||
assertEquals(1, signedParts.size());
|
||||
assertSame(message, signedParts.get(0));
|
||||
|
@ -335,14 +421,15 @@ public class MessageDecryptVerifierTest {
|
|||
public void findEncrypted__withMultipartMixedSubSigned__shouldReturnSigned() throws Exception {
|
||||
Message message = messageFromBody(
|
||||
multipart("mixed",
|
||||
multipart("signed",
|
||||
bodypart("text/plain"),
|
||||
bodypart("application/pgp-signature")
|
||||
multipart("signed", "protocol=\"application/pgp-signature\"",
|
||||
bodypart("text/plain"),
|
||||
bodypart("application/pgp-signature")
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
List<Part> signedParts = MessageDecryptVerifier.findSignedParts(message, messageCryptoAnnotations);
|
||||
List<Part> signedParts = MessageCryptoStructureDetector
|
||||
.findMultipartSignedParts(message, messageCryptoAnnotations);
|
||||
|
||||
assertEquals(1, signedParts.size());
|
||||
assertSame(getPart(message, 0), signedParts.get(0));
|
||||
|
@ -352,7 +439,7 @@ public class MessageDecryptVerifierTest {
|
|||
public void findEncrypted__withMultipartMixedSubSignedAndText__shouldReturnSigned() throws Exception {
|
||||
Message message = messageFromBody(
|
||||
multipart("mixed",
|
||||
multipart("signed",
|
||||
multipart("signed", "application/pgp-signature",
|
||||
bodypart("text/plain"),
|
||||
bodypart("application/pgp-signature")
|
||||
),
|
||||
|
@ -360,7 +447,8 @@ public class MessageDecryptVerifierTest {
|
|||
)
|
||||
);
|
||||
|
||||
List<Part> signedParts = MessageDecryptVerifier.findSignedParts(message, messageCryptoAnnotations);
|
||||
List<Part> signedParts = MessageCryptoStructureDetector
|
||||
.findMultipartSignedParts(message, messageCryptoAnnotations);
|
||||
|
||||
assertEquals(1, signedParts.size());
|
||||
assertSame(getPart(message, 0), signedParts.get(0));
|
||||
|
@ -371,14 +459,15 @@ public class MessageDecryptVerifierTest {
|
|||
Message message = messageFromBody(
|
||||
multipart("mixed",
|
||||
bodypart("text/plain"),
|
||||
multipart("signed",
|
||||
multipart("signed", "application/pgp-signature",
|
||||
bodypart("text/plain"),
|
||||
bodypart("application/pgp-signature")
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
List<Part> signedParts = MessageDecryptVerifier.findSignedParts(message, messageCryptoAnnotations);
|
||||
List<Part> signedParts = MessageCryptoStructureDetector
|
||||
.findMultipartSignedParts(message, messageCryptoAnnotations);
|
||||
|
||||
assertEquals(1, signedParts.size());
|
||||
assertSame(getPart(message, 1), signedParts.get(0));
|
||||
|
@ -395,7 +484,7 @@ public class MessageDecryptVerifierTest {
|
|||
MimeMessage message = new MimeMessage();
|
||||
message.setBody(new TextBody(pgpInlineData));
|
||||
|
||||
assertTrue(MessageDecryptVerifier.isPartPgpInlineEncrypted(message));
|
||||
assertTrue(MessageCryptoStructureDetector.isPartPgpInlineEncrypted(message));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -410,8 +499,8 @@ public class MessageDecryptVerifierTest {
|
|||
MimeMessage message = new MimeMessage();
|
||||
message.setBody(new TextBody(pgpInlineData));
|
||||
|
||||
assertTrue(MessageDecryptVerifier.isPartPgpInlineEncryptedOrSigned(message));
|
||||
assertTrue(MessageDecryptVerifier.isPartPgpInlineEncrypted(message));
|
||||
assertTrue(MessageCryptoStructureDetector.isPartPgpInlineEncryptedOrSigned(message));
|
||||
assertTrue(MessageCryptoStructureDetector.isPartPgpInlineEncrypted(message));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -426,8 +515,8 @@ public class MessageDecryptVerifierTest {
|
|||
MimeMessage message = new MimeMessage();
|
||||
message.setBody(new TextBody(pgpInlineData));
|
||||
|
||||
assertFalse(MessageDecryptVerifier.isPartPgpInlineEncryptedOrSigned(message));
|
||||
assertFalse(MessageDecryptVerifier.isPartPgpInlineEncrypted(message));
|
||||
assertFalse(MessageCryptoStructureDetector.isPartPgpInlineEncryptedOrSigned(message));
|
||||
assertFalse(MessageCryptoStructureDetector.isPartPgpInlineEncrypted(message));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -444,7 +533,7 @@ public class MessageDecryptVerifierTest {
|
|||
MimeMessage message = new MimeMessage();
|
||||
message.setBody(new TextBody(pgpInlineData));
|
||||
|
||||
assertTrue(MessageDecryptVerifier.isPartPgpInlineEncryptedOrSigned(message));
|
||||
assertTrue(MessageCryptoStructureDetector.isPartPgpInlineEncryptedOrSigned(message));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -461,44 +550,14 @@ public class MessageDecryptVerifierTest {
|
|||
MimeMessage message = new MimeMessage();
|
||||
message.setBody(new TextBody(pgpInlineData));
|
||||
|
||||
assertFalse(MessageDecryptVerifier.isPartPgpInlineEncrypted(message));
|
||||
assertFalse(MessageCryptoStructureDetector.isPartPgpInlineEncrypted(message));
|
||||
}
|
||||
|
||||
MimeMessage messageFromBody(BodyPart bodyPart) throws MessagingException {
|
||||
MimeMessage message = new MimeMessage();
|
||||
MimeMessageHelper.setBody(message, bodyPart.getBody());
|
||||
return message;
|
||||
}
|
||||
|
||||
MimeBodyPart multipart(String type, BodyPart... subParts) throws MessagingException {
|
||||
MimeMultipart multiPart = MimeMultipart.newInstance();
|
||||
multiPart.setSubType(type);
|
||||
for (BodyPart subPart : subParts) {
|
||||
multiPart.addBodyPart(subPart);
|
||||
}
|
||||
return new MimeBodyPart(multiPart);
|
||||
}
|
||||
|
||||
BodyPart bodypart(String type) throws MessagingException {
|
||||
return new MimeBodyPart(null, type);
|
||||
}
|
||||
|
||||
BodyPart bodypart(String type, String text) throws MessagingException {
|
||||
TextBody textBody = new TextBody(text);
|
||||
return new MimeBodyPart(textBody, type);
|
||||
}
|
||||
|
||||
public static Part getPart(Part searchRootPart, int... indexes) {
|
||||
static Part getPart(Part searchRootPart, int... indexes) {
|
||||
Part part = searchRootPart;
|
||||
for (int index : indexes) {
|
||||
part = ((Multipart) part.getBody()).getBodyPart(index);
|
||||
}
|
||||
return part;
|
||||
}
|
||||
|
||||
//TODO: Find a cleaner way to do this
|
||||
private static void setContentTypeWithProtocol(Part part, String mimeType, String protocol)
|
||||
throws MessagingException {
|
||||
part.setHeader(MimeHeader.HEADER_CONTENT_TYPE, mimeType + "; protocol=\"" + protocol + "\"");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.fsck.k9.message;
|
||||
|
||||
|
||||
import com.fsck.k9.mail.Body;
|
||||
import com.fsck.k9.mail.BodyPart;
|
||||
import com.fsck.k9.mail.MessagingException;
|
||||
import com.fsck.k9.mail.internet.MimeBodyPart;
|
||||
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.TextBody;
|
||||
|
||||
|
||||
public class TestMessageConstructionUtils {
|
||||
public static MimeMessage messageFromBody(BodyPart bodyPart) throws MessagingException {
|
||||
MimeMessage message = new MimeMessage();
|
||||
MimeMessageHelper.setBody(message, bodyPart.getBody());
|
||||
if (bodyPart.getContentType() != null) {
|
||||
message.setHeader("Content-Type", bodyPart.getContentType());
|
||||
}
|
||||
message.setUid("msguid");
|
||||
return message;
|
||||
}
|
||||
|
||||
public static MimeBodyPart multipart(String type, BodyPart... subParts) throws MessagingException {
|
||||
return multipart(type, null, subParts);
|
||||
}
|
||||
|
||||
public static MimeBodyPart multipart(String type, String typeParameters, BodyPart... subParts) throws MessagingException {
|
||||
MimeMultipart multiPart = MimeMultipart.newInstance();
|
||||
multiPart.setSubType(type);
|
||||
for (BodyPart subPart : subParts) {
|
||||
multiPart.addBodyPart(subPart);
|
||||
}
|
||||
MimeBodyPart mimeBodyPart = new MimeBodyPart(multiPart);
|
||||
if (typeParameters != null) {
|
||||
mimeBodyPart.setHeader(MimeHeader.HEADER_CONTENT_TYPE,
|
||||
mimeBodyPart.getContentType() + "; " + typeParameters);
|
||||
}
|
||||
return mimeBodyPart;
|
||||
}
|
||||
|
||||
public static BodyPart bodypart(String type) throws MessagingException {
|
||||
return new MimeBodyPart(null, type);
|
||||
}
|
||||
|
||||
public static BodyPart bodypart(String type, String text) throws MessagingException {
|
||||
TextBody textBody = new TextBody(text);
|
||||
return new MimeBodyPart(textBody, type);
|
||||
}
|
||||
|
||||
public static BodyPart bodypart(String type, Body body) throws MessagingException {
|
||||
return new MimeBodyPart(body, type);
|
||||
}
|
||||
}
|
|
@ -14,10 +14,8 @@ import com.fsck.k9.mail.Address;
|
|||
import com.fsck.k9.mail.Body;
|
||||
import com.fsck.k9.mail.BodyPart;
|
||||
import com.fsck.k9.mail.Message;
|
||||
import com.fsck.k9.mail.Multipart;
|
||||
import com.fsck.k9.mail.internet.MimeBodyPart;
|
||||
import com.fsck.k9.mail.internet.MimeMessage;
|
||||
import com.fsck.k9.mail.internet.MimeMultipart;
|
||||
import com.fsck.k9.mail.internet.TextBody;
|
||||
import com.fsck.k9.mailstore.CryptoResultAnnotation;
|
||||
import com.fsck.k9.mailstore.CryptoResultAnnotation.CryptoError;
|
||||
|
@ -37,11 +35,13 @@ import org.robolectric.RobolectricTestRunner;
|
|||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import static com.fsck.k9.message.TestMessageConstructionUtils.bodypart;
|
||||
import static com.fsck.k9.message.TestMessageConstructionUtils.messageFromBody;
|
||||
import static com.fsck.k9.message.TestMessageConstructionUtils.multipart;
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertSame;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Matchers.same;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
@ -84,7 +84,7 @@ public class MessageCryptoHelperTest {
|
|||
message.setHeader("Content-Type", "text/plain");
|
||||
|
||||
MessageCryptoCallback messageCryptoCallback = mock(MessageCryptoCallback.class);
|
||||
messageCryptoHelper.asyncStartOrResumeProcessingMessage(message, messageCryptoCallback, null);
|
||||
messageCryptoHelper.asyncStartOrResumeProcessingMessage(message, messageCryptoCallback, null, false);
|
||||
|
||||
ArgumentCaptor<MessageCryptoAnnotations> captor = ArgumentCaptor.forClass(MessageCryptoAnnotations.class);
|
||||
verify(messageCryptoCallback).onCryptoOperationsFinished(captor.capture());
|
||||
|
@ -107,7 +107,7 @@ public class MessageCryptoHelperTest {
|
|||
|
||||
|
||||
MessageCryptoCallback messageCryptoCallback = mock(MessageCryptoCallback.class);
|
||||
messageCryptoHelper.asyncStartOrResumeProcessingMessage(message, messageCryptoCallback, null);
|
||||
messageCryptoHelper.asyncStartOrResumeProcessingMessage(message, messageCryptoCallback, null, false);
|
||||
|
||||
|
||||
ArgumentCaptor<MessageCryptoAnnotations> captor = ArgumentCaptor.forClass(MessageCryptoAnnotations.class);
|
||||
|
@ -124,12 +124,15 @@ public class MessageCryptoHelperTest {
|
|||
|
||||
@Test
|
||||
public void multipartSigned__withNullBody__shouldReturnSignedIncomplete() throws Exception {
|
||||
MimeMessage message = new MimeMessage();
|
||||
message.setUid("msguid");
|
||||
message.setHeader("Content-Type", "multipart/signed");
|
||||
Message message = messageFromBody(
|
||||
multipart("signed", "protocol=\"application/pgp-signature\"",
|
||||
bodypart("text/plain"),
|
||||
bodypart("application/pgp-signature")
|
||||
)
|
||||
);
|
||||
|
||||
MessageCryptoCallback messageCryptoCallback = mock(MessageCryptoCallback.class);
|
||||
messageCryptoHelper.asyncStartOrResumeProcessingMessage(message, messageCryptoCallback, null);
|
||||
messageCryptoHelper.asyncStartOrResumeProcessingMessage(message, messageCryptoCallback, null, true);
|
||||
|
||||
assertPartAnnotationHasState(message, messageCryptoCallback, CryptoError.OPENPGP_SIGNED_BUT_INCOMPLETE, null,
|
||||
null, null, null);
|
||||
|
@ -137,12 +140,15 @@ public class MessageCryptoHelperTest {
|
|||
|
||||
@Test
|
||||
public void multipartEncrypted__withNullBody__shouldReturnEncryptedIncomplete() throws Exception {
|
||||
MimeMessage message = new MimeMessage();
|
||||
message.setUid("msguid");
|
||||
message.setHeader("Content-Type", "multipart/encrypted");
|
||||
Message message = messageFromBody(
|
||||
multipart("encrypted", "protocol=\"application/pgp-encrypted\"",
|
||||
bodypart("application/pgp-encrypted"),
|
||||
bodypart("application/octet-stream")
|
||||
)
|
||||
);
|
||||
|
||||
MessageCryptoCallback messageCryptoCallback = mock(MessageCryptoCallback.class);
|
||||
messageCryptoHelper.asyncStartOrResumeProcessingMessage(message, messageCryptoCallback, null);
|
||||
messageCryptoHelper.asyncStartOrResumeProcessingMessage(message, messageCryptoCallback, null, false);
|
||||
|
||||
assertPartAnnotationHasState(
|
||||
message, messageCryptoCallback, CryptoError.OPENPGP_ENCRYPTED_BUT_INCOMPLETE, null, null, null, null);
|
||||
|
@ -150,13 +156,15 @@ public class MessageCryptoHelperTest {
|
|||
|
||||
@Test
|
||||
public void multipartEncrypted__withUnknownProtocol__shouldReturnEncryptedUnsupported() throws Exception {
|
||||
MimeMessage message = new MimeMessage();
|
||||
message.setUid("msguid");
|
||||
message.setHeader("Content-Type", "multipart/encrypted; protocol=\"unknown protocol\"");
|
||||
message.setBody(new MimeMultipart("multipart/encrypted", "--------"));
|
||||
Message message = messageFromBody(
|
||||
multipart("encrypted", "protocol=\"application/bad-protocol\"",
|
||||
bodypart("application/bad-protocol", "content"),
|
||||
bodypart("application/octet-stream", "content")
|
||||
)
|
||||
);
|
||||
|
||||
MessageCryptoCallback messageCryptoCallback = mock(MessageCryptoCallback.class);
|
||||
messageCryptoHelper.asyncStartOrResumeProcessingMessage(message, messageCryptoCallback, null);
|
||||
messageCryptoHelper.asyncStartOrResumeProcessingMessage(message, messageCryptoCallback, null, false);
|
||||
|
||||
assertPartAnnotationHasState(message, messageCryptoCallback, CryptoError.ENCRYPTED_BUT_UNSUPPORTED, null, null,
|
||||
null, null);
|
||||
|
@ -164,13 +172,15 @@ public class MessageCryptoHelperTest {
|
|||
|
||||
@Test
|
||||
public void multipartSigned__withUnknownProtocol__shouldReturnSignedUnsupported() throws Exception {
|
||||
MimeMessage message = new MimeMessage();
|
||||
message.setUid("msguid");
|
||||
message.setHeader("Content-Type", "multipart/signed; protocol=\"unknown protocol\"");
|
||||
message.setBody(new MimeMultipart("multipart/encrypted", "--------"));
|
||||
Message message = messageFromBody(
|
||||
multipart("signed", "protocol=\"application/bad-protocol\"",
|
||||
bodypart("text/plain", "content"),
|
||||
bodypart("application/bad-protocol", "content")
|
||||
)
|
||||
);
|
||||
|
||||
MessageCryptoCallback messageCryptoCallback = mock(MessageCryptoCallback.class);
|
||||
messageCryptoHelper.asyncStartOrResumeProcessingMessage(message, messageCryptoCallback, null);
|
||||
messageCryptoHelper.asyncStartOrResumeProcessingMessage(message, messageCryptoCallback, null, true);
|
||||
|
||||
assertPartAnnotationHasState(message, messageCryptoCallback, CryptoError.SIGNED_BUT_UNSUPPORTED, null, null,
|
||||
null, null);
|
||||
|
@ -178,18 +188,14 @@ public class MessageCryptoHelperTest {
|
|||
|
||||
@Test
|
||||
public void multipartSigned__shouldCallOpenPgpApiAsync() throws Exception {
|
||||
BodyPart signedBodyPart = spy(new MimeBodyPart(new TextBody("text")));
|
||||
BodyPart signatureBodyPart = new MimeBodyPart(new TextBody("text"));
|
||||
|
||||
Multipart messageBody = new MimeMultipart("boundary1");
|
||||
messageBody.addBodyPart(signedBodyPart);
|
||||
messageBody.addBodyPart(signatureBodyPart);
|
||||
|
||||
MimeMessage message = new MimeMessage();
|
||||
message.setUid("msguid");
|
||||
message.setHeader("Content-Type", "multipart/signed; protocol=\"application/pgp-signature\"");
|
||||
BodyPart signedBodyPart = spy(bodypart("text/plain", "content"));
|
||||
Message message = messageFromBody(
|
||||
multipart("signed", "protocol=\"application/pgp-signature\"",
|
||||
signedBodyPart,
|
||||
bodypart("application/pgp-signature", "content")
|
||||
)
|
||||
);
|
||||
message.setFrom(Address.parse("Test <test@example.org>")[0]);
|
||||
message.setBody(messageBody);
|
||||
|
||||
OutputStream outputStream = mock(OutputStream.class);
|
||||
|
||||
|
@ -204,21 +210,46 @@ public class MessageCryptoHelperTest {
|
|||
verifyNoMoreInteractions(autocryptOperations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipartSigned__withSignOnlyDisabled__shouldReturnNothing() throws Exception {
|
||||
Message message = messageFromBody(
|
||||
multipart("signed", "protocol=\"application/pgp-signature\"",
|
||||
bodypart("text/plain", "content"),
|
||||
bodypart("application/pgp-signature", "content")
|
||||
)
|
||||
);
|
||||
|
||||
MessageCryptoCallback messageCryptoCallback = mock(MessageCryptoCallback.class);
|
||||
messageCryptoHelper.asyncStartOrResumeProcessingMessage(message, messageCryptoCallback, null, false);
|
||||
|
||||
assertReturnsWithNoCryptoAnnotations(messageCryptoCallback);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipartSigned__withSignOnlyDisabledAndNullBody__shouldReturnNothing() throws Exception {
|
||||
Message message = messageFromBody(
|
||||
multipart("signed", "protocol=\"application/pgp-signature\"",
|
||||
bodypart("text/plain"),
|
||||
bodypart("application/pgp-signature")
|
||||
)
|
||||
);
|
||||
|
||||
MessageCryptoCallback messageCryptoCallback = mock(MessageCryptoCallback.class);
|
||||
messageCryptoHelper.asyncStartOrResumeProcessingMessage(message, messageCryptoCallback, null, false);
|
||||
|
||||
assertReturnsWithNoCryptoAnnotations(messageCryptoCallback);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipartEncrypted__shouldCallOpenPgpApiAsync() throws Exception {
|
||||
BodyPart dummyBodyPart = new MimeBodyPart(new TextBody("text"));
|
||||
Body encryptedBody = spy(new TextBody("encrypted data"));
|
||||
BodyPart encryptedBodyPart = spy(new MimeBodyPart(encryptedBody));
|
||||
|
||||
Multipart messageBody = new MimeMultipart("boundary1");
|
||||
messageBody.addBodyPart(dummyBodyPart);
|
||||
messageBody.addBodyPart(encryptedBodyPart);
|
||||
|
||||
MimeMessage message = new MimeMessage();
|
||||
message.setUid("msguid");
|
||||
message.setHeader("Content-Type", "multipart/encrypted; protocol=\"application/pgp-encrypted\"");
|
||||
Message message = messageFromBody(
|
||||
multipart("encrypted", "protocol=\"application/pgp-encrypted\"",
|
||||
bodypart("application/pgp-encrypted", "content"),
|
||||
bodypart("application/octet-stream", encryptedBody)
|
||||
)
|
||||
);
|
||||
message.setFrom(Address.parse("Test <test@example.org>")[0]);
|
||||
message.setBody(messageBody);
|
||||
|
||||
OutputStream outputStream = mock(OutputStream.class);
|
||||
|
||||
|
@ -248,7 +279,7 @@ public class MessageCryptoHelperTest {
|
|||
|
||||
private void processEncryptedMessageAndCaptureMocks(Message message, Body encryptedBody, OutputStream outputStream)
|
||||
throws Exception {
|
||||
messageCryptoHelper.asyncStartOrResumeProcessingMessage(message, messageCryptoCallback, null);
|
||||
messageCryptoHelper.asyncStartOrResumeProcessingMessage(message, messageCryptoCallback, null, false);
|
||||
|
||||
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
|
||||
ArgumentCaptor<OpenPgpDataSource> dataSourceCaptor = ArgumentCaptor.forClass(OpenPgpDataSource.class);
|
||||
|
@ -266,7 +297,7 @@ public class MessageCryptoHelperTest {
|
|||
|
||||
private void processSignedMessageAndCaptureMocks(Message message, BodyPart signedBodyPart,
|
||||
OutputStream outputStream) throws Exception {
|
||||
messageCryptoHelper.asyncStartOrResumeProcessingMessage(message, messageCryptoCallback, null);
|
||||
messageCryptoHelper.asyncStartOrResumeProcessingMessage(message, messageCryptoCallback, null, true);
|
||||
|
||||
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
|
||||
ArgumentCaptor<OpenPgpDataSource> dataSourceCaptor = ArgumentCaptor.forClass(OpenPgpDataSource.class);
|
||||
|
@ -282,6 +313,15 @@ public class MessageCryptoHelperTest {
|
|||
verify(signedBodyPart).writeTo(outputStream);
|
||||
}
|
||||
|
||||
private void assertReturnsWithNoCryptoAnnotations(MessageCryptoCallback messageCryptoCallback) {
|
||||
ArgumentCaptor<MessageCryptoAnnotations> captor = ArgumentCaptor.forClass(MessageCryptoAnnotations.class);
|
||||
verify(messageCryptoCallback).onCryptoOperationsFinished(captor.capture());
|
||||
verifyNoMoreInteractions(messageCryptoCallback);
|
||||
|
||||
MessageCryptoAnnotations annotations = captor.getValue();
|
||||
assertTrue(annotations.isEmpty());
|
||||
}
|
||||
|
||||
private void assertPartAnnotationHasState(Message message, MessageCryptoCallback messageCryptoCallback,
|
||||
CryptoError cryptoErrorState, MimeBodyPart replacementPart, OpenPgpDecryptionResult openPgpDecryptionResult,
|
||||
OpenPgpSignatureResult openPgpSignatureResult, PendingIntent openPgpPendingIntent) {
|
||||
|
|
|
@ -80,7 +80,7 @@ public class OpenPgpUtils {
|
|||
}
|
||||
|
||||
public static String extractClearsignedMessage(String text) {
|
||||
if (!text.startsWith(PGP_MARKER_CLEARSIGN_BEGIN_MESSAGE)) {
|
||||
if (text == null || !text.startsWith(PGP_MARKER_CLEARSIGN_BEGIN_MESSAGE)) {
|
||||
return null;
|
||||
}
|
||||
int endOfHeader = text.indexOf("\r\n\r\n") +4;
|
||||
|
|
Loading…
Reference in a new issue