Merge pull request #1513 from fiaxh/pgp_background_decryption
PGP messages background decryption
This commit is contained in:
commit
6a458b853c
|
@ -0,0 +1,162 @@
|
||||||
|
package eu.siacs.conversations.crypto;
|
||||||
|
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.entities.Message;
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onOpenPgpServiceBound() {
|
||||||
|
decryptAllMessages();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRunning() {
|
||||||
|
synchronized (keychainLockedLock) {
|
||||||
|
return !keychainLocked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -50,6 +50,7 @@ public class PgpEngine {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReturn(Intent result) {
|
public void onReturn(Intent result) {
|
||||||
|
notifyPgpDecryptionService(message.getContact().getAccount(), OpenPgpApi.ACTION_DECRYPT_VERIFY, result);
|
||||||
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE,
|
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE,
|
||||||
OpenPgpApi.RESULT_CODE_ERROR)) {
|
OpenPgpApi.RESULT_CODE_ERROR)) {
|
||||||
case OpenPgpApi.RESULT_CODE_SUCCESS:
|
case OpenPgpApi.RESULT_CODE_SUCCESS:
|
||||||
|
@ -64,6 +65,7 @@ public class PgpEngine {
|
||||||
&& manager.getAutoAcceptFileSize() > 0) {
|
&& manager.getAutoAcceptFileSize() > 0) {
|
||||||
manager.createNewDownloadConnection(message);
|
manager.createNewDownloadConnection(message);
|
||||||
}
|
}
|
||||||
|
mXmppConnectionService.updateMessage(message);
|
||||||
callback.success(message);
|
callback.success(message);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -158,6 +160,7 @@ public class PgpEngine {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReturn(Intent result) {
|
public void onReturn(Intent result) {
|
||||||
|
notifyPgpDecryptionService(message.getContact().getAccount(), OpenPgpApi.ACTION_ENCRYPT, result);
|
||||||
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE,
|
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE,
|
||||||
OpenPgpApi.RESULT_CODE_ERROR)) {
|
OpenPgpApi.RESULT_CODE_ERROR)) {
|
||||||
case OpenPgpApi.RESULT_CODE_SUCCESS:
|
case OpenPgpApi.RESULT_CODE_SUCCESS:
|
||||||
|
@ -203,6 +206,7 @@ public class PgpEngine {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReturn(Intent result) {
|
public void onReturn(Intent result) {
|
||||||
|
notifyPgpDecryptionService(message.getContact().getAccount(), OpenPgpApi.ACTION_ENCRYPT, result);
|
||||||
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE,
|
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE,
|
||||||
OpenPgpApi.RESULT_CODE_ERROR)) {
|
OpenPgpApi.RESULT_CODE_ERROR)) {
|
||||||
case OpenPgpApi.RESULT_CODE_SUCCESS:
|
case OpenPgpApi.RESULT_CODE_SUCCESS:
|
||||||
|
@ -252,6 +256,7 @@ public class PgpEngine {
|
||||||
InputStream is = new ByteArrayInputStream(pgpSig.toString().getBytes());
|
InputStream is = new ByteArrayInputStream(pgpSig.toString().getBytes());
|
||||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
Intent result = api.executeApi(params, is, os);
|
Intent result = api.executeApi(params, is, os);
|
||||||
|
notifyPgpDecryptionService(account, OpenPgpApi.ACTION_DECRYPT_VERIFY, result);
|
||||||
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE,
|
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE,
|
||||||
OpenPgpApi.RESULT_CODE_ERROR)) {
|
OpenPgpApi.RESULT_CODE_ERROR)) {
|
||||||
case OpenPgpApi.RESULT_CODE_SUCCESS:
|
case OpenPgpApi.RESULT_CODE_SUCCESS:
|
||||||
|
@ -282,6 +287,7 @@ public class PgpEngine {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReturn(Intent result) {
|
public void onReturn(Intent result) {
|
||||||
|
notifyPgpDecryptionService(account, OpenPgpApi.ACTION_SIGN, result);
|
||||||
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0)) {
|
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0)) {
|
||||||
case OpenPgpApi.RESULT_CODE_SUCCESS:
|
case OpenPgpApi.RESULT_CODE_SUCCESS:
|
||||||
StringBuilder signatureBuilder = new StringBuilder();
|
StringBuilder signatureBuilder = new StringBuilder();
|
||||||
|
@ -368,4 +374,17 @@ public class PgpEngine {
|
||||||
return (PendingIntent) result
|
return (PendingIntent) result
|
||||||
.getParcelableExtra(OpenPgpApi.RESULT_INTENT);
|
.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import android.content.ContentValues;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.crypto.PgpDecryptionService;
|
||||||
import net.java.otr4j.crypto.OtrCryptoEngineImpl;
|
import net.java.otr4j.crypto.OtrCryptoEngineImpl;
|
||||||
import net.java.otr4j.crypto.OtrCryptoException;
|
import net.java.otr4j.crypto.OtrCryptoException;
|
||||||
|
|
||||||
|
@ -137,6 +138,7 @@ public class Account extends AbstractEntity {
|
||||||
protected boolean online = false;
|
protected boolean online = false;
|
||||||
private OtrService mOtrService = null;
|
private OtrService mOtrService = null;
|
||||||
private AxolotlService axolotlService = null;
|
private AxolotlService axolotlService = null;
|
||||||
|
private PgpDecryptionService pgpDecryptionService = null;
|
||||||
private XmppConnection xmppConnection = null;
|
private XmppConnection xmppConnection = null;
|
||||||
private long mEndGracePeriod = 0L;
|
private long mEndGracePeriod = 0L;
|
||||||
private String otrFingerprint;
|
private String otrFingerprint;
|
||||||
|
@ -313,12 +315,17 @@ public class Account extends AbstractEntity {
|
||||||
if (xmppConnection != null) {
|
if (xmppConnection != null) {
|
||||||
xmppConnection.addOnAdvancedStreamFeaturesAvailableListener(axolotlService);
|
xmppConnection.addOnAdvancedStreamFeaturesAvailableListener(axolotlService);
|
||||||
}
|
}
|
||||||
|
this.pgpDecryptionService = new PgpDecryptionService(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public OtrService getOtrService() {
|
public OtrService getOtrService() {
|
||||||
return this.mOtrService;
|
return this.mOtrService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PgpDecryptionService getPgpDecryptionService() {
|
||||||
|
return pgpDecryptionService;
|
||||||
|
}
|
||||||
|
|
||||||
public XmppConnection getXmppConnection() {
|
public XmppConnection getXmppConnection() {
|
||||||
return this.xmppConnection;
|
return this.xmppConnection;
|
||||||
}
|
}
|
||||||
|
|
|
@ -777,6 +777,7 @@ public class Conversation extends AbstractEntity implements Blockable {
|
||||||
synchronized (this.messages) {
|
synchronized (this.messages) {
|
||||||
this.messages.addAll(index, messages);
|
this.messages.addAll(index, messages);
|
||||||
}
|
}
|
||||||
|
account.getPgpDecryptionService().addAll(messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sort() {
|
public void sort() {
|
||||||
|
|
|
@ -3,6 +3,7 @@ package eu.siacs.conversations.parser;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.crypto.PgpDecryptionService;
|
||||||
import net.java.otr4j.session.Session;
|
import net.java.otr4j.session.Session;
|
||||||
import net.java.otr4j.session.SessionStatus;
|
import net.java.otr4j.session.SessionStatus;
|
||||||
|
|
||||||
|
@ -114,6 +115,13 @@ public class MessageParser extends AbstractParser implements
|
||||||
return finishedMessage;
|
return finishedMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Message parsePGPChat(final Conversation conversation, String pgpEncrypted, int status) {
|
||||||
|
final Message message = new Message(conversation, pgpEncrypted, Message.ENCRYPTION_PGP, status);
|
||||||
|
PgpDecryptionService pgpDecryptionService = conversation.getAccount().getPgpDecryptionService();
|
||||||
|
pgpDecryptionService.add(message);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
private class Invite {
|
private class Invite {
|
||||||
Jid jid;
|
Jid jid;
|
||||||
String password;
|
String password;
|
||||||
|
@ -337,7 +345,7 @@ public class MessageParser extends AbstractParser implements
|
||||||
message = new Message(conversation, body, Message.ENCRYPTION_NONE, status);
|
message = new Message(conversation, body, Message.ENCRYPTION_NONE, status);
|
||||||
}
|
}
|
||||||
} else if (pgpEncrypted != null) {
|
} else if (pgpEncrypted != null) {
|
||||||
message = new Message(conversation, pgpEncrypted, Message.ENCRYPTION_PGP, status);
|
message = parsePGPChat(conversation, pgpEncrypted, status);
|
||||||
} else if (axolotlEncrypted != null) {
|
} else if (axolotlEncrypted != null) {
|
||||||
message = parseAxolotlChat(axolotlEncrypted, from, remoteMsgId, conversation, status);
|
message = parseAxolotlChat(axolotlEncrypted, from, remoteMsgId, conversation, status);
|
||||||
if (message == null) {
|
if (message == null) {
|
||||||
|
|
|
@ -177,7 +177,7 @@ public class NotificationService {
|
||||||
mBuilder.setColor(mXmppConnectionService.getResources().getColor(R.color.primary));
|
mBuilder.setColor(mXmppConnectionService.getResources().getColor(R.color.primary));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateNotification(final boolean notify) {
|
public void updateNotification(final boolean notify) {
|
||||||
final NotificationManager notificationManager = (NotificationManager) mXmppConnectionService
|
final NotificationManager notificationManager = (NotificationManager) mXmppConnectionService
|
||||||
.getSystemService(Context.NOTIFICATION_SERVICE);
|
.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
final SharedPreferences preferences = mXmppConnectionService.getPreferences();
|
final SharedPreferences preferences = mXmppConnectionService.getPreferences();
|
||||||
|
|
|
@ -37,6 +37,7 @@ import net.java.otr4j.session.SessionID;
|
||||||
import net.java.otr4j.session.SessionImpl;
|
import net.java.otr4j.session.SessionImpl;
|
||||||
import net.java.otr4j.session.SessionStatus;
|
import net.java.otr4j.session.SessionStatus;
|
||||||
|
|
||||||
|
import org.openintents.openpgp.IOpenPgpService;
|
||||||
import org.openintents.openpgp.util.OpenPgpApi;
|
import org.openintents.openpgp.util.OpenPgpApi;
|
||||||
import org.openintents.openpgp.util.OpenPgpServiceConnection;
|
import org.openintents.openpgp.util.OpenPgpServiceConnection;
|
||||||
|
|
||||||
|
@ -659,7 +660,19 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
||||||
getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, contactObserver);
|
getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, contactObserver);
|
||||||
this.fileObserver.startWatching();
|
this.fileObserver.startWatching();
|
||||||
|
|
||||||
this.pgpServiceConnection = new OpenPgpServiceConnection(getApplicationContext(), "org.sufficientlysecure.keychain");
|
this.pgpServiceConnection = new OpenPgpServiceConnection(getApplicationContext(), "org.sufficientlysecure.keychain", new OpenPgpServiceConnection.OnBound() {
|
||||||
|
@Override
|
||||||
|
public void onBound(IOpenPgpService service) {
|
||||||
|
for (Account account : accounts) {
|
||||||
|
if (account.getPgpDecryptionService() != null) {
|
||||||
|
account.getPgpDecryptionService().onOpenPgpServiceBound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Exception e) { }
|
||||||
|
});
|
||||||
this.pgpServiceConnection.bindToService();
|
this.pgpServiceConnection.bindToService();
|
||||||
|
|
||||||
this.pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
|
this.pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
|
||||||
|
|
|
@ -1194,8 +1194,7 @@ public class ConversationActivity extends XmppActivity
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
if (resultCode == RESULT_OK) {
|
if (resultCode == RESULT_OK) {
|
||||||
if (requestCode == REQUEST_DECRYPT_PGP) {
|
if (requestCode == REQUEST_DECRYPT_PGP) {
|
||||||
mConversationFragment.hideSnackbar();
|
mConversationFragment.onActivityResult(requestCode, resultCode, data);
|
||||||
mConversationFragment.updateMessages();
|
|
||||||
} else if (requestCode == ATTACHMENT_CHOICE_CHOOSE_IMAGE) {
|
} else if (requestCode == ATTACHMENT_CHOICE_CHOOSE_IMAGE) {
|
||||||
mPendingImageUris.clear();
|
mPendingImageUris.clear();
|
||||||
mPendingImageUris.addAll(extractUriFromIntent(data));
|
mPendingImageUris.addAll(extractUriFromIntent(data));
|
||||||
|
@ -1240,6 +1239,9 @@ public class ConversationActivity extends XmppActivity
|
||||||
} else {
|
} else {
|
||||||
mPendingImageUris.clear();
|
mPendingImageUris.clear();
|
||||||
mPendingFileUris.clear();
|
mPendingFileUris.clear();
|
||||||
|
if (requestCode == ConversationActivity.REQUEST_DECRYPT_PGP) {
|
||||||
|
mConversationFragment.onActivityResult(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import android.content.Intent;
|
||||||
import android.content.IntentSender;
|
import android.content.IntentSender;
|
||||||
import android.content.IntentSender.SendIntentException;
|
import android.content.IntentSender.SendIntentException;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
import android.view.ContextMenu;
|
import android.view.ContextMenu;
|
||||||
import android.view.ContextMenu.ContextMenuInfo;
|
import android.view.ContextMenu.ContextMenuInfo;
|
||||||
|
@ -199,21 +200,47 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
private IntentSender askForPassphraseIntent = null;
|
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() {
|
protected OnClickListener clickToDecryptListener = new OnClickListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
if (activity.hasPgp() && askForPassphraseIntent != null) {
|
if (keychainUnlock == KEYCHAIN_UNLOCK_REQUIRED
|
||||||
try {
|
&& activity.hasPgp() && !conversation.getAccount().getPgpDecryptionService().isRunning()) {
|
||||||
getActivity().startIntentSenderForResult(
|
keychainUnlock = KEYCHAIN_UNLOCK_PENDING;
|
||||||
askForPassphraseIntent,
|
updateSnackBar(conversation);
|
||||||
ConversationActivity.REQUEST_DECRYPT_PGP, null, 0,
|
Message message = getLastPgpDecryptableMessage();
|
||||||
0, 0);
|
if (message != null) {
|
||||||
askForPassphraseIntent = null;
|
activity.xmppConnectionService.getPgpEngine().decrypt(message, new UiCallback<Message>() {
|
||||||
} catch (SendIntentException e) {
|
@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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
keychainUnlock = KEYCHAIN_UNLOCK_NOT_REQUIRED;
|
||||||
|
updatePgpMessages();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -224,8 +251,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
|
||||||
activity.verifyOtrSessionDialog(conversation, v);
|
activity.verifyOtrSessionDialog(conversation, v);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
private ConcurrentLinkedQueue<Message> mEncryptedMessages = new ConcurrentLinkedQueue<>();
|
|
||||||
private boolean mDecryptJobRunning = false;
|
|
||||||
private OnEditorActionListener mEditorActionListener = new OnEditorActionListener() {
|
private OnEditorActionListener mEditorActionListener = new OnEditorActionListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -629,7 +654,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStop() {
|
public void onStop() {
|
||||||
mDecryptJobRunning = false;
|
|
||||||
super.onStop();
|
super.onStop();
|
||||||
if (this.conversation != null) {
|
if (this.conversation != null) {
|
||||||
final String msg = mEditMessage.getText().toString();
|
final String msg = mEditMessage.getText().toString();
|
||||||
|
@ -661,10 +685,8 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
|
||||||
this.conversation.trim();
|
this.conversation.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.askForPassphraseIntent = null;
|
this.keychainUnlock = KEYCHAIN_UNLOCK_NOT_REQUIRED;
|
||||||
this.conversation = conversation;
|
this.conversation = conversation;
|
||||||
this.mDecryptJobRunning = false;
|
|
||||||
this.mEncryptedMessages.clear();
|
|
||||||
if (this.conversation.getMode() == Conversation.MODE_MULTI) {
|
if (this.conversation.getMode() == Conversation.MODE_MULTI) {
|
||||||
this.conversation.setNextCounterpart(null);
|
this.conversation.setNextCounterpart(null);
|
||||||
}
|
}
|
||||||
|
@ -767,7 +789,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (askForPassphraseIntent != null) {
|
} else if (keychainUnlock == KEYCHAIN_UNLOCK_REQUIRED) {
|
||||||
showSnackbar(R.string.openpgp_messages_found, R.string.decrypt, clickToDecryptListener);
|
showSnackbar(R.string.openpgp_messages_found, R.string.decrypt, clickToDecryptListener);
|
||||||
} else if (mode == Conversation.MODE_SINGLE
|
} else if (mode == Conversation.MODE_SINGLE
|
||||||
&& conversation.smpRequested()) {
|
&& conversation.smpRequested()) {
|
||||||
|
@ -791,19 +813,9 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
|
||||||
}
|
}
|
||||||
final ConversationActivity activity = (ConversationActivity) getActivity();
|
final ConversationActivity activity = (ConversationActivity) getActivity();
|
||||||
if (this.conversation != null) {
|
if (this.conversation != null) {
|
||||||
updateSnackBar(this.conversation);
|
|
||||||
conversation.populateWithMessages(ConversationFragment.this.messageList);
|
conversation.populateWithMessages(ConversationFragment.this.messageList);
|
||||||
for (final Message message : this.messageList) {
|
updatePgpMessages();
|
||||||
if (message.getEncryption() == Message.ENCRYPTION_PGP
|
updateSnackBar(conversation);
|
||||||
&& (message.getStatus() == Message.STATUS_RECEIVED || message
|
|
||||||
.getStatus() >= Message.STATUS_SEND)
|
|
||||||
&& message.getTransferable() == null) {
|
|
||||||
if (!mEncryptedMessages.contains(message)) {
|
|
||||||
mEncryptedMessages.add(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
decryptNext();
|
|
||||||
updateStatusMessages();
|
updateStatusMessages();
|
||||||
this.messageListAdapter.notifyDataSetChanged();
|
this.messageListAdapter.notifyDataSetChanged();
|
||||||
updateChatMsgHint();
|
updateChatMsgHint();
|
||||||
|
@ -815,48 +827,29 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void decryptNext() {
|
public void updatePgpMessages() {
|
||||||
Message next = this.mEncryptedMessages.peek();
|
if (keychainUnlock != KEYCHAIN_UNLOCK_PENDING) {
|
||||||
PgpEngine engine = activity.xmppConnectionService.getPgpEngine();
|
if (getLastPgpDecryptableMessage() != null
|
||||||
|
&& !conversation.getAccount().getPgpDecryptionService().isRunning()) {
|
||||||
if (next != null && engine != null && !mDecryptJobRunning) {
|
keychainUnlock = KEYCHAIN_UNLOCK_REQUIRED;
|
||||||
mDecryptJobRunning = true;
|
} else {
|
||||||
engine.decrypt(next, new UiCallback<Message>() {
|
keychainUnlock = KEYCHAIN_UNLOCK_NOT_REQUIRED;
|
||||||
|
}
|
||||||
@Override
|
|
||||||
public void userInputRequried(PendingIntent pi, Message message) {
|
|
||||||
mDecryptJobRunning = false;
|
|
||||||
askForPassphraseIntent = pi.getIntentSender();
|
|
||||||
updateSnackBar(conversation);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void success(Message message) {
|
|
||||||
mDecryptJobRunning = false;
|
|
||||||
try {
|
|
||||||
mEncryptedMessages.remove();
|
|
||||||
} catch (final NoSuchElementException ignored) {
|
|
||||||
|
|
||||||
}
|
|
||||||
askForPassphraseIntent = null;
|
|
||||||
activity.xmppConnectionService.updateMessage(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void error(int error, Message message) {
|
|
||||||
message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED);
|
|
||||||
mDecryptJobRunning = false;
|
|
||||||
try {
|
|
||||||
mEncryptedMessages.remove();
|
|
||||||
} catch (final NoSuchElementException ignored) {
|
|
||||||
|
|
||||||
}
|
|
||||||
activity.refreshUi();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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() {
|
private void messageSent() {
|
||||||
int size = this.messageList.size();
|
int size = this.messageList.size();
|
||||||
messagesView.setSelection(size - 1);
|
messagesView.setSelection(size - 1);
|
||||||
|
@ -1274,7 +1267,11 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
|
||||||
public void onActivityResult(int requestCode, int resultCode,
|
public void onActivityResult(int requestCode, int resultCode,
|
||||||
final Intent data) {
|
final Intent data) {
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
if (requestCode == ConversationActivity.REQUEST_TRUST_KEYS_TEXT) {
|
if (requestCode == ConversationActivity.REQUEST_DECRYPT_PGP) {
|
||||||
|
activity.getSelectedConversation().getAccount().getPgpDecryptionService().onKeychainUnlocked();
|
||||||
|
keychainUnlock = KEYCHAIN_UNLOCK_NOT_REQUIRED;
|
||||||
|
updatePgpMessages();
|
||||||
|
} 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());
|
||||||
sendAxolotlMessage(message);
|
sendAxolotlMessage(message);
|
||||||
|
@ -1282,6 +1279,11 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
|
||||||
int choice = data.getIntExtra("choice", ConversationActivity.ATTACHMENT_CHOICE_INVALID);
|
int choice = data.getIntExtra("choice", ConversationActivity.ATTACHMENT_CHOICE_INVALID);
|
||||||
activity.selectPresenceToAttachFile(choice, conversation.getNextEncryption());
|
activity.selectPresenceToAttachFile(choice, conversation.getNextEncryption());
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (requestCode == ConversationActivity.REQUEST_DECRYPT_PGP) {
|
||||||
|
keychainUnlock = KEYCHAIN_UNLOCK_NOT_REQUIRED;
|
||||||
|
updatePgpMessages();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -550,7 +550,11 @@ public class MessageAdapter extends ArrayAdapter<Message> {
|
||||||
}
|
}
|
||||||
} else if (message.getEncryption() == Message.ENCRYPTION_PGP) {
|
} else if (message.getEncryption() == Message.ENCRYPTION_PGP) {
|
||||||
if (activity.hasPgp()) {
|
if (activity.hasPgp()) {
|
||||||
displayInfoMessage(viewHolder,activity.getString(R.string.encrypted_message),darkBackground);
|
if (account.getPgpDecryptionService().isRunning()) {
|
||||||
|
displayInfoMessage(viewHolder, activity.getString(R.string.message_decrypting), darkBackground);
|
||||||
|
} else {
|
||||||
|
displayInfoMessage(viewHolder, activity.getString(R.string.pgp_message), darkBackground);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
displayInfoMessage(viewHolder,activity.getString(R.string.install_openkeychain),darkBackground);
|
displayInfoMessage(viewHolder,activity.getString(R.string.install_openkeychain),darkBackground);
|
||||||
if (viewHolder != null) {
|
if (viewHolder != null) {
|
||||||
|
|
|
@ -30,7 +30,8 @@
|
||||||
<string name="minutes_ago">%d mins ago</string>
|
<string name="minutes_ago">%d mins ago</string>
|
||||||
<string name="unread_conversations">unread Conversations</string>
|
<string name="unread_conversations">unread Conversations</string>
|
||||||
<string name="sending">sending…</string>
|
<string name="sending">sending…</string>
|
||||||
<string name="encrypted_message">Decrypting message. Please wait…</string>
|
<string name="message_decrypting">Decrypting message. Please wait…</string>
|
||||||
|
<string name="pgp_message">OpenPGP encrypted message</string>
|
||||||
<string name="nick_in_use">Nickname is already in use</string>
|
<string name="nick_in_use">Nickname is already in use</string>
|
||||||
<string name="admin">Admin</string>
|
<string name="admin">Admin</string>
|
||||||
<string name="owner">Owner</string>
|
<string name="owner">Owner</string>
|
||||||
|
|
Loading…
Reference in New Issue