Archive old sessions when an identity key has changed

This commit is contained in:
AsamK 2022-01-22 13:21:56 +01:00
parent 7d935749aa
commit a3c5cfd2f4
4 changed files with 34 additions and 18 deletions

View file

@ -86,6 +86,8 @@ import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
public class ManagerImpl implements Manager { public class ManagerImpl implements Manager {
private final static Logger logger = LoggerFactory.getLogger(ManagerImpl.class); private final static Logger logger = LoggerFactory.getLogger(ManagerImpl.class);
@ -101,6 +103,7 @@ public class ManagerImpl implements Manager {
private final Set<ReceiveMessageHandler> weakHandlers = new HashSet<>(); private final Set<ReceiveMessageHandler> weakHandlers = new HashSet<>();
private final Set<ReceiveMessageHandler> messageHandlers = new HashSet<>(); private final Set<ReceiveMessageHandler> messageHandlers = new HashSet<>();
private final List<Runnable> closedListeners = new ArrayList<>(); private final List<Runnable> closedListeners = new ArrayList<>();
private final CompositeDisposable disposable = new CompositeDisposable();
ManagerImpl( ManagerImpl(
SignalAccount account, SignalAccount account,
@ -141,6 +144,20 @@ public class ManagerImpl implements Manager {
this.notifyAll(); this.notifyAll();
} }
}); });
disposable.add(account.getIdentityKeyStore().getIdentityChanges().subscribe(recipientId -> {
logger.trace("Archiving old sessions");
account.getSessionStore().archiveSessions(recipientId);
account.getSenderKeyStore().deleteSharedWith(recipientId);
final var profile = account.getRecipientStore().getProfile(recipientId);
if (profile != null) {
account.getRecipientStore()
.storeProfile(recipientId,
Profile.newBuilder(profile)
.withUnidentifiedAccessMode(Profile.UnidentifiedAccessMode.UNKNOWN)
.withLastUpdateTimestamp(0)
.build());
}
}));
} }
@Override @Override
@ -982,6 +999,7 @@ public class ManagerImpl implements Manager {
executor.shutdown(); executor.shutdown();
dependencies.getSignalWebSocket().disconnect(); dependencies.getSignalWebSocket().disconnect();
disposable.dispose();
synchronized (closedListeners) { synchronized (closedListeners) {
closedListeners.forEach(Runnable::run); closedListeners.forEach(Runnable::run);

View file

@ -110,11 +110,7 @@ public class IdentityHelper {
) { ) {
final var identityKey = identityFailure.getIdentityKey(); final var identityKey = identityFailure.getIdentityKey();
if (identityKey != null) { if (identityKey != null) {
final var newIdentity = account.getIdentityKeyStore().saveIdentity(recipientId, identityKey, new Date()); account.getIdentityKeyStore().saveIdentity(recipientId, identityKey, new Date());
if (newIdentity) {
account.getSessionStore().archiveSessions(recipientId);
account.getSenderKeyStore().deleteSharedWith(recipientId);
}
} else { } else {
// Retrieve profile to get the current identity key from the server // Retrieve profile to get the current identity key from the server
context.getProfileHelper().refreshRecipientProfile(recipientId); context.getProfileHelper().refreshRecipientProfile(recipientId);

View file

@ -279,25 +279,18 @@ public final class ProfileHelper {
.build(); .build();
} }
logger.trace("Storing profile");
account.getProfileStore().storeProfile(recipientId, newProfile);
try { try {
logger.trace("Storing identity"); logger.trace("Storing identity");
var newIdentity = account.getIdentityKeyStore() final var identityKey = new IdentityKey(Base64.getDecoder().decode(encryptedProfile.getIdentityKey()));
.saveIdentity(recipientId, account.getIdentityKeyStore().saveIdentity(recipientId, identityKey, new Date());
new IdentityKey(Base64.getDecoder().decode(encryptedProfile.getIdentityKey())),
new Date());
if (newIdentity) {
logger.trace("Archiving old sessions");
account.getSessionStore().archiveSessions(recipientId);
account.getSenderKeyStore().deleteSharedWith(recipientId);
}
} catch (InvalidKeyException ignored) { } catch (InvalidKeyException ignored) {
logger.warn("Got invalid identity key in profile for {}", logger.warn("Got invalid identity key in profile for {}",
context.getRecipientHelper().resolveSignalServiceAddress(recipientId).getIdentifier()); context.getRecipientHelper().resolveSignalServiceAddress(recipientId).getIdentifier());
} }
logger.trace("Storing profile");
account.getProfileStore().storeProfile(recipientId, newProfile);
logger.trace("Done handling retrieved profile"); logger.trace("Done handling retrieved profile");
}).doOnError(e -> { }).doOnError(e -> {
logger.warn("Failed to retrieve profile, ignoring: {}", e.getMessage()); logger.warn("Failed to retrieve profile, ignoring: {}", e.getMessage());

View file

@ -29,6 +29,9 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import io.reactivex.rxjava3.subjects.PublishSubject;
import io.reactivex.rxjava3.subjects.Subject;
public class IdentityKeyStore implements org.whispersystems.libsignal.state.IdentityKeyStore { public class IdentityKeyStore implements org.whispersystems.libsignal.state.IdentityKeyStore {
private final static Logger logger = LoggerFactory.getLogger(IdentityKeyStore.class); private final static Logger logger = LoggerFactory.getLogger(IdentityKeyStore.class);
@ -42,6 +45,7 @@ public class IdentityKeyStore implements org.whispersystems.libsignal.state.Iden
private final IdentityKeyPair identityKeyPair; private final IdentityKeyPair identityKeyPair;
private final int localRegistrationId; private final int localRegistrationId;
private final TrustNewIdentity trustNewIdentity; private final TrustNewIdentity trustNewIdentity;
private final PublishSubject<RecipientId> identityChanges = PublishSubject.create();
private boolean isRetryingDecryption = false; private boolean isRetryingDecryption = false;
@ -59,6 +63,10 @@ public class IdentityKeyStore implements org.whispersystems.libsignal.state.Iden
this.trustNewIdentity = trustNewIdentity; this.trustNewIdentity = trustNewIdentity;
} }
public Subject<RecipientId> getIdentityChanges() {
return identityChanges;
}
@Override @Override
public IdentityKeyPair getIdentityKeyPair() { public IdentityKeyPair getIdentityKeyPair() {
return identityKeyPair; return identityKeyPair;
@ -94,6 +102,7 @@ public class IdentityKeyStore implements org.whispersystems.libsignal.state.Iden
logger.debug("Storing new identity for recipient {} with trust {}", recipientId, trustLevel); logger.debug("Storing new identity for recipient {} with trust {}", recipientId, trustLevel);
final var newIdentityInfo = new IdentityInfo(recipientId, identityKey, trustLevel, added); final var newIdentityInfo = new IdentityInfo(recipientId, identityKey, trustLevel, added);
storeIdentityLocked(recipientId, newIdentityInfo); storeIdentityLocked(recipientId, newIdentityInfo);
identityChanges.onNext(recipientId);
return true; return true;
} }
} }