replicate directory updates on GCM/APN token & signed prekey changes

This commit is contained in:
Jeffrey Griffin 2018-12-19 12:08:24 -08:00 committed by Brian Acton
parent 266f1c3a49
commit dbfe4fd5ac
6 changed files with 50 additions and 16 deletions

View File

@ -211,7 +211,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
environment.lifecycle().manage(directoryReconciler); environment.lifecycle().manage(directoryReconciler);
AttachmentController attachmentController = new AttachmentController(rateLimiters, urlSigner); AttachmentController attachmentController = new AttachmentController(rateLimiters, urlSigner);
KeysController keysController = new KeysController(rateLimiters, keys, accountsManager); KeysController keysController = new KeysController(rateLimiters, keys, accountsManager, directoryQueue);
MessageController messageController = new MessageController(rateLimiters, pushSender, receiptSender, accountsManager, messagesManager, apnFallbackManager); MessageController messageController = new MessageController(rateLimiters, pushSender, receiptSender, accountsManager, messagesManager, apnFallbackManager);
ProfileController profileController = new ProfileController(rateLimiters , accountsManager, config.getProfilesConfiguration()); ProfileController profileController = new ProfileController(rateLimiters , accountsManager, config.getProfilesConfiguration());

View File

@ -270,7 +270,8 @@ public class AccountController {
@Path("/gcm/") @Path("/gcm/")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void setGcmRegistrationId(@Auth Account account, @Valid GcmRegistrationId registrationId) { public void setGcmRegistrationId(@Auth Account account, @Valid GcmRegistrationId registrationId) {
Device device = account.getAuthenticatedDevice().get(); Device device = account.getAuthenticatedDevice().get();
boolean wasAccountActive = account.isActive();
if (device.getGcmId() != null && if (device.getGcmId() != null &&
device.getGcmId().equals(registrationId.getGcmRegistrationId())) device.getGcmId().equals(registrationId.getGcmRegistrationId()))
@ -286,6 +287,10 @@ public class AccountController {
else device.setFetchesMessages(false); else device.setFetchesMessages(false);
accounts.update(account); accounts.update(account);
if (!wasAccountActive && account.isActive()) {
directoryQueue.addRegisteredUser(account.getNumber());
}
} }
@Timed @Timed
@ -308,12 +313,18 @@ public class AccountController {
@Path("/apn/") @Path("/apn/")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void setApnRegistrationId(@Auth Account account, @Valid ApnRegistrationId registrationId) { public void setApnRegistrationId(@Auth Account account, @Valid ApnRegistrationId registrationId) {
Device device = account.getAuthenticatedDevice().get(); Device device = account.getAuthenticatedDevice().get();
boolean wasAccountActive = account.isActive();
device.setApnId(registrationId.getApnRegistrationId()); device.setApnId(registrationId.getApnRegistrationId());
device.setVoipApnId(registrationId.getVoipRegistrationId()); device.setVoipApnId(registrationId.getVoipRegistrationId());
device.setGcmId(null); device.setGcmId(null);
device.setFetchesMessages(true); device.setFetchesMessages(true);
accounts.update(account); accounts.update(account);
if (!wasAccountActive && account.isActive()) {
directoryQueue.addRegisteredUser(account.getNumber());
}
} }
@Timed @Timed
@ -413,7 +424,11 @@ public class AccountController {
newUserMeter.mark(); newUserMeter.mark();
} }
directoryQueue.addRegisteredUser(number); if (account.isActive()) {
directoryQueue.addRegisteredUser(number);
} else {
directoryQueue.deleteRegisteredUser(number);
}
messagesManager.clear(number); messagesManager.clear(number);
pendingAccounts.remove(number); pendingAccounts.remove(number);

View File

@ -29,6 +29,7 @@ import org.whispersystems.textsecuregcm.entities.PreKeyResponseItem;
import org.whispersystems.textsecuregcm.entities.PreKeyState; import org.whispersystems.textsecuregcm.entities.PreKeyState;
import org.whispersystems.textsecuregcm.entities.SignedPreKey; import org.whispersystems.textsecuregcm.entities.SignedPreKey;
import org.whispersystems.textsecuregcm.limits.RateLimiters; import org.whispersystems.textsecuregcm.limits.RateLimiters;
import org.whispersystems.textsecuregcm.sqs.DirectoryQueue;
import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.AccountsManager; import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.Device; import org.whispersystems.textsecuregcm.storage.Device;
@ -61,11 +62,13 @@ public class KeysController {
private final RateLimiters rateLimiters; private final RateLimiters rateLimiters;
private final Keys keys; private final Keys keys;
private final AccountsManager accounts; private final AccountsManager accounts;
private final DirectoryQueue directoryQueue;
public KeysController(RateLimiters rateLimiters, Keys keys, AccountsManager accounts) { public KeysController(RateLimiters rateLimiters, Keys keys, AccountsManager accounts, DirectoryQueue directoryQueue) {
this.rateLimiters = rateLimiters; this.rateLimiters = rateLimiters;
this.keys = keys; this.keys = keys;
this.accounts = accounts; this.accounts = accounts;
this.directoryQueue = directoryQueue;
} }
@GET @GET
@ -84,8 +87,9 @@ public class KeysController {
@PUT @PUT
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void setKeys(@Auth Account account, @Valid PreKeyState preKeys) { public void setKeys(@Auth Account account, @Valid PreKeyState preKeys) {
Device device = account.getAuthenticatedDevice().get(); Device device = account.getAuthenticatedDevice().get();
boolean updateAccount = false; boolean wasAccountActive = account.isActive();
boolean updateAccount = false;
if (!preKeys.getSignedPreKey().equals(device.getSignedPreKey())) { if (!preKeys.getSignedPreKey().equals(device.getSignedPreKey())) {
device.setSignedPreKey(preKeys.getSignedPreKey()); device.setSignedPreKey(preKeys.getSignedPreKey());
@ -99,6 +103,10 @@ public class KeysController {
if (updateAccount) { if (updateAccount) {
accounts.update(account); accounts.update(account);
if (!wasAccountActive && account.isActive()) {
directoryQueue.addRegisteredUser(account.getNumber());
}
} }
keys.store(account.getNumber(), device.getId(), preKeys.getPreKeys()); keys.store(account.getNumber(), device.getId(), preKeys.getPreKeys());
@ -158,9 +166,15 @@ public class KeysController {
@Path("/signed") @Path("/signed")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public void setSignedKey(@Auth Account account, @Valid SignedPreKey signedPreKey) { public void setSignedKey(@Auth Account account, @Valid SignedPreKey signedPreKey) {
Device device = account.getAuthenticatedDevice().get(); Device device = account.getAuthenticatedDevice().get();
boolean wasAccountActive = account.isActive();
device.setSignedPreKey(signedPreKey); device.setSignedPreKey(signedPreKey);
accounts.update(account); accounts.update(account);
if (!wasAccountActive && account.isActive()) {
directoryQueue.addRegisteredUser(account.getNumber());
}
} }
@Timed @Timed

View File

@ -10,6 +10,7 @@ import org.whispersystems.textsecuregcm.WhisperServerConfiguration;
import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials; import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials;
import org.whispersystems.textsecuregcm.providers.RedisClientFactory; import org.whispersystems.textsecuregcm.providers.RedisClientFactory;
import org.whispersystems.textsecuregcm.redis.ReplicatedJedisPool; import org.whispersystems.textsecuregcm.redis.ReplicatedJedisPool;
import org.whispersystems.textsecuregcm.sqs.DirectoryQueue;
import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.Accounts; import org.whispersystems.textsecuregcm.storage.Accounts;
import org.whispersystems.textsecuregcm.storage.AccountsManager; import org.whispersystems.textsecuregcm.storage.AccountsManager;
@ -76,6 +77,7 @@ public class DeleteUserCommand extends EnvironmentCommand<WhisperServerConfigura
Accounts accounts = dbi.onDemand(Accounts.class); Accounts accounts = dbi.onDemand(Accounts.class);
ReplicatedJedisPool cacheClient = new RedisClientFactory(configuration.getCacheConfiguration().getUrl(), configuration.getCacheConfiguration().getReplicaUrls()).getRedisClientPool(); ReplicatedJedisPool cacheClient = new RedisClientFactory(configuration.getCacheConfiguration().getUrl(), configuration.getCacheConfiguration().getReplicaUrls()).getRedisClientPool();
ReplicatedJedisPool redisClient = new RedisClientFactory(configuration.getDirectoryConfiguration().getRedisConfiguration().getUrl(), configuration.getDirectoryConfiguration().getRedisConfiguration().getReplicaUrls()).getRedisClientPool(); ReplicatedJedisPool redisClient = new RedisClientFactory(configuration.getDirectoryConfiguration().getRedisConfiguration().getUrl(), configuration.getDirectoryConfiguration().getRedisConfiguration().getReplicaUrls()).getRedisClientPool();
DirectoryQueue directoryQueue = new DirectoryQueue(configuration.getDirectoryConfiguration().getSqsConfiguration());
DirectoryManager directory = new DirectoryManager(redisClient); DirectoryManager directory = new DirectoryManager(redisClient);
AccountsManager accountsManager = new AccountsManager(accounts, directory, cacheClient); AccountsManager accountsManager = new AccountsManager(accounts, directory, cacheClient);
@ -94,6 +96,7 @@ public class DeleteUserCommand extends EnvironmentCommand<WhisperServerConfigura
device.get().setAuthenticationCredentials(new AuthenticationCredentials(Base64.encodeBytes(random))); device.get().setAuthenticationCredentials(new AuthenticationCredentials(Base64.encodeBytes(random)));
accountsManager.update(account.get()); accountsManager.update(account.get());
directoryQueue.deleteRegisteredUser(account.get().getNumber());
logger.warn("Removed " + account.get().getNumber()); logger.warn("Removed " + account.get().getNumber());
} else { } else {

View File

@ -236,7 +236,7 @@ public class AccountControllerTest {
assertThat(response.getStatus()).isEqualTo(204); assertThat(response.getStatus()).isEqualTo(204);
verify(accountsManager, times(1)).create(isA(Account.class)); verify(accountsManager, times(1)).create(isA(Account.class));
verify(directoryQueue, times(1)).addRegisteredUser(eq(SENDER)); verify(directoryQueue, times(1)).deleteRegisteredUser(eq(SENDER));
} }
@Test @Test

View File

@ -14,6 +14,7 @@ import org.whispersystems.textsecuregcm.entities.PreKeyState;
import org.whispersystems.textsecuregcm.entities.SignedPreKey; import org.whispersystems.textsecuregcm.entities.SignedPreKey;
import org.whispersystems.textsecuregcm.limits.RateLimiter; import org.whispersystems.textsecuregcm.limits.RateLimiter;
import org.whispersystems.textsecuregcm.limits.RateLimiters; import org.whispersystems.textsecuregcm.limits.RateLimiters;
import org.whispersystems.textsecuregcm.sqs.DirectoryQueue;
import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.AccountsManager; import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.Device; import org.whispersystems.textsecuregcm.storage.Device;
@ -54,9 +55,10 @@ public class KeyControllerTest {
private final SignedPreKey SAMPLE_SIGNED_KEY2 = new SignedPreKey(2222, "foobar", "sig22"); private final SignedPreKey SAMPLE_SIGNED_KEY2 = new SignedPreKey(2222, "foobar", "sig22");
private final SignedPreKey SAMPLE_SIGNED_KEY3 = new SignedPreKey(3333, "barfoo", "sig33"); private final SignedPreKey SAMPLE_SIGNED_KEY3 = new SignedPreKey(3333, "barfoo", "sig33");
private final Keys keys = mock(Keys.class ); private final Keys keys = mock(Keys.class );
private final AccountsManager accounts = mock(AccountsManager.class); private final AccountsManager accounts = mock(AccountsManager.class);
private final Account existsAccount = mock(Account.class ); private final DirectoryQueue directoryQueue = mock(DirectoryQueue.class);
private final Account existsAccount = mock(Account.class );
private RateLimiters rateLimiters = mock(RateLimiters.class); private RateLimiters rateLimiters = mock(RateLimiters.class);
private RateLimiter rateLimiter = mock(RateLimiter.class ); private RateLimiter rateLimiter = mock(RateLimiter.class );
@ -66,7 +68,7 @@ public class KeyControllerTest {
.addProvider(AuthHelper.getAuthFilter()) .addProvider(AuthHelper.getAuthFilter())
.addProvider(new AuthValueFactoryProvider.Binder<>(Account.class)) .addProvider(new AuthValueFactoryProvider.Binder<>(Account.class))
.setTestContainerFactory(new GrizzlyWebTestContainerFactory()) .setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource(new KeysController(rateLimiters, keys, accounts)) .addResource(new KeysController(rateLimiters, keys, accounts, directoryQueue))
.build(); .build();
@Before @Before