remove OTR

This commit is contained in:
Christian Schneppe 2020-06-10 21:45:59 +02:00
parent 74c11b6712
commit 2f812d5a7d
28 changed files with 17 additions and 1809 deletions

View file

@ -50,7 +50,6 @@ dependencies {
exclude group: 'com.android.support', module: 'exifinterface'
}
implementation 'org.bouncycastle:bcmail-jdk15on:1.64'
implementation 'org.jitsi:org.otr4j:0.22'
implementation 'org.gnu.inet:libidn:1.15'
implementation 'com.google.zxing:core:3.3.3' // > 3.3.x not working below SDK 24
implementation 'de.measite.minidns:minidns-hla:0.2.4'

View file

@ -243,10 +243,6 @@
<activity
android:name=".ui.PublishGroupChatProfilePictureActivity"
android:label="@string/group_chat_avatar" />
<activity
android:name=".ui.VerifyOTRActivity"
android:label="@string/verify_otr"
android:windowSoftInputMode="stateHidden" />
<activity
android:name=".ui.ShareWithActivity"
android:label="@string/app_name"

View file

@ -1,312 +0,0 @@
package eu.siacs.conversations.crypto;
import android.util.Log;
import net.java.otr4j.OtrEngineHost;
import net.java.otr4j.OtrException;
import net.java.otr4j.OtrPolicy;
import net.java.otr4j.OtrPolicyImpl;
import net.java.otr4j.crypto.OtrCryptoEngineImpl;
import net.java.otr4j.crypto.OtrCryptoException;
import net.java.otr4j.session.FragmenterInstructions;
import net.java.otr4j.session.InstanceTag;
import net.java.otr4j.session.SessionID;
import org.json.JSONException;
import org.json.JSONObject;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.DSAPrivateKeySpec;
import java.security.spec.DSAPublicKeySpec;
import java.security.spec.InvalidKeySpecException;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.generator.MessageGenerator;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.chatstate.ChatState;
import eu.siacs.conversations.xmpp.jid.OtrJidHelper;
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
public class OtrService extends OtrCryptoEngineImpl implements OtrEngineHost {
private Account account;
private OtrPolicy otrPolicy;
private KeyPair keyPair;
private XmppConnectionService mXmppConnectionService;
public OtrService(XmppConnectionService service, Account account) {
this.account = account;
this.otrPolicy = new OtrPolicyImpl();
this.otrPolicy.setAllowV1(false);
this.otrPolicy.setAllowV2(true);
this.otrPolicy.setAllowV3(true);
this.keyPair = loadKey(account.getKeys());
this.mXmppConnectionService = service;
}
private KeyPair loadKey(final JSONObject keys) {
if (keys == null) {
return null;
}
synchronized (keys) {
try {
BigInteger x = new BigInteger(keys.getString("otr_x"), 16);
BigInteger y = new BigInteger(keys.getString("otr_y"), 16);
BigInteger p = new BigInteger(keys.getString("otr_p"), 16);
BigInteger q = new BigInteger(keys.getString("otr_q"), 16);
BigInteger g = new BigInteger(keys.getString("otr_g"), 16);
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
DSAPublicKeySpec pubKeySpec = new DSAPublicKeySpec(y, p, q, g);
DSAPrivateKeySpec privateKeySpec = new DSAPrivateKeySpec(x, p, q, g);
PublicKey publicKey = keyFactory.generatePublic(pubKeySpec);
PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
return new KeyPair(publicKey, privateKey);
} catch (JSONException e) {
return null;
} catch (NoSuchAlgorithmException e) {
return null;
} catch (InvalidKeySpecException e) {
return null;
}
}
}
private void saveKey() {
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
KeyFactory keyFactory;
try {
keyFactory = KeyFactory.getInstance("DSA");
DSAPrivateKeySpec privateKeySpec = keyFactory.getKeySpec(
privateKey, DSAPrivateKeySpec.class);
DSAPublicKeySpec publicKeySpec = keyFactory.getKeySpec(publicKey,
DSAPublicKeySpec.class);
this.account.setKey("otr_x", privateKeySpec.getX().toString(16));
this.account.setKey("otr_g", privateKeySpec.getG().toString(16));
this.account.setKey("otr_p", privateKeySpec.getP().toString(16));
this.account.setKey("otr_q", privateKeySpec.getQ().toString(16));
this.account.setKey("otr_y", publicKeySpec.getY().toString(16));
} catch (final NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (final InvalidKeySpecException e) {
e.printStackTrace();
}
}
@Override
public void askForSecret(SessionID id, InstanceTag instanceTag, String question) {
try {
final Jid jid = OtrJidHelper.fromSessionID(id);
Conversation conversation = this.mXmppConnectionService.find(this.account, jid);
if (conversation != null) {
conversation.smp().hint = question;
conversation.smp().status = Conversation.Smp.STATUS_CONTACT_REQUESTED;
mXmppConnectionService.updateConversationUi();
}
} catch (IllegalArgumentException e) {
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": smp in invalid session " + id.toString());
}
}
@Override
public void finishedSessionMessage(SessionID arg0, String arg1)
throws OtrException {
}
@Override
public String getFallbackMessage(SessionID arg0) {
return MessageGenerator.OTR_FALLBACK_MESSAGE;
}
@Override
public byte[] getLocalFingerprintRaw(SessionID arg0) {
try {
return getFingerprintRaw(getPublicKey());
} catch (OtrCryptoException e) {
return null;
}
}
public PublicKey getPublicKey() {
if (this.keyPair == null) {
return null;
}
return this.keyPair.getPublic();
}
@Override
public KeyPair getLocalKeyPair(SessionID arg0) throws OtrException {
if (this.keyPair == null) {
KeyPairGenerator kg;
try {
kg = KeyPairGenerator.getInstance("DSA");
this.keyPair = kg.genKeyPair();
this.saveKey();
mXmppConnectionService.databaseBackend.updateAccount(account);
} catch (NoSuchAlgorithmException e) {
Log.d(Config.LOGTAG,
"error generating key pair " + e.getMessage());
}
}
return this.keyPair;
}
@Override
public String getReplyForUnreadableMessage(SessionID arg0) {
// TODO Auto-generated method stub
return null;
}
@Override
public OtrPolicy getSessionPolicy(SessionID arg0) {
return otrPolicy;
}
@Override
public void injectMessage(SessionID session, String body)
throws OtrException {
MessagePacket packet = new MessagePacket();
packet.setFrom(account.getJid());
if (session.getUserID().isEmpty()) {
packet.setAttribute("to", session.getAccountID());
} else {
packet.setAttribute("to", session.getAccountID() + "/" + session.getUserID());
}
packet.setBody(body);
MessageGenerator.addMessageHints(packet);
try {
Jid jid = OtrJidHelper.fromSessionID(session);
Conversation conversation = mXmppConnectionService.find(account, jid);
if (conversation != null && conversation.setOutgoingChatState(Config.DEFAULT_CHAT_STATE)) {
if (mXmppConnectionService.sendChatStates()) {
packet.addChild(ChatState.toElement(conversation.getOutgoingChatState()));
}
}
} catch (final IllegalArgumentException ignored) {
}
packet.setType(MessagePacket.TYPE_CHAT);
packet.addChild("encryption", "urn:xmpp:eme:0").setAttribute("namespace", "urn:xmpp:otr:0");
account.getXmppConnection().sendMessagePacket(packet);
}
@Override
public void messageFromAnotherInstanceReceived(SessionID session) {
sendOtrErrorMessage(session, "Message from another OTR-instance received");
}
@Override
public void multipleInstancesDetected(SessionID arg0) {
// TODO Auto-generated method stub
}
@Override
public void requireEncryptedMessage(SessionID arg0, String arg1)
throws OtrException {
// TODO Auto-generated method stub
}
@Override
public void showError(SessionID arg0, String arg1) throws OtrException {
Log.d(Config.LOGTAG, "show error");
}
@Override
public void smpAborted(SessionID id) throws OtrException {
setSmpStatus(id, Conversation.Smp.STATUS_NONE);
}
private void setSmpStatus(SessionID id, int status) {
try {
final Jid jid = OtrJidHelper.fromSessionID(id);
Conversation conversation = this.mXmppConnectionService.find(this.account, jid);
if (conversation != null) {
conversation.smp().status = status;
mXmppConnectionService.updateConversationUi();
}
} catch (final IllegalArgumentException ignored) {
}
}
@Override
public void smpError(SessionID id, int arg1, boolean arg2)
throws OtrException {
setSmpStatus(id, Conversation.Smp.STATUS_NONE);
}
@Override
public void unencryptedMessageReceived(SessionID arg0, String arg1)
throws OtrException {
throw new OtrException(new Exception("unencrypted message received"));
}
@Override
public void unreadableMessageReceived(SessionID session) throws OtrException {
Log.d(Config.LOGTAG, "unreadable message received");
sendOtrErrorMessage(session, "You sent me an unreadable OTR-encrypted message");
}
public void sendOtrErrorMessage(SessionID session, String errorText) {
try {
Jid jid = OtrJidHelper.fromSessionID(session);
Conversation conversation = mXmppConnectionService.find(account, jid);
String id = conversation == null ? null : conversation.getLastReceivedOtrMessageId();
if (id != null) {
MessagePacket packet = mXmppConnectionService.getMessageGenerator()
.generateOtrError(jid, id, errorText);
packet.setFrom(account.getJid());
mXmppConnectionService.sendMessagePacket(account, packet);
Log.d(Config.LOGTAG, packet.toString());
Log.d(Config.LOGTAG, account.getJid().asBareJid().toString()
+ ": unreadable OTR message in " + conversation.getName());
}
} catch (IllegalArgumentException e) {
return;
}
}
@Override
public void unverify(SessionID id, String arg1) {
setSmpStatus(id, Conversation.Smp.STATUS_FAILED);
}
@Override
public void verify(SessionID id, String fingerprint, boolean approved) {
Log.d(Config.LOGTAG, "OtrService.verify(" + id.toString() + "," + fingerprint + "," + String.valueOf(approved) + ")");
try {
final Jid jid = OtrJidHelper.fromSessionID(id);
Conversation conversation = this.mXmppConnectionService.find(this.account, jid);
if (conversation != null) {
if (approved) {
conversation.getContact().addOtrFingerprint(fingerprint);
}
conversation.smp().hint = null;
conversation.smp().status = Conversation.Smp.STATUS_VERIFIED;
mXmppConnectionService.updateConversationUi();
mXmppConnectionService.syncRosterToDisk(conversation.getAccount());
}
} catch (final IllegalArgumentException ignored) {
}
}
@Override
public FragmenterInstructions getFragmenterInstructions(SessionID sessionID) {
return null;
}
}

View file

@ -6,27 +6,20 @@ import android.os.SystemClock;
import android.util.Log;
import android.util.Pair;
import net.java.otr4j.crypto.OtrCryptoEngineImpl;
import net.java.otr4j.crypto.OtrCryptoException;
import org.json.JSONException;
import org.json.JSONObject;
import java.security.PublicKey;
import java.security.interfaces.DSAPublicKey;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.OtrService;
import eu.siacs.conversations.crypto.PgpDecryptionService;
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession;
@ -34,9 +27,9 @@ import eu.siacs.conversations.services.AvatarService;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.XmppConnection;
import eu.siacs.conversations.xmpp.jingle.RtpCapability;
import eu.siacs.conversations.xmpp.Jid;
public class Account extends AbstractEntity implements AvatarService.Avatarable {
@ -89,7 +82,6 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
protected String hostname = null;
protected int port = 5222;
protected boolean online = false;
private OtrService mOtrService = null;
private String rosterVersion;
private String displayName = null;
private AxolotlService axolotlService = null;
@ -404,7 +396,6 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
}
public void initAccountServices(final XmppConnectionService context) {
this.mOtrService = new OtrService(context, this);
this.axolotlService = new AxolotlService(this, context);
this.pgpDecryptionService = new PgpDecryptionService(context);
if (xmppConnection != null) {
@ -412,10 +403,6 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
}
}
public OtrService getOtrService() {
return this.mOtrService;
}
public PgpDecryptionService getPgpDecryptionService() {
return this.pgpDecryptionService;
}
@ -428,26 +415,6 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
this.xmppConnection = connection;
}
public String getOtrFingerprint() {
if (this.otrFingerprint == null) {
try {
if (this.mOtrService == null) {
return null;
}
final PublicKey publicKey = this.mOtrService.getPublicKey();
if (publicKey == null || !(publicKey instanceof DSAPublicKey)) {
return null;
}
this.otrFingerprint = new OtrCryptoEngineImpl().getFingerprint(publicKey).toLowerCase(Locale.US);
return this.otrFingerprint;
} catch (final OtrCryptoException ignored) {
return null;
}
} else {
return this.otrFingerprint;
}
}
public String getRosterVersion() {
if (this.rosterVersion == null) {
return "";
@ -611,10 +578,6 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
private List<XmppUri.Fingerprint> getFingerprints() {
ArrayList<XmppUri.Fingerprint> fingerprints = new ArrayList<>();
final String otr = this.getOtrFingerprint();
if (otr != null) {
fingerprints.add(new XmppUri.Fingerprint(XmppUri.FingerprintType.OTR, otr));
}
if (axolotlService == null) {
return fingerprints;
}

View file

@ -9,23 +9,16 @@ import androidx.annotation.Nullable;
import com.google.common.collect.ComparisonChain;
import net.java.otr4j.OtrException;
import net.java.otr4j.crypto.OtrCryptoException;
import net.java.otr4j.session.SessionID;
import net.java.otr4j.session.SessionImpl;
import net.java.otr4j.session.SessionStatus;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.security.interfaces.DSAPublicKey;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicBoolean;
import eu.siacs.conversations.Config;
@ -36,9 +29,9 @@ import eu.siacs.conversations.services.AvatarService;
import eu.siacs.conversations.services.QuickConversationsService;
import eu.siacs.conversations.utils.JidHelper;
import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.chatstate.ChatState;
import eu.siacs.conversations.xmpp.mam.MamReference;
import eu.siacs.conversations.xmpp.Jid;
import static eu.siacs.conversations.entities.Bookmark.printableValue;
@ -85,15 +78,10 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
private int mode;
private JSONObject attributes;
private Jid nextCounterpart;
private transient SessionImpl otrSession;
private transient String otrFingerprint = null;
private Smp mSmp = new Smp();
private transient MucOptions mucOptions = null;
private byte[] symmetricKey;
private boolean messagesLeftOnServer = true;
private ChatState mOutgoingChatState = Config.DEFAULT_CHAT_STATE;
private ChatState mIncomingChatState = Config.DEFAULT_CHAT_STATE;
private String mLastReceivedOtrMessageId = null;
private String mFirstMamReference = null;
public Conversation(final String name, final Account account, final Jid contactJid,
@ -357,17 +345,6 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
}
}
public void findUnsentMessagesWithEncryption(int encryptionType, OnMessageFound onMessageFound) {
synchronized (this.messages) {
for (Message message : this.messages) {
if ((message.getStatus() == Message.STATUS_UNSEND || message.getStatus() == Message.STATUS_WAITING)
&& (message.getEncryption() == encryptionType)) {
onMessageFound.onMessageFound(message);
}
}
}
}
public void findUnsentTextMessages(OnMessageFound onMessageFound) {
final ArrayList<Message> results = new ArrayList<>();
synchronized (this.messages) {
@ -489,14 +466,6 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
return getContact().getBlockedJid();
}
public String getLastReceivedOtrMessageId() {
return this.mLastReceivedOtrMessageId;
}
public void setLastReceivedOtrMessageId(String id) {
this.mLastReceivedOtrMessageId = id;
}
public int countMessages() {
synchronized (this.messages) {
return this.messages.size();
@ -693,112 +662,6 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
this.mode = mode;
}
public SessionImpl startOtrSession(String presence, boolean sendStart) {
if (this.otrSession != null) {
return this.otrSession;
} else {
final SessionID sessionId = new SessionID(this.getJid().asBareJid().toString(),
presence,
"xmpp");
this.otrSession = new SessionImpl(sessionId, getAccount().getOtrService());
try {
if (sendStart) {
this.otrSession.startSession();
return this.otrSession;
}
return this.otrSession;
} catch (OtrException e) {
return null;
}
}
}
public SessionImpl getOtrSession() {
return this.otrSession;
}
public void resetOtrSession() {
this.otrFingerprint = null;
this.otrSession = null;
this.mSmp.hint = null;
this.mSmp.secret = null;
this.mSmp.status = Smp.STATUS_NONE;
}
public Smp smp() {
return mSmp;
}
public boolean startOtrIfNeeded() {
if (this.otrSession != null && this.otrSession.getSessionStatus() != SessionStatus.ENCRYPTED) {
try {
this.otrSession.startSession();
return true;
} catch (OtrException e) {
this.resetOtrSession();
return false;
}
} else {
return true;
}
}
public boolean endOtrIfNeeded() {
if (this.otrSession != null) {
if (this.otrSession.getSessionStatus() == SessionStatus.ENCRYPTED) {
try {
this.otrSession.endSession();
this.resetOtrSession();
return true;
} catch (OtrException e) {
this.resetOtrSession();
return false;
}
} else {
this.resetOtrSession();
return false;
}
} else {
return false;
}
}
public boolean hasValidOtrSession() {
return this.otrSession != null;
}
public synchronized String getOtrFingerprint() {
if (this.otrFingerprint == null) {
try {
if (getOtrSession() == null || getOtrSession().getSessionStatus() != SessionStatus.ENCRYPTED) {
return null;
}
DSAPublicKey remotePubKey = (DSAPublicKey) getOtrSession().getRemotePublicKey();
this.otrFingerprint = getAccount().getOtrService().getFingerprint(remotePubKey).toLowerCase(Locale.US);
} catch (final OtrCryptoException ignored) {
return null;
} catch (final UnsupportedOperationException ignored) {
return null;
}
}
return this.otrFingerprint;
}
public boolean verifyOtrFingerprint() {
final String fingerprint = getOtrFingerprint();
if (fingerprint != null) {
getContact().addOtrFingerprint(fingerprint);
return true;
} else {
return false;
}
}
public boolean isOtrFingerprintVerified() {
return getContact().getOtrFingerprints().contains(getOtrFingerprint());
}
/**
* short for is Private and Non-anonymous
*/
@ -834,7 +697,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
}
public int getNextEncryption() {
if (!Config.supportOmemo() && !Config.supportOpenPgp() && !Config.supportOtr()) {
if (!Config.supportOmemo() && !Config.supportOpenPgp()) {
return Message.ENCRYPTION_NONE;
}
if (OmemoSetting.isAlways()) {
@ -850,10 +713,8 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
defaultEncryption = Message.ENCRYPTION_NONE;
}
int encryption = this.getIntAttribute(ATTRIBUTE_NEXT_ENCRYPTION, defaultEncryption);
if (encryption < 0) {
if (encryption == Message.ENCRYPTION_OTR || encryption < 0) {
return defaultEncryption;
} else if (encryption == Message.ENCRYPTION_OTR) {
return encryption;
} else {
return encryption;
}
@ -868,10 +729,6 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
return nextMessage == null ? "" : nextMessage;
}
public boolean smpRequested() {
return smp().status == Smp.STATUS_CONTACT_REQUESTED;
}
public @Nullable
Draft getDraft() {
long timestamp = getLongAttribute(ATTRIBUTE_NEXT_MESSAGE_TIMESTAMP, 0);
@ -894,14 +751,6 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
return changed;
}
public void setSymmetricKey(byte[] key) {
this.symmetricKey = key;
}
public byte[] getSymmetricKey() {
return this.symmetricKey;
}
public Bookmark getBookmark() {
return this.account.getBookmark(this.contactJid);
}
@ -1263,16 +1112,4 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
return message;
}
}
public class Smp {
public static final int STATUS_NONE = 0;
public static final int STATUS_CONTACT_REQUESTED = 1;
public static final int STATUS_WE_REQUESTED = 2;
public static final int STATUS_FAILED = 3;
public static final int STATUS_VERIFIED = 4;
public String secret = null;
public String hint = null;
public int status = 0;
}
}
}

View file

@ -1,8 +1,5 @@
package eu.siacs.conversations.generator;
import net.java.otr4j.OtrException;
import net.java.otr4j.session.Session;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@ -29,7 +26,6 @@ import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
import eu.siacs.conversations.xmpp.Jid;
public class MessageGenerator extends AbstractGenerator {
public static final String OTR_FALLBACK_MESSAGE = "I would like to start a private (OTR encrypted) conversation but your client doesnt seem to support that";
private static final String OMEMO_FALLBACK_MESSAGE = "I sent you an OMEMO encrypted message but your client doesnt seem to support that. Find more information on https://conversations.im/omemo";
private static final String PGP_FALLBACK_MESSAGE = "I sent you a PGP encrypted message but your client doesnt seem to support that.";
@ -111,29 +107,6 @@ public class MessageGenerator extends AbstractGenerator {
packet.addChild("no-permanent-storage", "urn:xmpp:hints"); //do not copy this. this is wrong. it is *store*
}
public MessagePacket generateOtrChat(Message message) {
Conversation conversation = (Conversation) message.getConversation();
Session otrSession = conversation.getOtrSession();
if (otrSession == null) {
return null;
}
MessagePacket packet = preparePacket(message);
addMessageHints(packet);
try {
String content;
if (message.hasFileOnRemoteHost()) {
content = message.getFileParams().url.toString();
} else {
content = message.getBody();
}
packet.setBody(otrSession.transformSending(content)[0]);
packet.addChild("encryption", "urn:xmpp:eme:0").setAttribute("namespace", "urn:xmpp:otr:0");
return packet;
} catch (OtrException e) {
return null;
}
}
public MessagePacket generateChat(Message message) {
MessagePacket packet = preparePacket(message);
String content;

View file

@ -1,13 +1,8 @@
package eu.siacs.conversations.parser;
import android.os.Build;
import android.text.Html;
import android.util.Log;
import android.util.Pair;
import net.java.otr4j.session.Session;
import net.java.otr4j.session.SessionStatus;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@ -22,7 +17,6 @@ import java.util.UUID;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.OtrService;
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
import eu.siacs.conversations.crypto.axolotl.BrokenSessionException;
import eu.siacs.conversations.crypto.axolotl.NotEncryptedForThisDeviceException;
@ -35,10 +29,8 @@ import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Conversational;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.MucOptions;
import eu.siacs.conversations.entities.Presence;
import eu.siacs.conversations.entities.ReadByMarker;
import eu.siacs.conversations.entities.ReceiptRequest;
import eu.siacs.conversations.entities.ServiceDiscoveryResult;
import eu.siacs.conversations.entities.RtpSessionStatus;
import eu.siacs.conversations.http.HttpConnectionManager;
import eu.siacs.conversations.http.P1S3UrlStreamHandler;
@ -49,20 +41,19 @@ import eu.siacs.conversations.utils.Namespace;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.LocalizedContent;
import eu.siacs.conversations.xmpp.InvalidJid;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.OnMessagePacketReceived;
import eu.siacs.conversations.xmpp.chatstate.ChatState;
import eu.siacs.conversations.xmpp.jingle.JingleConnectionManager;
import eu.siacs.conversations.xmpp.jingle.JingleRtpConnection;
import eu.siacs.conversations.xmpp.pep.Avatar;
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
import eu.siacs.conversations.xmpp.Jid;
import static eu.siacs.conversations.entities.Message.DELETED_MESSAGE_BODY;
import static eu.siacs.conversations.entities.Message.DELETED_MESSAGE_BODY_OLD;
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");
@ -107,30 +98,6 @@ 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) {
@ -159,66 +126,6 @@ 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;
@ -436,12 +343,6 @@ 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;
}
@ -597,20 +498,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
}
}
final Message message;
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 (xP1S3url != null) {
if (xP1S3url != null) {
message = new Message(conversation, xP1S3url.toString(), Message.ENCRYPTION_NONE, status);
message.setOob(true);
if (CryptoHelper.isPgpEncryptedUrl(xP1S3url.toString())) {
@ -854,13 +742,6 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
processMessageReceipts(account, packet, 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 (message.trusted() && message.treatAsDownloadable() && manager.getAutoAcceptFileSize() > 0) {

View file

@ -47,12 +47,6 @@ import androidx.core.content.ContextCompat;
import com.google.common.base.Objects;
import com.google.common.base.Strings;
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 org.conscrypt.Conscrypt;
import org.openintents.openpgp.IOpenPgpService2;
import org.openintents.openpgp.util.OpenPgpApi;
@ -145,6 +139,7 @@ import eu.siacs.conversations.utils.StringUtils;
import eu.siacs.conversations.utils.WakeLockHelper;
import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.OnBindListener;
import eu.siacs.conversations.xmpp.OnContactStatusChanged;
import eu.siacs.conversations.xmpp.OnIqPacketReceived;
@ -158,7 +153,6 @@ import eu.siacs.conversations.xmpp.Patches;
import eu.siacs.conversations.xmpp.XmppConnection;
import eu.siacs.conversations.xmpp.chatstate.ChatState;
import eu.siacs.conversations.xmpp.forms.Data;
import eu.siacs.conversations.xmpp.jid.OtrJidHelper;
import eu.siacs.conversations.xmpp.jingle.AbstractJingleConnection;
import eu.siacs.conversations.xmpp.jingle.JingleConnectionManager;
import eu.siacs.conversations.xmpp.jingle.Media;
@ -170,7 +164,6 @@ import eu.siacs.conversations.xmpp.stanzas.IqPacket;
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
import me.leolin.shortcutbadger.ShortcutBadger;
import eu.siacs.conversations.xmpp.Jid;
import static eu.siacs.conversations.ui.SettingsActivity.ALLOW_MESSAGE_CORRECTION;
import static eu.siacs.conversations.ui.SettingsActivity.CHAT_STATES;
@ -247,18 +240,9 @@ 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();
}
}
}
}
};
@ -378,9 +362,11 @@ public class XmppConnectionService extends Service {
public void onStatusChanged(final Account account) {
XmppConnection connection = account.getXmppConnection();
updateAccountUi();
if (account.getStatus() == Account.State.ONLINE || account.getStatus().isError()) {
mQuickConversationsService.signalAccountStateChange();
}
if (account.getStatus() == Account.State.ONLINE) {
synchronized (mLowPingTimeoutMode) {
if (mLowPingTimeoutMode.remove(account.getJid().asBareJid())) {
@ -413,9 +399,6 @@ 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);
}
}
@ -467,7 +450,6 @@ public class XmppConnectionService extends Service {
getNotificationService().updateErrorNotification();
}
};
private OpenPgpServiceConnection pgpServiceConnection;
private PgpEngine mPgpEngine = null;
private WakeLock wakeLock;
@ -1629,12 +1611,6 @@ public class XmppConnectionService extends Service {
}
}
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);
if (account.isOnlineAndConnected() && !inProgressJoin) {
@ -1666,30 +1642,6 @@ 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()) {
@ -1742,12 +1694,6 @@ 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;
@ -3582,12 +3528,6 @@ 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());
}
}
}
}
@ -3637,65 +3577,6 @@ public class XmppConnectionService extends Service {
pushContactToServer(contact);
}
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) {
contact.resetOption(Contact.Options.DIRTY_DELETE);
contact.setOption(Contact.Options.DIRTY_PUSH);
@ -4973,10 +4854,7 @@ public class XmppConnectionService extends Service {
boolean performedVerification = false;
final AxolotlService axolotlService = contact.getAccount().getAxolotlService();
for (XmppUri.Fingerprint fp : fingerprints) {
if (fp.type == XmppUri.FingerprintType.OTR) {
performedVerification |= contact.addOtrFingerprint(fp.fingerprint);
needsRosterWrite |= performedVerification;
} else if (fp.type == XmppUri.FingerprintType.OMEMO) {
if (fp.type == XmppUri.FingerprintType.OMEMO) {
String fingerprint = "05" + fp.fingerprint.replaceAll("\\s", "");
FingerprintStatus fingerprintStatus = axolotlService.getFingerprintTrust(fingerprint);
if (fingerprintStatus != null) {

View file

@ -60,7 +60,6 @@ import eu.siacs.conversations.ui.util.AvatarWorkerTask;
import eu.siacs.conversations.ui.util.GridManager;
import eu.siacs.conversations.ui.util.JidDialog;
import eu.siacs.conversations.utils.Compatibility;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.EmojiWrapper;
import eu.siacs.conversations.utils.Emoticons;
import eu.siacs.conversations.utils.IrregularUnicodeDetector;
@ -69,11 +68,11 @@ import eu.siacs.conversations.utils.Namespace;
import eu.siacs.conversations.utils.TimeFrameUtils;
import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
import eu.siacs.conversations.xmpp.XmppConnection;
import me.drakeet.support.toast.ToastCompat;
import eu.siacs.conversations.xmpp.Jid;
import static eu.siacs.conversations.ui.util.IntroHelper.showIntro;
@ -577,26 +576,6 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
binding.detailsContactKeys.removeAllViews();
boolean hasKeys = false;
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (Config.supportOtr()) {
for (final String otrFingerprint : contact.getOtrFingerprints()) {
hasKeys = true;
View view = inflater.inflate(R.layout.contact_key, binding.detailsContactKeys, false);
TextView key = view.findViewById(R.id.key);
TextView keyType = view.findViewById(R.id.key_type);
ImageButton removeButton = view
.findViewById(R.id.button_remove);
removeButton.setVisibility(View.VISIBLE);
key.setText(CryptoHelper.prettifyFingerprint(otrFingerprint));
if (otrFingerprint != null && otrFingerprint.equalsIgnoreCase(messageFingerprint)) {
keyType.setText(R.string.otr_fingerprint_selected_message);
keyType.setTextColor(ContextCompat.getColor(this, R.color.accent));
} else {
keyType.setText(R.string.otr_fingerprint);
}
binding.detailsContactKeys.addView(view);
removeButton.setOnClickListener(v -> confirmToDeleteFingerprint(otrFingerprint));
}
}
final AxolotlService axolotlService = contact.getAccount().getAxolotlService();
if (Config.supportOmemo() && axolotlService != null) {
final Collection<XmppAxolotlSession> sessions = axolotlService.findSessionsForContact(contact);
@ -671,21 +650,6 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
}
}
protected void confirmToDeleteFingerprint(final String fingerprint) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.delete_fingerprint);
builder.setMessage(R.string.sure_delete_fingerprint);
builder.setNegativeButton(R.string.cancel, null);
builder.setPositiveButton(R.string.delete,
(dialog, which) -> {
if (contact.deleteOtrFingerprint(fingerprint)) {
populateView();
xmppConnectionService.syncRosterToDisk(contact.getAccount());
}
});
builder.create().show();
}
public void onBackendConnected() {
if (accountJid != null && contactJid != null) {
Account account = xmppConnectionService.findAccountByJid(accountJid);

View file

@ -67,8 +67,6 @@ import androidx.databinding.DataBindingUtil;
import com.google.common.base.Optional;
import net.java.otr4j.session.SessionStatus;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@ -202,12 +200,6 @@ 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 boolean reInitRequiredOnStart = true;
private MediaPreviewAdapter mediaPreviewAdapter;
@ -426,18 +418,6 @@ 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() {
@ -908,9 +888,6 @@ 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;
@ -1474,7 +1451,6 @@ 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);
@ -1666,10 +1642,6 @@ 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) {
@ -1867,19 +1839,6 @@ 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://github.com/kriztan/Pix-Art-Messenger/blob/master/docs/encryption.md");
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(getActivity());
@ -2685,27 +2644,9 @@ 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 (mode == Conversation.MODE_SINGLE
&& conversation.smpRequested()) {
showSnackbar(R.string.smp_requested, R.string.verify, this.mAnswerSmpClickListener);
} else if (mode == Conversation.MODE_SINGLE
&& conversation.getNextEncryption() == Message.ENCRYPTION_OTR) {
showSnackbar(R.string.otr_warning, R.string.readmore, OTRwarning);
} 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.xmppConnectionService.warnUnecryptedChat()) {
if (conversation.getNextEncryption() == Message.ENCRYPTION_NONE && conversation.isSingleOrPrivateAndNonAnonymous() && ((Config.supportOmemo() && Conversation.suitableForOmemoByDefault(conversation)) ||
(Config.supportOpenPgp() && account.isPgpDecryptionServiceConnected()) || (
mode == Conversation.MODE_SINGLE && Config.supportOtr()))) {
(Config.supportOpenPgp() && account.isPgpDecryptionServiceConnected()))) {
if (ENCRYPTION_EXCEPTIONS.contains(conversation.getJid().toString()) || conversation.getJid().toString().equals(account.getJid().getDomain())) {
hideSnackbar();
} else {
@ -3082,17 +3023,6 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
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;

View file

@ -60,8 +60,6 @@ import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar;
import androidx.databinding.DataBindingUtil;
import net.java.otr4j.session.SessionStatus;
import org.openintents.openpgp.util.OpenPgpApi;
import java.util.Arrays;
@ -808,33 +806,6 @@ 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)) {

View file

@ -1297,25 +1297,6 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
} else {
this.binding.pgpFingerprintBox.setVisibility(View.GONE);
}
final String otrFingerprint = this.mAccount.getOtrFingerprint();
if (otrFingerprint != null && Config.supportOtr()) {
if ("otr".equals(messageFingerprint)) {
this.binding.otrFingerprintDesc.setTextColor(ContextCompat.getColor(this, R.color.accent));
}
this.binding.otrFingerprintBox.setVisibility(View.VISIBLE);
this.binding.otrFingerprint.setText(CryptoHelper.prettifyFingerprint(otrFingerprint));
this.binding.actionCopyToClipboard.setVisibility(View.VISIBLE);
this.binding.actionCopyToClipboard.setOnClickListener(v -> {
if (copyTextToClipboard(CryptoHelper.prettifyFingerprint(otrFingerprint), R.string.otr_fingerprint)) {
ToastCompat.makeText(
EditAccountActivity.this,
R.string.toast_message_otr_fingerprint,
Toast.LENGTH_SHORT).show();
}
});
} else {
this.binding.otrFingerprintBox.setVisibility(View.GONE);
}
final String ownAxolotlFingerprint = this.mAccount.getAxolotlService().getOwnFingerprint();
if (ownAxolotlFingerprint != null && Config.supportOmemo()) {
this.binding.axolotlFingerprintBox.setVisibility(View.VISIBLE);

View file

@ -1,450 +0,0 @@
package eu.siacs.conversations.ui;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import net.java.otr4j.OtrException;
import net.java.otr4j.session.Session;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.xmpp.Jid;
import me.drakeet.support.toast.ToastCompat;
public class VerifyOTRActivity extends XmppActivity implements XmppConnectionService.OnConversationUpdate {
public static final String ACTION_VERIFY_CONTACT = "verify_contact";
public static final int MODE_SCAN_FINGERPRINT = -0x0502;
public static final int MODE_ASK_QUESTION = 0x0503;
public static final int MODE_ANSWER_QUESTION = 0x0504;
public static final int MODE_MANUAL_VERIFICATION = 0x0505;
private LinearLayout mManualVerificationArea;
private LinearLayout mSmpVerificationArea;
private TextView mRemoteFingerprint;
private TextView mYourFingerprint;
private TextView mVerificationExplain;
private TextView mStatusMessage;
private TextView mSharedSecretHint;
private EditText mSharedSecretHintEditable;
private EditText mSharedSecretSecret;
private Button mLeftButton;
private Button mRightButton;
private Account mAccount;
private Conversation mConversation;
private int mode = MODE_MANUAL_VERIFICATION;
private XmppUri mPendingUri = null;
private DialogInterface.OnClickListener mVerifyFingerprintListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int click) {
mConversation.verifyOtrFingerprint();
xmppConnectionService.syncRosterToDisk(mConversation.getAccount());
ToastCompat.makeText(VerifyOTRActivity.this, R.string.verified, Toast.LENGTH_SHORT).show();
finish();
}
};
private View.OnClickListener mCreateSharedSecretListener = new View.OnClickListener() {
@Override
public void onClick(final View view) {
if (isAccountOnline()) {
final String question = mSharedSecretHintEditable.getText().toString();
final String secret = mSharedSecretSecret.getText().toString();
if (question.trim().isEmpty()) {
mSharedSecretHintEditable.requestFocus();
mSharedSecretHintEditable.setError(getString(R.string.shared_secret_hint_should_not_be_empty));
} else if (secret.trim().isEmpty()) {
mSharedSecretSecret.requestFocus();
mSharedSecretSecret.setError(getString(R.string.shared_secret_can_not_be_empty));
} else {
mSharedSecretSecret.setError(null);
mSharedSecretHintEditable.setError(null);
initSmp(question, secret);
updateView();
}
}
}
};
private View.OnClickListener mCancelSharedSecretListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
if (isAccountOnline()) {
abortSmp();
updateView();
}
}
};
private View.OnClickListener mRespondSharedSecretListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
if (isAccountOnline()) {
final String question = mSharedSecretHintEditable.getText().toString();
final String secret = mSharedSecretSecret.getText().toString();
respondSmp(question, secret);
updateView();
}
}
};
private View.OnClickListener mRetrySharedSecretListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
mConversation.smp().status = Conversation.Smp.STATUS_NONE;
mConversation.smp().hint = null;
mConversation.smp().secret = null;
updateView();
}
};
private View.OnClickListener mFinishListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
mConversation.smp().status = Conversation.Smp.STATUS_NONE;
finish();
}
};
protected boolean initSmp(final String question, final String secret) {
final Session session = mConversation.getOtrSession();
if (session != null) {
try {
session.initSmp(question, secret);
mConversation.smp().status = Conversation.Smp.STATUS_WE_REQUESTED;
mConversation.smp().secret = secret;
mConversation.smp().hint = question;
return true;
} catch (OtrException e) {
return false;
}
} else {
return false;
}
}
protected boolean abortSmp() {
final Session session = mConversation.getOtrSession();
if (session != null) {
try {
session.abortSmp();
mConversation.smp().status = Conversation.Smp.STATUS_NONE;
mConversation.smp().hint = null;
mConversation.smp().secret = null;
return true;
} catch (OtrException e) {
return false;
}
} else {
return false;
}
}
protected boolean respondSmp(final String question, final String secret) {
final Session session = mConversation.getOtrSession();
if (session != null) {
try {
session.respondSmp(question, secret);
return true;
} catch (OtrException e) {
return false;
}
} else {
return false;
}
}
protected boolean verifyWithUri(XmppUri uri) {
Contact contact = mConversation.getContact();
if (this.mConversation.getContact().getJid().equals(uri.getJid()) && uri.hasFingerprints()) {
xmppConnectionService.verifyFingerprints(contact, uri.getFingerprints());
ToastCompat.makeText(this, R.string.verified, Toast.LENGTH_SHORT).show();
updateView();
return true;
} else {
ToastCompat.makeText(this, R.string.could_not_verify_fingerprint, Toast.LENGTH_SHORT).show();
return false;
}
}
protected boolean isAccountOnline() {
if (this.mAccount.getStatus() != Account.State.ONLINE) {
ToastCompat.makeText(this, R.string.not_connected_try_again, Toast.LENGTH_SHORT).show();
return false;
} else {
return true;
}
}
protected boolean handleIntent(Intent intent) {
if (intent != null && intent.getAction().equals(ACTION_VERIFY_CONTACT)) {
this.mAccount = extractAccount(intent);
if (this.mAccount == null) {
return false;
}
try {
this.mConversation = this.xmppConnectionService.find(this.mAccount, Jid.of(intent.getExtras().getString("contact")));
if (this.mConversation == null) {
return false;
}
} catch (final IllegalArgumentException ignored) {
ignored.printStackTrace();
return false;
} catch (Exception e) {
e.printStackTrace();
return false;
}
this.mode = intent.getIntExtra("mode", MODE_MANUAL_VERIFICATION);
// todo scan OTR fingerprint
if (this.mode == MODE_SCAN_FINGERPRINT) {
Log.d(Config.LOGTAG, "Scan OTR fingerprint is not implemented in this version");
//new IntentIntegrator(this).initiateScan();
return false;
}
return true;
} else {
return false;
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
// todo onActivityResult for OTR scan
Log.d(Config.LOGTAG, "Scan OTR fingerprint result is not implemented in this version");
/*if ((requestCode & 0xFFFF) == IntentIntegrator.REQUEST_CODE) {
IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
if (scanResult != null && scanResult.getFormatName() != null) {
String data = scanResult.getContents();
XmppUri uri = new XmppUri(data);
if (xmppConnectionServiceBound) {
verifyWithUri(uri);
finish();
} else {
this.mPendingUri = uri;
}
} else {
finish();
}
}*/
super.onActivityResult(requestCode, requestCode, intent);
}
@Override
protected void onBackendConnected() {
if (handleIntent(getIntent())) {
updateView();
} else if (mPendingUri != null) {
verifyWithUri(mPendingUri);
finish();
mPendingUri = null;
}
setIntent(null);
}
protected void updateView() {
if (this.mConversation != null && this.mConversation.hasValidOtrSession()) {
final ActionBar actionBar = getSupportActionBar();
this.mVerificationExplain.setText(R.string.no_otr_session_found);
invalidateOptionsMenu();
switch (this.mode) {
case MODE_ASK_QUESTION:
if (actionBar != null) {
actionBar.setTitle(R.string.ask_question);
}
this.updateViewAskQuestion();
break;
case MODE_ANSWER_QUESTION:
if (actionBar != null) {
actionBar.setTitle(R.string.smp_requested);
}
this.updateViewAnswerQuestion();
break;
case MODE_MANUAL_VERIFICATION:
default:
if (actionBar != null) {
actionBar.setTitle(R.string.manually_verify);
}
this.updateViewManualVerification();
break;
}
} else {
this.mManualVerificationArea.setVisibility(View.GONE);
this.mSmpVerificationArea.setVisibility(View.GONE);
}
}
protected void updateViewManualVerification() {
this.mVerificationExplain.setText(R.string.manual_verification_explanation);
this.mManualVerificationArea.setVisibility(View.VISIBLE);
this.mSmpVerificationArea.setVisibility(View.GONE);
this.mYourFingerprint.setText(CryptoHelper.prettifyFingerprint(this.mAccount.getOtrFingerprint()));
this.mRemoteFingerprint.setText(CryptoHelper.prettifyFingerprint(this.mConversation.getOtrFingerprint()));
if (this.mConversation.isOtrFingerprintVerified()) {
deactivateButton(this.mRightButton, R.string.verified);
activateButton(this.mLeftButton, R.string.cancel, this.mFinishListener);
} else {
activateButton(this.mLeftButton, R.string.cancel, this.mFinishListener);
activateButton(this.mRightButton, R.string.verify, new View.OnClickListener() {
@Override
public void onClick(View view) {
showManuallyVerifyDialog();
}
});
}
}
protected void updateViewAskQuestion() {
this.mManualVerificationArea.setVisibility(View.GONE);
this.mSmpVerificationArea.setVisibility(View.VISIBLE);
this.mVerificationExplain.setText(R.string.smp_explain_question);
final int smpStatus = this.mConversation.smp().status;
switch (smpStatus) {
case Conversation.Smp.STATUS_WE_REQUESTED:
this.mStatusMessage.setVisibility(View.GONE);
this.mSharedSecretHintEditable.setVisibility(View.VISIBLE);
this.mSharedSecretSecret.setVisibility(View.VISIBLE);
this.mSharedSecretHintEditable.setText(this.mConversation.smp().hint);
this.mSharedSecretSecret.setText(this.mConversation.smp().secret);
this.activateButton(this.mLeftButton, R.string.cancel, this.mCancelSharedSecretListener);
this.deactivateButton(this.mRightButton, R.string.in_progress);
break;
case Conversation.Smp.STATUS_FAILED:
this.mStatusMessage.setVisibility(View.GONE);
this.mSharedSecretHintEditable.setVisibility(View.VISIBLE);
this.mSharedSecretSecret.setVisibility(View.VISIBLE);
this.mSharedSecretSecret.requestFocus();
this.mSharedSecretSecret.setError(getString(R.string.secrets_do_not_match));
this.deactivateButton(this.mLeftButton, R.string.cancel);
this.activateButton(this.mRightButton, R.string.try_again, this.mRetrySharedSecretListener);
break;
case Conversation.Smp.STATUS_VERIFIED:
this.mSharedSecretHintEditable.setText("");
this.mSharedSecretHintEditable.setVisibility(View.GONE);
this.mSharedSecretSecret.setText("");
this.mSharedSecretSecret.setVisibility(View.GONE);
this.mStatusMessage.setVisibility(View.VISIBLE);
this.deactivateButton(this.mLeftButton, R.string.cancel);
this.activateButton(this.mRightButton, R.string.finish, this.mFinishListener);
break;
default:
this.mStatusMessage.setVisibility(View.GONE);
this.mSharedSecretHintEditable.setVisibility(View.VISIBLE);
this.mSharedSecretSecret.setVisibility(View.VISIBLE);
this.activateButton(this.mLeftButton, R.string.cancel, this.mFinishListener);
this.activateButton(this.mRightButton, R.string.ask_question, this.mCreateSharedSecretListener);
break;
}
}
protected void updateViewAnswerQuestion() {
this.mManualVerificationArea.setVisibility(View.GONE);
this.mSmpVerificationArea.setVisibility(View.VISIBLE);
this.mVerificationExplain.setText(R.string.smp_explain_answer);
this.mSharedSecretHintEditable.setVisibility(View.GONE);
this.mSharedSecretHint.setVisibility(View.VISIBLE);
this.deactivateButton(this.mLeftButton, R.string.cancel);
final int smpStatus = this.mConversation.smp().status;
switch (smpStatus) {
case Conversation.Smp.STATUS_CONTACT_REQUESTED:
this.mStatusMessage.setVisibility(View.GONE);
this.mSharedSecretHint.setText(this.mConversation.smp().hint);
this.activateButton(this.mRightButton, R.string.respond, this.mRespondSharedSecretListener);
break;
case Conversation.Smp.STATUS_VERIFIED:
this.mSharedSecretHintEditable.setText("");
this.mSharedSecretHintEditable.setVisibility(View.GONE);
this.mSharedSecretHint.setVisibility(View.GONE);
this.mSharedSecretSecret.setText("");
this.mSharedSecretSecret.setVisibility(View.GONE);
this.mStatusMessage.setVisibility(View.VISIBLE);
this.activateButton(this.mRightButton, R.string.finish, this.mFinishListener);
break;
case Conversation.Smp.STATUS_FAILED:
default:
this.mSharedSecretSecret.requestFocus();
this.mSharedSecretSecret.setError(getString(R.string.secrets_do_not_match));
this.activateButton(this.mRightButton, R.string.finish, this.mFinishListener);
break;
}
}
protected void activateButton(Button button, int text, View.OnClickListener listener) {
button.setEnabled(true);
button.setText(text);
button.setOnClickListener(listener);
}
protected void deactivateButton(Button button, int text) {
button.setEnabled(false);
button.setText(text);
button.setOnClickListener(null);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_verify_otr);
this.mRemoteFingerprint = findViewById(R.id.remote_fingerprint);
this.mYourFingerprint = findViewById(R.id.your_fingerprint);
this.mLeftButton = findViewById(R.id.left_button);
this.mRightButton = findViewById(R.id.right_button);
this.mVerificationExplain = findViewById(R.id.verification_explanation);
this.mStatusMessage = findViewById(R.id.status_message);
this.mSharedSecretSecret = findViewById(R.id.shared_secret_secret);
this.mSharedSecretHintEditable = findViewById(R.id.shared_secret_hint_editable);
this.mSharedSecretHint = findViewById(R.id.shared_secret_hint);
this.mManualVerificationArea = findViewById(R.id.manual_verification_area);
this.mSmpVerificationArea = findViewById(R.id.smp_verification_area);
}
@Override
public boolean onCreateOptionsMenu(final Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.verify_otr, menu);
return true;
}
private void showManuallyVerifyDialog() {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.manually_verify);
builder.setMessage(R.string.are_you_sure_verify_fingerprint);
builder.setNegativeButton(R.string.cancel, null);
builder.setPositiveButton(R.string.verify, mVerifyFingerprintListener);
builder.create().show();
}
@Override
protected String getShareableUri() {
if (mAccount != null) {
return mAccount.getShareableUri();
} else {
return "";
}
}
public void onConversationUpdate() {
refreshUi();
}
@Override
protected void refreshUiReal() {
updateView();
}
}

View file

@ -39,7 +39,6 @@ import android.provider.Settings;
import android.text.InputType;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Pair;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
@ -55,18 +54,13 @@ import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.content.ContextCompat;
import androidx.databinding.DataBindingUtil;
import net.java.otr4j.session.SessionID;
import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
@ -87,18 +81,16 @@ import eu.siacs.conversations.services.XmppConnectionService.XmppConnectionBinde
import eu.siacs.conversations.ui.util.PresenceSelector;
import eu.siacs.conversations.ui.util.SoftKeyboardUtils;
import eu.siacs.conversations.utils.AccountUtils;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.ExceptionHelper;
import eu.siacs.conversations.utils.MenuDoubleTabUtil;
import eu.siacs.conversations.utils.ThemeHelper;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.XmppConnection;
import me.drakeet.support.toast.ToastCompat;
import pl.droidsonroids.gif.GifDrawable;
import static eu.siacs.conversations.ui.SettingsActivity.ENABLE_OTR_ENCRYPTION;
import static eu.siacs.conversations.ui.SettingsActivity.USE_BUNDLED_EMOJIS;
import static eu.siacs.conversations.ui.SettingsActivity.USE_INTERNAL_UPDATER;
@ -455,10 +447,6 @@ public abstract class XmppActivity extends ActionBarActivity {
return getBooleanPreference("unicolored_chatbg", R.bool.use_unicolored_chatbg);
}
public boolean enableOTR() {
return getBooleanPreference(ENABLE_OTR_ENCRYPTION, R.bool.enable_otr);
}
public void setBubbleColor(final View v, final int backgroundColor, final int borderColor) {
GradientDrawable shape = (GradientDrawable) v.getBackground();
shape.setColor(backgroundColor);
@ -868,19 +856,8 @@ public abstract class XmppActivity extends ActionBarActivity {
public void selectPresence(final Conversation conversation, final PresenceSelector.OnPresenceSelected listener) {
final Contact contact = conversation.getContact();
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()) {
showAddToRosterDialog(conversation);
if (!contact.showInRoster()) {
showAddToRosterDialog(conversation.getContact());
} else {
final Presences presences = contact.getPresences();
if (presences.size() == 0) {
@ -909,56 +886,6 @@ public abstract class XmppActivity extends ActionBarActivity {
}
}
private void showPresenceSelectionDialog(Presences presences, final Conversation conversation, final OnPresenceSelected listener) {
final Contact contact = conversation.getContact();
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getString(R.string.choose_presence));
final String[] resourceArray = presences.toResourceArray();
Pair<Map<String, String>, Map<String, String>> typeAndName = presences.toTypeAndNameMap();
final Map<String, String> resourceTypeMap = typeAndName.first;
final Map<String, String> resourceNameMap = typeAndName.second;
final String[] readableIdentities = new String[resourceArray.length];
final AtomicInteger selectedResource = new AtomicInteger(0);
for (int i = 0; i < resourceArray.length; ++i) {
String resource = resourceArray[i];
if (resource.equals(contact.getLastResource())) {
selectedResource.set(i);
}
String type = resourceTypeMap.get(resource);
String name = resourceNameMap.get(resource);
if (type != null) {
if (Collections.frequency(resourceTypeMap.values(), type) == 1) {
readableIdentities[i] = PresenceSelector.translateType(this, type);
} else if (name != null) {
if (Collections.frequency(resourceNameMap.values(), name) == 1
|| CryptoHelper.UUID_PATTERN.matcher(resource).matches()) {
readableIdentities[i] = PresenceSelector.translateType(this, type) + " (" + name + ")";
} else {
readableIdentities[i] = PresenceSelector.translateType(this, type) + " (" + name + " / " + resource + ")";
}
} else {
readableIdentities[i] = PresenceSelector.translateType(this, type) + " (" + resource + ")";
}
} else {
readableIdentities[i] = resource;
}
}
builder.setSingleChoiceItems(readableIdentities,
selectedResource.get(),
(dialog, which) -> selectedResource.set(which));
builder.setNegativeButton(R.string.cancel, null);
builder.setPositiveButton(R.string.ok, (dialog, which) -> {
try {
Jid next = Jid.of(contact.getJid().getLocal(), contact.getJid().getDomain(), resourceArray[selectedResource.get()]);
conversation.setNextCounterpart(next);
} catch (IllegalArgumentException e) {
conversation.setNextCounterpart(null);
}
listener.onPresenceSelected();
});
builder.create().show();
}
protected void onActivityResult(int requestCode, int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_INVITE_TO_CONVERSATION && resultCode == RESULT_OK) {

View file

@ -104,7 +104,6 @@ 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);
@ -133,10 +132,6 @@ public class ConversationMenuConfigurator {
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());
@ -144,9 +139,6 @@ public class ConversationMenuConfigurator {
case Message.ENCRYPTION_NONE:
none.setChecked(true);
break;
case Message.ENCRYPTION_OTR:
otr.setChecked(true);
break;
case Message.ENCRYPTION_PGP:
pgp.setChecked(true);
break;

View file

@ -567,8 +567,6 @@ public class UIHelper {
} else {
return context.getString(R.string.send_message_to_x, conversation.getName());
}
case Message.ENCRYPTION_OTR:
return context.getString(R.string.send_otr_message);
case Message.ENCRYPTION_AXOLOTL:
AxolotlService axolotlService = conversation.getAccount().getAxolotlService();
if (axolotlService != null && axolotlService.trustedSessionVerified(conversation)) {

View file

@ -1,16 +0,0 @@
package eu.siacs.conversations.xmpp.jid;
import net.java.otr4j.session.SessionID;
import eu.siacs.conversations.xmpp.Jid;
public final class OtrJidHelper {
public static Jid fromSessionID(final SessionID id) throws IllegalArgumentException {
if (id.getUserID().isEmpty()) {
return Jid.of(id.getAccountID());
} else {
return Jid.of(id.getAccountID() + "/" + id.getUserID());
}
}
}

View file

@ -729,58 +729,6 @@
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:id="@+id/otr_fingerprint_box"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginTop="24dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_toStartOf="@+id/key_actions"
android:layout_toLeftOf="@+id/key_actions"
android:orientation="vertical">
<TextView
android:id="@+id/otr_fingerprint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.Conversations.Fingerprint" />
<TextView
android:id="@+id/otr_fingerprint_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/otr_fingerprint"
android:textAppearance="@style/TextAppearance.Conversations.Caption" />
</LinearLayout>
<LinearLayout
android:id="@+id/key_actions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:orientation="horizontal">
<ImageButton
android:id="@+id/action_copy_to_clipboard"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/copy_otr_clipboard_description"
android:padding="@dimen/image_button_padding"
android:src="?attr/icon_copy"
android:visibility="visible" />
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:id="@+id/axolotl_fingerprint_box"
android:layout_width="wrap_content"

View file

@ -1,156 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/color_background_tertiary">
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="@+id/button_bar">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:layout_marginEnd="@dimen/activity_horizontal_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:layout_marginBottom="@dimen/activity_vertical_margin"
android:orientation="vertical">
<TextView
android:id="@+id/verification_explanation"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<LinearLayout
android:id="@+id/manual_verification_area"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:orientation="vertical">
<TextView
android:id="@+id/your_fingerprint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="monospace"
android:textColor="?attr/text_Color_Main"
android:textSize="?attr/TextSizeBody"
android:typeface="monospace" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/your_fingerprint"
android:textColor="?attr/text_Color_Main"
android:textSize="?attr/TextSizeInfo" />
<TextView
android:id="@+id/remote_fingerprint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:fontFamily="monospace"
android:textColor="?attr/text_Color_Main"
android:textSize="?attr/TextSizeBody"
android:typeface="monospace" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:text="@string/remote_fingerprint"
android:textColor="?attr/text_Color_Main"
android:textSize="?attr/TextSizeInfo" />
</LinearLayout>
<LinearLayout
android:id="@+id/smp_verification_area"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginTop="16dp"
android:orientation="vertical">
<TextView
android:id="@+id/status_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/verified"
android:textColor="?attr/text_Color_Main"
android:textSize="?attr/TextSizeHeadline"
android:textStyle="bold"
android:visibility="gone" />
<TextView
android:id="@+id/shared_secret_hint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:textColor="?attr/text_Color_Main"
android:textSize="?attr/TextSizeBody"
android:textStyle="bold"
android:visibility="gone" />
<EditText
android:id="@+id/shared_secret_hint_editable"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:hint="@string/shared_secret_hint"
android:inputType="textAutoComplete"
android:textColor="?attr/text_Color_Main"
android:textColorHint="?attr/colorAccent"
android:textSize="?attr/TextSizeBody" />
<EditText
android:id="@+id/shared_secret_secret"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:hint="@string/shared_secret_secret"
android:inputType="textPassword"
android:textColor="?attr/text_Color_Main"
android:textColorHint="?attr/colorAccent"
android:textSize="?attr/TextSizeBody" />
</LinearLayout>
</LinearLayout>
</ScrollView>
<LinearLayout
android:id="@+id/button_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true">
<Button
android:id="@+id/left_button"
style="@style/Widget.Conversations.Button.Borderless"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<View
android:layout_width="1dp"
android:layout_height="fill_parent"
android:layout_marginTop="7dp"
android:layout_marginBottom="7dp"
android:background="?attr/color_background_primary" />
<Button
android:id="@+id/right_button"
style="@style/Widget.Conversations.Button.Borderless"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
</RelativeLayout>

View file

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/activatedBackgroundIndicator"
android:padding="12dp"
android:id="@+id/presence_template">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:orientation="vertical"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_toLeftOf="@+id/delete_button"
android:layout_toStartOf="@+id/delete_button"
android:layout_marginRight="8dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/presence_status_message"
android:textAppearance="@style/TextAppearance.Conversations.Body1"/>
<TextView
android:id="@+id/status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="1dp"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:paddingTop="1dp"
android:textAllCaps="true"
android:textAppearance="@style/TextAppearance.Conversations.Tag"
android:layout_marginTop="4dp"/>
</LinearLayout>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/delete_button"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="@dimen/image_button_padding"
android:alpha="?attr/icon_alpha"
android:src="?attr/icon_remove"/>
</RelativeLayout>

View file

@ -37,9 +37,6 @@
<item
android:id="@+id/encryption_choice_axolotl"
android:title="@string/encryption_choice_omemo" />
<item
android:id="@+id/encryption_choice_otr"
android:title="@string/encryption_choice_otr" />
<item
android:id="@+id/encryption_choice_pgp"
android:title="@string/encryption_choice_pgp" />

View file

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/ask_question"
android:title="@string/ask_question" />
<item
android:id="@+id/manual_verification"
android:title="@string/manually_verify" />
</menu>

View file

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_show_qr_code"
android:title="@string/show_qr_code"
app:showAsAction="never" />
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
app:showAsAction="never"
android:title="@string/action_settings" />
</menu>

View file

@ -24,7 +24,6 @@
\n\nhttps://github.com/ge0rg/MemorizingTrustManager\n(The MIT License (MIT))
\n\nhttps://github.com/MiniDNS/minidns\n(WTFPL)
\n\nhttps://github.com/open-keychain/openkeychain-api-lib\n(Apache License, Version 2.0)
\n\nhttps://github.com/jitsi/otr4j\n(LGPL-3.0)
\n\nhttps://developer.android.com/tools/support-library\n(Apache License, Version 2.0)
\n\nhttps://github.com/google/material-design-icons\n(CC BY 4.0)
\n\nhttps://github.com/leolin310148/ShortcutBadger\n(Apache License, Version 2.0)

View file

@ -56,7 +56,6 @@
<bool name="use_internal_updater">true</bool>
<bool name="show_own_accounts">true</bool>
<bool name="vibrate_in_chat">true</bool>
<bool name="enable_otr">false</bool>
<integer name="auto_accept_filesize_wifi">10485760</integer>
<integer name="auto_accept_filesize_mobile">524288</integer>
<integer name="auto_accept_filesize_roaming">0</integer>

View file

@ -8,4 +8,5 @@
<item name="TAG_FINGERPRINT" type="id" />
<item name="TAG_FINGERPRINT_STATUS" type="id" />
<item name="TAG_AUDIO_PLAYER_VIEW_HOLDER" type="id" />
<item name="status" type="id" />
</resources>

View file

@ -77,7 +77,6 @@
<string name="choose_presence">Choose device</string>
<string name="send_unencrypted_message">Send unencrypted message</string>
<string name="send_message_to_x">Send message to %s</string>
<string name="send_otr_message">Send OTR encrypted message</string>
<string name="send_omemo_message">Send OMEMO encrypted message</string>
<string name="send_omemo_x509_message">Send v\\OMEMO encrypted message</string>
<string name="send_pgp_message">Send OpenPGP encrypted message</string>
@ -184,11 +183,8 @@
<string name="last_seen_day">1 day ago</string>
<string name="last_seen_days">%d days ago</string>
<string name="install_openkeychain">Encrypted message. Please install OpenKeychain to decrypt.</string>
<string name="unknown_otr_fingerprint">Unknown OTR fingerprint</string>
<string name="openpgp_messages_found">OpenPGP encrypted messages found</string>
<string name="your_fingerprint">Your fingerprint</string>
<string name="otr_fingerprint">OTR fingerprint</string>
<string name="otr_fingerprint_selected_message">OTR fingerprint of message</string>
<string name="openpgp_key_id">OpenPGP Key ID</string>
<string name="omemo_fingerprint">OMEMO fingerprint</string>
<string name="omemo_fingerprint_x509">v\\OMEMO fingerprint</string>
@ -266,7 +262,6 @@
<string name="pref_expert_options_other">Other</string>
<string name="pref_autojoin">Synchronize with bookmarks</string>
<string name="pref_autojoin_summary">Join and leave group chats according to auto-join flag in your bookmarks.</string>
<string name="toast_message_otr_fingerprint">OTR fingerprint copied to clipboard!</string>
<string name="toast_message_omemo_fingerprint">OMEMO fingerprint copied to clipboard!</string>
<string name="conference_banned">You are banned from this group chat</string>
<string name="conference_members_only">This group chat is members only</string>
@ -286,7 +281,6 @@
<string name="show_qr_code">Show QR code</string>
<string name="show_block_list">Show block list</string>
<string name="account_details">Account details</string>
<string name="verify_otr">Verify OTR</string>
<string name="remote_fingerprint">Remote Fingerprint</string>
<string name="shared_secret_hint">Hint or Question</string>
<string name="shared_secret_secret">Shared Secret</string>
@ -299,7 +293,6 @@
<string name="finish">Finish</string>
<string name="verified">Verified!</string>
<string name="smp_requested">Contact requested SMP verification</string>
<string name="no_otr_session_found">No valid OTR session has been found!</string>
<string name="conversations_foreground_service" translatable="false">Pix-Art Messenger</string>
<string name="pref_create_backup">Create backup</string>
<string name="pref_create_backup_summary">Write backup files to %s</string>
@ -321,13 +314,11 @@
<string name="no_application_found_to_open_file">No application found to open file</string>
<string name="could_not_verify_fingerprint">Could not verify fingerprint</string>
<string name="manually_verify">Manually verify</string>
<string name="are_you_sure_verify_fingerprint">Are you sure that you want to verify your contacts OTR fingerprint?</string>
<string name="pref_show_dynamic_tags">Show dynamic tags</string>
<string name="pref_show_dynamic_tags_summary">Display read-only tags underneath contacts</string>
<string name="no_conference_server_found">No group chat server found</string>
<string name="conference_creation_failed">Group chat creation failed!</string>
<string name="account_image_description">Account avatar</string>
<string name="copy_otr_clipboard_description">Copy OTR fingerprint to clipboard</string>
<string name="copy_omemo_clipboard_description">Copy OMEMO fingerprint to clipboard</string>
<string name="regenerate_omemo_key">Regenerate OMEMO key</string>
<string name="clear_other_devices">Clear devices</string>
@ -341,7 +332,6 @@
<string name="updating">Updating…</string>
<string name="password_changed">Password changed!</string>
<string name="could_not_change_password">Could not change password</string>
<string name="otr_session_not_started">Send a message to start an encrypted chat</string>
<string name="ask_question">Ask question</string>
<string name="smp_explain_question">If you and your contact have a secret in common that no one else knows (like an inside joke or simply what you had for lunch the last time you met) you can use that secret to verify each others fingerprints.\n\nYou provide a hint or a question for your contact who will respond with a case-sensitive answer.</string>
<string name="smp_explain_answer">Your contact would like to verify your fingerprint by challenging you with a shared secret. Your contact provided the following hint or question for that secret.</string>
@ -989,8 +979,6 @@
<string name="pref_theme_orange">Orange</string>
<string name="pref_theme_color_options_summary">Select the theme color palette</string>
<string name="pref_theme_color_options">Theme color</string>
<string name="pref_enable_otr_summary">Enable OTR encryption for message encryption</string>
<string name="pref_enable_otr">Enable OTR encryption</string>
<string name="magic_create_text_on_x">You have been invited to %1$s. We will guide you through the process of creating an account.\nWhen picking %1$s as a provider you will be able to communicate with users of other providers by giving them your full XMPP address.</string>
<string name="account_status_regis_invalid_token">Invalid registration token</string>
<string name="magic_create_text_fixed">You have been invited to %1$s. A username has already been picked for you. We will guide you through the process of creating an account.\nYou will be able to communicate with users of other providers by giving them your full XMPP address.</string>
@ -1048,7 +1036,6 @@
<string name="only_one_call_at_a_time">You can only have one call at a time.</string>
<string name="missed_call">Missed call</string>
<string name="could_not_switch_camera">Could not switch camera</string>
<string name="otr_warning">The support of OTR encryption will drop in June 2020. Click read more to get more information. A link in a browser will open.</string>
<string name="readmore">Read more</string>
<string name="add_to_favorites">Add to favorites</string>
<string name="remove_from_favorites">Remove from favorites</string>

View file

@ -468,11 +468,6 @@
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"