get rid of OTR
This commit is contained in:
parent
fc5a2922e9
commit
bf6b54a7aa
|
@ -45,7 +45,6 @@ dependencies {
|
||||||
implementation "com.android.support:design:$supportLibVersion"
|
implementation "com.android.support:design:$supportLibVersion"
|
||||||
freeImplementation "com.android.support:support-emoji-bundled:$supportLibVersion"
|
freeImplementation "com.android.support:support-emoji-bundled:$supportLibVersion"
|
||||||
implementation 'org.bouncycastle:bcmail-jdk15on:1.58'
|
implementation 'org.bouncycastle:bcmail-jdk15on:1.58'
|
||||||
implementation 'org.jitsi:org.otr4j:0.22'
|
|
||||||
implementation 'org.gnu.inet:libidn:1.15'
|
implementation 'org.gnu.inet:libidn:1.15'
|
||||||
implementation 'com.google.zxing:core:3.3.0'
|
implementation 'com.google.zxing:core:3.3.0'
|
||||||
implementation 'de.measite.minidns:minidns-hla:0.2.4'
|
implementation 'de.measite.minidns:minidns-hla:0.2.4'
|
||||||
|
|
|
@ -141,10 +141,6 @@
|
||||||
android:name=".ui.PublishProfilePictureActivity"
|
android:name=".ui.PublishProfilePictureActivity"
|
||||||
android:label="@string/mgmt_account_publish_avatar"
|
android:label="@string/mgmt_account_publish_avatar"
|
||||||
android:windowSoftInputMode="stateHidden" />
|
android:windowSoftInputMode="stateHidden" />
|
||||||
<activity
|
|
||||||
android:name=".ui.VerifyOTRActivity"
|
|
||||||
android:label="@string/verify_otr"
|
|
||||||
android:windowSoftInputMode="stateHidden" />
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.ShareWithActivity"
|
android:name=".ui.ShareWithActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
|
|
@ -1,310 +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.chatstate.ChatState;
|
|
||||||
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
|
|
||||||
import eu.siacs.conversations.xmpp.jid.Jid;
|
|
||||||
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 | InvalidKeySpecException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void askForSecret(SessionID id, InstanceTag instanceTag, String question) {
|
|
||||||
try {
|
|
||||||
final Jid jid = Jid.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 (InvalidJidException e) {
|
|
||||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": 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 = Jid.fromSessionID(session);
|
|
||||||
Conversation conversation = mXmppConnectionService.find(account,jid);
|
|
||||||
if (conversation != null && conversation.setOutgoingChatState(Config.DEFAULT_CHATSTATE)) {
|
|
||||||
if (mXmppConnectionService.sendChatStates()) {
|
|
||||||
packet.addChild(ChatState.toElement(conversation.getOutgoingChatState()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (final InvalidJidException 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 = Jid.fromSessionID(id);
|
|
||||||
Conversation conversation = this.mXmppConnectionService.find(this.account,jid);
|
|
||||||
if (conversation!=null) {
|
|
||||||
conversation.smp().status = status;
|
|
||||||
mXmppConnectionService.updateConversationUi();
|
|
||||||
}
|
|
||||||
} catch (final InvalidJidException 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 = Jid.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().toBareJid().toString()
|
|
||||||
+": unreadable OTR message in "+conversation.getName());
|
|
||||||
}
|
|
||||||
} catch (InvalidJidException 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 = Jid.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 InvalidJidException ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FragmenterInstructions getFragmenterInstructions(SessionID sessionID) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -7,24 +7,17 @@ import android.util.Pair;
|
||||||
|
|
||||||
import eu.siacs.conversations.crypto.PgpDecryptionService;
|
import eu.siacs.conversations.crypto.PgpDecryptionService;
|
||||||
|
|
||||||
import net.java.otr4j.crypto.OtrCryptoEngineImpl;
|
|
||||||
import net.java.otr4j.crypto.OtrCryptoException;
|
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.security.interfaces.DSAPublicKey;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
|
||||||
import eu.siacs.conversations.R;
|
import eu.siacs.conversations.R;
|
||||||
import eu.siacs.conversations.crypto.OtrService;
|
|
||||||
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
||||||
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession;
|
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession;
|
||||||
import eu.siacs.conversations.services.XmppConnectionService;
|
import eu.siacs.conversations.services.XmppConnectionService;
|
||||||
|
@ -241,7 +234,6 @@ public class Account extends AbstractEntity {
|
||||||
protected String hostname = null;
|
protected String hostname = null;
|
||||||
protected int port = 5222;
|
protected int port = 5222;
|
||||||
protected boolean online = false;
|
protected boolean online = false;
|
||||||
private OtrService mOtrService = null;
|
|
||||||
private AxolotlService axolotlService = null;
|
private AxolotlService axolotlService = null;
|
||||||
private PgpDecryptionService pgpDecryptionService = null;
|
private PgpDecryptionService pgpDecryptionService = null;
|
||||||
private XmppConnection xmppConnection = null;
|
private XmppConnection xmppConnection = null;
|
||||||
|
@ -499,7 +491,6 @@ public class Account extends AbstractEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initAccountServices(final XmppConnectionService context) {
|
public void initAccountServices(final XmppConnectionService context) {
|
||||||
this.mOtrService = new OtrService(context, this);
|
|
||||||
this.axolotlService = new AxolotlService(this, context);
|
this.axolotlService = new AxolotlService(this, context);
|
||||||
this.pgpDecryptionService = new PgpDecryptionService(context);
|
this.pgpDecryptionService = new PgpDecryptionService(context);
|
||||||
if (xmppConnection != null) {
|
if (xmppConnection != null) {
|
||||||
|
@ -507,10 +498,6 @@ public class Account extends AbstractEntity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public OtrService getOtrService() {
|
|
||||||
return this.mOtrService;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PgpDecryptionService getPgpDecryptionService() {
|
public PgpDecryptionService getPgpDecryptionService() {
|
||||||
return this.pgpDecryptionService;
|
return this.pgpDecryptionService;
|
||||||
}
|
}
|
||||||
|
@ -523,26 +510,6 @@ public class Account extends AbstractEntity {
|
||||||
this.xmppConnection = connection;
|
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() {
|
public String getRosterVersion() {
|
||||||
if (this.rosterVersion == null) {
|
if (this.rosterVersion == null) {
|
||||||
return "";
|
return "";
|
||||||
|
@ -674,10 +641,6 @@ public class Account extends AbstractEntity {
|
||||||
|
|
||||||
private List<XmppUri.Fingerprint> getFingerprints() {
|
private List<XmppUri.Fingerprint> getFingerprints() {
|
||||||
ArrayList<XmppUri.Fingerprint> fingerprints = new ArrayList<>();
|
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) {
|
if (axolotlService == null) {
|
||||||
return fingerprints;
|
return fingerprints;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,17 +4,10 @@ import android.content.ContentValues;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
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.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.security.interfaces.DSAPublicKey;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
@ -77,11 +70,6 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
|
||||||
protected final ArrayList<Message> messages = new ArrayList<>();
|
protected final ArrayList<Message> messages = new ArrayList<>();
|
||||||
protected Account account = null;
|
protected Account account = null;
|
||||||
|
|
||||||
private transient SessionImpl otrSession;
|
|
||||||
|
|
||||||
private transient String otrFingerprint = null;
|
|
||||||
private Smp mSmp = new Smp();
|
|
||||||
|
|
||||||
private transient MucOptions mucOptions = null;
|
private transient MucOptions mucOptions = null;
|
||||||
|
|
||||||
private byte[] symmetricKey;
|
private byte[] symmetricKey;
|
||||||
|
@ -89,7 +77,6 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
|
||||||
private boolean messagesLeftOnServer = true;
|
private boolean messagesLeftOnServer = true;
|
||||||
private ChatState mOutgoingChatState = Config.DEFAULT_CHATSTATE;
|
private ChatState mOutgoingChatState = Config.DEFAULT_CHATSTATE;
|
||||||
private ChatState mIncomingChatState = Config.DEFAULT_CHATSTATE;
|
private ChatState mIncomingChatState = Config.DEFAULT_CHATSTATE;
|
||||||
private String mLastReceivedOtrMessageId = null;
|
|
||||||
private String mFirstMamReference = null;
|
private String mFirstMamReference = null;
|
||||||
private Message correctingMessage;
|
private Message correctingMessage;
|
||||||
public AtomicBoolean messagesLoaded = new AtomicBoolean(true);
|
public AtomicBoolean messagesLoaded = new AtomicBoolean(true);
|
||||||
|
@ -335,14 +322,6 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
|
||||||
return getContact().getBlockedJid();
|
return getContact().getBlockedJid();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getLastReceivedOtrMessageId() {
|
|
||||||
return this.mLastReceivedOtrMessageId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLastReceivedOtrMessageId(String id) {
|
|
||||||
this.mLastReceivedOtrMessageId = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int countMessages() {
|
public int countMessages() {
|
||||||
synchronized (this.messages) {
|
synchronized (this.messages) {
|
||||||
return this.messages.size();
|
return this.messages.size();
|
||||||
|
@ -587,110 +566,6 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
|
||||||
this.mode = mode;
|
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().toBareJid().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 | 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
|
* short for is Private and Non-anonymous
|
||||||
*/
|
*/
|
||||||
|
@ -735,8 +610,6 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
|
||||||
return Config.supportUnencrypted() ? selectedEncryption : getDefaultEncryption();
|
return Config.supportUnencrypted() ? selectedEncryption : getDefaultEncryption();
|
||||||
case Message.ENCRYPTION_AXOLOTL:
|
case Message.ENCRYPTION_AXOLOTL:
|
||||||
return Config.supportOmemo() ? selectedEncryption : getDefaultEncryption();
|
return Config.supportOmemo() ? selectedEncryption : getDefaultEncryption();
|
||||||
case Message.ENCRYPTION_OTR:
|
|
||||||
return Config.supportOtr() ? selectedEncryption : getDefaultEncryption();
|
|
||||||
case Message.ENCRYPTION_PGP:
|
case Message.ENCRYPTION_PGP:
|
||||||
case Message.ENCRYPTION_DECRYPTED:
|
case Message.ENCRYPTION_DECRYPTED:
|
||||||
case Message.ENCRYPTION_DECRYPTION_FAILED:
|
case Message.ENCRYPTION_DECRYPTION_FAILED:
|
||||||
|
@ -753,8 +626,6 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
|
||||||
} else if (Config.supportOmemo()
|
} else if (Config.supportOmemo()
|
||||||
&& (axolotlService != null && axolotlService.isConversationAxolotlCapable(this) || !Config.multipleEncryptionChoices())) {
|
&& (axolotlService != null && axolotlService.isConversationAxolotlCapable(this) || !Config.multipleEncryptionChoices())) {
|
||||||
return Message.ENCRYPTION_AXOLOTL;
|
return Message.ENCRYPTION_AXOLOTL;
|
||||||
} else if (Config.supportOtr() && mode == MODE_SINGLE) {
|
|
||||||
return Message.ENCRYPTION_OTR;
|
|
||||||
} else if (Config.supportOpenPgp()) {
|
} else if (Config.supportOpenPgp()) {
|
||||||
return Message.ENCRYPTION_PGP;
|
return Message.ENCRYPTION_PGP;
|
||||||
} else {
|
} else {
|
||||||
|
@ -771,10 +642,6 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
|
||||||
return nextMessage == null ? "" : nextMessage;
|
return nextMessage == null ? "" : nextMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean smpRequested() {
|
|
||||||
return smp().status == Smp.STATUS_CONTACT_REQUESTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean setNextMessage(String message) {
|
public boolean setNextMessage(String message) {
|
||||||
boolean changed = !getNextMessage().equals(message);
|
boolean changed = !getNextMessage().equals(message);
|
||||||
this.setAttribute(ATTRIBUTE_NEXT_MESSAGE, message);
|
this.setAttribute(ATTRIBUTE_NEXT_MESSAGE, message);
|
||||||
|
|
|
@ -6,7 +6,7 @@ import java.util.List;
|
||||||
public interface Transferable {
|
public interface Transferable {
|
||||||
|
|
||||||
List<String> VALID_IMAGE_EXTENSIONS = Arrays.asList("webp", "jpeg", "jpg", "png", "jpe");
|
List<String> VALID_IMAGE_EXTENSIONS = Arrays.asList("webp", "jpeg", "jpg", "png", "jpe");
|
||||||
List<String> VALID_CRYPTO_EXTENSIONS = Arrays.asList("pgp", "gpg", "otr");
|
List<String> VALID_CRYPTO_EXTENSIONS = Arrays.asList("pgp", "gpg");
|
||||||
List<String> WELL_KNOWN_EXTENSIONS = Arrays.asList("pdf","m4a","mp4","3gp","aac","amr","mp3");
|
List<String> WELL_KNOWN_EXTENSIONS = Arrays.asList("pdf","m4a","mp4","3gp","aac","amr","mp3");
|
||||||
|
|
||||||
int STATUS_UNKNOWN = 0x200;
|
int STATUS_UNKNOWN = 0x200;
|
||||||
|
|
|
@ -118,9 +118,6 @@ public abstract class AbstractGenerator {
|
||||||
if (!mXmppConnectionService.useTorToConnect()) {
|
if (!mXmppConnectionService.useTorToConnect()) {
|
||||||
features.addAll(Arrays.asList(PRIVACY_SENSITIVE));
|
features.addAll(Arrays.asList(PRIVACY_SENSITIVE));
|
||||||
}
|
}
|
||||||
if (Config.supportOtr()) {
|
|
||||||
features.addAll(Arrays.asList(OTR));
|
|
||||||
}
|
|
||||||
if (mXmppConnectionService.broadcastLastActivity()) {
|
if (mXmppConnectionService.broadcastLastActivity()) {
|
||||||
features.add(Namespace.IDLE);
|
features.add(Namespace.IDLE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
package eu.siacs.conversations.generator;
|
package eu.siacs.conversations.generator;
|
||||||
|
|
||||||
import net.java.otr4j.OtrException;
|
|
||||||
import net.java.otr4j.session.Session;
|
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -24,7 +21,6 @@ import eu.siacs.conversations.xmpp.jid.Jid;
|
||||||
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
|
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
|
||||||
|
|
||||||
public class MessageGenerator extends AbstractGenerator {
|
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 doesn’t seem to support that";
|
|
||||||
private static final String OMEMO_FALLBACK_MESSAGE = "I sent you an OMEMO encrypted message but your client doesn’t seem to support that. Find more information on https://conversations.im/omemo";
|
private static final String OMEMO_FALLBACK_MESSAGE = "I sent you an OMEMO encrypted message but your client doesn’t 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 doesn’t seem to support that.";
|
private static final String PGP_FALLBACK_MESSAGE = "I sent you a PGP encrypted message but your client doesn’t seem to support that.";
|
||||||
|
|
||||||
|
@ -112,29 +108,6 @@ public class MessageGenerator extends AbstractGenerator {
|
||||||
packet.addChild("no-permanent-storage", "urn:xmpp:hints"); //do not copy this. this is wrong. it is *store*
|
packet.addChild("no-permanent-storage", "urn:xmpp:hints"); //do not copy this. this is wrong. it is *store*
|
||||||
}
|
}
|
||||||
|
|
||||||
public MessagePacket generateOtrChat(Message message) {
|
|
||||||
Session otrSession = message.getConversation().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) {
|
public MessagePacket generateChat(Message message) {
|
||||||
MessagePacket packet = preparePacket(message);
|
MessagePacket packet = preparePacket(message);
|
||||||
String content;
|
String content;
|
||||||
|
@ -254,17 +227,4 @@ public class MessageGenerator extends AbstractGenerator {
|
||||||
packet.addChild("store", "urn:xmpp:hints");
|
packet.addChild("store", "urn:xmpp:hints");
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MessagePacket generateOtrError(Jid to, String id, String errorText) {
|
|
||||||
MessagePacket packet = new MessagePacket();
|
|
||||||
packet.setType(MessagePacket.TYPE_ERROR);
|
|
||||||
packet.setAttribute("id",id);
|
|
||||||
packet.setTo(to);
|
|
||||||
Element error = packet.addChild("error");
|
|
||||||
error.setAttribute("code","406");
|
|
||||||
error.setAttribute("type","modify");
|
|
||||||
error.addChild("not-acceptable","urn:ietf:params:xml:ns:xmpp-stanzas");
|
|
||||||
error.addChild("text").setContent("?OTR Error:" + errorText);
|
|
||||||
return packet;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,9 +96,7 @@ public class HttpDownloadConnection implements Transferable {
|
||||||
this.file.setKeyAndIv(CryptoHelper.hexToBytes(reference));
|
this.file.setKeyAndIv(CryptoHelper.hexToBytes(reference));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((this.message.getEncryption() == Message.ENCRYPTION_OTR
|
if (this.message.getEncryption() == Message.ENCRYPTION_AXOLOTL && this.file.getKey() == null) {
|
||||||
|| this.message.getEncryption() == Message.ENCRYPTION_AXOLOTL)
|
|
||||||
&& this.file.getKey() == null) {
|
|
||||||
this.message.setEncryption(Message.ENCRYPTION_NONE);
|
this.message.setEncryption(Message.ENCRYPTION_NONE);
|
||||||
}
|
}
|
||||||
checkFileSize(interactive);
|
checkFileSize(interactive);
|
||||||
|
|
|
@ -1,13 +1,8 @@
|
||||||
package eu.siacs.conversations.parser;
|
package eu.siacs.conversations.parser;
|
||||||
|
|
||||||
import android.os.Build;
|
|
||||||
import android.text.Html;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
import net.java.otr4j.session.Session;
|
|
||||||
import net.java.otr4j.session.SessionStatus;
|
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -19,7 +14,6 @@ import java.util.UUID;
|
||||||
|
|
||||||
import eu.siacs.conversations.Config;
|
import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.R;
|
import eu.siacs.conversations.R;
|
||||||
import eu.siacs.conversations.crypto.OtrService;
|
|
||||||
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
||||||
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlMessage;
|
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlMessage;
|
||||||
import eu.siacs.conversations.entities.Account;
|
import eu.siacs.conversations.entities.Account;
|
||||||
|
@ -28,10 +22,8 @@ import eu.siacs.conversations.entities.Contact;
|
||||||
import eu.siacs.conversations.entities.Conversation;
|
import eu.siacs.conversations.entities.Conversation;
|
||||||
import eu.siacs.conversations.entities.Message;
|
import eu.siacs.conversations.entities.Message;
|
||||||
import eu.siacs.conversations.entities.MucOptions;
|
import eu.siacs.conversations.entities.MucOptions;
|
||||||
import eu.siacs.conversations.entities.Presence;
|
|
||||||
import eu.siacs.conversations.entities.ReadByMarker;
|
import eu.siacs.conversations.entities.ReadByMarker;
|
||||||
import eu.siacs.conversations.entities.ReceiptRequest;
|
import eu.siacs.conversations.entities.ReceiptRequest;
|
||||||
import eu.siacs.conversations.entities.ServiceDiscoveryResult;
|
|
||||||
import eu.siacs.conversations.http.HttpConnectionManager;
|
import eu.siacs.conversations.http.HttpConnectionManager;
|
||||||
import eu.siacs.conversations.services.MessageArchiveService;
|
import eu.siacs.conversations.services.MessageArchiveService;
|
||||||
import eu.siacs.conversations.services.XmppConnectionService;
|
import eu.siacs.conversations.services.XmppConnectionService;
|
||||||
|
@ -46,8 +38,6 @@ import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
|
||||||
|
|
||||||
public class MessageParser extends AbstractParser implements OnMessagePacketReceived {
|
public class MessageParser extends AbstractParser implements OnMessagePacketReceived {
|
||||||
|
|
||||||
private static final List<String> CLIENTS_SENDING_HTML_IN_OTR = Arrays.asList("Pidgin", "Adium", "Trillian");
|
|
||||||
|
|
||||||
public MessageParser(XmppConnectionService service) {
|
public MessageParser(XmppConnectionService service) {
|
||||||
super(service);
|
super(service);
|
||||||
}
|
}
|
||||||
|
@ -80,90 +70,6 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Message parseOtrChat(String body, Jid from, String id, Conversation conversation) {
|
|
||||||
String presence;
|
|
||||||
if (from.isBareJid()) {
|
|
||||||
presence = "";
|
|
||||||
} else {
|
|
||||||
presence = from.getResourcepart();
|
|
||||||
}
|
|
||||||
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().toBareJid() + ": 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 static boolean clientMightSendHtml(Account account, Jid from) {
|
|
||||||
String resource = from.getResourcepart();
|
|
||||||
if (resource == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Presence presence = account.getRoster().getContact(from).getPresences().getPresences().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 Message parseAxolotlChat(Element axolotlMessage, Jid from, Conversation conversation, int status, boolean postpone) {
|
private Message parseAxolotlChat(Element axolotlMessage, Jid from, Conversation conversation, int status, boolean postpone) {
|
||||||
final AxolotlService service = conversation.getAccount().getAxolotlService();
|
final AxolotlService service = conversation.getAccount().getAxolotlService();
|
||||||
final XmppAxolotlMessage xmppAxolotlMessage;
|
final XmppAxolotlMessage xmppAxolotlMessage;
|
||||||
|
@ -316,11 +222,6 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
|
||||||
packet.getId(),
|
packet.getId(),
|
||||||
Message.STATUS_SEND_FAILED,
|
Message.STATUS_SEND_FAILED,
|
||||||
extractErrorMessage(packet));
|
extractErrorMessage(packet));
|
||||||
if (message != null) {
|
|
||||||
if (message.getEncryption() == Message.ENCRYPTION_OTR) {
|
|
||||||
message.getConversation().endOtrIfNeeded();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -467,17 +368,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final Message message;
|
final Message message;
|
||||||
if (body != null && body.startsWith("?OTR") && Config.supportOtr()) {
|
if (pgpEncrypted != null && Config.supportOpenPgp()) {
|
||||||
if (!isForwarded && !isTypeGroupChat && isProperlyAddressed && !conversationMultiMode) {
|
|
||||||
message = parseOtrChat(body, from, remoteMsgId, conversation);
|
|
||||||
if (message == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": ignoring OTR message from " + from + " isForwarded=" + Boolean.toString(isForwarded) + ", isProperlyAddressed=" + Boolean.valueOf(isProperlyAddressed));
|
|
||||||
message = new Message(conversation, body, Message.ENCRYPTION_NONE, status);
|
|
||||||
}
|
|
||||||
} else if (pgpEncrypted != null && Config.supportOpenPgp()) {
|
|
||||||
message = new Message(conversation, pgpEncrypted, Message.ENCRYPTION_PGP, status);
|
message = new Message(conversation, pgpEncrypted, Message.ENCRYPTION_PGP, status);
|
||||||
} else if (axolotlEncrypted != null && Config.supportOmemo()) {
|
} else if (axolotlEncrypted != null && Config.supportOmemo()) {
|
||||||
Jid origin;
|
Jid origin;
|
||||||
|
@ -669,13 +560,6 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
|
||||||
processMessageReceipts(account, packet, query);
|
processMessageReceipts(account, packet, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.getStatus() == Message.STATUS_RECEIVED
|
|
||||||
&& conversation.getOtrSession() != null
|
|
||||||
&& !conversation.getOtrSession().getSessionID().getUserID()
|
|
||||||
.equals(message.getCounterpart().getResourcepart())) {
|
|
||||||
conversation.endOtrIfNeeded();
|
|
||||||
}
|
|
||||||
|
|
||||||
mXmppConnectionService.databaseBackend.createMessage(message);
|
mXmppConnectionService.databaseBackend.createMessage(message);
|
||||||
final HttpConnectionManager manager = this.mXmppConnectionService.getHttpConnectionManager();
|
final HttpConnectionManager manager = this.mXmppConnectionService.getHttpConnectionManager();
|
||||||
if (message.trusted() && message.treatAsDownloadable() && manager.getAutoAcceptFileSize() > 0) {
|
if (message.trusted() && message.treatAsDownloadable() && manager.getAutoAcceptFileSize() > 0) {
|
||||||
|
|
|
@ -34,12 +34,6 @@ import android.util.Log;
|
||||||
import android.util.LruCache;
|
import android.util.LruCache;
|
||||||
import android.util.Pair;
|
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 org.openintents.openpgp.IOpenPgpService2;
|
import org.openintents.openpgp.IOpenPgpService2;
|
||||||
import org.openintents.openpgp.util.OpenPgpApi;
|
import org.openintents.openpgp.util.OpenPgpApi;
|
||||||
import org.openintents.openpgp.util.OpenPgpServiceConnection;
|
import org.openintents.openpgp.util.OpenPgpServiceConnection;
|
||||||
|
@ -214,18 +208,9 @@ public class XmppConnectionService extends Service {
|
||||||
Conversation conversation = find(getConversations(), contact);
|
Conversation conversation = find(getConversations(), contact);
|
||||||
if (conversation != null) {
|
if (conversation != null) {
|
||||||
if (online) {
|
if (online) {
|
||||||
conversation.endOtrIfNeeded();
|
|
||||||
if (contact.getPresences().size() == 1) {
|
if (contact.getPresences().size() == 1) {
|
||||||
sendUnsentMessages(conversation);
|
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -351,11 +336,7 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
List<Conversation> conversations = getConversations();
|
List<Conversation> conversations = getConversations();
|
||||||
for (Conversation conversation : conversations) {
|
for (Conversation conversation : conversations) {
|
||||||
if (conversation.getAccount() == account
|
if (conversation.getAccount() == account && !account.pendingConferenceJoins.contains(conversation)) {
|
||||||
&& !account.pendingConferenceJoins.contains(conversation)) {
|
|
||||||
if (!conversation.startOtrIfNeeded()) {
|
|
||||||
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": couldn't start OTR with " + conversation.getContact().getJid() + " when needed");
|
|
||||||
}
|
|
||||||
sendUnsentMessages(conversation);
|
sendUnsentMessages(conversation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1209,17 +1190,6 @@ public class XmppConnectionService extends Service {
|
||||||
boolean saveInDb = addToConversation;
|
boolean saveInDb = addToConversation;
|
||||||
message.setStatus(Message.STATUS_WAITING);
|
message.setStatus(Message.STATUS_WAITING);
|
||||||
|
|
||||||
if (!resend && message.getEncryption() != Message.ENCRYPTION_OTR) {
|
|
||||||
message.getConversation().endOtrIfNeeded();
|
|
||||||
message.getConversation().findUnsentMessagesWithEncryption(Message.ENCRYPTION_OTR,
|
|
||||||
new Conversation.OnMessageFound() {
|
|
||||||
@Override
|
|
||||||
public void onMessageFound(Message message) {
|
|
||||||
markMessage(message, Message.STATUS_SEND_FAILED);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (account.isOnlineAndConnected()) {
|
if (account.isOnlineAndConnected()) {
|
||||||
switch (message.getEncryption()) {
|
switch (message.getEncryption()) {
|
||||||
case Message.ENCRYPTION_NONE:
|
case Message.ENCRYPTION_NONE:
|
||||||
|
@ -1249,30 +1219,6 @@ public class XmppConnectionService extends Service {
|
||||||
packet = mMessageGenerator.generatePgpChat(message);
|
packet = mMessageGenerator.generatePgpChat(message);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Message.ENCRYPTION_OTR:
|
|
||||||
SessionImpl otrSession = conversation.getOtrSession();
|
|
||||||
if (otrSession != null && otrSession.getSessionStatus() == SessionStatus.ENCRYPTED) {
|
|
||||||
try {
|
|
||||||
message.setCounterpart(Jid.fromSessionID(otrSession.getSessionID()));
|
|
||||||
} catch (InvalidJidException e) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (message.needsUploading()) {
|
|
||||||
mJingleConnectionManager.createNewConnection(message);
|
|
||||||
} else {
|
|
||||||
packet = mMessageGenerator.generateOtrChat(message);
|
|
||||||
}
|
|
||||||
} else if (otrSession == null) {
|
|
||||||
if (message.fixCounterpart()) {
|
|
||||||
conversation.startOtrSession(message.getCounterpart().getResourcepart(), true);
|
|
||||||
} else {
|
|
||||||
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": could not fix counterpart for OTR message to contact " + message.getCounterpart());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.d(Config.LOGTAG, account.getJid().toBareJid() + " OTR session with " + message.getContact() + " is in wrong state: " + otrSession.getSessionStatus().toString());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Message.ENCRYPTION_AXOLOTL:
|
case Message.ENCRYPTION_AXOLOTL:
|
||||||
message.setFingerprint(account.getAxolotlService().getOwnFingerprint());
|
message.setFingerprint(account.getAxolotlService().getOwnFingerprint());
|
||||||
if (message.needsUploading()) {
|
if (message.needsUploading()) {
|
||||||
|
@ -1324,12 +1270,6 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Message.ENCRYPTION_OTR:
|
|
||||||
if (!conversation.hasValidOtrSession() && message.getCounterpart() != null) {
|
|
||||||
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": create otr session without starting for " + message.getContact().getJid());
|
|
||||||
conversation.startOtrSession(message.getCounterpart().getResourcepart(), false);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Message.ENCRYPTION_AXOLOTL:
|
case Message.ENCRYPTION_AXOLOTL:
|
||||||
message.setFingerprint(account.getAxolotlService().getOwnFingerprint());
|
message.setFingerprint(account.getAxolotlService().getOwnFingerprint());
|
||||||
break;
|
break;
|
||||||
|
@ -1804,7 +1744,6 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
leaveMuc(conversation);
|
leaveMuc(conversation);
|
||||||
} else {
|
} else {
|
||||||
conversation.endOtrIfNeeded();
|
|
||||||
if (conversation.getContact().getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
|
if (conversation.getContact().getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
|
||||||
Log.d(Config.LOGTAG, "Canceling presence request from " + conversation.getJid().toString());
|
Log.d(Config.LOGTAG, "Canceling presence request from " + conversation.getJid().toString());
|
||||||
sendPresencePacket(
|
sendPresencePacket(
|
||||||
|
@ -1941,8 +1880,6 @@ public class XmppConnectionService extends Service {
|
||||||
if (conversation.getAccount() == account) {
|
if (conversation.getAccount() == account) {
|
||||||
if (conversation.getMode() == Conversation.MODE_MULTI) {
|
if (conversation.getMode() == Conversation.MODE_MULTI) {
|
||||||
leaveMuc(conversation);
|
leaveMuc(conversation);
|
||||||
} else if (conversation.getMode() == Conversation.MODE_SINGLE) {
|
|
||||||
conversation.endOtrIfNeeded();
|
|
||||||
}
|
}
|
||||||
conversations.remove(conversation);
|
conversations.remove(conversation);
|
||||||
}
|
}
|
||||||
|
@ -2750,12 +2687,6 @@ public class XmppConnectionService extends Service {
|
||||||
if (conversation.getAccount() == account) {
|
if (conversation.getAccount() == account) {
|
||||||
if (conversation.getMode() == Conversation.MODE_MULTI) {
|
if (conversation.getMode() == Conversation.MODE_MULTI) {
|
||||||
leaveMuc(conversation, true);
|
leaveMuc(conversation, true);
|
||||||
} else {
|
|
||||||
if (conversation.endOtrIfNeeded()) {
|
|
||||||
Log.d(Config.LOGTAG, account.getJid().toBareJid()
|
|
||||||
+ ": ended otr session with "
|
|
||||||
+ conversation.getJid());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2800,65 +2731,6 @@ public class XmppConnectionService extends Service {
|
||||||
pushContactToServer(contact);
|
pushContactToServer(contact);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onOtrSessionEstablished(Conversation conversation) {
|
|
||||||
final Account account = conversation.getAccount();
|
|
||||||
final Session otrSession = conversation.getOtrSession();
|
|
||||||
Log.d(Config.LOGTAG,
|
|
||||||
account.getJid().toBareJid() + " 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.fromString(id.getAccountID() + "/" + id.getUserID()));
|
|
||||||
} catch (InvalidJidException e) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (message.needsUploading()) {
|
|
||||||
mJingleConnectionManager.createNewConnection(message);
|
|
||||||
} else {
|
|
||||||
MessagePacket outPacket = mMessageGenerator.generateOtrChat(message);
|
|
||||||
if (outPacket != null) {
|
|
||||||
mMessageGenerator.addDelay(outPacket, message.getTimeSent());
|
|
||||||
message.setStatus(Message.STATUS_SEND);
|
|
||||||
databaseBackend.updateMessage(message);
|
|
||||||
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) {
|
public void pushContactToServer(final Contact contact) {
|
||||||
contact.resetOption(Contact.Options.DIRTY_DELETE);
|
contact.resetOption(Contact.Options.DIRTY_DELETE);
|
||||||
contact.setOption(Contact.Options.DIRTY_PUSH);
|
contact.setOption(Contact.Options.DIRTY_PUSH);
|
||||||
|
@ -3959,14 +3831,10 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean verifyFingerprints(Contact contact, List<XmppUri.Fingerprint> fingerprints) {
|
public boolean verifyFingerprints(Contact contact, List<XmppUri.Fingerprint> fingerprints) {
|
||||||
boolean needsRosterWrite = false;
|
|
||||||
boolean performedVerification = false;
|
boolean performedVerification = false;
|
||||||
final AxolotlService axolotlService = contact.getAccount().getAxolotlService();
|
final AxolotlService axolotlService = contact.getAccount().getAxolotlService();
|
||||||
for (XmppUri.Fingerprint fp : fingerprints) {
|
for (XmppUri.Fingerprint fp : fingerprints) {
|
||||||
if (fp.type == XmppUri.FingerprintType.OTR) {
|
if (fp.type == XmppUri.FingerprintType.OMEMO) {
|
||||||
performedVerification |= contact.addOtrFingerprint(fp.fingerprint);
|
|
||||||
needsRosterWrite |= performedVerification;
|
|
||||||
} else if (fp.type == XmppUri.FingerprintType.OMEMO) {
|
|
||||||
String fingerprint = "05" + fp.fingerprint.replaceAll("\\s", "");
|
String fingerprint = "05" + fp.fingerprint.replaceAll("\\s", "");
|
||||||
FingerprintStatus fingerprintStatus = axolotlService.getFingerprintTrust(fingerprint);
|
FingerprintStatus fingerprintStatus = axolotlService.getFingerprintTrust(fingerprint);
|
||||||
if (fingerprintStatus != null) {
|
if (fingerprintStatus != null) {
|
||||||
|
@ -3979,9 +3847,6 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (needsRosterWrite) {
|
|
||||||
syncRosterToDisk(contact.getAccount());
|
|
||||||
}
|
|
||||||
return performedVerification;
|
return performedVerification;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -409,33 +409,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
|
||||||
|
|
||||||
binding.detailsContactKeys.removeAllViews();
|
binding.detailsContactKeys.removeAllViews();
|
||||||
boolean hasKeys = false;
|
boolean hasKeys = false;
|
||||||
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
final LayoutInflater inflater = getLayoutInflater();
|
||||||
if (Config.supportOtr()) {
|
|
||||||
for (final String otrFingerprint : contact.getOtrFingerprints()) {
|
|
||||||
hasKeys = true;
|
|
||||||
View view = inflater.inflate(R.layout.contact_key, binding.detailsContactKeys, false);
|
|
||||||
TextView key = (TextView) view.findViewById(R.id.key);
|
|
||||||
TextView keyType = (TextView) view.findViewById(R.id.key_type);
|
|
||||||
ImageButton removeButton = (ImageButton) 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(new OnClickListener() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
confirmToDeleteFingerprint(otrFingerprint);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final AxolotlService axolotlService = contact.getAccount().getAxolotlService();
|
final AxolotlService axolotlService = contact.getAccount().getAxolotlService();
|
||||||
if (Config.supportOmemo() && axolotlService != null) {
|
if (Config.supportOmemo() && axolotlService != null) {
|
||||||
boolean skippedInactive = false;
|
boolean skippedInactive = false;
|
||||||
|
|
|
@ -32,12 +32,8 @@ import android.widget.AdapterView;
|
||||||
import android.widget.AdapterView.OnItemClickListener;
|
import android.widget.AdapterView.OnItemClickListener;
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
import android.widget.PopupMenu;
|
|
||||||
import android.widget.PopupMenu.OnMenuItemClickListener;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import net.java.otr4j.session.SessionStatus;
|
|
||||||
|
|
||||||
import org.openintents.openpgp.util.OpenPgpApi;
|
import org.openintents.openpgp.util.OpenPgpApi;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -454,17 +450,12 @@ public class ConversationActivity extends XmppActivity
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void configureEncryptionMenu(Conversation conversation, Menu menu) {
|
private static void configureEncryptionMenu(Conversation conversation, Menu menu) {
|
||||||
MenuItem otr = menu.findItem(R.id.encryption_choice_otr);
|
|
||||||
MenuItem none = menu.findItem(R.id.encryption_choice_none);
|
MenuItem none = menu.findItem(R.id.encryption_choice_none);
|
||||||
MenuItem pgp = menu.findItem(R.id.encryption_choice_pgp);
|
MenuItem pgp = menu.findItem(R.id.encryption_choice_pgp);
|
||||||
MenuItem axolotl = menu.findItem(R.id.encryption_choice_axolotl);
|
MenuItem axolotl = menu.findItem(R.id.encryption_choice_axolotl);
|
||||||
pgp.setVisible(Config.supportOpenPgp());
|
pgp.setVisible(Config.supportOpenPgp());
|
||||||
none.setVisible(Config.supportUnencrypted() || conversation.getMode() == Conversation.MODE_MULTI);
|
none.setVisible(Config.supportUnencrypted() || conversation.getMode() == Conversation.MODE_MULTI);
|
||||||
otr.setVisible(Config.supportOtr());
|
|
||||||
axolotl.setVisible(Config.supportOmemo());
|
axolotl.setVisible(Config.supportOmemo());
|
||||||
if (conversation.getMode() == Conversation.MODE_MULTI) {
|
|
||||||
otr.setVisible(false);
|
|
||||||
}
|
|
||||||
if (!conversation.getAccount().getAxolotlService().isConversationAxolotlCapable(conversation)) {
|
if (!conversation.getAccount().getAxolotlService().isConversationAxolotlCapable(conversation)) {
|
||||||
axolotl.setEnabled(false);
|
axolotl.setEnabled(false);
|
||||||
}
|
}
|
||||||
|
@ -472,9 +463,6 @@ public class ConversationActivity extends XmppActivity
|
||||||
case Message.ENCRYPTION_NONE:
|
case Message.ENCRYPTION_NONE:
|
||||||
none.setChecked(true);
|
none.setChecked(true);
|
||||||
break;
|
break;
|
||||||
case Message.ENCRYPTION_OTR:
|
|
||||||
otr.setChecked(true);
|
|
||||||
break;
|
|
||||||
case Message.ENCRYPTION_PGP:
|
case Message.ENCRYPTION_PGP:
|
||||||
pgp.setChecked(true);
|
pgp.setChecked(true);
|
||||||
break;
|
break;
|
||||||
|
@ -542,7 +530,7 @@ public class ConversationActivity extends XmppActivity
|
||||||
startActivity(getInstallApkIntent(fallbackPackageId));
|
startActivity(getInstallApkIntent(fallbackPackageId));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if ((account.httpUploadAvailable() || attachmentChoice == ATTACHMENT_CHOICE_LOCATION) && encryption != Message.ENCRYPTION_OTR) {
|
if (account.httpUploadAvailable() || attachmentChoice == ATTACHMENT_CHOICE_LOCATION) {
|
||||||
conversation.setNextCounterpart(null);
|
conversation.setNextCounterpart(null);
|
||||||
callback.onPresenceSelected();
|
callback.onPresenceSelected();
|
||||||
} else {
|
} else {
|
||||||
|
@ -699,7 +687,6 @@ public class ConversationActivity extends XmppActivity
|
||||||
} else if (getSelectedConversation() != null) {
|
} else if (getSelectedConversation() != null) {
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case R.id.encryption_choice_axolotl:
|
case R.id.encryption_choice_axolotl:
|
||||||
case R.id.encryption_choice_otr:
|
|
||||||
case R.id.encryption_choice_pgp:
|
case R.id.encryption_choice_pgp:
|
||||||
case R.id.encryption_choice_none:
|
case R.id.encryption_choice_none:
|
||||||
handleEncryptionSelection(item);
|
handleEncryptionSelection(item);
|
||||||
|
@ -808,41 +795,6 @@ public class ConversationActivity extends XmppActivity
|
||||||
builder.create().show();
|
builder.create().show();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void verifyOtrSessionDialog(final Conversation conversation, View view) {
|
|
||||||
if (!conversation.hasValidOtrSession() || conversation.getOtrSession().getSessionStatus() != SessionStatus.ENCRYPTED) {
|
|
||||||
Toast.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(new OnMenuItemClickListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onMenuItemClick(MenuItem menuItem) {
|
|
||||||
Intent intent = new Intent(ConversationActivity.this, VerifyOTRActivity.class);
|
|
||||||
intent.setAction(VerifyOTRActivity.ACTION_VERIFY_CONTACT);
|
|
||||||
intent.putExtra("contact", conversation.getContact().getJid().toBareJid().toString());
|
|
||||||
intent.putExtra(EXTRA_ACCOUNT, conversation.getAccount().getJid().toBareJid().toString());
|
|
||||||
switch (menuItem.getItemId()) {
|
|
||||||
case R.id.scan_fingerprint:
|
|
||||||
intent.putExtra("mode", VerifyOTRActivity.MODE_SCAN_FINGERPRINT);
|
|
||||||
break;
|
|
||||||
case R.id.ask_question:
|
|
||||||
intent.putExtra("mode", VerifyOTRActivity.MODE_ASK_QUESTION);
|
|
||||||
break;
|
|
||||||
case R.id.manual_verification:
|
|
||||||
intent.putExtra("mode", VerifyOTRActivity.MODE_MANUAL_VERIFICATION);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
startActivity(intent);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
popup.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleEncryptionSelection(MenuItem item) {
|
private void handleEncryptionSelection(MenuItem item) {
|
||||||
Conversation conversation = getSelectedConversation();
|
Conversation conversation = getSelectedConversation();
|
||||||
if (conversation == null) {
|
if (conversation == null) {
|
||||||
|
@ -854,10 +806,6 @@ public class ConversationActivity extends XmppActivity
|
||||||
conversation.setNextEncryption(Message.ENCRYPTION_NONE);
|
conversation.setNextEncryption(Message.ENCRYPTION_NONE);
|
||||||
item.setChecked(true);
|
item.setChecked(true);
|
||||||
break;
|
break;
|
||||||
case R.id.encryption_choice_otr:
|
|
||||||
conversation.setNextEncryption(Message.ENCRYPTION_OTR);
|
|
||||||
item.setChecked(true);
|
|
||||||
break;
|
|
||||||
case R.id.encryption_choice_pgp:
|
case R.id.encryption_choice_pgp:
|
||||||
if (hasPgp()) {
|
if (hasPgp()) {
|
||||||
if (conversation.getAccount().getPgpSignature() != null) {
|
if (conversation.getAccount().getPgpSignature() != null) {
|
||||||
|
@ -1388,8 +1336,7 @@ public class ConversationActivity extends XmppActivity
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (c == null || c.getMode() == Conversation.MODE_MULTI
|
if (c == null || c.getMode() == Conversation.MODE_MULTI
|
||||||
|| FileBackend.allFilesUnderSize(this, uris, getMaxHttpUploadSize(c))
|
|| FileBackend.allFilesUnderSize(this, uris, getMaxHttpUploadSize(c))) {
|
||||||
|| c.getNextEncryption() == Message.ENCRYPTION_OTR) {
|
|
||||||
callback.onPresenceSelected();
|
callback.onPresenceSelected();
|
||||||
} else {
|
} else {
|
||||||
selectPresence(c, callback);
|
selectPresence(c, callback);
|
||||||
|
|
|
@ -42,8 +42,6 @@ import android.widget.TextView;
|
||||||
import android.widget.TextView.OnEditorActionListener;
|
import android.widget.TextView.OnEditorActionListener;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import net.java.otr4j.session.SessionStatus;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -221,13 +219,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
protected OnClickListener clickToVerify = new OnClickListener() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
activity.verifyOtrSessionDialog(conversation, v);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
private EditMessage.OnCommitContentListener mEditorContentListener = new EditMessage.OnCommitContentListener() {
|
private EditMessage.OnCommitContentListener mEditorContentListener = new EditMessage.OnCommitContentListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onCommitContent(InputContentInfoCompat inputContentInfo, int flags, Bundle opts, String[] contentMimeTypes) {
|
public boolean onCommitContent(InputContentInfoCompat inputContentInfo, int flags, Bundle opts, String[] contentMimeTypes) {
|
||||||
|
@ -316,17 +308,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
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("contact", conversation.getContact().getJid().toBareJid().toString());
|
|
||||||
intent.putExtra(VerifyOTRActivity.EXTRA_ACCOUNT, conversation.getAccount().getJid().toBareJid().toString());
|
|
||||||
intent.putExtra("mode", VerifyOTRActivity.MODE_ANSWER_QUESTION);
|
|
||||||
startActivity(intent);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
protected OnClickListener clickToDecryptListener = new OnClickListener() {
|
protected OnClickListener clickToDecryptListener = new OnClickListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -483,9 +465,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
|
||||||
message.setUuid(UUID.randomUUID().toString());
|
message.setUuid(UUID.randomUUID().toString());
|
||||||
}
|
}
|
||||||
switch (message.getConversation().getNextEncryption()) {
|
switch (message.getConversation().getNextEncryption()) {
|
||||||
case Message.ENCRYPTION_OTR:
|
|
||||||
sendOtrMessage(message);
|
|
||||||
break;
|
|
||||||
case Message.ENCRYPTION_PGP:
|
case Message.ENCRYPTION_PGP:
|
||||||
sendPgpMessage(message);
|
sendPgpMessage(message);
|
||||||
break;
|
break;
|
||||||
|
@ -600,8 +579,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
|
||||||
if (message.getEncryption() == Message.ENCRYPTION_PGP
|
if (message.getEncryption() == Message.ENCRYPTION_PGP
|
||||||
|| message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
|
|| message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
|
||||||
fingerprint = "pgp";
|
fingerprint = "pgp";
|
||||||
} else if (message.getEncryption() == Message.ENCRYPTION_OTR) {
|
|
||||||
fingerprint = "otr";
|
|
||||||
} else {
|
} else {
|
||||||
fingerprint = message.getFingerprint();
|
fingerprint = message.getFingerprint();
|
||||||
}
|
}
|
||||||
|
@ -1114,14 +1091,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
|
||||||
}
|
}
|
||||||
} else if (account.hasPendingPgpIntent(conversation)) {
|
} else if (account.hasPendingPgpIntent(conversation)) {
|
||||||
showSnackbar(R.string.openpgp_messages_found, R.string.decrypt, clickToDecryptListener);
|
showSnackbar(R.string.openpgp_messages_found, R.string.decrypt, clickToDecryptListener);
|
||||||
} else if (mode == Conversation.MODE_SINGLE
|
|
||||||
&& 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
|
} else if (connection != null
|
||||||
&& connection.getFeatures().blocking()
|
&& connection.getFeatures().blocking()
|
||||||
&& conversation.countMessages() != 0
|
&& conversation.countMessages() != 0
|
||||||
|
@ -1612,21 +1581,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
|
||||||
messageSent();
|
messageSent();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void sendOtrMessage(final Message message) {
|
|
||||||
final ConversationActivity activity = (ConversationActivity) getActivity();
|
|
||||||
final XmppConnectionService xmppService = activity.xmppConnectionService;
|
|
||||||
activity.selectPresence(message.getConversation(),
|
|
||||||
new OnPresenceSelected() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPresenceSelected() {
|
|
||||||
message.setCounterpart(conversation.getNextCounterpart());
|
|
||||||
xmppService.sendMessage(message);
|
|
||||||
messageSent();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void appendText(String text) {
|
public void appendText(String text) {
|
||||||
if (text == null) {
|
if (text == null) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -96,17 +96,13 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
|
||||||
private TextView mServerInfoHttpUpload;
|
private TextView mServerInfoHttpUpload;
|
||||||
private TextView mServerInfoPush;
|
private TextView mServerInfoPush;
|
||||||
private TextView mSessionEst;
|
private TextView mSessionEst;
|
||||||
private TextView mOtrFingerprint;
|
|
||||||
private TextView mAxolotlFingerprint;
|
private TextView mAxolotlFingerprint;
|
||||||
private TextView mPgpFingerprint;
|
private TextView mPgpFingerprint;
|
||||||
private TextView mOwnFingerprintDesc;
|
private TextView mOwnFingerprintDesc;
|
||||||
private TextView mOtrFingerprintDesc;
|
|
||||||
private TextView getmPgpFingerprintDesc;
|
private TextView getmPgpFingerprintDesc;
|
||||||
private ImageView mAvatar;
|
private ImageView mAvatar;
|
||||||
private RelativeLayout mOtrFingerprintBox;
|
|
||||||
private RelativeLayout mAxolotlFingerprintBox;
|
private RelativeLayout mAxolotlFingerprintBox;
|
||||||
private RelativeLayout mPgpFingerprintBox;
|
private RelativeLayout mPgpFingerprintBox;
|
||||||
private ImageButton mOtrFingerprintToClipboardButton;
|
|
||||||
private ImageButton mAxolotlFingerprintToClipboardButton;
|
private ImageButton mAxolotlFingerprintToClipboardButton;
|
||||||
private ImageButton mPgpDeleteFingerprintButton;
|
private ImageButton mPgpDeleteFingerprintButton;
|
||||||
private LinearLayout keys;
|
private LinearLayout keys;
|
||||||
|
@ -567,10 +563,6 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
|
||||||
this.mPgpFingerprint = (TextView) findViewById(R.id.pgp_fingerprint);
|
this.mPgpFingerprint = (TextView) findViewById(R.id.pgp_fingerprint);
|
||||||
this.getmPgpFingerprintDesc = (TextView) findViewById(R.id.pgp_fingerprint_desc);
|
this.getmPgpFingerprintDesc = (TextView) findViewById(R.id.pgp_fingerprint_desc);
|
||||||
this.mPgpDeleteFingerprintButton = (ImageButton) findViewById(R.id.action_delete_pgp);
|
this.mPgpDeleteFingerprintButton = (ImageButton) findViewById(R.id.action_delete_pgp);
|
||||||
this.mOtrFingerprint = (TextView) findViewById(R.id.otr_fingerprint);
|
|
||||||
this.mOtrFingerprintDesc = (TextView) findViewById(R.id.otr_fingerprint_desc);
|
|
||||||
this.mOtrFingerprintBox = (RelativeLayout) findViewById(R.id.otr_fingerprint_box);
|
|
||||||
this.mOtrFingerprintToClipboardButton = (ImageButton) findViewById(R.id.action_copy_to_clipboard);
|
|
||||||
this.mAxolotlFingerprint = (TextView) findViewById(R.id.axolotl_fingerprint);
|
this.mAxolotlFingerprint = (TextView) findViewById(R.id.axolotl_fingerprint);
|
||||||
this.mAxolotlFingerprintBox = (RelativeLayout) findViewById(R.id.axolotl_fingerprint_box);
|
this.mAxolotlFingerprintBox = (RelativeLayout) findViewById(R.id.axolotl_fingerprint_box);
|
||||||
this.mAxolotlFingerprintToClipboardButton = (ImageButton) findViewById(R.id.action_copy_axolotl_to_clipboard);
|
this.mAxolotlFingerprintToClipboardButton = (ImageButton) findViewById(R.id.action_copy_axolotl_to_clipboard);
|
||||||
|
@ -980,25 +972,6 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
|
||||||
} else {
|
} else {
|
||||||
this.mPgpFingerprintBox.setVisibility(View.GONE);
|
this.mPgpFingerprintBox.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
final String otrFingerprint = this.mAccount.getOtrFingerprint();
|
|
||||||
if (otrFingerprint != null && Config.supportOtr()) {
|
|
||||||
if ("otr".equals(messageFingerprint)) {
|
|
||||||
this.mOtrFingerprintDesc.setTextColor(ContextCompat.getColor(this, R.color.accent));
|
|
||||||
}
|
|
||||||
this.mOtrFingerprintBox.setVisibility(View.VISIBLE);
|
|
||||||
this.mOtrFingerprint.setText(CryptoHelper.prettifyFingerprint(otrFingerprint));
|
|
||||||
this.mOtrFingerprintToClipboardButton.setVisibility(View.VISIBLE);
|
|
||||||
this.mOtrFingerprintToClipboardButton.setOnClickListener(v -> {
|
|
||||||
if (copyTextToClipboard(CryptoHelper.prettifyFingerprint(otrFingerprint), R.string.otr_fingerprint)) {
|
|
||||||
Toast.makeText(
|
|
||||||
EditAccountActivity.this,
|
|
||||||
R.string.toast_message_otr_fingerprint,
|
|
||||||
Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.mOtrFingerprintBox.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
final String ownAxolotlFingerprint = this.mAccount.getAxolotlService().getOwnFingerprint();
|
final String ownAxolotlFingerprint = this.mAccount.getAxolotlService().getOwnFingerprint();
|
||||||
if (ownAxolotlFingerprint != null && Config.supportOmemo()) {
|
if (ownAxolotlFingerprint != null && Config.supportOmemo()) {
|
||||||
this.mAxolotlFingerprintBox.setVisibility(View.VISIBLE);
|
this.mAxolotlFingerprintBox.setVisibility(View.VISIBLE);
|
||||||
|
|
|
@ -332,8 +332,7 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
|
||||||
if (account.httpUploadAvailable()
|
if (account.httpUploadAvailable()
|
||||||
&& ((share.image && !neverCompressPictures())
|
&& ((share.image && !neverCompressPictures())
|
||||||
|| conversation.getMode() == Conversation.MODE_MULTI
|
|| conversation.getMode() == Conversation.MODE_MULTI
|
||||||
|| FileBackend.allFilesUnderSize(this, share.uris, max))
|
|| FileBackend.allFilesUnderSize(this, share.uris, max))) {
|
||||||
&& conversation.getNextEncryption() != Message.ENCRYPTION_OTR) {
|
|
||||||
callback.onPresenceSelected();
|
callback.onPresenceSelected();
|
||||||
} else {
|
} else {
|
||||||
selectPresence(conversation, callback);
|
selectPresence(conversation, callback);
|
||||||
|
|
|
@ -1,443 +0,0 @@
|
||||||
package eu.siacs.conversations.ui;
|
|
||||||
|
|
||||||
import android.support.v7.app.AlertDialog;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.support.v7.app.ActionBar;
|
|
||||||
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 net.java.otr4j.OtrException;
|
|
||||||
import net.java.otr4j.session.Session;
|
|
||||||
|
|
||||||
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.utils.zxing.IntentIntegrator;
|
|
||||||
import eu.siacs.conversations.utils.zxing.IntentResult;
|
|
||||||
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
|
|
||||||
import eu.siacs.conversations.xmpp.jid.Jid;
|
|
||||||
|
|
||||||
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());
|
|
||||||
Toast.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());
|
|
||||||
Toast.makeText(this,R.string.verified,Toast.LENGTH_SHORT).show();
|
|
||||||
updateView();
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
Toast.makeText(this,R.string.could_not_verify_fingerprint,Toast.LENGTH_SHORT).show();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean isAccountOnline() {
|
|
||||||
if (this.mAccount.getStatus() != Account.State.ONLINE) {
|
|
||||||
Toast.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.fromString(intent.getExtras().getString("contact")));
|
|
||||||
if (this.mConversation == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (final InvalidJidException ignored) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
this.mode = intent.getIntExtra("mode", MODE_MANUAL_VERIFICATION);
|
|
||||||
if (this.mode == MODE_SCAN_FINGERPRINT) {
|
|
||||||
new IntentIntegrator(this).initiateScan();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
|
||||||
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.setTextColor(getPrimaryTextColor());
|
|
||||||
button.setText(text);
|
|
||||||
button.setOnClickListener(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void deactivateButton(Button button, int text) {
|
|
||||||
button.setEnabled(false);
|
|
||||||
button.setTextColor(getSecondaryTextColor());
|
|
||||||
button.setText(text);
|
|
||||||
button.setOnClickListener(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setContentView(R.layout.activity_verify_otr);
|
|
||||||
this.mRemoteFingerprint = (TextView) findViewById(R.id.remote_fingerprint);
|
|
||||||
this.mYourFingerprint = (TextView) findViewById(R.id.your_fingerprint);
|
|
||||||
this.mLeftButton = (Button) findViewById(R.id.left_button);
|
|
||||||
this.mRightButton = (Button) findViewById(R.id.right_button);
|
|
||||||
this.mVerificationExplain = (TextView) findViewById(R.id.verification_explanation);
|
|
||||||
this.mStatusMessage = (TextView) findViewById(R.id.status_message);
|
|
||||||
this.mSharedSecretSecret = (EditText) findViewById(R.id.shared_secret_secret);
|
|
||||||
this.mSharedSecretHintEditable = (EditText) findViewById(R.id.shared_secret_hint_editable);
|
|
||||||
this.mSharedSecretHint = (TextView) findViewById(R.id.shared_secret_hint);
|
|
||||||
this.mManualVerificationArea = (LinearLayout) findViewById(R.id.manual_verification_area);
|
|
||||||
this.mSmpVerificationArea = (LinearLayout) 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() {
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -48,8 +48,6 @@ import android.widget.EditText;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import net.java.otr4j.session.SessionID;
|
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -782,17 +780,7 @@ public abstract class XmppActivity extends AppCompatActivity {
|
||||||
public void selectPresence(final Conversation conversation,
|
public void selectPresence(final Conversation conversation,
|
||||||
final OnPresenceSelected listener) {
|
final OnPresenceSelected listener) {
|
||||||
final Contact contact = conversation.getContact();
|
final Contact contact = conversation.getContact();
|
||||||
if (conversation.hasValidOtrSession()) {
|
if (!contact.showInRoster()) {
|
||||||
SessionID id = conversation.getOtrSession().getSessionID();
|
|
||||||
Jid jid;
|
|
||||||
try {
|
|
||||||
jid = Jid.fromString(id.getAccountID() + "/" + id.getUserID());
|
|
||||||
} catch (InvalidJidException e) {
|
|
||||||
jid = null;
|
|
||||||
}
|
|
||||||
conversation.setNextCounterpart(jid);
|
|
||||||
listener.onPresenceSelected();
|
|
||||||
} else if (!contact.showInRoster()) {
|
|
||||||
showAddToRosterDialog(conversation);
|
showAddToRosterDialog(conversation);
|
||||||
} else {
|
} else {
|
||||||
final Presences presences = contact.getPresences();
|
final Presences presences = contact.getPresences();
|
||||||
|
|
|
@ -483,8 +483,6 @@ public class UIHelper {
|
||||||
} else {
|
} else {
|
||||||
return context.getString(R.string.send_message_to_x, conversation.getName());
|
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:
|
case Message.ENCRYPTION_AXOLOTL:
|
||||||
AxolotlService axolotlService = conversation.getAccount().getAxolotlService();
|
AxolotlService axolotlService = conversation.getAccount().getAxolotlService();
|
||||||
if (axolotlService != null && axolotlService.trustedSessionVerified(conversation)) {
|
if (axolotlService != null && axolotlService.trustedSessionVerified(conversation)) {
|
||||||
|
|
|
@ -132,9 +132,6 @@ public class XmppUri {
|
||||||
if (parts.length == 2) {
|
if (parts.length == 2) {
|
||||||
String key = parts[0].toLowerCase(Locale.US);
|
String key = parts[0].toLowerCase(Locale.US);
|
||||||
String value = parts[1].toLowerCase(Locale.US);
|
String value = parts[1].toLowerCase(Locale.US);
|
||||||
if (OTR_URI_PARAM.equals(key)) {
|
|
||||||
fingerprints.add(new Fingerprint(FingerprintType.OTR,value));
|
|
||||||
}
|
|
||||||
if (key.startsWith(OMEMO_URI_PARAM)) {
|
if (key.startsWith(OMEMO_URI_PARAM)) {
|
||||||
try {
|
try {
|
||||||
int id = Integer.parseInt(key.substring(OMEMO_URI_PARAM.length()));
|
int id = Integer.parseInt(key.substring(OMEMO_URI_PARAM.length()));
|
||||||
|
@ -213,8 +210,7 @@ public class XmppUri {
|
||||||
return fingerprints.size() > 0;
|
return fingerprints.size() > 0;
|
||||||
}
|
}
|
||||||
public enum FingerprintType {
|
public enum FingerprintType {
|
||||||
OMEMO,
|
OMEMO
|
||||||
OTR
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getFingerprintUri(String base, List<XmppUri.Fingerprint> fingerprints, char seperator) {
|
public static String getFingerprintUri(String base, List<XmppUri.Fingerprint> fingerprints, char seperator) {
|
||||||
|
@ -225,8 +221,6 @@ public class XmppUri {
|
||||||
if (type == XmppUri.FingerprintType.OMEMO) {
|
if (type == XmppUri.FingerprintType.OMEMO) {
|
||||||
builder.append(XmppUri.OMEMO_URI_PARAM);
|
builder.append(XmppUri.OMEMO_URI_PARAM);
|
||||||
builder.append(fingerprints.get(i).deviceId);
|
builder.append(fingerprints.get(i).deviceId);
|
||||||
} else if (type == XmppUri.FingerprintType.OTR) {
|
|
||||||
builder.append(XmppUri.OTR_URI_PARAM);
|
|
||||||
}
|
}
|
||||||
builder.append('=');
|
builder.append('=');
|
||||||
builder.append(fingerprints.get(i).fingerprint);
|
builder.append(fingerprints.get(i).fingerprint);
|
||||||
|
|
|
@ -2,8 +2,6 @@ package eu.siacs.conversations.xmpp.jid;
|
||||||
|
|
||||||
import android.util.LruCache;
|
import android.util.LruCache;
|
||||||
|
|
||||||
import net.java.otr4j.session.SessionID;
|
|
||||||
|
|
||||||
import java.net.IDN;
|
import java.net.IDN;
|
||||||
|
|
||||||
import eu.siacs.conversations.Config;
|
import eu.siacs.conversations.Config;
|
||||||
|
@ -51,14 +49,6 @@ public final class Jid {
|
||||||
return resourcepart;
|
return resourcepart;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Jid fromSessionID(final SessionID id) throws InvalidJidException{
|
|
||||||
if (id.getUserID().isEmpty()) {
|
|
||||||
return Jid.fromString(id.getAccountID());
|
|
||||||
} else {
|
|
||||||
return Jid.fromString(id.getAccountID()+"/"+id.getUserID());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Jid fromString(final String jid) throws InvalidJidException {
|
public static Jid fromString(final String jid) throws InvalidJidException {
|
||||||
return Jid.fromString(jid, false);
|
return Jid.fromString(jid, false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -404,12 +404,8 @@ public class JingleConnection implements Transferable {
|
||||||
} else {
|
} else {
|
||||||
message.setType(Message.TYPE_FILE);
|
message.setType(Message.TYPE_FILE);
|
||||||
}
|
}
|
||||||
if (filename[filename.length - 1].equals("otr")) {
|
|
||||||
message.setEncryption(Message.ENCRYPTION_OTR);
|
|
||||||
} else {
|
|
||||||
message.setEncryption(Message.ENCRYPTION_PGP);
|
message.setEncryption(Message.ENCRYPTION_PGP);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
message.setType(Message.TYPE_FILE);
|
message.setType(Message.TYPE_FILE);
|
||||||
}
|
}
|
||||||
|
@ -418,9 +414,7 @@ public class JingleConnection implements Transferable {
|
||||||
if (!fileNameElement.getContent().isEmpty()) {
|
if (!fileNameElement.getContent().isEmpty()) {
|
||||||
String parts[] = fileNameElement.getContent().split("/");
|
String parts[] = fileNameElement.getContent().split("/");
|
||||||
suffix = parts[parts.length - 1];
|
suffix = parts[parts.length - 1];
|
||||||
if (message.getEncryption() == Message.ENCRYPTION_OTR && suffix.endsWith(".otr")) {
|
if (message.getEncryption() == Message.ENCRYPTION_PGP && (suffix.endsWith(".pgp") || suffix.endsWith(".gpg"))) {
|
||||||
suffix = suffix.substring(0,suffix.length() - 4);
|
|
||||||
} else if (message.getEncryption() == Message.ENCRYPTION_PGP && (suffix.endsWith(".pgp") || suffix.endsWith(".gpg"))) {
|
|
||||||
suffix = suffix.substring(0,suffix.length() - 4);
|
suffix = suffix.substring(0,suffix.length() - 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -457,15 +451,6 @@ public class JingleConnection implements Transferable {
|
||||||
} else {
|
} else {
|
||||||
Log.d(Config.LOGTAG,"could not process KeyTransportMessage");
|
Log.d(Config.LOGTAG,"could not process KeyTransportMessage");
|
||||||
}
|
}
|
||||||
} else if (message.getEncryption() == Message.ENCRYPTION_OTR) {
|
|
||||||
byte[] key = conversation.getSymmetricKey();
|
|
||||||
if (key == null) {
|
|
||||||
this.sendCancel();
|
|
||||||
this.fail();
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
this.file.setKeyAndIv(key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.file.setExpectedSize(size);
|
this.file.setExpectedSize(size);
|
||||||
message.resetFileParams();
|
message.resetFileParams();
|
||||||
|
@ -488,17 +473,7 @@ public class JingleConnection implements Transferable {
|
||||||
this.file = this.mXmppConnectionService.getFileBackend().getFile(message, false);
|
this.file = this.mXmppConnectionService.getFileBackend().getFile(message, false);
|
||||||
Pair<InputStream,Integer> pair;
|
Pair<InputStream,Integer> pair;
|
||||||
try {
|
try {
|
||||||
if (message.getEncryption() == Message.ENCRYPTION_OTR) {
|
if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL) {
|
||||||
Conversation conversation = this.message.getConversation();
|
|
||||||
if (!this.mXmppConnectionService.renewSymmetricKey(conversation)) {
|
|
||||||
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": could not set symmetric key");
|
|
||||||
cancel();
|
|
||||||
}
|
|
||||||
this.file.setKeyAndIv(conversation.getSymmetricKey());
|
|
||||||
pair = AbstractConnectionManager.createInputStream(this.file, false);
|
|
||||||
this.file.setExpectedSize(pair.second);
|
|
||||||
content.setFileOffer(this.file, true, this.ftVersion);
|
|
||||||
} else if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL) {
|
|
||||||
this.file.setKey(mXmppAxolotlMessage.getInnerKey());
|
this.file.setKey(mXmppAxolotlMessage.getInnerKey());
|
||||||
this.file.setIv(mXmppAxolotlMessage.getIV());
|
this.file.setIv(mXmppAxolotlMessage.getIV());
|
||||||
pair = AbstractConnectionManager.createInputStream(this.file, true);
|
pair = AbstractConnectionManager.createInputStream(this.file, true);
|
||||||
|
|
|
@ -525,52 +525,6 @@
|
||||||
android:visibility="visible"/>
|
android:visibility="visible"/>
|
||||||
</RelativeLayout>
|
</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_alignParentLeft="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:layout_toLeftOf="@+id/action_copy_to_clipboard"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/otr_fingerprint"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:fontFamily="monospace"
|
|
||||||
android:textColor="?attr/color_text_primary"
|
|
||||||
android:textSize="?attr/TextSizeBody"
|
|
||||||
android:typeface="monospace"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/otr_fingerprint_desc"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/otr_fingerprint"
|
|
||||||
android:textColor="?attr/color_text_secondary"
|
|
||||||
android:textSize="?attr/TextSizeInfo"/>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/action_copy_to_clipboard"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:alpha="?attr/icon_alpha"
|
|
||||||
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"/>
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/axolotl_fingerprint_box"
|
android:id="@+id/axolotl_fingerprint_box"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|
|
@ -21,9 +21,6 @@
|
||||||
<item
|
<item
|
||||||
android:id="@+id/encryption_choice_axolotl"
|
android:id="@+id/encryption_choice_axolotl"
|
||||||
android:title="@string/encryption_choice_omemo"/>
|
android:title="@string/encryption_choice_omemo"/>
|
||||||
<item
|
|
||||||
android:id="@+id/encryption_choice_otr"
|
|
||||||
android:title="@string/encryption_choice_otr"/>
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/encryption_choice_pgp"
|
android:id="@+id/encryption_choice_pgp"
|
||||||
android:title="@string/encryption_choice_pgp"/>
|
android:title="@string/encryption_choice_pgp"/>
|
||||||
|
|
Loading…
Reference in a new issue