request device list when encountering unknown device
This commit is contained in:
parent
c3f5273813
commit
cf17a2ac6d
|
@ -2,7 +2,7 @@
|
||||||
"formatVersion": 1,
|
"formatVersion": 1,
|
||||||
"database": {
|
"database": {
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"identityHash": "a619bdeae0408fc2250a0bf2b9ab1f4e",
|
"identityHash": "983b8fb918cf0019a31e3a59b37dc368",
|
||||||
"entities": [
|
"entities": [
|
||||||
{
|
{
|
||||||
"tableName": "account",
|
"tableName": "account",
|
||||||
|
@ -362,7 +362,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"tableName": "axolotl_device_list_item",
|
"tableName": "axolotl_device_list_item",
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `deviceListId` INTEGER NOT NULL, `deviceId` INTEGER, FOREIGN KEY(`deviceListId`) REFERENCES `axolotl_device_list`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `deviceListId` INTEGER NOT NULL, `deviceId` INTEGER, `confirmedInPep` INTEGER NOT NULL, FOREIGN KEY(`deviceListId`) REFERENCES `axolotl_device_list`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"fieldPath": "id",
|
"fieldPath": "id",
|
||||||
|
@ -381,6 +381,12 @@
|
||||||
"columnName": "deviceId",
|
"columnName": "deviceId",
|
||||||
"affinity": "INTEGER",
|
"affinity": "INTEGER",
|
||||||
"notNull": false
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "confirmedInPep",
|
||||||
|
"columnName": "confirmedInPep",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"primaryKey": {
|
"primaryKey": {
|
||||||
|
@ -2364,7 +2370,7 @@
|
||||||
"views": [],
|
"views": [],
|
||||||
"setupQueries": [
|
"setupQueries": [
|
||||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'a619bdeae0408fc2250a0bf2b9ab1f4e')"
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '983b8fb918cf0019a31e3a59b37dc368')"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package im.conversations.android.axolotl;
|
package im.conversations.android.axolotl;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
import org.jxmpp.jid.BareJid;
|
import org.jxmpp.jid.BareJid;
|
||||||
import org.whispersystems.libsignal.SignalProtocolAddress;
|
import org.whispersystems.libsignal.SignalProtocolAddress;
|
||||||
|
|
||||||
|
@ -26,4 +27,18 @@ public class AxolotlAddress extends SignalProtocolAddress {
|
||||||
SignalProtocolAddress.class.getSimpleName(),
|
SignalProtocolAddress.class.getSimpleName(),
|
||||||
AxolotlAddress.class.getSimpleName()));
|
AxolotlAddress.class.getSimpleName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
if (!super.equals(o)) return false;
|
||||||
|
AxolotlAddress that = (AxolotlAddress) o;
|
||||||
|
return Objects.equal(jid, that.jid);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(super.hashCode(), jid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,16 +8,19 @@ public class AxolotlPayload {
|
||||||
public final AxolotlAddress axolotlAddress;
|
public final AxolotlAddress axolotlAddress;
|
||||||
public final IdentityKey identityKey;
|
public final IdentityKey identityKey;
|
||||||
public final boolean preKeyMessage;
|
public final boolean preKeyMessage;
|
||||||
|
public final boolean inDeviceList;
|
||||||
public final byte[] payload;
|
public final byte[] payload;
|
||||||
|
|
||||||
public AxolotlPayload(
|
public AxolotlPayload(
|
||||||
AxolotlAddress axolotlAddress,
|
AxolotlAddress axolotlAddress,
|
||||||
final IdentityKey identityKey,
|
final IdentityKey identityKey,
|
||||||
final boolean preKeyMessage,
|
final boolean preKeyMessage,
|
||||||
|
final boolean inDeviceList,
|
||||||
byte[] payload) {
|
byte[] payload) {
|
||||||
this.axolotlAddress = axolotlAddress;
|
this.axolotlAddress = axolotlAddress;
|
||||||
this.identityKey = identityKey;
|
this.identityKey = identityKey;
|
||||||
this.preKeyMessage = preKeyMessage;
|
this.preKeyMessage = preKeyMessage;
|
||||||
|
this.inDeviceList = inDeviceList;
|
||||||
this.payload = payload;
|
this.payload = payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,10 @@ package im.conversations.android.axolotl;
|
||||||
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import com.google.common.base.Optional;
|
import com.google.common.base.Optional;
|
||||||
|
import com.google.common.collect.ArrayListMultimap;
|
||||||
|
import com.google.common.collect.ImmutableMultimap;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
import eu.siacs.conversations.xmpp.jingle.OmemoVerification;
|
import eu.siacs.conversations.xmpp.jingle.OmemoVerification;
|
||||||
import im.conversations.android.AbstractAccountService;
|
import im.conversations.android.AbstractAccountService;
|
||||||
import im.conversations.android.database.AxolotlDatabaseStore;
|
import im.conversations.android.database.AxolotlDatabaseStore;
|
||||||
|
@ -14,6 +18,8 @@ import im.conversations.android.xmpp.model.axolotl.Payload;
|
||||||
import java.security.InvalidAlgorithmParameterException;
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.NoSuchProviderException;
|
import java.security.NoSuchProviderException;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
import javax.crypto.BadPaddingException;
|
import javax.crypto.BadPaddingException;
|
||||||
import javax.crypto.Cipher;
|
import javax.crypto.Cipher;
|
||||||
import javax.crypto.IllegalBlockSizeException;
|
import javax.crypto.IllegalBlockSizeException;
|
||||||
|
@ -21,6 +27,7 @@ import javax.crypto.NoSuchPaddingException;
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
import javax.crypto.spec.IvParameterSpec;
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import org.jxmpp.jid.BareJid;
|
||||||
import org.jxmpp.jid.Jid;
|
import org.jxmpp.jid.Jid;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -49,12 +56,21 @@ public class AxolotlService extends AbstractAccountService {
|
||||||
|
|
||||||
private final SignalProtocolStore signalProtocolStore;
|
private final SignalProtocolStore signalProtocolStore;
|
||||||
|
|
||||||
|
private PostDecryptionHook postDecryptionHook;
|
||||||
|
|
||||||
|
private final Set<AxolotlAddress> freshSessions = new HashSet<>();
|
||||||
|
private final Multimap<BareJid, Integer> devicesNotInPep = ArrayListMultimap.create();
|
||||||
|
|
||||||
public AxolotlService(
|
public AxolotlService(
|
||||||
final Account account, final ConversationsDatabase conversationsDatabase) {
|
final Account account, final ConversationsDatabase conversationsDatabase) {
|
||||||
super(account, conversationsDatabase);
|
super(account, conversationsDatabase);
|
||||||
this.signalProtocolStore = new AxolotlDatabaseStore(account, conversationsDatabase);
|
this.signalProtocolStore = new AxolotlDatabaseStore(account, conversationsDatabase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPostDecryptionHook(final PostDecryptionHook postDecryptionHook) {
|
||||||
|
this.postDecryptionHook = postDecryptionHook;
|
||||||
|
}
|
||||||
|
|
||||||
private AxolotlSession buildReceivingSession(
|
private AxolotlSession buildReceivingSession(
|
||||||
final Jid from, final IdentityKey identityKey, final Header header) {
|
final Jid from, final IdentityKey identityKey, final Header header) {
|
||||||
final Optional<Integer> sid = header.getSourceDevice();
|
final Optional<Integer> sid = header.getSourceDevice();
|
||||||
|
@ -88,8 +104,9 @@ public class AxolotlService extends AbstractAccountService {
|
||||||
|
|
||||||
public AxolotlPayload decrypt(final Jid from, final Encrypted encrypted)
|
public AxolotlPayload decrypt(final Jid from, final Encrypted encrypted)
|
||||||
throws AxolotlDecryptionException {
|
throws AxolotlDecryptionException {
|
||||||
|
final AxolotlPayload axolotlPayload;
|
||||||
try {
|
try {
|
||||||
return decryptOrThrow(from, encrypted);
|
axolotlPayload = decryptOrThrow(from, encrypted);
|
||||||
} catch (final IllegalArgumentException
|
} catch (final IllegalArgumentException
|
||||||
| NotEncryptedForThisDeviceException
|
| NotEncryptedForThisDeviceException
|
||||||
| InvalidMessageException
|
| InvalidMessageException
|
||||||
|
@ -110,6 +127,8 @@ public class AxolotlService extends AbstractAccountService {
|
||||||
| BadPaddingException e) {
|
| BadPaddingException e) {
|
||||||
throw new AxolotlDecryptionException(e);
|
throw new AxolotlDecryptionException(e);
|
||||||
}
|
}
|
||||||
|
registerForHook(axolotlPayload);
|
||||||
|
return axolotlPayload;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AxolotlPayload decryptOrThrow(final Jid from, final Encrypted encrypted)
|
private AxolotlPayload decryptOrThrow(final Jid from, final Encrypted encrypted)
|
||||||
|
@ -151,9 +170,10 @@ public class AxolotlService extends AbstractAccountService {
|
||||||
throw new OutdatedSenderException(
|
throw new OutdatedSenderException(
|
||||||
"Key did not contain auth tag. Sender needs to update their OMEMO client");
|
"Key did not contain auth tag. Sender needs to update their OMEMO client");
|
||||||
}
|
}
|
||||||
|
final var inDeviceList = database.axolotlDao().hasDeviceId(account, session.axolotlAddress);
|
||||||
if (payload == null) {
|
if (payload == null) {
|
||||||
return new AxolotlPayload(
|
return new AxolotlPayload(
|
||||||
session.axolotlAddress, session.identityKey, preKeyMessage, null);
|
session.axolotlAddress, session.identityKey, preKeyMessage, inDeviceList, null);
|
||||||
}
|
}
|
||||||
final byte[] key = new byte[16];
|
final byte[] key = new byte[16];
|
||||||
final byte[] authTag = new byte[16];
|
final byte[] authTag = new byte[16];
|
||||||
|
@ -175,7 +195,44 @@ public class AxolotlService extends AbstractAccountService {
|
||||||
System.arraycopy(authTag, 0, payloadWithAuthTag, payloadAsBytes.length, authTag.length);
|
System.arraycopy(authTag, 0, payloadWithAuthTag, payloadAsBytes.length, authTag.length);
|
||||||
final byte[] decryptedPayload = cipher.doFinal(payloadWithAuthTag);
|
final byte[] decryptedPayload = cipher.doFinal(payloadWithAuthTag);
|
||||||
return new AxolotlPayload(
|
return new AxolotlPayload(
|
||||||
session.axolotlAddress, session.identityKey, preKeyMessage, decryptedPayload);
|
session.axolotlAddress,
|
||||||
|
session.identityKey,
|
||||||
|
preKeyMessage,
|
||||||
|
inDeviceList,
|
||||||
|
decryptedPayload);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerForHook(final AxolotlPayload axolotlPayload) {
|
||||||
|
synchronized (this.freshSessions) {
|
||||||
|
if (axolotlPayload.preKeyMessage) {
|
||||||
|
this.freshSessions.add(axolotlPayload.axolotlAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
synchronized (this.devicesNotInPep) {
|
||||||
|
if (!axolotlPayload.inDeviceList) {
|
||||||
|
this.devicesNotInPep.put(
|
||||||
|
axolotlPayload.axolotlAddress.getJid(),
|
||||||
|
axolotlPayload.axolotlAddress.getDeviceId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void executePostDecryptionHook() {
|
||||||
|
final var hook = this.postDecryptionHook;
|
||||||
|
if (hook == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final Set<AxolotlAddress> freshSessions;
|
||||||
|
synchronized (this.freshSessions) {
|
||||||
|
freshSessions = ImmutableSet.copyOf(this.freshSessions);
|
||||||
|
this.freshSessions.clear();
|
||||||
|
}
|
||||||
|
final Multimap<BareJid, Integer> devicesNotInPep;
|
||||||
|
synchronized (this.devicesNotInPep) {
|
||||||
|
devicesNotInPep = ImmutableMultimap.copyOf(this.devicesNotInPep);
|
||||||
|
}
|
||||||
|
hook.executeHook(freshSessions);
|
||||||
|
hook.executeHook(devicesNotInPep);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SignalProtocolStore getSignalProtocolStore() {
|
public SignalProtocolStore getSignalProtocolStore() {
|
||||||
|
@ -212,4 +269,10 @@ public class AxolotlService extends AbstractAccountService {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface PostDecryptionHook {
|
||||||
|
void executeHook(final Set<AxolotlAddress> freshSessions);
|
||||||
|
|
||||||
|
void executeHook(final Multimap<BareJid, Integer> devicesNotInPep);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import androidx.room.OnConflictStrategy;
|
||||||
import androidx.room.Query;
|
import androidx.room.Query;
|
||||||
import androidx.room.Transaction;
|
import androidx.room.Transaction;
|
||||||
import com.google.common.collect.Collections2;
|
import com.google.common.collect.Collections2;
|
||||||
|
import im.conversations.android.axolotl.AxolotlAddress;
|
||||||
import im.conversations.android.database.entity.AxolotlDeviceListEntity;
|
import im.conversations.android.database.entity.AxolotlDeviceListEntity;
|
||||||
import im.conversations.android.database.entity.AxolotlDeviceListItemEntity;
|
import im.conversations.android.database.entity.AxolotlDeviceListItemEntity;
|
||||||
import im.conversations.android.database.entity.AxolotlIdentityEntity;
|
import im.conversations.android.database.entity.AxolotlIdentityEntity;
|
||||||
|
@ -35,14 +36,34 @@ public abstract class AxolotlDao {
|
||||||
@Insert
|
@Insert
|
||||||
protected abstract void insert(Collection<AxolotlDeviceListItemEntity> entities);
|
protected abstract void insert(Collection<AxolotlDeviceListItemEntity> entities);
|
||||||
|
|
||||||
|
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||||
|
protected abstract void insertUnconfirmed(Collection<AxolotlDeviceListItemEntity> entities);
|
||||||
|
|
||||||
@Transaction
|
@Transaction
|
||||||
public void setDeviceList(Account account, BareJid from, Set<Integer> deviceIds) {
|
public void setDeviceList(Account account, BareJid from, Set<Integer> deviceIds) {
|
||||||
final var listId = insert(AxolotlDeviceListEntity.of(account.id, from));
|
final var listId = insert(AxolotlDeviceListEntity.of(account.id, from));
|
||||||
insert(
|
insert(
|
||||||
Collections2.transform(
|
Collections2.transform(
|
||||||
deviceIds, deviceId -> AxolotlDeviceListItemEntity.of(listId, deviceId)));
|
deviceIds,
|
||||||
|
deviceId -> AxolotlDeviceListItemEntity.of(listId, deviceId, true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
public void setUnconfirmedDevices(
|
||||||
|
final Account account, final BareJid address, Set<Integer> unconfirmedDeviceIds) {
|
||||||
|
final Long listId = getDeviceListId(account.id, address);
|
||||||
|
if (listId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
insertUnconfirmed(
|
||||||
|
Collections2.transform(
|
||||||
|
unconfirmedDeviceIds,
|
||||||
|
deviceId -> AxolotlDeviceListItemEntity.of(listId, deviceId, false)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Query("SELECT id FROM axolotl_device_list WHERE accountId=:account AND address=:address")
|
||||||
|
abstract Long getDeviceListId(long account, final BareJid address);
|
||||||
|
|
||||||
@Query(
|
@Query(
|
||||||
"SELECT EXISTS(SELECT deviceId FROM axolotl_device_list JOIN axolotl_device_list_item"
|
"SELECT EXISTS(SELECT deviceId FROM axolotl_device_list JOIN axolotl_device_list_item"
|
||||||
+ " ON axolotl_device_list.id=axolotl_device_list_item.deviceListId WHERE"
|
+ " ON axolotl_device_list.id=axolotl_device_list_item.deviceListId WHERE"
|
||||||
|
@ -50,6 +71,10 @@ public abstract class AxolotlDao {
|
||||||
public abstract boolean hasDeviceId(
|
public abstract boolean hasDeviceId(
|
||||||
final long account, final BareJid address, final int deviceId);
|
final long account, final BareJid address, final int deviceId);
|
||||||
|
|
||||||
|
public boolean hasDeviceId(final Account account, final AxolotlAddress axolotlAddress) {
|
||||||
|
return hasDeviceId(account.id, axolotlAddress.getJid(), axolotlAddress.getDeviceId());
|
||||||
|
}
|
||||||
|
|
||||||
@Transaction
|
@Transaction
|
||||||
public void setDeviceListError(
|
public void setDeviceListError(
|
||||||
final Account account, final BareJid address, Condition condition) {
|
final Account account, final BareJid address, Condition condition) {
|
||||||
|
|
|
@ -29,10 +29,14 @@ public class AxolotlDeviceListItemEntity {
|
||||||
|
|
||||||
public Integer deviceId;
|
public Integer deviceId;
|
||||||
|
|
||||||
public static AxolotlDeviceListItemEntity of(final long deviceListId, final int deviceId) {
|
public boolean confirmedInPep;
|
||||||
|
|
||||||
|
public static AxolotlDeviceListItemEntity of(
|
||||||
|
final long deviceListId, final int deviceId, final boolean confirmedInPep) {
|
||||||
final var entity = new AxolotlDeviceListItemEntity();
|
final var entity = new AxolotlDeviceListItemEntity();
|
||||||
entity.deviceListId = deviceListId;
|
entity.deviceListId = deviceListId;
|
||||||
entity.deviceId = deviceId;
|
entity.deviceId = deviceId;
|
||||||
|
entity.confirmedInPep = confirmedInPep;
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,12 @@ public class Transformer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean transform(final MessageTransformation transformation) {
|
public boolean transform(final MessageTransformation transformation) {
|
||||||
return database.runInTransaction(() -> transform(database, transformation));
|
return database.runInTransaction(
|
||||||
|
() -> {
|
||||||
|
final var sendDeliveryReceipts = transform(database, transformation);
|
||||||
|
axolotlService.executePostDecryptionHook();
|
||||||
|
return sendDeliveryReceipts;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,9 +2,12 @@ package im.conversations.android.xmpp.manager;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import com.google.common.base.Function;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
import com.google.common.util.concurrent.FutureCallback;
|
import com.google.common.util.concurrent.FutureCallback;
|
||||||
import com.google.common.util.concurrent.Futures;
|
import com.google.common.util.concurrent.Futures;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
@ -51,7 +54,7 @@ import org.whispersystems.libsignal.state.SignalProtocolStore;
|
||||||
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
|
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
|
||||||
import org.whispersystems.libsignal.util.KeyHelper;
|
import org.whispersystems.libsignal.util.KeyHelper;
|
||||||
|
|
||||||
public class AxolotlManager extends AbstractManager {
|
public class AxolotlManager extends AbstractManager implements AxolotlService.PostDecryptionHook {
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(AxolotlManager.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(AxolotlManager.class);
|
||||||
|
|
||||||
|
@ -64,6 +67,7 @@ public class AxolotlManager extends AbstractManager {
|
||||||
this.axolotlService =
|
this.axolotlService =
|
||||||
new AxolotlService(
|
new AxolotlService(
|
||||||
connection.getAccount(), ConversationsDatabase.getInstance(context));
|
connection.getAccount(), ConversationsDatabase.getInstance(context));
|
||||||
|
this.axolotlService.setPostDecryptionHook(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AxolotlService getAxolotlService() {
|
public AxolotlService getAxolotlService() {
|
||||||
|
@ -301,7 +305,6 @@ public class AxolotlManager extends AbstractManager {
|
||||||
signedPreKeyRecord.getKeyPair().getPublicKey(),
|
signedPreKeyRecord.getKeyPair().getPublicKey(),
|
||||||
signedPreKeyRecord.getSignature());
|
signedPreKeyRecord.getSignature());
|
||||||
bundle.addPreKeys(getDatabase().axolotlDao().getPreKeys(getAccount().id));
|
bundle.addPreKeys(getDatabase().axolotlDao().getPreKeys(getAccount().id));
|
||||||
LOGGER.info("bundle {}", bundle);
|
|
||||||
return bundle;
|
return bundle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -492,4 +495,63 @@ public class AxolotlManager extends AbstractManager {
|
||||||
private SignalProtocolStore signalProtocolStore() {
|
private SignalProtocolStore signalProtocolStore() {
|
||||||
return this.axolotlService.getSignalProtocolStore();
|
return this.axolotlService.getSignalProtocolStore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void executeHook(final Set<AxolotlAddress> freshSessions) {
|
||||||
|
for (final AxolotlAddress axolotlAddress : freshSessions) {
|
||||||
|
LOGGER.info(
|
||||||
|
"fresh session from {}/{}",
|
||||||
|
axolotlAddress.getJid(),
|
||||||
|
axolotlAddress.getDeviceId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void executeHook(Multimap<BareJid, Integer> devicesNotInPep) {
|
||||||
|
for (final Map.Entry<BareJid, Collection<Integer>> entries :
|
||||||
|
devicesNotInPep.asMap().entrySet()) {
|
||||||
|
if (entries.getValue().isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Warning. This will leak our resource to anyone who knows our jid + device id
|
||||||
|
// TODO we could limit this to addresses in our roster; however the point of this
|
||||||
|
// exercise is mostly to improve reliability with people not in our roster
|
||||||
|
confirmDeviceInPep(entries.getKey(), ImmutableSet.copyOf(entries.getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void confirmDeviceInPep(final BareJid address, final Set<Integer> devices) {
|
||||||
|
final var deviceListFuture = this.fetchDeviceIds(address);
|
||||||
|
final var caughtDeviceListFuture =
|
||||||
|
Futures.catching(
|
||||||
|
deviceListFuture,
|
||||||
|
Exception.class,
|
||||||
|
(Function<Exception, Set<Integer>>) input -> Collections.emptySet(),
|
||||||
|
MoreExecutors.directExecutor());
|
||||||
|
Futures.addCallback(
|
||||||
|
caughtDeviceListFuture,
|
||||||
|
new FutureCallback<>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(final Set<Integer> devicesInPep) {
|
||||||
|
final Set<Integer> unconfirmedDevices =
|
||||||
|
Sets.difference(devices, devicesInPep);
|
||||||
|
if (unconfirmedDevices.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LOGGER.info(
|
||||||
|
"Found unconfirmed devices for {}: {}",
|
||||||
|
address,
|
||||||
|
unconfirmedDevices);
|
||||||
|
getDatabase()
|
||||||
|
.axolotlDao()
|
||||||
|
.setUnconfirmedDevices(getAccount(), address, unconfirmedDevices);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(@NonNull Throwable throwable) {
|
||||||
|
LOGGER.error("Could not confirm device list for {}", address, throwable);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getDatabase().getQueryExecutor());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ public class MessageProcessor extends XmppConnection.Delegate implements Consume
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGGER.info(
|
LOGGER.debug(
|
||||||
"Message from {} with {} in level {}",
|
"Message from {} with {} in level {}",
|
||||||
message.getFrom(),
|
message.getFrom(),
|
||||||
message.getExtensionIds(),
|
message.getExtensionIds(),
|
||||||
|
|
Loading…
Reference in a new issue