Displace client presence when existing account reregisters

This commit is contained in:
Katherine Yen 2023-05-05 11:31:18 -07:00 committed by GitHub
parent f6c4ba898b
commit c309afc04b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 18 additions and 2 deletions

View File

@ -33,11 +33,14 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.LongStream;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.redis.ClusterLuaScript; import org.whispersystems.textsecuregcm.redis.ClusterLuaScript;
import org.whispersystems.textsecuregcm.redis.FaultTolerantPubSubConnection; import org.whispersystems.textsecuregcm.redis.FaultTolerantPubSubConnection;
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster; import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster;
import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.util.Constants; import org.whispersystems.textsecuregcm.util.Constants;
/** /**
@ -198,6 +201,10 @@ public class ClientPresenceManager extends RedisClusterPubSubAdapter<String, Str
}); });
} }
public void disconnectAllPresencesForUuid(final UUID accountUuid) {
disconnectAllPresences(accountUuid, Device.ALL_POSSIBLE_DEVICE_IDS);
}
public void disconnectPresence(final UUID accountUuid, final long deviceId) { public void disconnectPresence(final UUID accountUuid, final long deviceId) {
disconnectAllPresences(accountUuid, List.of(deviceId)); disconnectAllPresences(accountUuid, List.of(deviceId));
} }

View File

@ -219,6 +219,7 @@ public class AccountsManager {
keys.delete(actualUuid); keys.delete(actualUuid);
keys.delete(account.getPhoneNumberIdentifier()); keys.delete(account.getPhoneNumberIdentifier());
profilesManager.deleteAll(actualUuid); profilesManager.deleteAll(actualUuid);
clientPresenceManager.disconnectAllPresencesForUuid(actualUuid);
} }
final Tags tags; final Tags tags;

View File

@ -6,8 +6,11 @@ package org.whispersystems.textsecuregcm.storage;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
import java.util.OptionalInt; import java.util.OptionalInt;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.LongStream;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.whispersystems.textsecuregcm.auth.SaltedTokenHash; import org.whispersystems.textsecuregcm.auth.SaltedTokenHash;
import org.whispersystems.textsecuregcm.entities.SignedPreKey; import org.whispersystems.textsecuregcm.entities.SignedPreKey;
@ -16,6 +19,8 @@ import org.whispersystems.textsecuregcm.util.Util;
public class Device { public class Device {
public static final long MASTER_ID = 1; public static final long MASTER_ID = 1;
public static final int MAXIMUM_DEVICE_ID = 256;
public static final List<Long> ALL_POSSIBLE_DEVICE_IDS = LongStream.range(1, MAXIMUM_DEVICE_ID).boxed().collect(Collectors.toList());
@JsonProperty @JsonProperty
private long id; private long id;

View File

@ -332,7 +332,7 @@ public class MessagesCache extends RedisClusterPubSubAdapter<String, String> imp
public void clear(final UUID destinationUuid) { public void clear(final UUID destinationUuid) {
// TODO Remove null check in a fully UUID-based world // TODO Remove null check in a fully UUID-based world
if (destinationUuid != null) { if (destinationUuid != null) {
for (int i = 1; i < 256; i++) { for (int i = 1; i < Device.MAXIMUM_DEVICE_ID; i++) {
clear(destinationUuid, i); clear(destinationUuid, i);
} }
} }

View File

@ -73,6 +73,7 @@ class AccountsManagerTest {
private Keys keys; private Keys keys;
private MessagesManager messagesManager; private MessagesManager messagesManager;
private ProfilesManager profilesManager; private ProfilesManager profilesManager;
private ClientPresenceManager clientPresenceManager;
private ExperimentEnrollmentManager enrollmentManager; private ExperimentEnrollmentManager enrollmentManager;
private Map<String, UUID> phoneNumberIdentifiersByE164; private Map<String, UUID> phoneNumberIdentifiersByE164;
@ -95,6 +96,7 @@ class AccountsManagerTest {
keys = mock(Keys.class); keys = mock(Keys.class);
messagesManager = mock(MessagesManager.class); messagesManager = mock(MessagesManager.class);
profilesManager = mock(ProfilesManager.class); profilesManager = mock(ProfilesManager.class);
clientPresenceManager = mock(ClientPresenceManager.class);
//noinspection unchecked //noinspection unchecked
commands = mock(RedisAdvancedClusterCommands.class); commands = mock(RedisAdvancedClusterCommands.class);
@ -155,7 +157,7 @@ class AccountsManagerTest {
storageClient, storageClient,
backupClient, backupClient,
svr2Client, svr2Client,
mock(ClientPresenceManager.class), clientPresenceManager,
enrollmentManager, enrollmentManager,
mock(RegistrationRecoveryPasswordsManager.class), mock(RegistrationRecoveryPasswordsManager.class),
mock(Clock.class)); mock(Clock.class));
@ -560,6 +562,7 @@ class AccountsManagerTest {
verify(keys).delete(phoneNumberIdentifiersByE164.get(e164)); verify(keys).delete(phoneNumberIdentifiersByE164.get(e164));
verify(messagesManager).clear(existingUuid); verify(messagesManager).clear(existingUuid);
verify(profilesManager).deleteAll(existingUuid); verify(profilesManager).deleteAll(existingUuid);
verify(clientPresenceManager).disconnectAllPresencesForUuid(existingUuid);
} }
@Test @Test