aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java')
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java305
1 files changed, 162 insertions, 143 deletions
diff --git a/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java b/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java
index ed67dc65..2bc270c1 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 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 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.ui.UiCallback;
-
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
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();
-
- public PgpDecryptionService(XmppConnectionService xmppConnectionService) {
- this.xmppConnectionService = xmppConnectionService;
- }
-
- 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();
- }
+ private final XmppConnectionService mXmppConnectionService;
+ private OpenPgpApi openPgpApi = null;
- public void onOpenPgpServiceBound() {
- decryptAllMessages();
- }
-
- public boolean isRunning() {
- synchronized (keychainLockedLock) {
- return !keychainLocked;
- }
- }
+ protected final ArrayDeque<Message> messages = new ArrayDeque();
+ Message currentMessage;
+ private PendingIntent pendingIntent;
- 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);
- }
- }
+ public PgpDecryptionService(XmppConnectionService service) {
+ this.mXmppConnectionService = service;
+ }
- 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);
- }
- }
+ public synchronized void decrypt(final Message message) {
+ messages.add(message);
+ continueDecryption();
}
- 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);
- }
+ 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 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;
+ }
}