mirror of
https://github.com/moparisthebest/k-9
synced 2024-11-27 11:42:16 -05:00
early support for detached signatures
This commit is contained in:
parent
38d3564c57
commit
712acf4481
@ -19,13 +19,13 @@ import static junit.framework.Assert.assertSame;
|
||||
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class MessageDecryptorTest {
|
||||
public class MessageDecryptVerifyerTest {
|
||||
|
||||
@Test
|
||||
public void findEncryptedPartsShouldReturnEmptyListForEmptyMessage() throws Exception {
|
||||
MimeMessage emptyMessage = new MimeMessage();
|
||||
|
||||
List<Part> encryptedParts = MessageDecryptor.findEncryptedParts(emptyMessage);
|
||||
List<Part> encryptedParts = MessageDecryptVerifyer.findEncryptedParts(emptyMessage);
|
||||
assertEquals(0, encryptedParts.size());
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@ public class MessageDecryptorTest {
|
||||
MimeMessage message = new MimeMessage();
|
||||
message.setBody(new TextBody("message text"));
|
||||
|
||||
List<Part> encryptedParts = MessageDecryptor.findEncryptedParts(message);
|
||||
List<Part> encryptedParts = MessageDecryptVerifyer.findEncryptedParts(message);
|
||||
assertEquals(0, encryptedParts.size());
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ public class MessageDecryptorTest {
|
||||
mulitpartEncrypted.setSubType("encrypted");
|
||||
MimeMessageHelper.setBody(message, mulitpartEncrypted);
|
||||
|
||||
List<Part> encryptedParts = MessageDecryptor.findEncryptedParts(message);
|
||||
List<Part> encryptedParts = MessageDecryptVerifyer.findEncryptedParts(message);
|
||||
assertEquals(1, encryptedParts.size());
|
||||
assertSame(message, encryptedParts.get(0));
|
||||
}
|
||||
@ -70,7 +70,7 @@ public class MessageDecryptorTest {
|
||||
MimeBodyPart bodyPartThree = new MimeBodyPart(mulitpartEncryptedThree);
|
||||
multipartMixed.addBodyPart(bodyPartThree);
|
||||
|
||||
List<Part> encryptedParts = MessageDecryptor.findEncryptedParts(message);
|
||||
List<Part> encryptedParts = MessageDecryptVerifyer.findEncryptedParts(message);
|
||||
assertEquals(2, encryptedParts.size());
|
||||
assertSame(bodyPartOne, encryptedParts.get(0));
|
||||
assertSame(bodyPartThree, encryptedParts.get(1));
|
@ -0,0 +1,106 @@
|
||||
package com.fsck.k9.crypto;
|
||||
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
import com.fsck.k9.mail.Body;
|
||||
import com.fsck.k9.mail.BodyPart;
|
||||
import com.fsck.k9.mail.MessagingException;
|
||||
import com.fsck.k9.mail.Multipart;
|
||||
import com.fsck.k9.mail.Part;
|
||||
|
||||
|
||||
public class MessageDecryptVerifyer {
|
||||
private static final String MULTIPART_ENCRYPTED = "multipart/encrypted";
|
||||
private static final String MULTIPART_SIGNED = "multipart/signed";
|
||||
private static final String PROTOCOL_PARAMETER = "protocol";
|
||||
private static final String APPLICATION_PGP_ENCRYPTED = "application/pgp-encrypted";
|
||||
private static final String APPLICATION_PGP_SIGNATURE = "application/pgp-signature";
|
||||
|
||||
public static List<Part> findEncryptedParts(Part startPart) {
|
||||
List<Part> encryptedParts = new ArrayList<Part>();
|
||||
Stack<Part> partsToCheck = new Stack<Part>();
|
||||
partsToCheck.push(startPart);
|
||||
|
||||
while (!partsToCheck.isEmpty()) {
|
||||
Part part = partsToCheck.pop();
|
||||
String mimeType = part.getMimeType();
|
||||
Body body = part.getBody();
|
||||
|
||||
if (MULTIPART_ENCRYPTED.equals(mimeType)) {
|
||||
encryptedParts.add(part);
|
||||
} else if (body instanceof Multipart) {
|
||||
Multipart multipart = (Multipart) body;
|
||||
for (int i = multipart.getCount() - 1; i >= 0; i--) {
|
||||
BodyPart bodyPart = multipart.getBodyPart(i);
|
||||
partsToCheck.push(bodyPart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return encryptedParts;
|
||||
}
|
||||
|
||||
public static List<Part> findSignedParts(Part startPart) {
|
||||
List<Part> signedParts = new ArrayList<Part>();
|
||||
Stack<Part> partsToCheck = new Stack<Part>();
|
||||
partsToCheck.push(startPart);
|
||||
|
||||
while (!partsToCheck.isEmpty()) {
|
||||
Part part = partsToCheck.pop();
|
||||
String mimeType = part.getMimeType();
|
||||
Body body = part.getBody();
|
||||
|
||||
if (MULTIPART_SIGNED.equals(mimeType)) {
|
||||
signedParts.add(part);
|
||||
} else if (body instanceof Multipart) {
|
||||
Multipart multipart = (Multipart) body;
|
||||
for (int i = multipart.getCount() - 1; i >= 0; i--) {
|
||||
BodyPart bodyPart = multipart.getBodyPart(i);
|
||||
partsToCheck.push(bodyPart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return signedParts;
|
||||
}
|
||||
|
||||
public static byte[] getSignatureData(Part part) throws IOException, MessagingException {
|
||||
|
||||
if (MULTIPART_SIGNED.equals(part.getMimeType())) {
|
||||
Body body = part.getBody();
|
||||
if (body instanceof Multipart) {
|
||||
Multipart multi = (Multipart) body;
|
||||
BodyPart signatureBody = multi.getBodyPart(1);
|
||||
if (APPLICATION_PGP_SIGNATURE.equals(signatureBody.getMimeType())) {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
signatureBody.getBody().writeTo(bos);
|
||||
return bos.toByteArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isPgpMimePart(Part part) {
|
||||
return isPgpMimeSignedPart(part) || isPgpMimeEncryptedPart(part);
|
||||
}
|
||||
|
||||
public static boolean isPgpMimeSignedPart(Part part) {
|
||||
return MULTIPART_SIGNED.equals(part.getMimeType());
|
||||
}
|
||||
|
||||
public static boolean isPgpMimeEncryptedPart(Part part) {
|
||||
//FIXME: Doesn't work right now because LocalMessage.getContentType() doesn't load headers from database
|
||||
// String contentType = part.getContentType();
|
||||
// String protocol = MimeUtility.getHeaderParameter(contentType, PROTOCOL_PARAMETER);
|
||||
// return APPLICATION_PGP_ENCRYPTED.equals(protocol);
|
||||
return MULTIPART_ENCRYPTED.equals(part.getMimeType());
|
||||
}
|
||||
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
package com.fsck.k9.crypto;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
import com.fsck.k9.mail.Body;
|
||||
import com.fsck.k9.mail.BodyPart;
|
||||
import com.fsck.k9.mail.Multipart;
|
||||
import com.fsck.k9.mail.Part;
|
||||
import com.fsck.k9.mail.internet.MimeUtility;
|
||||
|
||||
|
||||
public class MessageDecryptor {
|
||||
private static final String MULTIPART_ENCRYPTED = "multipart/encrypted";
|
||||
private static final String PROTOCOL_PARAMETER = "protocol";
|
||||
private static final String APPLICATION_PGP_ENCRYPTED = "application/pgp-encrypted";
|
||||
|
||||
public static List<Part> findEncryptedParts(Part startPart) {
|
||||
List<Part> encryptedParts = new ArrayList<Part>();
|
||||
Stack<Part> partsToCheck = new Stack<Part>();
|
||||
partsToCheck.push(startPart);
|
||||
|
||||
while (!partsToCheck.isEmpty()) {
|
||||
Part part = partsToCheck.pop();
|
||||
String mimeType = part.getMimeType();
|
||||
Body body = part.getBody();
|
||||
|
||||
if (MULTIPART_ENCRYPTED.equals(mimeType)) {
|
||||
encryptedParts.add(part);
|
||||
} else if (body instanceof Multipart) {
|
||||
Multipart multipart = (Multipart) body;
|
||||
for (int i = multipart.getCount() - 1; i >= 0; i--) {
|
||||
BodyPart bodyPart = multipart.getBodyPart(i);
|
||||
partsToCheck.push(bodyPart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return encryptedParts;
|
||||
}
|
||||
|
||||
public static boolean isPgpMimeEncryptedPart(Part part) {
|
||||
//FIXME: Doesn't work right now because LocalMessage.getContentType() doesn't load headers from database
|
||||
// String contentType = part.getContentType();
|
||||
// String protocol = MimeUtility.getHeaderParameter(contentType, PROTOCOL_PARAMETER);
|
||||
// return APPLICATION_PGP_ENCRYPTED.equals(protocol);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -24,13 +24,11 @@ import org.apache.james.mime4j.parser.MimeStreamParser;
|
||||
import org.apache.james.mime4j.stream.BodyDescriptor;
|
||||
import org.apache.james.mime4j.stream.Field;
|
||||
import org.apache.james.mime4j.stream.MimeConfig;
|
||||
import org.openintents.openpgp.OpenPgpError;
|
||||
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||
|
||||
|
||||
public class DecryptStreamParser {
|
||||
public static DecryptedBodyPart parse(InputStream inputStream) throws MessagingException, IOException {
|
||||
DecryptedBodyPart decryptedRootPart = new DecryptedBodyPart();
|
||||
public static OpenPgpResultBodyPart parse(InputStream inputStream) throws MessagingException, IOException {
|
||||
OpenPgpResultBodyPart decryptedRootPart = new OpenPgpResultBodyPart(true);
|
||||
|
||||
MimeConfig parserConfig = new MimeConfig();
|
||||
parserConfig.setMaxHeaderLen(-1);
|
||||
@ -66,10 +64,10 @@ public class DecryptStreamParser {
|
||||
|
||||
|
||||
private static class PartBuilder implements ContentHandler {
|
||||
private final DecryptedBodyPart decryptedRootPart;
|
||||
private final OpenPgpResultBodyPart decryptedRootPart;
|
||||
private final Stack<Object> stack = new Stack<Object>();
|
||||
|
||||
public PartBuilder(DecryptedBodyPart decryptedRootPart) throws MessagingException {
|
||||
public PartBuilder(OpenPgpResultBodyPart decryptedRootPart) throws MessagingException {
|
||||
this.decryptedRootPart = decryptedRootPart;
|
||||
}
|
||||
|
||||
@ -182,28 +180,4 @@ public class DecryptStreamParser {
|
||||
}
|
||||
}
|
||||
|
||||
public static class DecryptedBodyPart extends MimeBodyPart {
|
||||
private OpenPgpSignatureResult signatureResult;
|
||||
private OpenPgpError error;
|
||||
|
||||
public DecryptedBodyPart() throws MessagingException {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
public OpenPgpSignatureResult getSignatureResult() {
|
||||
return signatureResult;
|
||||
}
|
||||
|
||||
public void setSignatureResult(OpenPgpSignatureResult signatureResult) {
|
||||
this.signatureResult = signatureResult;
|
||||
}
|
||||
|
||||
public OpenPgpError getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public void setError(OpenPgpError error) {
|
||||
this.error = error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,9 @@ package com.fsck.k9.mailstore;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.R;
|
||||
import com.fsck.k9.crypto.MessageDecryptor;
|
||||
import com.fsck.k9.crypto.MessageDecryptVerifyer;
|
||||
import com.fsck.k9.mail.Address;
|
||||
import com.fsck.k9.mail.Body;
|
||||
import com.fsck.k9.mail.BodyPart;
|
||||
@ -20,7 +18,6 @@ import com.fsck.k9.mail.internet.MessageExtractor;
|
||||
import com.fsck.k9.mail.internet.MimeHeader;
|
||||
import com.fsck.k9.mail.internet.MimeUtility;
|
||||
import com.fsck.k9.mail.internet.Viewable;
|
||||
import com.fsck.k9.mailstore.DecryptStreamParser.DecryptedBodyPart;
|
||||
import com.fsck.k9.mailstore.MessageViewInfo.MessageViewContainer;
|
||||
import com.fsck.k9.provider.AttachmentProvider;
|
||||
import org.openintents.openpgp.OpenPgpError;
|
||||
@ -443,7 +440,7 @@ public class LocalMessageExtractor {
|
||||
// TODO fill from part
|
||||
OpenPgpSignatureResult pgpResult = getSignatureResultForPart(part);
|
||||
OpenPgpError pgpError = null;
|
||||
boolean wasEncrypted = false;
|
||||
boolean wasEncrypted = getPartWasEncrypted(part);
|
||||
PendingIntent pendingIntent = null;
|
||||
|
||||
containers.add(new MessageViewContainer(
|
||||
@ -454,6 +451,10 @@ public class LocalMessageExtractor {
|
||||
return new MessageViewInfo(containers, message);
|
||||
}
|
||||
|
||||
private static boolean getPartWasEncrypted(Part part) {
|
||||
return (part instanceof OpenPgpResultBodyPart) && ((OpenPgpResultBodyPart) part).wasEncrypted();
|
||||
}
|
||||
|
||||
public static List<Part> getCryptPieces(Part part) throws MessagingException {
|
||||
ArrayList<Part> parts = new ArrayList<Part>();
|
||||
if (!getCryptSubPieces(part, parts)) {
|
||||
@ -477,6 +478,9 @@ public class LocalMessageExtractor {
|
||||
parts.add(part);
|
||||
return true;
|
||||
}
|
||||
} else if (MessageDecryptVerifyer.isPgpMimeSignedPart(part)) {
|
||||
parts.add(part);
|
||||
return true;
|
||||
} else if (isPgpMimeDecryptedPart(part)) {
|
||||
parts.add(multi.getBodyPart(2));
|
||||
return true;
|
||||
@ -488,14 +492,21 @@ public class LocalMessageExtractor {
|
||||
public static boolean isPgpMimeDecryptedPart (Part part) {
|
||||
Body body = part.getBody();
|
||||
return (body instanceof Multipart)
|
||||
&& MessageDecryptor.isPgpMimeEncryptedPart(part)
|
||||
&& ((Multipart) part.getBody()).getBodyParts().size() == 3;
|
||||
&& MessageDecryptVerifyer.isPgpMimeEncryptedPart(part)
|
||||
&& ((Multipart) part.getBody()).getCount() == 3;
|
||||
}
|
||||
|
||||
private static OpenPgpSignatureResult getSignatureResultForPart(Part part) {
|
||||
if (part instanceof DecryptedBodyPart) {
|
||||
DecryptedBodyPart decryptedBodyPart = (DecryptedBodyPart) part;
|
||||
return decryptedBodyPart.getSignatureResult();
|
||||
if (part instanceof OpenPgpResultBodyPart) {
|
||||
OpenPgpResultBodyPart openPgpResultBodyPart = (OpenPgpResultBodyPart) part;
|
||||
return openPgpResultBodyPart.getSignatureResult();
|
||||
}
|
||||
if (MessageDecryptVerifyer.isPgpMimeSignedPart(part)) {
|
||||
Multipart multi = (Multipart) part.getBody();
|
||||
if (multi.getCount() == 3 && multi.getBodyPart(2) instanceof OpenPgpResultBodyPart) {
|
||||
OpenPgpResultBodyPart openPgpResultBodyPart = (OpenPgpResultBodyPart) multi.getBodyPart(2);
|
||||
return openPgpResultBodyPart.getSignatureResult();
|
||||
}
|
||||
}
|
||||
|
||||
return NO_SIGNATURE_RESULT;
|
||||
|
@ -0,0 +1,38 @@
|
||||
package com.fsck.k9.mailstore;
|
||||
|
||||
|
||||
import com.fsck.k9.mail.MessagingException;
|
||||
import com.fsck.k9.mail.internet.MimeBodyPart;
|
||||
import org.openintents.openpgp.OpenPgpError;
|
||||
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||
|
||||
|
||||
public class OpenPgpResultBodyPart extends MimeBodyPart {
|
||||
private boolean wasEncrypted;
|
||||
private OpenPgpSignatureResult signatureResult;
|
||||
private OpenPgpError error;
|
||||
|
||||
public OpenPgpResultBodyPart(boolean wasEncrypted) throws MessagingException {
|
||||
this.wasEncrypted = wasEncrypted;
|
||||
}
|
||||
|
||||
public OpenPgpSignatureResult getSignatureResult() {
|
||||
return signatureResult;
|
||||
}
|
||||
|
||||
public void setSignatureResult(OpenPgpSignatureResult signatureResult) {
|
||||
this.signatureResult = signatureResult;
|
||||
}
|
||||
|
||||
public OpenPgpError getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public void setError(OpenPgpError error) {
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public boolean wasEncrypted() {
|
||||
return wasEncrypted;
|
||||
}
|
||||
}
|
@ -47,7 +47,7 @@ import com.fsck.k9.activity.MessageList;
|
||||
import com.fsck.k9.activity.MessageReference;
|
||||
import com.fsck.k9.controller.MessagingController;
|
||||
import com.fsck.k9.controller.MessagingListener;
|
||||
import com.fsck.k9.crypto.MessageDecryptor;
|
||||
import com.fsck.k9.crypto.MessageDecryptVerifyer;
|
||||
import com.fsck.k9.crypto.OpenPgpApiHelper;
|
||||
import com.fsck.k9.crypto.PgpData;
|
||||
import com.fsck.k9.fragment.ConfirmationDialogFragment;
|
||||
@ -64,7 +64,7 @@ import com.fsck.k9.mail.Multipart;
|
||||
import com.fsck.k9.mail.Part;
|
||||
import com.fsck.k9.mailstore.AttachmentViewInfo;
|
||||
import com.fsck.k9.mailstore.DecryptStreamParser;
|
||||
import com.fsck.k9.mailstore.DecryptStreamParser.DecryptedBodyPart;
|
||||
import com.fsck.k9.mailstore.OpenPgpResultBodyPart;
|
||||
import com.fsck.k9.mailstore.LocalMessage;
|
||||
import com.fsck.k9.mailstore.MessageViewInfo;
|
||||
import com.fsck.k9.ui.message.DecodeMessageLoader;
|
||||
@ -139,10 +139,10 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
|
||||
private LoaderCallbacks<MessageViewInfo> decodeMessageLoaderCallback = new DecodeMessageLoaderCallback();
|
||||
private MessageViewInfo messageViewInfo;
|
||||
private AttachmentViewInfo currentAttachmentViewInfo;
|
||||
private Deque<Part> partsToDecrypt;
|
||||
private Deque<Part> partsToDecryptOrVerify;
|
||||
private OpenPgpApi openPgpApi;
|
||||
private Part currentlyDecryptingPart;
|
||||
private Intent currentDecryptingResult;
|
||||
private Part currentlyDecrypringOrVerifyingPart;
|
||||
private Intent currentCryptoResult;
|
||||
|
||||
|
||||
@Override
|
||||
@ -257,38 +257,42 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
|
||||
if (message.isBodyMissing()) {
|
||||
startDownloadingMessageBody(message);
|
||||
} else {
|
||||
decryptMessagePartsIfNecessary(message);
|
||||
decryptOrVerifyMessagePartsIfNecessary(message);
|
||||
}
|
||||
}
|
||||
|
||||
private void decryptMessagePartsIfNecessary(LocalMessage message) {
|
||||
List<Part> encryptedParts = MessageDecryptor.findEncryptedParts(message);
|
||||
if (!encryptedParts.isEmpty()) {
|
||||
partsToDecrypt = new ArrayDeque<Part>(encryptedParts);
|
||||
decryptNextPartOrStartExtractingTextAndAttachments();
|
||||
private void decryptOrVerifyMessagePartsIfNecessary(LocalMessage message) {
|
||||
List<Part> encryptedParts = MessageDecryptVerifyer.findEncryptedParts(message);
|
||||
List<Part> signedParts = MessageDecryptVerifyer.findSignedParts(message);
|
||||
if (!encryptedParts.isEmpty() || !signedParts.isEmpty()) {
|
||||
partsToDecryptOrVerify = new ArrayDeque<Part>();
|
||||
partsToDecryptOrVerify.addAll(encryptedParts);
|
||||
partsToDecryptOrVerify.addAll(signedParts);
|
||||
decryptOrVerifyNextPartOrStartExtractingTextAndAttachments();
|
||||
} else {
|
||||
startExtractingTextAndAttachments(message);
|
||||
}
|
||||
}
|
||||
|
||||
private void decryptNextPartOrStartExtractingTextAndAttachments() {
|
||||
if (partsToDecrypt.isEmpty()) {
|
||||
startExtractingTextAndAttachments(mMessage);
|
||||
private void decryptOrVerifyNextPartOrStartExtractingTextAndAttachments() {
|
||||
if (!partsToDecryptOrVerify.isEmpty()) {
|
||||
|
||||
Part part = partsToDecryptOrVerify.peekFirst();
|
||||
if (MessageDecryptVerifyer.isPgpMimePart(part)) {
|
||||
startDecryptingOrVerifyingPart(part);
|
||||
} else {
|
||||
partsToDecryptOrVerify.removeFirst();
|
||||
decryptOrVerifyNextPartOrStartExtractingTextAndAttachments();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Part part = partsToDecrypt.peekFirst();
|
||||
if (MessageDecryptor.isPgpMimeEncryptedPart(part)) {
|
||||
startDecryptingPart(part);
|
||||
} else {
|
||||
// Note: We currently only support PGP/MIME multipart/encrypted parts
|
||||
startExtractingTextAndAttachments(mMessage);
|
||||
|
||||
partsToDecrypt.removeFirst();
|
||||
decryptNextPartOrStartExtractingTextAndAttachments();
|
||||
}
|
||||
}
|
||||
|
||||
private void startDecryptingPart(Part part) {
|
||||
private void startDecryptingOrVerifyingPart(Part part) {
|
||||
Multipart multipart = (Multipart) part.getBody();
|
||||
if (multipart == null) {
|
||||
throw new RuntimeException("Downloading missing parts before decryption isn't supported yet");
|
||||
@ -297,7 +301,7 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
|
||||
if (!isBoundToCryptoProviderService()) {
|
||||
connectToCryptoProviderService();
|
||||
} else {
|
||||
decryptPart(part);
|
||||
decryptOrVerifyPart(part);
|
||||
}
|
||||
}
|
||||
|
||||
@ -313,7 +317,7 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
|
||||
public void onBound(IOpenPgpService service) {
|
||||
openPgpApi = new OpenPgpApi(getContext(), service);
|
||||
|
||||
decryptNextPartOrStartExtractingTextAndAttachments();
|
||||
decryptOrVerifyNextPartOrStartExtractingTextAndAttachments();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -323,8 +327,8 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
|
||||
}).bindToService();
|
||||
}
|
||||
|
||||
private void decryptPart(Part part) {
|
||||
currentlyDecryptingPart = part;
|
||||
private void decryptOrVerifyPart(Part part) {
|
||||
currentlyDecrypringOrVerifyingPart = part;
|
||||
decryptVerify(new Intent());
|
||||
}
|
||||
|
||||
@ -336,24 +340,66 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
|
||||
intent.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, accountName);
|
||||
|
||||
try {
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
PipedInputStream pipedInputStream = getPipedInputStreamForEncryptedData();
|
||||
PipedOutputStream decryptedOutputStream = getPipedOutputStreamForDecryptedData(latch);
|
||||
PipedInputStream pipedInputStream;
|
||||
PipedOutputStream decryptedOutputStream;
|
||||
final CountDownLatch latch;
|
||||
|
||||
if (MessageDecryptVerifyer.isPgpMimeSignedPart(currentlyDecrypringOrVerifyingPart)) {
|
||||
pipedInputStream = getPipedInputStreamForSignedData();
|
||||
|
||||
byte[] signatureData = MessageDecryptVerifyer.getSignatureData(currentlyDecrypringOrVerifyingPart);
|
||||
intent.putExtra(OpenPgpApi.EXTRA_DETACHED_SIGNATURE, signatureData);
|
||||
decryptedOutputStream = null;
|
||||
latch = null;
|
||||
} else {
|
||||
pipedInputStream = getPipedInputStreamForEncryptedData();
|
||||
latch = new CountDownLatch(1);
|
||||
decryptedOutputStream = getPipedOutputStreamForDecryptedData(latch);
|
||||
}
|
||||
|
||||
openPgpApi.executeApiAsync(intent, pipedInputStream, decryptedOutputStream, new IOpenPgpCallback() {
|
||||
@Override
|
||||
public void onReturn(Intent result) {
|
||||
currentCryptoResult = result;
|
||||
|
||||
if (latch != null) {
|
||||
Log.d(K9.LOG_TAG, "on result!");
|
||||
currentDecryptingResult = result;
|
||||
latch.countDown();
|
||||
return;
|
||||
}
|
||||
|
||||
onCryptoConverge(null);
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
Log.e(K9.LOG_TAG, "IOException", e);
|
||||
} catch (MessagingException e) {
|
||||
Log.e(K9.LOG_TAG, "MessagingException", e);
|
||||
}
|
||||
}
|
||||
|
||||
private PipedInputStream getPipedInputStreamForSignedData() throws IOException {
|
||||
PipedInputStream pipedInputStream = new PipedInputStream();
|
||||
|
||||
final PipedOutputStream out = new PipedOutputStream(pipedInputStream);
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Multipart multipartSignedMultipart = (Multipart) currentlyDecrypringOrVerifyingPart.getBody();
|
||||
BodyPart signatureBodyPart = multipartSignedMultipart.getBodyPart(0);
|
||||
Log.d(K9.LOG_TAG, "signed data type: " + signatureBodyPart.getMimeType());
|
||||
signatureBodyPart.writeTo(out);
|
||||
} catch (Exception e) {
|
||||
Log.e(K9.LOG_TAG, "Exception while writing message to crypto provider", e);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
|
||||
return pipedInputStream;
|
||||
}
|
||||
|
||||
private PipedInputStream getPipedInputStreamForEncryptedData() throws IOException {
|
||||
PipedInputStream pipedInputStream = new PipedInputStream();
|
||||
|
||||
@ -362,7 +408,7 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Multipart multipartEncryptedMultipart = (Multipart) currentlyDecryptingPart.getBody();
|
||||
Multipart multipartEncryptedMultipart = (Multipart) currentlyDecrypringOrVerifyingPart.getBody();
|
||||
BodyPart encryptionPayloadPart = multipartEncryptedMultipart.getBodyPart(1);
|
||||
Body encryptionPayloadBody = encryptionPayloadPart.getBody();
|
||||
encryptionPayloadBody.writeTo(out);
|
||||
@ -378,10 +424,10 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
|
||||
private PipedOutputStream getPipedOutputStreamForDecryptedData(final CountDownLatch latch) throws IOException {
|
||||
PipedOutputStream decryptedOutputStream = new PipedOutputStream();
|
||||
final PipedInputStream decryptedInputStream = new PipedInputStream(decryptedOutputStream);
|
||||
new AsyncTask<Void, Void, DecryptedBodyPart>() {
|
||||
new AsyncTask<Void, Void, OpenPgpResultBodyPart>() {
|
||||
@Override
|
||||
protected DecryptedBodyPart doInBackground(Void... params) {
|
||||
DecryptedBodyPart decryptedPart = null;
|
||||
protected OpenPgpResultBodyPart doInBackground(Void... params) {
|
||||
OpenPgpResultBodyPart decryptedPart = null;
|
||||
try {
|
||||
decryptedPart = DecryptStreamParser.parse(decryptedInputStream);
|
||||
|
||||
@ -396,21 +442,21 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(DecryptedBodyPart decryptedPart) {
|
||||
onDecryptionConverge(decryptedPart);
|
||||
protected void onPostExecute(OpenPgpResultBodyPart decryptedPart) {
|
||||
onCryptoConverge(decryptedPart);
|
||||
}
|
||||
}.execute();
|
||||
return decryptedOutputStream;
|
||||
}
|
||||
|
||||
private void onDecryptionConverge (DecryptedBodyPart decryptedPart) {
|
||||
private void onCryptoConverge(OpenPgpResultBodyPart openPgpResultBodyPart) {
|
||||
try {
|
||||
if (currentDecryptingResult == null) {
|
||||
if (currentCryptoResult == null) {
|
||||
Log.e(K9.LOG_TAG, "Internal error: we should have a result here!");
|
||||
return;
|
||||
}
|
||||
|
||||
int resultCode = currentDecryptingResult.getIntExtra(OpenPgpApi.RESULT_CODE, INVALID_OPENPGP_RESULT_CODE);
|
||||
int resultCode = currentCryptoResult.getIntExtra(OpenPgpApi.RESULT_CODE, INVALID_OPENPGP_RESULT_CODE);
|
||||
if (K9.DEBUG) {
|
||||
Log.d(K9.LOG_TAG, "OpenPGP API decryptVerify result code: " + resultCode);
|
||||
}
|
||||
@ -421,7 +467,7 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
|
||||
break;
|
||||
}
|
||||
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED: {
|
||||
PendingIntent pendingIntent = currentDecryptingResult.getParcelableExtra(OpenPgpApi.RESULT_INTENT);
|
||||
PendingIntent pendingIntent = currentCryptoResult.getParcelableExtra(OpenPgpApi.RESULT_INTENT);
|
||||
if (pendingIntent == null) {
|
||||
throw new AssertionError("Expecting PendingIntent on USER_INTERACTION_REQUIRED!");
|
||||
}
|
||||
@ -435,62 +481,68 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
|
||||
break;
|
||||
}
|
||||
case OpenPgpApi.RESULT_CODE_ERROR: {
|
||||
OpenPgpError error = currentDecryptingResult.getParcelableExtra(OpenPgpApi.RESULT_ERROR);
|
||||
OpenPgpError error = currentCryptoResult.getParcelableExtra(OpenPgpApi.RESULT_ERROR);
|
||||
|
||||
if (K9.DEBUG) {
|
||||
Log.w(K9.LOG_TAG, "OpenPGP API error: " + error.getMessage());
|
||||
}
|
||||
|
||||
onDecryptionFailed(error);
|
||||
onCryptoFailed(error);
|
||||
break;
|
||||
}
|
||||
case OpenPgpApi.RESULT_CODE_SUCCESS: {
|
||||
if (openPgpResultBodyPart == null) {
|
||||
openPgpResultBodyPart = new OpenPgpResultBodyPart(false);
|
||||
}
|
||||
OpenPgpSignatureResult signatureResult =
|
||||
currentDecryptingResult.getParcelableExtra(OpenPgpApi.RESULT_SIGNATURE);
|
||||
decryptedPart.setSignatureResult(signatureResult);
|
||||
currentCryptoResult.getParcelableExtra(OpenPgpApi.RESULT_SIGNATURE);
|
||||
openPgpResultBodyPart.setSignatureResult(signatureResult);
|
||||
|
||||
onDecryptionSuccess(decryptedPart);
|
||||
onCryptoSuccess(openPgpResultBodyPart);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (MessagingException e) {
|
||||
// catching the empty OpenPgpResultBodyPart constructor above - this can't actually happen
|
||||
Log.e(K9.LOG_TAG, "This shouldn't happen", e);
|
||||
} finally {
|
||||
currentDecryptingResult = null;
|
||||
currentCryptoResult = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void handleCryptoResult(int resultCode, Intent data) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
decryptNextPartOrStartExtractingTextAndAttachments();
|
||||
decryptOrVerifyNextPartOrStartExtractingTextAndAttachments();
|
||||
} else {
|
||||
//FIXME: don't pass null
|
||||
onDecryptionFailed(null);
|
||||
onCryptoFailed(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void onDecryptionSuccess(DecryptedBodyPart decryptedPart) {
|
||||
addDecryptedPartToMessage(decryptedPart);
|
||||
onDecryptionFinished();
|
||||
private void onCryptoSuccess(OpenPgpResultBodyPart decryptedPart) {
|
||||
addOpenPgpResultPartToMessage(decryptedPart);
|
||||
onCryptoFinished();
|
||||
}
|
||||
|
||||
private void addDecryptedPartToMessage(DecryptedBodyPart decryptedPart) {
|
||||
Multipart multipart = (Multipart) currentlyDecryptingPart.getBody();
|
||||
private void addOpenPgpResultPartToMessage(OpenPgpResultBodyPart decryptedPart) {
|
||||
Multipart multipart = (Multipart) currentlyDecrypringOrVerifyingPart.getBody();
|
||||
multipart.addBodyPart(decryptedPart);
|
||||
}
|
||||
|
||||
private void onDecryptionFailed(OpenPgpError error) {
|
||||
private void onCryptoFailed(OpenPgpError error) {
|
||||
try {
|
||||
DecryptedBodyPart errorPart = new DecryptedBodyPart();
|
||||
OpenPgpResultBodyPart errorPart = new OpenPgpResultBodyPart(false);
|
||||
errorPart.setError(error);
|
||||
addDecryptedPartToMessage(errorPart);
|
||||
addOpenPgpResultPartToMessage(errorPart);
|
||||
} catch (MessagingException e) {
|
||||
Log.e(K9.LOG_TAG, "This shouldn't happen", e);
|
||||
}
|
||||
onDecryptionFinished();
|
||||
onCryptoFinished();
|
||||
}
|
||||
|
||||
private void onDecryptionFinished() {
|
||||
partsToDecrypt.removeFirst();
|
||||
decryptNextPartOrStartExtractingTextAndAttachments();
|
||||
private void onCryptoFinished() {
|
||||
partsToDecryptOrVerify.removeFirst();
|
||||
decryptOrVerifyNextPartOrStartExtractingTextAndAttachments();
|
||||
}
|
||||
|
||||
private void onLoadMessageFromDatabaseFailed() {
|
||||
@ -527,7 +579,6 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
|
||||
}
|
||||
|
||||
private void onDecodeMessageFinished(MessageViewInfo messageContainer) {
|
||||
//TODO: handle decryption and signature verification
|
||||
this.messageViewInfo = messageContainer;
|
||||
showMessage(messageContainer);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user