forked from mirror/monocles_chat_clean
reactivated OTR (Arne)
This commit is contained in:
parent
87de2963d1
commit
4510188bcf
8 changed files with 388 additions and 10 deletions
|
@ -14,6 +14,15 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import android.os.Build;
|
||||
import android.text.Html;
|
||||
|
||||
import net.java.otr4j.session.Session;
|
||||
import net.java.otr4j.session.SessionStatus;
|
||||
import eu.siacs.conversations.crypto.OtrService;
|
||||
import eu.siacs.conversations.entities.Presence;
|
||||
import eu.siacs.conversations.entities.ServiceDiscoveryResult;
|
||||
|
||||
import eu.siacs.conversations.Config;
|
||||
import eu.siacs.conversations.R;
|
||||
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
||||
|
@ -52,6 +61,8 @@ import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
|
|||
|
||||
public class MessageParser extends AbstractParser implements OnMessagePacketReceived {
|
||||
|
||||
private static final List<String> CLIENTS_SENDING_HTML_IN_OTR = Arrays.asList("Pidgin", "Adium", "Trillian");
|
||||
|
||||
private static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss", Locale.ENGLISH);
|
||||
|
||||
private static final List<String> JINGLE_MESSAGE_ELEMENT_NAMES = Arrays.asList("accept", "propose", "proceed", "reject", "retract");
|
||||
|
@ -96,6 +107,31 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
|
|||
return result != null ? result : fallback;
|
||||
}
|
||||
|
||||
private static boolean clientMightSendHtml(Account account, Jid from) {
|
||||
String resource = from.getResource();
|
||||
if (resource == null) {
|
||||
return false;
|
||||
}
|
||||
Presence presence = account.getRoster().getContact(from).getPresences().getPresencesMap().get(resource);
|
||||
ServiceDiscoveryResult disco = presence == null ? null : presence.getServiceDiscoveryResult();
|
||||
if (disco == null) {
|
||||
return false;
|
||||
}
|
||||
return hasIdentityKnowForSendingHtml(disco.getIdentities());
|
||||
}
|
||||
|
||||
private static boolean hasIdentityKnowForSendingHtml(List<ServiceDiscoveryResult.Identity> identities) {
|
||||
for (ServiceDiscoveryResult.Identity identity : identities) {
|
||||
if (identity.getName() != null) {
|
||||
if (CLIENTS_SENDING_HTML_IN_OTR.contains(identity.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private boolean extractChatState(Conversation c, final boolean isTypeGroupChat, final MessagePacket packet) {
|
||||
ChatState state = ChatState.parse(packet);
|
||||
if (state != null && c != null) {
|
||||
|
@ -127,6 +163,67 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
|
|||
return false;
|
||||
}
|
||||
|
||||
private Message parseOtrChat(String body, Jid from, String id, Conversation conversation) {
|
||||
String presence;
|
||||
if (from.isBareJid()) {
|
||||
presence = "";
|
||||
} else {
|
||||
presence = from.getResource();
|
||||
}
|
||||
if (body.matches("^\\?OTRv\\d{1,2}\\?.*")) {
|
||||
conversation.endOtrIfNeeded();
|
||||
}
|
||||
if (!conversation.hasValidOtrSession()) {
|
||||
conversation.startOtrSession(presence, false);
|
||||
} else {
|
||||
String foreignPresence = conversation.getOtrSession().getSessionID().getUserID();
|
||||
if (!foreignPresence.equals(presence)) {
|
||||
conversation.endOtrIfNeeded();
|
||||
conversation.startOtrSession(presence, false);
|
||||
}
|
||||
}
|
||||
try {
|
||||
conversation.setLastReceivedOtrMessageId(id);
|
||||
Session otrSession = conversation.getOtrSession();
|
||||
body = otrSession.transformReceiving(body);
|
||||
SessionStatus status = otrSession.getSessionStatus();
|
||||
if (body == null && status == SessionStatus.ENCRYPTED) {
|
||||
mXmppConnectionService.onOtrSessionEstablished(conversation);
|
||||
return null;
|
||||
} else if (body == null && status == SessionStatus.FINISHED) {
|
||||
conversation.resetOtrSession();
|
||||
mXmppConnectionService.updateConversationUi();
|
||||
return null;
|
||||
} else if (body == null || (body.isEmpty())) {
|
||||
return null;
|
||||
}
|
||||
if (body.startsWith(CryptoHelper.FILETRANSFER)) {
|
||||
String key = body.substring(CryptoHelper.FILETRANSFER.length());
|
||||
conversation.setSymmetricKey(CryptoHelper.hexToBytes(key));
|
||||
return null;
|
||||
}
|
||||
if (clientMightSendHtml(conversation.getAccount(), from)) {
|
||||
Log.d(Config.LOGTAG, conversation.getAccount().getJid().asBareJid() + ": received OTR message from bad behaving client. escaping HTML…");
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
body = Html.fromHtml(body, Html.FROM_HTML_MODE_LEGACY).toString();
|
||||
} else {
|
||||
body = Html.fromHtml(body).toString();
|
||||
}
|
||||
}
|
||||
|
||||
final OtrService otrService = conversation.getAccount().getOtrService();
|
||||
Message finishedMessage = new Message(conversation, body, Message.ENCRYPTION_OTR, Message.STATUS_RECEIVED);
|
||||
finishedMessage.setFingerprint(otrService.getFingerprint(otrSession.getRemotePublicKey()));
|
||||
conversation.setLastReceivedOtrMessageId(null);
|
||||
|
||||
return finishedMessage;
|
||||
} catch (Exception e) {
|
||||
conversation.resetOtrSession();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Message parseAxolotlChat(Element axolotlMessage, Jid from, Conversation conversation, int status, final boolean checkedForDuplicates, boolean postpone) {
|
||||
final AxolotlService service = conversation.getAccount().getAxolotlService();
|
||||
final XmppAxolotlMessage xmppAxolotlMessage;
|
||||
|
@ -354,6 +451,15 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (message != null) {
|
||||
if (message.getEncryption() == Message.ENCRYPTION_OTR) {
|
||||
Conversation conversation = (Conversation) message.getConversation();
|
||||
conversation.endOtrIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -521,7 +627,20 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
|
|||
}
|
||||
}
|
||||
final Message message;
|
||||
if (pgpEncrypted != null && Config.supportOpenPgp()) {
|
||||
if (body != null && body.content.startsWith("?OTR") && Config.supportOtr()) {
|
||||
if (!isForwarded && !isTypeGroupChat && isProperlyAddressed && !conversationMultiMode) {
|
||||
message = parseOtrChat(body.content, from, remoteMsgId, conversation);
|
||||
if (message == null) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": ignoring OTR message from " + from + " isForwarded=" + Boolean.toString(isForwarded) + ", isProperlyAddressed=" + Boolean.valueOf(isProperlyAddressed));
|
||||
message = new Message(conversation, body.content, Message.ENCRYPTION_NONE, status);
|
||||
if (body.count > 1) {
|
||||
message.setBodyLanguage(body.language);
|
||||
}
|
||||
}
|
||||
} else if (pgpEncrypted != null && Config.supportOpenPgp()) {
|
||||
message = new Message(conversation, pgpEncrypted, Message.ENCRYPTION_PGP, status);
|
||||
} else if (axolotlEncrypted != null && Config.supportOmemo()) {
|
||||
Jid origin;
|
||||
|
@ -835,6 +954,13 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
|
|||
processMessageReceipts(account, packet, remoteMsgId, query);
|
||||
}
|
||||
|
||||
if (message.getStatus() == Message.STATUS_RECEIVED
|
||||
&& conversation.getOtrSession() != null
|
||||
&& !conversation.getOtrSession().getSessionID().getUserID()
|
||||
.equals(message.getCounterpart().getResource())) {
|
||||
conversation.endOtrIfNeeded();
|
||||
}
|
||||
|
||||
mXmppConnectionService.databaseBackend.createMessage(message);
|
||||
final HttpConnectionManager manager = this.mXmppConnectionService.getHttpConnectionManager();
|
||||
if ((mXmppConnectionService.easyDownloader() || message.trusted()) && message.treatAsDownloadable() && manager.getAutoAcceptFileSize() > 0) {
|
||||
|
|
|
@ -60,6 +60,13 @@ import android.util.DisplayMetrics;
|
|||
import android.util.Log;
|
||||
import android.util.LruCache;
|
||||
import android.util.Pair;
|
||||
import net.java.otr4j.OtrException;
|
||||
import net.java.otr4j.session.Session;
|
||||
import net.java.otr4j.session.SessionID;
|
||||
import net.java.otr4j.session.SessionImpl;
|
||||
import net.java.otr4j.session.SessionStatus;
|
||||
import eu.siacs.conversations.xmpp.jid.OtrJidHelper;
|
||||
import eu.siacs.conversations.xmpp.Jid;
|
||||
|
||||
import androidx.annotation.BoolRes;
|
||||
import androidx.annotation.IntegerRes;
|
||||
|
@ -260,9 +267,18 @@ public class XmppConnectionService extends Service {
|
|||
Conversation conversation = find(getConversations(), contact);
|
||||
if (conversation != null) {
|
||||
if (online) {
|
||||
conversation.endOtrIfNeeded();
|
||||
if (contact.getPresences().size() == 1) {
|
||||
sendUnsentMessages(conversation);
|
||||
}
|
||||
} else {
|
||||
//check if the resource we are haveing a conversation with is still online
|
||||
if (conversation.hasValidOtrSession()) {
|
||||
String otrResource = conversation.getOtrSession().getSessionID().getUserID();
|
||||
if (!(Arrays.asList(contact.getPresences().toResourceArray()).contains(otrResource))) {
|
||||
conversation.endOtrIfNeeded();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -443,6 +459,9 @@ public class XmppConnectionService extends Service {
|
|||
if (conversation.getAccount() == account
|
||||
&& !pendingJoin
|
||||
&& !inProgressJoin) {
|
||||
if (!conversation.startOtrIfNeeded()) {
|
||||
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": couldn't start OTR with " + conversation.getContact().getJid() + " when needed");
|
||||
}
|
||||
sendUnsentMessages(conversation);
|
||||
}
|
||||
}
|
||||
|
@ -1786,6 +1805,11 @@ public class XmppConnectionService extends Service {
|
|||
databaseBackend.updateConversation(conversation);
|
||||
}
|
||||
}
|
||||
if (!resend && message.getEncryption() != Message.ENCRYPTION_OTR) {
|
||||
conversation.endOtrIfNeeded();
|
||||
conversation.findUnsentMessagesWithEncryption(Message.ENCRYPTION_OTR,
|
||||
message1 -> markMessage(message1, Message.STATUS_SEND_FAILED));
|
||||
}
|
||||
|
||||
final boolean inProgressJoin = isJoinInProgress(conversation);
|
||||
|
||||
|
@ -1818,6 +1842,30 @@ public class XmppConnectionService extends Service {
|
|||
packet = mMessageGenerator.generatePgpChat(message);
|
||||
}
|
||||
break;
|
||||
case Message.ENCRYPTION_OTR:
|
||||
SessionImpl otrSession = conversation.getOtrSession();
|
||||
if (otrSession != null && otrSession.getSessionStatus() == SessionStatus.ENCRYPTED) {
|
||||
try {
|
||||
message.setCounterpart(OtrJidHelper.fromSessionID(otrSession.getSessionID()));
|
||||
} catch (IllegalArgumentException e) {
|
||||
break;
|
||||
}
|
||||
if (message.needsUploading()) {
|
||||
mJingleConnectionManager.startJingleFileTransfer(message);
|
||||
} else {
|
||||
packet = mMessageGenerator.generateOtrChat(message);
|
||||
}
|
||||
} else if (otrSession == null) {
|
||||
if (message.fixCounterpart()) {
|
||||
conversation.startOtrSession(message.getCounterpart().getResource(), true);
|
||||
} else {
|
||||
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": could not fix counterpart for OTR message to contact " + message.getCounterpart());
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
Log.d(Config.LOGTAG, account.getJid().asBareJid() + " OTR session with " + message.getContact() + " is in wrong state: " + otrSession.getSessionStatus().toString());
|
||||
}
|
||||
break;
|
||||
case Message.ENCRYPTION_AXOLOTL:
|
||||
message.setFingerprint(account.getAxolotlService().getOwnFingerprint());
|
||||
if (message.needsUploading()) {
|
||||
|
@ -1870,6 +1918,12 @@ public class XmppConnectionService extends Service {
|
|||
}
|
||||
}
|
||||
break;
|
||||
case Message.ENCRYPTION_OTR:
|
||||
if (!conversation.hasValidOtrSession() && message.getCounterpart() != null) {
|
||||
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": create otr session without starting for " + message.getContact().getJid());
|
||||
conversation.startOtrSession(message.getCounterpart().getResource(), false);
|
||||
}
|
||||
break;
|
||||
case Message.ENCRYPTION_AXOLOTL:
|
||||
message.setFingerprint(account.getAxolotlService().getOwnFingerprint());
|
||||
break;
|
||||
|
@ -3776,6 +3830,12 @@ public class XmppConnectionService extends Service {
|
|||
if (conversation.getAccount() == account) {
|
||||
if (conversation.getMode() == Conversation.MODE_MULTI) {
|
||||
leaveMuc(conversation, true);
|
||||
} else {
|
||||
if (conversation.endOtrIfNeeded()) {
|
||||
Log.d(Config.LOGTAG, account.getJid().asBareJid()
|
||||
+ ": ended otr session with "
|
||||
+ conversation.getJid());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3832,6 +3892,65 @@ public class XmppConnectionService extends Service {
|
|||
}
|
||||
pushContactToServer(contact, preAuth);
|
||||
}
|
||||
public void onOtrSessionEstablished(Conversation conversation) {
|
||||
final Account account = conversation.getAccount();
|
||||
final Session otrSession = conversation.getOtrSession();
|
||||
Log.d(Config.LOGTAG,
|
||||
account.getJid().asBareJid() + " otr session established with "
|
||||
+ conversation.getJid() + "/"
|
||||
+ otrSession.getSessionID().getUserID());
|
||||
conversation.findUnsentMessagesWithEncryption(Message.ENCRYPTION_OTR, new Conversation.OnMessageFound() {
|
||||
|
||||
@Override
|
||||
public void onMessageFound(Message message) {
|
||||
SessionID id = otrSession.getSessionID();
|
||||
try {
|
||||
message.setCounterpart(Jid.of(id.getAccountID() + "/" + id.getUserID()));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return;
|
||||
}
|
||||
if (message.needsUploading()) {
|
||||
mJingleConnectionManager.startJingleFileTransfer(message);
|
||||
} else {
|
||||
MessagePacket outPacket = mMessageGenerator.generateOtrChat(message);
|
||||
if (outPacket != null) {
|
||||
mMessageGenerator.addDelay(outPacket, message.getTimeSent());
|
||||
message.setStatus(Message.STATUS_SEND);
|
||||
databaseBackend.updateMessage(message, false);
|
||||
sendMessagePacket(account, outPacket);
|
||||
}
|
||||
}
|
||||
updateConversationUi();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean renewSymmetricKey(Conversation conversation) {
|
||||
Account account = conversation.getAccount();
|
||||
byte[] symmetricKey = new byte[32];
|
||||
this.mRandom.nextBytes(symmetricKey);
|
||||
Session otrSession = conversation.getOtrSession();
|
||||
if (otrSession != null) {
|
||||
MessagePacket packet = new MessagePacket();
|
||||
packet.setType(MessagePacket.TYPE_CHAT);
|
||||
packet.setFrom(account.getJid());
|
||||
MessageGenerator.addMessageHints(packet);
|
||||
packet.setAttribute("to", otrSession.getSessionID().getAccountID() + "/"
|
||||
+ otrSession.getSessionID().getUserID());
|
||||
try {
|
||||
packet.setBody(otrSession
|
||||
.transformSending(CryptoHelper.FILETRANSFER
|
||||
+ CryptoHelper.bytesToHex(symmetricKey))[0]);
|
||||
sendMessagePacket(account, packet);
|
||||
conversation.setSymmetricKey(symmetricKey);
|
||||
return true;
|
||||
} catch (OtrException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public void pushContactToServer(final Contact contact) {
|
||||
pushContactToServer(contact, null);
|
||||
|
@ -5209,7 +5328,10 @@ public class XmppConnectionService extends Service {
|
|||
boolean performedVerification = false;
|
||||
final AxolotlService axolotlService = contact.getAccount().getAxolotlService();
|
||||
for (XmppUri.Fingerprint fp : fingerprints) {
|
||||
if (fp.type == XmppUri.FingerprintType.OMEMO) {
|
||||
if (fp.type == XmppUri.FingerprintType.OTR) {
|
||||
performedVerification |= contact.addOtrFingerprint(fp.fingerprint);
|
||||
needsRosterWrite |= performedVerification;
|
||||
} else if (fp.type == XmppUri.FingerprintType.OMEMO) {
|
||||
String fingerprint = "05" + fp.fingerprint.replaceAll("\\s", "");
|
||||
FingerprintStatus fingerprintStatus = axolotlService.getFingerprintTrust(fingerprint);
|
||||
if (fingerprintStatus != null) {
|
||||
|
|
|
@ -163,6 +163,7 @@ import eu.siacs.conversations.xmpp.jingle.JingleFileTransferConnection;
|
|||
import eu.siacs.conversations.xmpp.jingle.OngoingRtpSession;
|
||||
import eu.siacs.conversations.xmpp.jingle.RtpCapability;
|
||||
import me.drakeet.support.toast.ToastCompat;
|
||||
import net.java.otr4j.session.SessionStatus;
|
||||
|
||||
public class ConversationFragment extends XmppFragment implements EditMessage.KeyboardListener, MessageAdapter.OnContactPictureLongClicked, MessageAdapter.OnContactPictureClicked {
|
||||
|
||||
|
@ -212,6 +213,12 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
|
|||
private Toast messageLoaderToast;
|
||||
private ConversationsActivity activity;
|
||||
private Menu mOptionsMenu;
|
||||
protected OnClickListener clickToVerify = new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
activity.verifyOtrSessionDialog(conversation, v);
|
||||
}
|
||||
};
|
||||
|
||||
private final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm (z)", Locale.US);
|
||||
|
||||
|
@ -508,6 +515,18 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
|
|||
}
|
||||
}
|
||||
};
|
||||
private OnClickListener mAnswerSmpClickListener = new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Intent intent = new Intent(activity, VerifyOTRActivity.class);
|
||||
intent.setAction(VerifyOTRActivity.ACTION_VERIFY_CONTACT);
|
||||
intent.putExtra(EXTRA_ACCOUNT, conversation.getAccount().getJid().asBareJid().toString());
|
||||
intent.putExtra(VerifyOTRActivity.EXTRA_ACCOUNT, conversation.getAccount().getJid().asBareJid().toString());
|
||||
intent.putExtra("mode", VerifyOTRActivity.MODE_ANSWER_QUESTION);
|
||||
startActivity(intent);
|
||||
activity.overridePendingTransition(R.animator.fade_in, R.animator.fade_out);
|
||||
}
|
||||
};
|
||||
|
||||
protected OnClickListener clickToDecryptListener = new OnClickListener() {
|
||||
|
||||
|
@ -921,6 +940,9 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
|
|||
message.setUuid(UUID.randomUUID().toString());
|
||||
}
|
||||
switch (conversation.getNextEncryption()) {
|
||||
case Message.ENCRYPTION_OTR:
|
||||
sendOtrMessage(message);
|
||||
break;
|
||||
case Message.ENCRYPTION_PGP:
|
||||
sendPgpMessage(message);
|
||||
break;
|
||||
|
@ -1051,7 +1073,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
|
|||
break;
|
||||
case REQUEST_INVITE_TO_CONVERSATION:
|
||||
XmppActivity.ConferenceInvite invite = XmppActivity.ConferenceInvite.parse(data);
|
||||
if (invite != null) {
|
||||
if (invite != null && activity != null) {
|
||||
if (invite.execute(activity)) {
|
||||
activity.mToast = ToastCompat.makeText(activity, R.string.creating_conference, ToastCompat.LENGTH_LONG);
|
||||
activity.mToast.show();
|
||||
|
@ -1611,6 +1633,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
|
|||
}
|
||||
switch (item.getItemId()) {
|
||||
case R.id.encryption_choice_axolotl:
|
||||
case R.id.encryption_choice_otr:
|
||||
case R.id.encryption_choice_pgp:
|
||||
case R.id.encryption_choice_none:
|
||||
handleEncryptionSelection(item);
|
||||
|
@ -1797,6 +1820,10 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
|
|||
updated = conversation.setNextEncryption(Message.ENCRYPTION_NONE);
|
||||
item.setChecked(true);
|
||||
break;
|
||||
case R.id.encryption_choice_otr:
|
||||
updated = conversation.setNextEncryption(Message.ENCRYPTION_OTR);
|
||||
item.setChecked(true);
|
||||
break;
|
||||
case R.id.encryption_choice_pgp:
|
||||
if (activity.hasPgp()) {
|
||||
if (conversation.getAccount().getPgpSignature() != null) {
|
||||
|
@ -2011,6 +2038,20 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
|
|||
activity.xmppConnectionService.getHttpConnectionManager().createNewDownloadConnection(message, true);
|
||||
}
|
||||
|
||||
private OnClickListener OTRwarning = new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
try {
|
||||
final Uri uri = Uri.parse("https://monocles.wiki/index.php?title=Monocles_Chat");
|
||||
Intent browserIntent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
startActivity(browserIntent);
|
||||
} catch (Exception e) {
|
||||
ToastCompat.makeText(activity, R.string.no_application_found_to_open_link, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@SuppressLint("InflateParams")
|
||||
protected void clearHistoryDialog(final Conversation conversation) {
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity());
|
||||
|
@ -2808,6 +2849,9 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
|
|||
}
|
||||
|
||||
private void updateSnackBar(final Conversation conversation) {
|
||||
if (conversation == null) {
|
||||
return;
|
||||
}
|
||||
final Account account = conversation.getAccount();
|
||||
final XmppConnection connection = account.getXmppConnection();
|
||||
final int mode = conversation.getMode();
|
||||
|
@ -2882,9 +2926,24 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
|
|||
}
|
||||
} else if (account.hasPendingPgpIntent(conversation)) {
|
||||
showSnackbar(R.string.openpgp_messages_found, R.string.decrypt, clickToDecryptListener);
|
||||
} else if (activity.warnUnecryptedChat()) {
|
||||
} else if (mode == Conversation.MODE_SINGLE
|
||||
&& conversation.smpRequested()) {
|
||||
showSnackbar(R.string.smp_requested, R.string.verify, this.mAnswerSmpClickListener);
|
||||
} else if (mode == Conversation.MODE_SINGLE
|
||||
&& conversation.hasValidOtrSession()
|
||||
&& (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED)
|
||||
&& (!conversation.isOtrFingerprintVerified())) {
|
||||
showSnackbar(R.string.unknown_otr_fingerprint, R.string.verify, clickToVerify);
|
||||
} else if (connection != null
|
||||
&& connection.getFeatures().blocking()
|
||||
&& conversation.countMessages() != 0
|
||||
&& !conversation.isBlocked()
|
||||
&& conversation.isWithStranger()) {
|
||||
showSnackbar(R.string.received_message_from_stranger, R.string.block, mBlockClickListener);
|
||||
} else if (activity != null && activity.warnUnecryptedChat()) {
|
||||
if (conversation.getNextEncryption() == Message.ENCRYPTION_NONE && conversation.isSingleOrPrivateAndNonAnonymous() && ((Config.supportOmemo() && Conversation.suitableForOmemoByDefault(conversation)) ||
|
||||
(Config.supportOpenPgp() && account.isPgpDecryptionServiceConnected()))) {
|
||||
(Config.supportOpenPgp() && account.isPgpDecryptionServiceConnected()) || (
|
||||
mode == Conversation.MODE_SINGLE && Config.supportOtr()))) {
|
||||
if (ENCRYPTION_EXCEPTIONS.contains(conversation.getJid().toString()) || conversation.getJid().toString().equals(account.getJid().getDomain())) {
|
||||
hideSnackbar();
|
||||
} else {
|
||||
|
@ -3275,7 +3334,16 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
|
|||
builder.setPositiveButton(getString(R.string.send_unencrypted), listener);
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
protected void sendOtrMessage(final Message message) {
|
||||
final ConversationsActivity activity = (ConversationsActivity) getActivity();
|
||||
final XmppConnectionService xmppService = activity.xmppConnectionService;
|
||||
activity.selectPresence(conversation,
|
||||
() -> {
|
||||
message.setCounterpart(conversation.getNextCounterpart());
|
||||
xmppService.sendMessage(message);
|
||||
messageSent();
|
||||
});
|
||||
}
|
||||
public void appendText(String text, final boolean doNotAppend) {
|
||||
if (text == null) {
|
||||
return;
|
||||
|
|
|
@ -58,6 +58,10 @@ import android.view.Menu;
|
|||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import net.java.otr4j.session.SessionStatus;
|
||||
import androidx.appcompat.widget.PopupMenu;
|
||||
|
||||
import androidx.annotation.IdRes;
|
||||
import androidx.annotation.NonNull;
|
||||
|
@ -979,7 +983,32 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void verifyOtrSessionDialog(final Conversation conversation, View view) {
|
||||
if (!conversation.hasValidOtrSession() || conversation.getOtrSession().getSessionStatus() != SessionStatus.ENCRYPTED) {
|
||||
ToastCompat.makeText(this, R.string.otr_session_not_started, Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
if (view == null) {
|
||||
return;
|
||||
}
|
||||
PopupMenu popup = new PopupMenu(this, view);
|
||||
popup.inflate(R.menu.verification_choices);
|
||||
popup.setOnMenuItemClickListener(menuItem -> {
|
||||
Intent intent = new Intent(ConversationsActivity.this, VerifyOTRActivity.class);
|
||||
intent.setAction(VerifyOTRActivity.ACTION_VERIFY_CONTACT);
|
||||
intent.putExtra("contact", conversation.getContact().getJid().asBareJid().toString());
|
||||
intent.putExtra(EXTRA_ACCOUNT, conversation.getAccount().getJid().asBareJid().toString());
|
||||
switch (menuItem.getItemId()) {
|
||||
case R.id.ask_question:
|
||||
intent.putExtra("mode", VerifyOTRActivity.MODE_ASK_QUESTION);
|
||||
break;
|
||||
}
|
||||
startActivity(intent);
|
||||
overridePendingTransition(R.animator.fade_in, R.animator.fade_out);
|
||||
return true;
|
||||
});
|
||||
popup.show();
|
||||
}
|
||||
@Override
|
||||
public void onConversationArchived(Conversation conversation) {
|
||||
if (performRedirectIfNecessary(conversation, false)) {
|
||||
|
|
|
@ -87,6 +87,7 @@ public class SettingsActivity extends XmppActivity implements
|
|||
public static final String MAPPREVIEW_HOST = "mappreview_host";
|
||||
public static final String ALLOW_MESSAGE_CORRECTION = "allow_message_correction";
|
||||
public static final String ALLOW_MESSAGE_RETRACTION = "allow_message_retraction";
|
||||
public static final String ENABLE_OTR_ENCRYPTION = "enable_otr_encryption";
|
||||
public static final String USE_UNICOLORED_CHATBG = "unicolored_chatbg";
|
||||
public static final String EASY_DOWNLOADER = "easy_downloader";
|
||||
public static final String MIN_ANDROID_SDK21_SHOWN = "min_android_sdk21_shown";
|
||||
|
|
|
@ -105,6 +105,13 @@ import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
|
|||
import eu.siacs.conversations.xmpp.XmppConnection;
|
||||
import me.drakeet.support.toast.ToastCompat;
|
||||
import pl.droidsonroids.gif.GifDrawable;
|
||||
import android.util.Pair;
|
||||
import net.java.otr4j.session.SessionID;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import eu.siacs.conversations.utils.CryptoHelper;
|
||||
import static eu.siacs.conversations.ui.SettingsActivity.ENABLE_OTR_ENCRYPTION;
|
||||
|
||||
public abstract class XmppActivity extends ActionBarActivity {
|
||||
|
||||
|
@ -419,7 +426,17 @@ public abstract class XmppActivity extends ActionBarActivity {
|
|||
|
||||
public void selectPresence(final Conversation conversation, final PresenceSelector.OnPresenceSelected listener) {
|
||||
final Contact contact = conversation.getContact();
|
||||
if (contact.showInRoster() || contact.isSelf()) {
|
||||
if (conversation.hasValidOtrSession()) {
|
||||
SessionID id = conversation.getOtrSession().getSessionID();
|
||||
Jid jid;
|
||||
try {
|
||||
jid = Jid.of(id.getAccountID() + "/" + id.getUserID());
|
||||
} catch (IllegalArgumentException e) {
|
||||
jid = null;
|
||||
}
|
||||
conversation.setNextCounterpart(jid);
|
||||
listener.onPresenceSelected();
|
||||
} else if (contact.showInRoster() || contact.isSelf()) {
|
||||
final Presences presences = contact.getPresences();
|
||||
if (presences.size() == 0) {
|
||||
if (contact.isSelf()) {
|
||||
|
@ -485,7 +502,9 @@ public abstract class XmppActivity extends ActionBarActivity {
|
|||
public boolean unicoloredBG() {
|
||||
return getBooleanPreference("unicolored_chatbg", R.bool.use_unicolored_chatbg) || getPreferences().getString(SettingsActivity.THEME, getString(R.string.theme)).equals("black");
|
||||
}
|
||||
|
||||
public boolean enableOTR() {
|
||||
return getBooleanPreference(ENABLE_OTR_ENCRYPTION, R.bool.enable_otr);
|
||||
}
|
||||
public boolean showDateInQuotes() {
|
||||
return getBooleanPreference("show_date_in_quotes", R.bool.show_date_in_quotes);
|
||||
}
|
||||
|
|
|
@ -104,6 +104,7 @@ public class ConversationMenuConfigurator {
|
|||
return;
|
||||
}
|
||||
final MenuItem none = menu.findItem(R.id.encryption_choice_none);
|
||||
final MenuItem otr = menu.findItem(R.id.encryption_choice_otr);
|
||||
final MenuItem pgp = menu.findItem(R.id.encryption_choice_pgp);
|
||||
final MenuItem axolotl = menu.findItem(R.id.encryption_choice_axolotl);
|
||||
|
||||
|
@ -131,11 +132,18 @@ public class ConversationMenuConfigurator {
|
|||
if (conversation.getNextEncryption() != Message.ENCRYPTION_NONE) {
|
||||
menuSecure.setIcon(R.drawable.ic_lock_white_24dp);
|
||||
}
|
||||
|
||||
otr.setVisible(Config.supportOtr() && activity.enableOTR());
|
||||
if (conversation.getMode() == Conversation.MODE_MULTI) {
|
||||
otr.setVisible(false);
|
||||
}
|
||||
pgp.setVisible(Config.supportOpenPgp());
|
||||
none.setVisible(Config.supportUnencrypted() || conversation.getMode() == Conversation.MODE_MULTI);
|
||||
axolotl.setVisible(Config.supportOmemo());
|
||||
switch (conversation.getNextEncryption()) {
|
||||
case Message.ENCRYPTION_OTR:
|
||||
menuSecure.setTitle(R.string.encryption_choice_otr);
|
||||
otr.setChecked(true);
|
||||
break;
|
||||
case Message.ENCRYPTION_PGP:
|
||||
menuSecure.setTitle(R.string.encrypted_with_openpgp);
|
||||
pgp.setChecked(true);
|
||||
|
|
|
@ -509,6 +509,11 @@
|
|||
android:key="delete_omemo_identities"
|
||||
android:summary="@string/pref_delete_omemo_identities_summary"
|
||||
android:title="@string/pref_delete_omemo_identities" />
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="@bool/enable_otr"
|
||||
android:key="enable_otr_encryption"
|
||||
android:summary="@string/pref_enable_otr_summary"
|
||||
android:title="@string/pref_enable_otr" />
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="@bool/dont_trust_system_cas"
|
||||
android:key="dont_trust_system_cas"
|
||||
|
|
Loading…
Add table
Reference in a new issue