PgpService: feed result intent back into decryption

This commit is contained in:
Daniel Gultsch 2017-11-22 13:36:00 +01:00
parent 4596cad3cb
commit 8696cf2235
2 changed files with 203 additions and 197 deletions

View file

@ -25,216 +25,222 @@ import eu.siacs.conversations.services.XmppConnectionService;
public class PgpDecryptionService { public class PgpDecryptionService {
private final XmppConnectionService mXmppConnectionService;
private OpenPgpApi openPgpApi = null;
protected final ArrayDeque<Message> messages = new ArrayDeque(); protected final ArrayDeque<Message> messages = new ArrayDeque();
protected final HashSet<Message> pendingNotifications = new HashSet<>(); protected final HashSet<Message> pendingNotifications = new HashSet<>();
Message currentMessage; private final XmppConnectionService mXmppConnectionService;
private PendingIntent pendingIntent; private OpenPgpApi openPgpApi = null;
private Message currentMessage;
private PendingIntent pendingIntent;
private Intent userInteractionResult;
public PgpDecryptionService(XmppConnectionService service) { public PgpDecryptionService(XmppConnectionService service) {
this.mXmppConnectionService = service; this.mXmppConnectionService = service;
}
public synchronized boolean decrypt(final Message message, boolean notify) {
messages.add(message);
if (notify && pendingIntent == null) {
pendingNotifications.add(message);
continueDecryption();
return false;
} else {
continueDecryption();
return notify;
}
} }
public synchronized void decrypt(final List<Message> list) { public synchronized boolean decrypt(final Message message, boolean notify) {
for(Message message : list) { messages.add(message);
if (message.getEncryption() == Message.ENCRYPTION_PGP) { if (notify && pendingIntent == null) {
messages.add(message); pendingNotifications.add(message);
} continueDecryption();
} return false;
continueDecryption(); } else {
} continueDecryption();
return notify;
public synchronized void discard(List<Message> discards) {
this.messages.removeAll(discards);
this.pendingNotifications.removeAll(discards);
}
public synchronized void discard(Message message) {
this.messages.remove(message);
this.pendingNotifications.remove(message);
}
public void giveUpCurrentDecryption(){
Message message;
synchronized (this) {
if(currentMessage != null) {
return;
}
message = messages.peekFirst();
if (message == null) {
return;
}
discard(message);
}
synchronized (message){
if (message.getEncryption() == Message.ENCRYPTION_PGP) {
message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED);
}
}
mXmppConnectionService.updateMessage(message);
continueDecryption(true);
}
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 synchronized void continueDecryption(boolean resetPending) { public synchronized void decrypt(final List<Message> list) {
if (resetPending) { for (Message message : list) {
this.pendingIntent = null; if (message.getEncryption() == Message.ENCRYPTION_PGP) {
} messages.add(message);
continueDecryption(); }
} }
continueDecryption();
}
public synchronized void continueDecryption() { public synchronized void discard(List<Message> discards) {
if (currentMessage == null) { this.messages.removeAll(discards);
decryptNext(); this.pendingNotifications.removeAll(discards);
} }
}
private synchronized OpenPgpApi getOpenPgpApi() { public synchronized void discard(Message message) {
if (openPgpApi == null) { this.messages.remove(message);
this.openPgpApi = mXmppConnectionService.getOpenPgpApi(); this.pendingNotifications.remove(message);
} }
return this.openPgpApi;
}
private void executeApi(Message message) { public void giveUpCurrentDecryption() {
synchronized (message) { Message message;
Intent params = new Intent(); synchronized (this) {
params.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY); if (currentMessage != null) {
if (message.getType() == Message.TYPE_TEXT) { return;
InputStream is = new ByteArrayInputStream(message.getBody().getBytes()); }
final OutputStream os = new ByteArrayOutputStream(); message = messages.peekFirst();
Intent result = getOpenPgpApi().executeApi(params, is, os); if (message == null) {
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) { return;
case OpenPgpApi.RESULT_CODE_SUCCESS: }
try { discard(message);
os.flush(); }
final String body = os.toString(); synchronized (message) {
if (body == null) { if (message.getEncryption() == Message.ENCRYPTION_PGP) {
throw new IOException("body was null"); message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED);
} }
message.setBody(body); }
message.setEncryption(Message.ENCRYPTION_DECRYPTED); mXmppConnectionService.updateMessage(message);
final HttpConnectionManager manager = mXmppConnectionService.getHttpConnectionManager(); continueDecryption(true);
if (message.trusted() }
&& message.treatAsDownloadable()
&& 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) {
PendingIntent pendingIntent = result.getParcelableExtra(OpenPgpApi.RESULT_INTENT);
messages.addFirst(message);
currentMessage = null;
storePendingIntent(pendingIntent);
}
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) {
PendingIntent pendingIntent = result.getParcelableExtra(OpenPgpApi.RESULT_INTENT);
messages.addFirst(message);
currentMessage = null;
storePendingIntent(pendingIntent);
}
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) { protected synchronized void decryptNext() {
if (pendingNotifications.remove(message)) { if (pendingIntent == null
mXmppConnectionService.getNotificationService().push(message); && getOpenPgpApi() != null
} && (currentMessage = messages.poll()) != null) {
} new Thread(new Runnable() {
@Override
public void run() {
executeApi(currentMessage);
decryptNext();
}
}).start();
}
}
private void storePendingIntent(PendingIntent pendingIntent) { public synchronized void continueDecryption(boolean resetPending) {
this.pendingIntent = pendingIntent; if (resetPending) {
mXmppConnectionService.updateConversationUi(); this.pendingIntent = null;
} }
continueDecryption();
}
public synchronized boolean hasPendingIntent(Conversation conversation) { public synchronized void continueDecryption(Intent userInteractionResult) {
if (pendingIntent == null) { this.pendingIntent = null;
return false; this.userInteractionResult = userInteractionResult;
} else { continueDecryption();
for(Message message : messages) { }
if (message.getConversation() == conversation) {
return true;
}
}
return false;
}
}
public PendingIntent getPendingIntent() { public synchronized void continueDecryption() {
return pendingIntent; if (currentMessage == null) {
} decryptNext();
}
}
public boolean isConnected() { private synchronized OpenPgpApi getOpenPgpApi() {
return getOpenPgpApi() != null; if (openPgpApi == null) {
} this.openPgpApi = mXmppConnectionService.getOpenPgpApi();
}
return this.openPgpApi;
}
private void executeApi(Message message) {
synchronized (message) {
Intent params = userInteractionResult != null ? userInteractionResult : 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();
final String body = os.toString();
if (body == null) {
throw new IOException("body was null");
}
message.setBody(body);
message.setEncryption(Message.ENCRYPTION_DECRYPTED);
final HttpConnectionManager manager = mXmppConnectionService.getHttpConnectionManager();
if (message.trusted()
&& message.treatAsDownloadable()
&& 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) {
PendingIntent pendingIntent = result.getParcelableExtra(OpenPgpApi.RESULT_INTENT);
messages.addFirst(message);
currentMessage = null;
storePendingIntent(pendingIntent);
}
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) {
PendingIntent pendingIntent = result.getParcelableExtra(OpenPgpApi.RESULT_INTENT);
messages.addFirst(message);
currentMessage = null;
storePendingIntent(pendingIntent);
}
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);
}
}
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;
}
} }

View file

@ -1746,7 +1746,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
final Intent data) { final Intent data) {
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
if (requestCode == ConversationActivity.REQUEST_DECRYPT_PGP) { if (requestCode == ConversationActivity.REQUEST_DECRYPT_PGP) {
activity.getSelectedConversation().getAccount().getPgpDecryptionService().continueDecryption(true); activity.getSelectedConversation().getAccount().getPgpDecryptionService().continueDecryption(data);
} else if (requestCode == ConversationActivity.REQUEST_TRUST_KEYS_TEXT) { } else if (requestCode == ConversationActivity.REQUEST_TRUST_KEYS_TEXT) {
final String body = mEditMessage.getText().toString(); final String body = mEditMessage.getText().toString();
Message message = new Message(conversation, body, conversation.getNextEncryption()); Message message = new Message(conversation, body, conversation.getNextEncryption());