conversations-classic/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java

207 lines
8 KiB
Java
Raw Normal View History

2015-10-15 22:21:47 +00:00
package eu.siacs.conversations.crypto;
import android.app.PendingIntent;
2016-06-13 11:32:14 +00:00
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.HashSet;
2016-06-13 11:32:14 +00:00
import java.util.List;
2015-10-15 22:21:47 +00:00
2016-06-13 11:32:14 +00:00
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.DownloadableFile;
2015-10-15 22:21:47 +00:00
import eu.siacs.conversations.entities.Message;
2016-06-13 11:32:14 +00:00
import eu.siacs.conversations.http.HttpConnectionManager;
2015-10-15 22:21:47 +00:00
import eu.siacs.conversations.services.XmppConnectionService;
public class PgpDecryptionService {
2016-06-13 11:32:14 +00:00
private final XmppConnectionService mXmppConnectionService;
private OpenPgpApi openPgpApi = null;
2015-10-15 22:21:47 +00:00
2016-06-13 11:32:14 +00:00
protected final ArrayDeque<Message> messages = new ArrayDeque();
protected final HashSet<Message> pendingNotifications = new HashSet<>();
2016-06-13 11:32:14 +00:00
Message currentMessage;
private PendingIntent pendingIntent;
2015-10-15 22:21:47 +00:00
2016-06-13 11:32:14 +00:00
public PgpDecryptionService(XmppConnectionService service) {
this.mXmppConnectionService = service;
}
2015-10-15 22:21:47 +00:00
public synchronized boolean decrypt(final Message message, boolean notify) {
2016-06-13 11:32:14 +00:00
messages.add(message);
if (notify && pendingIntent == null) {
pendingNotifications.add(message);
continueDecryption();
return false;
} else {
continueDecryption();
return notify;
}
2015-10-15 22:21:47 +00:00
}
2016-06-13 11:32:14 +00:00
public synchronized void decrypt(final List<Message> list) {
for(Message message : list) {
if (message.getEncryption() == Message.ENCRYPTION_PGP) {
messages.add(message);
}
}
continueDecryption();
}
public synchronized void discard(List<Message> discards) {
this.messages.removeAll(discards);
this.pendingNotifications.removeAll(discards);
}
2016-06-13 11:32:14 +00:00
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();
2015-10-15 22:21:47 +00:00
}
}
2016-06-13 11:32:14 +00:00
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:
synchronized (PgpDecryptionService.this) {
messages.addFirst(message);
currentMessage = null;
storePendingIntent((PendingIntent) result.getParcelableExtra(OpenPgpApi.RESULT_INTENT));
}
2016-06-13 11:32:14 +00:00
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:
synchronized (PgpDecryptionService.this) {
messages.addFirst(message);
currentMessage = null;
storePendingIntent((PendingIntent) result.getParcelableExtra(OpenPgpApi.RESULT_INTENT));
}
2016-06-13 11:32:14 +00:00
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);
}
}
notifyIfPending(message);
}
private synchronized void notifyIfPending(Message message) {
if (pendingNotifications.remove(message)) {
mXmppConnectionService.getNotificationService().push(message);
}
2016-06-13 11:32:14 +00:00
}
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;
}
2015-10-15 22:21:47 +00:00
}