diff --git a/app/src/androidTest/java/im/conversations/android/xmpp/MessageTransformationTest.java b/app/src/androidTest/java/im/conversations/android/xmpp/MessageTransformationTest.java
index eab2b61c5..4e6a756e7 100644
--- a/app/src/androidTest/java/im/conversations/android/xmpp/MessageTransformationTest.java
+++ b/app/src/androidTest/java/im/conversations/android/xmpp/MessageTransformationTest.java
@@ -54,7 +54,7 @@ public class MessageTransformationTest {
final long id = database.accountDao().insert(account);
this.transformer =
- new Transformer(database, database.accountDao().getEnabledAccount(id).get());
+ new Transformer(database.accountDao().getEnabledAccount(id).get(), database);
}
@Test
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 4052c7f85..7b3d13f49 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -79,9 +79,12 @@
+ android:exported="false"/>
-
+
+ android:windowSoftInputMode="adjustResize">
-
+
diff --git a/app/src/main/java/im/conversations/android/AbstractAccountService.java b/app/src/main/java/im/conversations/android/AbstractAccountService.java
index 72b285537..afbabe14d 100644
--- a/app/src/main/java/im/conversations/android/AbstractAccountService.java
+++ b/app/src/main/java/im/conversations/android/AbstractAccountService.java
@@ -1,15 +1,15 @@
package im.conversations.android;
-import android.content.Context;
+import im.conversations.android.database.ConversationsDatabase;
import im.conversations.android.database.model.Account;
public abstract class AbstractAccountService {
- protected Context context;
protected Account account;
+ protected ConversationsDatabase database;
- protected AbstractAccountService(final Context context, final Account account) {
- this.context = context;
+ protected AbstractAccountService(final Account account, final ConversationsDatabase database) {
this.account = account;
+ this.database = database;
}
}
diff --git a/app/src/main/java/im/conversations/android/axolotl/AxolotlPayload.java b/app/src/main/java/im/conversations/android/axolotl/AxolotlPayload.java
index a3db568ed..48a767410 100644
--- a/app/src/main/java/im/conversations/android/axolotl/AxolotlPayload.java
+++ b/app/src/main/java/im/conversations/android/axolotl/AxolotlPayload.java
@@ -24,4 +24,8 @@ public class AxolotlPayload {
public String payloadAsString() {
return new String(payload, StandardCharsets.UTF_8);
}
+
+ public boolean hasPayload() {
+ return payload != null;
+ }
}
diff --git a/app/src/main/java/im/conversations/android/axolotl/AxolotlService.java b/app/src/main/java/im/conversations/android/axolotl/AxolotlService.java
index aaae7f52d..f8426f42e 100644
--- a/app/src/main/java/im/conversations/android/axolotl/AxolotlService.java
+++ b/app/src/main/java/im/conversations/android/axolotl/AxolotlService.java
@@ -1,11 +1,11 @@
package im.conversations.android.axolotl;
-import android.content.Context;
import android.os.Build;
import com.google.common.base.Optional;
import eu.siacs.conversations.xmpp.jingle.OmemoVerification;
import im.conversations.android.AbstractAccountService;
import im.conversations.android.database.AxolotlDatabaseStore;
+import im.conversations.android.database.ConversationsDatabase;
import im.conversations.android.database.model.Account;
import im.conversations.android.xmpp.model.axolotl.Encrypted;
import im.conversations.android.xmpp.model.axolotl.Header;
@@ -22,6 +22,8 @@ import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.jxmpp.jid.Jid;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.whispersystems.libsignal.DuplicateMessageException;
import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.InvalidKeyException;
@@ -38,6 +40,8 @@ import org.whispersystems.libsignal.state.SignalProtocolStore;
public class AxolotlService extends AbstractAccountService {
+ private static final Logger LOGGER = LoggerFactory.getLogger(AxolotlService.class);
+
public static final String KEY_TYPE = "AES";
public static final String CIPHER_MODE = "AES/GCM/NoPadding";
@@ -45,9 +49,10 @@ public class AxolotlService extends AbstractAccountService {
private final SignalProtocolStore signalProtocolStore;
- public AxolotlService(final Context context, final Account account) {
- super(context, account);
- this.signalProtocolStore = new AxolotlDatabaseStore(context, account);
+ public AxolotlService(
+ final Account account, final ConversationsDatabase conversationsDatabase) {
+ super(account, conversationsDatabase);
+ this.signalProtocolStore = new AxolotlDatabaseStore(account, conversationsDatabase);
}
private AxolotlSession buildReceivingSession(
@@ -119,6 +124,10 @@ public class AxolotlService extends AbstractAccountService {
final Header header = encrypted.getHeader();
final Key ourKey = header.getKey(signalProtocolStore.getLocalRegistrationId());
if (ourKey == null) {
+ LOGGER.info(
+ "looking for {} in {}",
+ signalProtocolStore.getLocalRegistrationId(),
+ header.getKeys());
throw new NotEncryptedForThisDeviceException();
}
final byte[] keyWithAuthTag;
diff --git a/app/src/main/java/im/conversations/android/database/AxolotlDatabaseStore.java b/app/src/main/java/im/conversations/android/database/AxolotlDatabaseStore.java
index 6c7dd8e7b..fd467d5b8 100644
--- a/app/src/main/java/im/conversations/android/database/AxolotlDatabaseStore.java
+++ b/app/src/main/java/im/conversations/android/database/AxolotlDatabaseStore.java
@@ -1,6 +1,5 @@
package im.conversations.android.database;
-import android.content.Context;
import im.conversations.android.AbstractAccountService;
import im.conversations.android.axolotl.AxolotlAddress;
import im.conversations.android.database.dao.AxolotlDao;
@@ -17,12 +16,13 @@ import org.whispersystems.libsignal.state.SignedPreKeyRecord;
public class AxolotlDatabaseStore extends AbstractAccountService implements SignalProtocolStore {
- public AxolotlDatabaseStore(final Context context, final Account account) {
- super(context, account);
+ public AxolotlDatabaseStore(
+ final Account account, final ConversationsDatabase conversationsDatabase) {
+ super(account, conversationsDatabase);
}
private AxolotlDao axolotlDao() {
- return ConversationsDatabase.getInstance(context).axolotlDao();
+ return database.axolotlDao();
}
@Override
diff --git a/app/src/main/java/im/conversations/android/tls/TrustManager.java b/app/src/main/java/im/conversations/android/tls/TrustManager.java
index cf220cf5a..46fac9cb7 100644
--- a/app/src/main/java/im/conversations/android/tls/TrustManager.java
+++ b/app/src/main/java/im/conversations/android/tls/TrustManager.java
@@ -1,16 +1,19 @@
package im.conversations.android.tls;
import android.content.Context;
-import im.conversations.android.AbstractAccountService;
import im.conversations.android.database.model.Account;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;
-public class TrustManager extends AbstractAccountService implements X509TrustManager {
+public class TrustManager implements X509TrustManager {
+
+ private final Context context;
+ private final Account account;
public TrustManager(final Context context, final Account account) {
- super(context, account);
+ this.context = context;
+ this.account = account;
}
@Override
diff --git a/app/src/main/java/im/conversations/android/transformer/Transformer.java b/app/src/main/java/im/conversations/android/transformer/Transformer.java
index c37c433f3..421e06b0c 100644
--- a/app/src/main/java/im/conversations/android/transformer/Transformer.java
+++ b/app/src/main/java/im/conversations/android/transformer/Transformer.java
@@ -4,6 +4,8 @@ import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
+import im.conversations.android.axolotl.AxolotlDecryptionException;
+import im.conversations.android.axolotl.AxolotlService;
import im.conversations.android.database.ConversationsDatabase;
import im.conversations.android.database.model.Account;
import im.conversations.android.database.model.ChatIdentifier;
@@ -36,10 +38,20 @@ public class Transformer {
private final ConversationsDatabase database;
private final Account account;
- public Transformer(final ConversationsDatabase database, final Account account) {
+ private final AxolotlService axolotlService;
+
+ public Transformer(final Account account, final ConversationsDatabase conversationsDatabase) {
+ this(account, conversationsDatabase, new AxolotlService(account, conversationsDatabase));
+ }
+
+ public Transformer(
+ final Account account,
+ final ConversationsDatabase database,
+ final AxolotlService axolotlService) {
Preconditions.checkArgument(account != null, "Account must not be null");
this.database = database;
this.account = account;
+ this.axolotlService = axolotlService;
}
public boolean transform(final MessageTransformation transformation) {
@@ -72,11 +84,30 @@ public class Transformer {
chat, transformation.messageId, MessageState.error(transformation));
return false;
}
+
final Replace messageCorrection = transformation.getExtension(Replace.class);
final Reactions reactions = transformation.getExtension(Reactions.class);
final Retract retract = transformation.getExtension(Retract.class);
- // TODO we need to remove fallbacks for reactions, retractions and potentially other things
- final List contents = parseContent(transformation);
+ final Encrypted encrypted = transformation.getExtension(Encrypted.class);
+ final List contents;
+ if (encrypted != null) {
+ try {
+ final var payload = axolotlService.decrypt(transformation.from, encrypted);
+ if (payload.hasPayload()) {
+ contents = ImmutableList.of(MessageContent.text(payload.payloadAsString(),null));
+ } else {
+ return true;
+ }
+ } catch (final AxolotlDecryptionException e) {
+ LOGGER.error("Could not decrypt message", e);
+ // TODO if message had payload create error message entry
+ return false;
+ }
+ } else {
+ // TODO we need to remove fallbacks for reactions, retractions and potentially other
+ // things
+ contents = parseContent(transformation);
+ }
final boolean identifiableSender =
Arrays.asList(Message.Type.NORMAL, Message.Type.CHAT).contains(messageType)
diff --git a/app/src/main/java/im/conversations/android/xmpp/XmppConnection.java b/app/src/main/java/im/conversations/android/xmpp/XmppConnection.java
index 6a5b74e1c..223c9e4ea 100644
--- a/app/src/main/java/im/conversations/android/xmpp/XmppConnection.java
+++ b/app/src/main/java/im/conversations/android/xmpp/XmppConnection.java
@@ -17,7 +17,6 @@ import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.SettableFuture;
-import im.conversations.android.AbstractAccountService;
import im.conversations.android.BuildConfig;
import im.conversations.android.Conversations;
import im.conversations.android.IDs;
@@ -106,13 +105,16 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmlpull.v1.XmlPullParserException;
-public class XmppConnection extends AbstractAccountService implements Runnable {
+public class XmppConnection implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(XmppConnection.class);
private static final boolean EXTENDED_SM_LOGGING = false;
private static final int CONNECT_DISCO_TIMEOUT = 20;
+ private final Context context;
+ private final Account account;
+
private final SparseArray mStanzaQueue = new SparseArray<>();
private final Hashtable>> packetCallbacks = new Hashtable<>();
private Socket socket;
@@ -155,7 +157,8 @@ public class XmppConnection extends AbstractAccountService implements Runnable {
private CountDownLatch mStreamCountDownLatch;
public XmppConnection(final Context context, final Account account) {
- super(context, account);
+ this.context = context;
+ this.account = account;
this.connectionAddress = account.address;
// these consumers are pure listeners; they don’t have public method except for accept|apply
diff --git a/app/src/main/java/im/conversations/android/xmpp/manager/AxolotlManager.java b/app/src/main/java/im/conversations/android/xmpp/manager/AxolotlManager.java
index 5bfbcbc25..e152673e2 100644
--- a/app/src/main/java/im/conversations/android/xmpp/manager/AxolotlManager.java
+++ b/app/src/main/java/im/conversations/android/xmpp/manager/AxolotlManager.java
@@ -22,6 +22,7 @@ import im.conversations.android.axolotl.AxolotlPayload;
import im.conversations.android.axolotl.AxolotlService;
import im.conversations.android.axolotl.AxolotlSession;
import im.conversations.android.axolotl.EncryptionBuilder;
+import im.conversations.android.database.ConversationsDatabase;
import im.conversations.android.xml.Element;
import im.conversations.android.xml.Namespace;
import im.conversations.android.xmpp.IqErrorException;
@@ -60,7 +61,13 @@ public class AxolotlManager extends AbstractManager {
public AxolotlManager(Context context, XmppConnection connection) {
super(context, connection);
- this.axolotlService = new AxolotlService(context, connection.getAccount());
+ this.axolotlService =
+ new AxolotlService(
+ connection.getAccount(), ConversationsDatabase.getInstance(context));
+ }
+
+ public AxolotlService getAxolotlService() {
+ return this.axolotlService;
}
public void handleItems(final BareJid from, final Items items) {
@@ -286,8 +293,11 @@ public class AxolotlManager extends AbstractManager {
throw new IllegalStateException("No signed PreKeys have been created yet");
}
bundle.setSignedPreKey(
- signedPreKeyRecord.getKeyPair().getPublicKey(), signedPreKeyRecord.getSignature());
- bundle.setPreKeys(getDatabase().axolotlDao().getPreKeys(getAccount().id));
+ signedPreKeyRecord.getId(),
+ signedPreKeyRecord.getKeyPair().getPublicKey(),
+ signedPreKeyRecord.getSignature());
+ bundle.addPreKeys(getDatabase().axolotlDao().getPreKeys(getAccount().id));
+ LOGGER.info("bundle {}", bundle);
return bundle;
}
diff --git a/app/src/main/java/im/conversations/android/xmpp/model/axolotl/Bundle.java b/app/src/main/java/im/conversations/android/xmpp/model/axolotl/Bundle.java
index ce0dd5da7..2321c2e49 100644
--- a/app/src/main/java/im/conversations/android/xmpp/model/axolotl/Bundle.java
+++ b/app/src/main/java/im/conversations/android/xmpp/model/axolotl/Bundle.java
@@ -40,14 +40,16 @@ public class Bundle extends Extension {
identityKey.setContent(ecPublicKey);
}
- public void setSignedPreKey(final ECPublicKey ecPublicKey, final byte[] signature) {
+ public void setSignedPreKey(
+ final int id, final ECPublicKey ecPublicKey, final byte[] signature) {
final var signedPreKey = this.addExtension(new SignedPreKey());
+ signedPreKey.setId(id);
signedPreKey.setContent(ecPublicKey);
final var signedPreKeySignature = this.addExtension(new SignedPreKeySignature());
signedPreKeySignature.setContent(signature);
}
- public void setPreKeys(final List preKeyRecords) {
+ public void addPreKeys(final List preKeyRecords) {
final var preKeys = this.addExtension(new PreKeys());
for (final PreKeyRecord preKeyRecord : preKeyRecords) {
final var preKey = preKeys.addExtension(new PreKey());
diff --git a/app/src/main/java/im/conversations/android/xmpp/model/axolotl/IV.java b/app/src/main/java/im/conversations/android/xmpp/model/axolotl/IV.java
index 93e368a00..22164976a 100644
--- a/app/src/main/java/im/conversations/android/xmpp/model/axolotl/IV.java
+++ b/app/src/main/java/im/conversations/android/xmpp/model/axolotl/IV.java
@@ -4,7 +4,7 @@ import im.conversations.android.annotation.XmlElement;
import im.conversations.android.xmpp.model.ByteContent;
import im.conversations.android.xmpp.model.Extension;
-@XmlElement
+@XmlElement(name = "iv")
public class IV extends Extension implements ByteContent {
public IV() {
diff --git a/app/src/main/java/im/conversations/android/xmpp/model/axolotl/PreKey.java b/app/src/main/java/im/conversations/android/xmpp/model/axolotl/PreKey.java
index b3c0eb35c..a7d39c1da 100644
--- a/app/src/main/java/im/conversations/android/xmpp/model/axolotl/PreKey.java
+++ b/app/src/main/java/im/conversations/android/xmpp/model/axolotl/PreKey.java
@@ -16,6 +16,6 @@ public class PreKey extends Extension implements ECPublicKeyContent {
}
public void setId(int id) {
- this.setAttribute("id", id);
+ this.setAttribute("preKeyId", id);
}
}
diff --git a/app/src/main/java/im/conversations/android/xmpp/model/axolotl/SignedPreKey.java b/app/src/main/java/im/conversations/android/xmpp/model/axolotl/SignedPreKey.java
index 2db2c3e35..0e0ca7282 100644
--- a/app/src/main/java/im/conversations/android/xmpp/model/axolotl/SignedPreKey.java
+++ b/app/src/main/java/im/conversations/android/xmpp/model/axolotl/SignedPreKey.java
@@ -14,4 +14,8 @@ public class SignedPreKey extends Extension implements ECPublicKeyContent {
public int getId() {
return Ints.saturatedCast(this.getLongAttribute("signedPreKeyId"));
}
+
+ public void setId(final int id) {
+ this.setAttribute("signedPreKeyId", id);
+ }
}
diff --git a/app/src/main/java/im/conversations/android/xmpp/model/state/Active.java b/app/src/main/java/im/conversations/android/xmpp/model/state/Active.java
index 8053b014b..15970bc5b 100644
--- a/app/src/main/java/im/conversations/android/xmpp/model/state/Active.java
+++ b/app/src/main/java/im/conversations/android/xmpp/model/state/Active.java
@@ -5,7 +5,7 @@ import im.conversations.android.annotation.XmlElement;
@XmlElement
public class Active extends ChatStateNotification {
- protected Active() {
+ public Active() {
super(Active.class);
}
}
diff --git a/app/src/main/java/im/conversations/android/xmpp/model/state/Composing.java b/app/src/main/java/im/conversations/android/xmpp/model/state/Composing.java
index e85dd9e5b..9871952e0 100644
--- a/app/src/main/java/im/conversations/android/xmpp/model/state/Composing.java
+++ b/app/src/main/java/im/conversations/android/xmpp/model/state/Composing.java
@@ -5,7 +5,7 @@ import im.conversations.android.annotation.XmlElement;
@XmlElement
public class Composing extends ChatStateNotification {
- protected Composing() {
+ public Composing() {
super(Composing.class);
}
}
diff --git a/app/src/main/java/im/conversations/android/xmpp/model/state/Gone.java b/app/src/main/java/im/conversations/android/xmpp/model/state/Gone.java
index 41b5a3fb6..a0a74e788 100644
--- a/app/src/main/java/im/conversations/android/xmpp/model/state/Gone.java
+++ b/app/src/main/java/im/conversations/android/xmpp/model/state/Gone.java
@@ -5,7 +5,7 @@ import im.conversations.android.annotation.XmlElement;
@XmlElement
public class Gone extends ChatStateNotification {
- protected Gone() {
+ public Gone() {
super(Gone.class);
}
}
diff --git a/app/src/main/java/im/conversations/android/xmpp/model/state/Inactive.java b/app/src/main/java/im/conversations/android/xmpp/model/state/Inactive.java
index a20b6f670..4a3670308 100644
--- a/app/src/main/java/im/conversations/android/xmpp/model/state/Inactive.java
+++ b/app/src/main/java/im/conversations/android/xmpp/model/state/Inactive.java
@@ -5,7 +5,7 @@ import im.conversations.android.annotation.XmlElement;
@XmlElement
public class Inactive extends ChatStateNotification {
- protected Inactive() {
+ public Inactive() {
super(Inactive.class);
}
}
diff --git a/app/src/main/java/im/conversations/android/xmpp/processor/MessageProcessor.java b/app/src/main/java/im/conversations/android/xmpp/processor/MessageProcessor.java
index 7e60fd254..eebf86c5b 100644
--- a/app/src/main/java/im/conversations/android/xmpp/processor/MessageProcessor.java
+++ b/app/src/main/java/im/conversations/android/xmpp/processor/MessageProcessor.java
@@ -6,6 +6,7 @@ import im.conversations.android.transformer.TransformationFactory;
import im.conversations.android.transformer.Transformer;
import im.conversations.android.xmpp.XmppConnection;
import im.conversations.android.xmpp.manager.ArchiveManager;
+import im.conversations.android.xmpp.manager.AxolotlManager;
import im.conversations.android.xmpp.manager.CarbonsManager;
import im.conversations.android.xmpp.manager.ChatStateManager;
import im.conversations.android.xmpp.manager.JingleConnectionManager;
@@ -83,7 +84,9 @@ public class MessageProcessor extends XmppConnection.Delegate implements Consume
final boolean sendReceipts;
if (transformation.isAnythingToTransform()) {
final var database = ConversationsDatabase.getInstance(context);
- final var transformer = new Transformer(database, getAccount());
+ final var axolotlService =
+ connection.getManager(AxolotlManager.class).getAxolotlService();
+ final var transformer = new Transformer(getAccount(), database, axolotlService);
sendReceipts = transformer.transform(transformation);
} else {
sendReceipts = true;
@@ -96,8 +99,6 @@ public class MessageProcessor extends XmppConnection.Delegate implements Consume
if (chatState != null) {
getManager(ChatStateManager.class).handle(from, chatState);
}
-
- // TODO pass JMI to JingleManager
}
private boolean isRoot() {