From 587fb3cca327a3422c3fc7bfd7f16dcf8b33487d Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 13 Jun 2016 13:32:14 +0200 Subject: [PATCH] refactored pgp decryption --- .../crypto/PgpDecryptionService.java | 297 ++++++++++-------- .../siacs/conversations/crypto/PgpEngine.java | 107 ------- .../siacs/conversations/entities/Account.java | 14 +- .../conversations/entities/Conversation.java | 2 +- .../http/HttpDownloadConnection.java | 2 +- .../conversations/parser/MessageParser.java | 6 +- .../services/XmppConnectionService.java | 17 +- .../ui/ConversationFragment.java | 91 +----- .../ui/adapter/MessageAdapter.java | 4 +- .../xmpp/jingle/JingleConnection.java | 2 +- src/main/res/values/strings.xml | 1 + 11 files changed, 207 insertions(+), 336 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java b/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java index ed67dc65f..2bc270c15 100644 --- a/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java +++ b/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java @@ -1,162 +1,181 @@ package eu.siacs.conversations.crypto; import android.app.PendingIntent; +import android.content.Intent; -import eu.siacs.conversations.entities.Message; -import eu.siacs.conversations.services.XmppConnectionService; -import eu.siacs.conversations.ui.UiCallback; +import org.openintents.openpgp.util.OpenPgpApi; -import java.util.Collections; -import java.util.LinkedList; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URL; +import java.util.ArrayDeque; import java.util.List; -import java.util.concurrent.ConcurrentHashMap; + +import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.entities.DownloadableFile; +import eu.siacs.conversations.entities.Message; +import eu.siacs.conversations.http.HttpConnectionManager; +import eu.siacs.conversations.services.XmppConnectionService; public class PgpDecryptionService { - private final XmppConnectionService xmppConnectionService; - private final ConcurrentHashMap> messages = new ConcurrentHashMap<>(); - private final ConcurrentHashMap decryptingMessages = new ConcurrentHashMap<>(); - private Boolean keychainLocked = false; - private final Object keychainLockedLock = new Object(); + private final XmppConnectionService mXmppConnectionService; + private OpenPgpApi openPgpApi = null; - public PgpDecryptionService(XmppConnectionService xmppConnectionService) { - this.xmppConnectionService = xmppConnectionService; + protected final ArrayDeque messages = new ArrayDeque(); + Message currentMessage; + private PendingIntent pendingIntent; + + + public PgpDecryptionService(XmppConnectionService service) { + this.mXmppConnectionService = service; + } + + public synchronized void decrypt(final Message message) { + messages.add(message); + continueDecryption(); } - public void add(Message message) { - if (isRunning()) { - decryptDirectly(message); - } else { - store(message); + public synchronized void decrypt(final List list) { + for(Message message : list) { + if (message.getEncryption() == Message.ENCRYPTION_PGP) { + messages.add(message); + } + } + continueDecryption(); + } + + protected synchronized void decryptNext() { + if (pendingIntent == null + && getOpenPgpApi() != null + && (currentMessage = messages.poll()) != null) { + new Thread(new Runnable() { + @Override + public void run() { + executeApi(currentMessage); + decryptNext(); + } + }).start(); } } - public void addAll(List messagesList) { - if (!messagesList.isEmpty()) { - String conversationUuid = messagesList.get(0).getConversation().getUuid(); - if (!messages.containsKey(conversationUuid)) { - List list = Collections.synchronizedList(new LinkedList()); - messages.put(conversationUuid, list); - } - synchronized (messages.get(conversationUuid)) { - messages.get(conversationUuid).addAll(messagesList); - } - decryptAllMessages(); - } - } + public synchronized void continueDecryption(boolean resetPending) { + if (resetPending) { + this.pendingIntent = null; + } + continueDecryption(); + } - public void onKeychainUnlocked() { - synchronized (keychainLockedLock) { - keychainLocked = false; - } - decryptAllMessages(); - } + public synchronized void continueDecryption() { + if (currentMessage == null) { + decryptNext(); + } + } - public void onKeychainLocked() { - synchronized (keychainLockedLock) { - keychainLocked = true; - } - xmppConnectionService.updateConversationUi(); - } + private synchronized OpenPgpApi getOpenPgpApi() { + if (openPgpApi == null) { + this.openPgpApi = mXmppConnectionService.getOpenPgpApi(); + } + return this.openPgpApi; + } - public void onOpenPgpServiceBound() { - decryptAllMessages(); - } + private void executeApi(Message message) { + Intent params = new Intent(); + params.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY); + if (message.getType() == Message.TYPE_TEXT) { + InputStream is = new ByteArrayInputStream(message.getBody().getBytes()); + final OutputStream os = new ByteArrayOutputStream(); + Intent result = getOpenPgpApi().executeApi(params, is, os); + switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) { + case OpenPgpApi.RESULT_CODE_SUCCESS: + try { + os.flush(); + message.setBody(os.toString()); + message.setEncryption(Message.ENCRYPTION_DECRYPTED); + final HttpConnectionManager manager = mXmppConnectionService.getHttpConnectionManager(); + if (message.trusted() + && message.treatAsDownloadable() != Message.Decision.NEVER + && manager.getAutoAcceptFileSize() > 0) { + manager.createNewDownloadConnection(message); + } + } catch (IOException e) { + message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED); + } + mXmppConnectionService.updateMessage(message); + break; + case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED: + messages.addFirst(message); + currentMessage = null; + storePendingIntent((PendingIntent) result.getParcelableExtra(OpenPgpApi.RESULT_INTENT)); + break; + case OpenPgpApi.RESULT_CODE_ERROR: + message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED); + mXmppConnectionService.updateMessage(message); + break; + } + } else if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE) { + try { + final DownloadableFile inputFile = mXmppConnectionService.getFileBackend().getFile(message, false); + final DownloadableFile outputFile = mXmppConnectionService.getFileBackend().getFile(message, true); + outputFile.getParentFile().mkdirs(); + outputFile.createNewFile(); + InputStream is = new FileInputStream(inputFile); + OutputStream os = new FileOutputStream(outputFile); + Intent result = getOpenPgpApi().executeApi(params, is, os); + switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) { + case OpenPgpApi.RESULT_CODE_SUCCESS: + URL url = message.getFileParams().url; + mXmppConnectionService.getFileBackend().updateFileParams(message,url); + message.setEncryption(Message.ENCRYPTION_DECRYPTED); + inputFile.delete(); + mXmppConnectionService.getFileBackend().updateMediaScanner(outputFile); + mXmppConnectionService.updateMessage(message); + break; + case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED: + messages.addFirst(message); + currentMessage = null; + storePendingIntent((PendingIntent) result.getParcelableExtra(OpenPgpApi.RESULT_INTENT)); + break; + case OpenPgpApi.RESULT_CODE_ERROR: + message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED); + mXmppConnectionService.updateMessage(message); + break; + } + } catch (final IOException e) { + message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED); + mXmppConnectionService.updateMessage(message); + } + } + } - public boolean isRunning() { - synchronized (keychainLockedLock) { - return !keychainLocked; - } - } + private void storePendingIntent(PendingIntent pendingIntent) { + this.pendingIntent = pendingIntent; + mXmppConnectionService.updateConversationUi(); + } - private void store(Message message) { - if (messages.containsKey(message.getConversation().getUuid())) { - messages.get(message.getConversation().getUuid()).add(message); - } else { - List messageList = Collections.synchronizedList(new LinkedList()); - messageList.add(message); - messages.put(message.getConversation().getUuid(), messageList); - } - } + public synchronized boolean hasPendingIntent(Conversation conversation) { + if (pendingIntent == null) { + return false; + } else { + for(Message message : messages) { + if (message.getConversation() == conversation) { + return true; + } + } + return false; + } + } - private void decryptAllMessages() { - for (String uuid : messages.keySet()) { - decryptMessages(uuid); - } - } + public PendingIntent getPendingIntent() { + return pendingIntent; + } - private void decryptMessages(final String uuid) { - synchronized (decryptingMessages) { - Boolean decrypting = decryptingMessages.get(uuid); - if ((decrypting != null && !decrypting) || decrypting == null) { - decryptingMessages.put(uuid, true); - decryptMessage(uuid); - } - } - } - - private void decryptMessage(final String uuid) { - Message message = null; - synchronized (messages.get(uuid)) { - while (!messages.get(uuid).isEmpty()) { - if (messages.get(uuid).get(0).getEncryption() == Message.ENCRYPTION_PGP) { - if (isRunning()) { - message = messages.get(uuid).remove(0); - } - break; - } else { - messages.get(uuid).remove(0); - } - } - if (message != null && xmppConnectionService.getPgpEngine() != null) { - xmppConnectionService.getPgpEngine().decrypt(message, new UiCallback() { - - @Override - public void userInputRequried(PendingIntent pi, Message message) { - messages.get(uuid).add(0, message); - decryptingMessages.put(uuid, false); - } - - @Override - public void success(Message message) { - xmppConnectionService.updateConversationUi(); - decryptMessage(uuid); - } - - @Override - public void error(int error, Message message) { - message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED); - xmppConnectionService.updateConversationUi(); - decryptMessage(uuid); - } - }); - } else { - decryptingMessages.put(uuid, false); - } - } - } - - private void decryptDirectly(final Message message) { - if (message.getEncryption() == Message.ENCRYPTION_PGP && xmppConnectionService.getPgpEngine() != null) { - xmppConnectionService.getPgpEngine().decrypt(message, new UiCallback() { - - @Override - public void userInputRequried(PendingIntent pi, Message message) { - store(message); - } - - @Override - public void success(Message message) { - xmppConnectionService.updateConversationUi(); - xmppConnectionService.getNotificationService().updateNotification(false); - } - - @Override - public void error(int error, Message message) { - message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED); - xmppConnectionService.updateConversationUi(); - } - }); - } - } + public boolean isConnected() { + return getOpenPgpApi() != null; + } } diff --git a/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java b/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java index b7d5ac8ca..fe3ac04b8 100644 --- a/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java +++ b/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java @@ -38,96 +38,6 @@ public class PgpEngine { this.mXmppConnectionService = service; } - public void decrypt(final Message message, final UiCallback callback) { - Intent params = new Intent(); - params.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY); - final String uuid = message.getUuid(); - if (message.getType() == Message.TYPE_TEXT) { - InputStream is = new ByteArrayInputStream(message.getBody().getBytes()); - final OutputStream os = new ByteArrayOutputStream(); - api.executeApiAsync(params, is, os, new IOpenPgpCallback() { - - @Override - public void onReturn(Intent result) { - notifyPgpDecryptionService(message.getConversation().getAccount(), OpenPgpApi.ACTION_DECRYPT_VERIFY, result); - switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) { - case OpenPgpApi.RESULT_CODE_SUCCESS: - try { - os.flush(); - if (message.getEncryption() == Message.ENCRYPTION_PGP - && message.getUuid().equals(uuid)) { - message.setBody(os.toString()); - message.setEncryption(Message.ENCRYPTION_DECRYPTED); - final HttpConnectionManager manager = mXmppConnectionService.getHttpConnectionManager(); - if (message.trusted() - && message.treatAsDownloadable() != Message.Decision.NEVER - && manager.getAutoAcceptFileSize() > 0) { - manager.createNewDownloadConnection(message); - } - mXmppConnectionService.updateMessage(message); - callback.success(message); - } - } catch (IOException e) { - callback.error(R.string.openpgp_error, message); - return; - } - - return; - case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED: - callback.userInputRequried((PendingIntent) result - .getParcelableExtra(OpenPgpApi.RESULT_INTENT), - message); - return; - case OpenPgpApi.RESULT_CODE_ERROR: - callback.error(R.string.openpgp_error, message); - } - } - }); - } else if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE) { - try { - final DownloadableFile inputFile = this.mXmppConnectionService - .getFileBackend().getFile(message, false); - final DownloadableFile outputFile = this.mXmppConnectionService - .getFileBackend().getFile(message, true); - outputFile.getParentFile().mkdirs(); - outputFile.createNewFile(); - InputStream is = new FileInputStream(inputFile); - OutputStream os = new FileOutputStream(outputFile); - api.executeApiAsync(params, is, os, new IOpenPgpCallback() { - - @Override - public void onReturn(Intent result) { - notifyPgpDecryptionService(message.getConversation().getAccount(), OpenPgpApi.ACTION_DECRYPT_VERIFY, result); - switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, - OpenPgpApi.RESULT_CODE_ERROR)) { - case OpenPgpApi.RESULT_CODE_SUCCESS: - URL url = message.getFileParams().url; - mXmppConnectionService.getFileBackend().updateFileParams(message,url); - message.setEncryption(Message.ENCRYPTION_DECRYPTED); - PgpEngine.this.mXmppConnectionService - .updateMessage(message); - inputFile.delete(); - mXmppConnectionService.getFileBackend().updateMediaScanner(outputFile); - callback.success(message); - return; - case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED: - callback.userInputRequried( - (PendingIntent) result - .getParcelableExtra(OpenPgpApi.RESULT_INTENT), - message); - return; - case OpenPgpApi.RESULT_CODE_ERROR: - callback.error(R.string.openpgp_error, message); - } - } - }); - } catch (final IOException e) { - callback.error(R.string.error_decrypting_file, message); - } - - } - } - public void encrypt(final Message message, final UiCallback callback) { Intent params = new Intent(); params.setAction(OpenPgpApi.ACTION_ENCRYPT); @@ -156,7 +66,6 @@ public class PgpEngine { @Override public void onReturn(Intent result) { - notifyPgpDecryptionService(message.getConversation().getAccount(), OpenPgpApi.ACTION_ENCRYPT, result); switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) { case OpenPgpApi.RESULT_CODE_SUCCESS: @@ -202,7 +111,6 @@ public class PgpEngine { @Override public void onReturn(Intent result) { - notifyPgpDecryptionService(message.getConversation().getAccount(), OpenPgpApi.ACTION_ENCRYPT, result); switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) { case OpenPgpApi.RESULT_CODE_SUCCESS: @@ -257,7 +165,6 @@ public class PgpEngine { InputStream is = new ByteArrayInputStream(pgpSig.toString().getBytes()); ByteArrayOutputStream os = new ByteArrayOutputStream(); Intent result = api.executeApi(params, is, os); - notifyPgpDecryptionService(account, OpenPgpApi.ACTION_DECRYPT_VERIFY, result); switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) { case OpenPgpApi.RESULT_CODE_SUCCESS: @@ -315,7 +222,6 @@ public class PgpEngine { @Override public void onReturn(Intent result) { - notifyPgpDecryptionService(account, OpenPgpApi.ACTION_SIGN, result); switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0)) { case OpenPgpApi.RESULT_CODE_SUCCESS: StringBuilder signatureBuilder = new StringBuilder(); @@ -397,17 +303,4 @@ public class PgpEngine { return (PendingIntent) result .getParcelableExtra(OpenPgpApi.RESULT_INTENT); } - - private void notifyPgpDecryptionService(Account account, String action, final Intent result) { - switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0)) { - case OpenPgpApi.RESULT_CODE_SUCCESS: - if (OpenPgpApi.ACTION_SIGN.equals(action)) { - account.getPgpDecryptionService().onKeychainUnlocked(); - } - break; - case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED: - account.getPgpDecryptionService().onKeychainLocked(); - break; - } - } } diff --git a/src/main/java/eu/siacs/conversations/entities/Account.java b/src/main/java/eu/siacs/conversations/entities/Account.java index 3e79fccd9..62c78cb68 100644 --- a/src/main/java/eu/siacs/conversations/entities/Account.java +++ b/src/main/java/eu/siacs/conversations/entities/Account.java @@ -6,6 +6,7 @@ import android.os.SystemClock; import android.util.Pair; import eu.siacs.conversations.crypto.PgpDecryptionService; + import net.java.otr4j.crypto.OtrCryptoEngineImpl; import net.java.otr4j.crypto.OtrCryptoException; @@ -20,7 +21,6 @@ import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; -import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.OtrService; import eu.siacs.conversations.crypto.axolotl.AxolotlService; @@ -83,6 +83,14 @@ public class Account extends AbstractEntity { return getRoster().getContact(jid); } + public boolean hasPendingPgpIntent(Conversation conversation) { + return pgpDecryptionService != null && pgpDecryptionService.hasPendingIntent(conversation); + } + + public boolean isPgpDecryptionServiceConnected() { + return pgpDecryptionService != null && pgpDecryptionService.isConnected(); + } + public enum State { DISABLED, OFFLINE, @@ -398,10 +406,10 @@ public class Account extends AbstractEntity { public void initAccountServices(final XmppConnectionService context) { this.mOtrService = new OtrService(context, this); this.axolotlService = new AxolotlService(this, context); + this.pgpDecryptionService = new PgpDecryptionService(context); if (xmppConnection != null) { xmppConnection.addOnAdvancedStreamFeaturesAvailableListener(axolotlService); } - this.pgpDecryptionService = new PgpDecryptionService(context); } public OtrService getOtrService() { @@ -409,7 +417,7 @@ public class Account extends AbstractEntity { } public PgpDecryptionService getPgpDecryptionService() { - return pgpDecryptionService; + return this.pgpDecryptionService; } public XmppConnection getXmppConnection() { diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index 37a57f7bf..182e86ddf 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -932,7 +932,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl synchronized (this.messages) { this.messages.addAll(index, messages); } - account.getPgpDecryptionService().addAll(messages); + account.getPgpDecryptionService().decrypt(messages); } public void sort() { diff --git a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java index a28bb6793..04dacbdbb 100644 --- a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java +++ b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java @@ -127,7 +127,7 @@ public class HttpDownloadConnection implements Transferable { message.setTransferable(null); mHttpConnectionManager.finishConnection(this); if (message.getEncryption() == Message.ENCRYPTION_PGP) { - message.getConversation().getAccount().getPgpDecryptionService().add(message); + message.getConversation().getAccount().getPgpDecryptionService().decrypt(message); } mXmppConnectionService.updateConversationUi(); if (acceptedAutomatically) { diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 2883b9a5c..86f96c370 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -7,7 +7,6 @@ import android.util.Pair; import net.java.otr4j.session.Session; import net.java.otr4j.session.SessionStatus; -import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; @@ -32,7 +31,6 @@ import eu.siacs.conversations.http.HttpConnectionManager; import eu.siacs.conversations.services.MessageArchiveService; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.utils.CryptoHelper; -import eu.siacs.conversations.utils.Xmlns; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.OnMessagePacketReceived; import eu.siacs.conversations.xmpp.chatstate.ChatState; @@ -484,7 +482,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece sendMessageReceipts(account, packet); } if (replacedMessage.getEncryption() == Message.ENCRYPTION_PGP) { - conversation.getAccount().getPgpDecryptionService().add(replacedMessage); + conversation.getAccount().getPgpDecryptionService().decrypt(replacedMessage); } return; } else { @@ -508,7 +506,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece } if (message.getEncryption() == Message.ENCRYPTION_PGP) { - conversation.getAccount().getPgpDecryptionService().add(message); + conversation.getAccount().getPgpDecryptionService().decrypt(message); } if (query == null || query.getWith() == null) { //either no mam or catchup diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 083c108ad..541bf4b9d 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -49,7 +49,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; @@ -62,6 +61,7 @@ import java.util.concurrent.CopyOnWriteArrayList; import de.duenndns.ssl.MemorizingTrustManager; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; +import eu.siacs.conversations.crypto.PgpDecryptionService; import eu.siacs.conversations.crypto.PgpEngine; import eu.siacs.conversations.crypto.axolotl.AxolotlService; import eu.siacs.conversations.crypto.axolotl.XmppAxolotlMessage; @@ -383,6 +383,16 @@ public class XmppConnectionService extends Service { } + public OpenPgpApi getOpenPgpApi() { + if (!Config.supportOpenPgp()) { + return null; + } else if (pgpServiceConnection != null && pgpServiceConnection.isBound()) { + return new OpenPgpApi(this, pgpServiceConnection.getService()); + } else { + return null; + } + } + public FileBackend getFileBackend() { return this.fileBackend; } @@ -754,8 +764,9 @@ public class XmppConnectionService extends Service { @Override public void onBound(IOpenPgpService2 service) { for (Account account : accounts) { - if (account.getPgpDecryptionService() != null) { - account.getPgpDecryptionService().onOpenPgpServiceBound(); + final PgpDecryptionService pgp = account.getPgpDecryptionService(); + if(pgp != null) { + pgp.continueDecryption(true); } } } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 53a365257..b996b71a2 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -9,12 +9,9 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentSender.SendIntentException; -import android.content.res.TypedArray; import android.os.Bundle; import android.os.Handler; -import android.support.annotation.Nullable; import android.text.InputType; -import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Gravity; @@ -214,49 +211,25 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } return -1; } - - private final int KEYCHAIN_UNLOCK_NOT_REQUIRED = 0; - private final int KEYCHAIN_UNLOCK_REQUIRED = 1; - private final int KEYCHAIN_UNLOCK_PENDING = 2; - private int keychainUnlock = KEYCHAIN_UNLOCK_NOT_REQUIRED; protected OnClickListener clickToDecryptListener = new OnClickListener() { @Override public void onClick(View v) { - if (keychainUnlock == KEYCHAIN_UNLOCK_REQUIRED - && activity.hasPgp() && !conversation.getAccount().getPgpDecryptionService().isRunning()) { - keychainUnlock = KEYCHAIN_UNLOCK_PENDING; - updateSnackBar(conversation); - Message message = getLastPgpDecryptableMessage(); - if (message != null) { - activity.xmppConnectionService.getPgpEngine().decrypt(message, new UiCallback() { - @Override - public void success(Message object) { - conversation.getAccount().getPgpDecryptionService().onKeychainUnlocked(); - keychainUnlock = KEYCHAIN_UNLOCK_NOT_REQUIRED; - } - - @Override - public void error(int errorCode, Message object) { - keychainUnlock = KEYCHAIN_UNLOCK_NOT_REQUIRED; - } - - @Override - public void userInputRequried(PendingIntent pi, Message object) { - try { - activity.startIntentSenderForResult(pi.getIntentSender(), - ConversationActivity.REQUEST_DECRYPT_PGP, null, 0, 0, 0); - } catch (SendIntentException e) { - keychainUnlock = KEYCHAIN_UNLOCK_NOT_REQUIRED; - updatePgpMessages(); - } - } - }); + PendingIntent pendingIntent = conversation.getAccount().getPgpDecryptionService().getPendingIntent(); + if (pendingIntent != null) { + try { + activity.startIntentSenderForResult(pendingIntent.getIntentSender(), + ConversationActivity.REQUEST_DECRYPT_PGP, + null, + 0, + 0, + 0); + } catch (SendIntentException e) { + Toast.makeText(activity,R.string.unable_to_connect_to_keychain, Toast.LENGTH_SHORT).show(); + conversation.getAccount().getPgpDecryptionService().continueDecryption(true); } - } else { - keychainUnlock = KEYCHAIN_UNLOCK_NOT_REQUIRED; - updatePgpMessages(); } + updateSnackBar(conversation); } }; protected OnClickListener clickToVerify = new OnClickListener() { @@ -722,7 +695,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa message.setEncryption(Message.ENCRYPTION_PGP); activity.updateConversationList(); updateMessages(); - conversation.getAccount().getPgpDecryptionService().add(message); + conversation.getAccount().getPgpDecryptionService().decrypt(message); } protected void privateMessageWith(final Jid counterpart) { @@ -789,7 +762,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa this.conversation.trim(); } - this.keychainUnlock = KEYCHAIN_UNLOCK_NOT_REQUIRED; this.conversation = conversation; boolean canWrite = this.conversation.getMode() == Conversation.MODE_SINGLE || this.conversation.getMucOptions().participating(); this.mEditMessage.setEnabled(canWrite); @@ -909,7 +881,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa default: break; } - } else if (keychainUnlock == KEYCHAIN_UNLOCK_REQUIRED) { + } else if (account.hasPendingPgpIntent(conversation)) { showSnackbar(R.string.openpgp_messages_found, R.string.decrypt, clickToDecryptListener); } else if (mode == Conversation.MODE_SINGLE && conversation.smpRequested()) { @@ -932,7 +904,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa final ConversationActivity activity = (ConversationActivity) getActivity(); if (this.conversation != null) { conversation.populateWithMessages(ConversationFragment.this.messageList); - updatePgpMessages(); updateSnackBar(conversation); updateStatusMessages(); this.messageListAdapter.notifyDataSetChanged(); @@ -945,29 +916,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } } - public void updatePgpMessages() { - if (keychainUnlock != KEYCHAIN_UNLOCK_PENDING) { - if (getLastPgpDecryptableMessage() != null - && !conversation.getAccount().getPgpDecryptionService().isRunning()) { - keychainUnlock = KEYCHAIN_UNLOCK_REQUIRED; - } else { - keychainUnlock = KEYCHAIN_UNLOCK_NOT_REQUIRED; - } - } - } - - @Nullable - private Message getLastPgpDecryptableMessage() { - for (final Message message : this.messageList) { - if (message.getEncryption() == Message.ENCRYPTION_PGP - && (message.getStatus() == Message.STATUS_RECEIVED || message.getStatus() >= Message.STATUS_SEND) - && message.getTransferable() == null) { - return message; - } - } - return null; - } - private void messageSent() { mEditMessage.setText(""); updateChatMsgHint(); @@ -1424,9 +1372,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa final Intent data) { if (resultCode == Activity.RESULT_OK) { if (requestCode == ConversationActivity.REQUEST_DECRYPT_PGP) { - activity.getSelectedConversation().getAccount().getPgpDecryptionService().onKeychainUnlocked(); - keychainUnlock = KEYCHAIN_UNLOCK_NOT_REQUIRED; - updatePgpMessages(); + activity.getSelectedConversation().getAccount().getPgpDecryptionService().continueDecryption(true); } else if (requestCode == ConversationActivity.REQUEST_TRUST_KEYS_TEXT) { final String body = mEditMessage.getText().toString(); Message message = new Message(conversation, body, conversation.getNextEncryption()); @@ -1435,11 +1381,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa int choice = data.getIntExtra("choice", ConversationActivity.ATTACHMENT_CHOICE_INVALID); activity.selectPresenceToAttachFile(choice, conversation.getNextEncryption()); } - } else { - if (requestCode == ConversationActivity.REQUEST_DECRYPT_PGP) { - keychainUnlock = KEYCHAIN_UNLOCK_NOT_REQUIRED; - updatePgpMessages(); - } } } diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java index e174401d2..56517e3bc 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -631,8 +631,8 @@ public class MessageAdapter extends ArrayAdapter { displayOpenableMessage(viewHolder, message); } } else if (message.getEncryption() == Message.ENCRYPTION_PGP) { - if (activity.hasPgp()) { - if (account.getPgpDecryptionService().isRunning()) { + if (account.isPgpDecryptionServiceConnected()) { + if (!account.hasPendingPgpIntent(conversation)) { displayInfoMessage(viewHolder, activity.getString(R.string.message_decrypting), darkBackground); } else { displayInfoMessage(viewHolder, activity.getString(R.string.pgp_message), darkBackground); diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java index c9ee6bdc2..dbcb4b6db 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java @@ -110,7 +110,7 @@ public class JingleConnection implements Transferable { if (message.getEncryption() != Message.ENCRYPTION_PGP) { mXmppConnectionService.getFileBackend().updateMediaScanner(file); } else { - account.getPgpDecryptionService().add(message); + account.getPgpDecryptionService().decrypt(message); } } diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 945d6fb91..328004af6 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -662,4 +662,5 @@ Dark theme Green Background Use green background for received messages + Unable to connect to OpenKeychain