diff options
author | Daniel Gultsch <daniel@gultsch.de> | 2016-06-13 13:32:14 +0200 |
---|---|---|
committer | Christian Schneppe <christian@pix-art.de> | 2016-06-14 21:27:06 +0200 |
commit | 3e748bc49a25c2700e6929286f7041e9c571d7f3 (patch) | |
tree | a965a4b18ddebf614ce4f7ef525124fcd336e200 /src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java | |
parent | dd3b9084af4483d6c1d27313d0d582b4e502fb00 (diff) |
refactored pgp decryption
Diffstat (limited to '')
-rw-r--r-- | src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java | 302 |
1 files changed, 164 insertions, 138 deletions
diff --git a/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java b/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java index 5afbe5c49..5eedee6da 100644 --- a/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java +++ b/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java @@ -1,162 +1,188 @@ package eu.siacs.conversations.crypto; import android.app.PendingIntent; - +import android.content.Intent; + +import org.openintents.openpgp.util.OpenPgpApi; + +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.Collections; import java.util.LinkedList; 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; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.ui.UiCallback; public class PgpDecryptionService { - private final XmppConnectionService xmppConnectionService; - private final ConcurrentHashMap<String, List<Message>> messages = new ConcurrentHashMap<>(); - private final ConcurrentHashMap<String, Boolean> 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<Message> messages = new ArrayDeque(); + Message currentMessage; + private PendingIntent pendingIntent; - public void add(Message message) { - if (isRunning()) { - decryptDirectly(message); - } else { - store(message); - } - } - public void addAll(List<Message> messagesList) { - if (!messagesList.isEmpty()) { - String conversationUuid = messagesList.get(0).getConversation().getUuid(); - if (!messages.containsKey(conversationUuid)) { - List<Message> list = Collections.synchronizedList(new LinkedList<Message>()); - messages.put(conversationUuid, list); - } - synchronized (messages.get(conversationUuid)) { - messages.get(conversationUuid).addAll(messagesList); - } - decryptAllMessages(); - } - } - - public void onKeychainUnlocked() { - synchronized (keychainLockedLock) { - keychainLocked = false; - } - decryptAllMessages(); - } - - public void onKeychainLocked() { - synchronized (keychainLockedLock) { - keychainLocked = true; - } - xmppConnectionService.updateConversationUi(); - } + public PgpDecryptionService(XmppConnectionService service) { + this.mXmppConnectionService = service; + } - public void onOpenPgpServiceBound() { - decryptAllMessages(); + public synchronized void decrypt(final Message message) { + messages.add(message); + continueDecryption(); } - public boolean isRunning() { - synchronized (keychainLockedLock) { - return !keychainLocked; + public synchronized void decrypt(final List<Message> 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(); } } - private void store(Message message) { - if (messages.containsKey(message.getConversation().getUuid())) { - messages.get(message.getConversation().getUuid()).add(message); - } else { - List<Message> messageList = Collections.synchronizedList(new LinkedList<Message>()); - messageList.add(message); - messages.put(message.getConversation().getUuid(), messageList); - } - } - - private void decryptAllMessages() { - for (String uuid : messages.keySet()) { - decryptMessages(uuid); - } - } - - 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<Message>() { - - @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<Message>() { - - @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 synchronized void continueDecryption(boolean resetPending) { + if (resetPending) { + this.pendingIntent = null; + } + continueDecryption(); + } + + public synchronized void continueDecryption() { + if (currentMessage == null) { + decryptNext(); + } + } + + private synchronized OpenPgpApi getOpenPgpApi() { + if (openPgpApi == null) { + this.openPgpApi = mXmppConnectionService.getOpenPgpApi(); + } + return this.openPgpApi; + } + + 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); + } + } + } + + private void storePendingIntent(PendingIntent pendingIntent) { + this.pendingIntent = pendingIntent; + mXmppConnectionService.updateConversationUi(); + } + + public synchronized boolean hasPendingIntent(Conversation conversation) { + if (pendingIntent == null) { + return false; + } else { + for(Message message : messages) { + if (message.getConversation() == conversation) { + return true; + } + } + return false; + } + } + + public PendingIntent getPendingIntent() { + return pendingIntent; + } + + public boolean isConnected() { + return getOpenPgpApi() != null; + } } |