Add unlink user command
This commit is contained in:
parent
c14ef7e6cf
commit
fbdcb942e8
|
@ -0,0 +1,202 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2023 Signal Messenger, LLC
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.whispersystems.textsecuregcm.workers;
|
||||||
|
|
||||||
|
import static com.codahale.metrics.MetricRegistry.name;
|
||||||
|
|
||||||
|
import com.amazonaws.ClientConfiguration;
|
||||||
|
import com.amazonaws.auth.InstanceProfileCredentialsProvider;
|
||||||
|
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
|
||||||
|
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
|
import io.dropwizard.setup.Environment;
|
||||||
|
import io.lettuce.core.resource.ClientResources;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.time.Clock;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import org.whispersystems.textsecuregcm.WhisperServerConfiguration;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
||||||
|
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
||||||
|
import org.whispersystems.textsecuregcm.controllers.SecureBackupController;
|
||||||
|
import org.whispersystems.textsecuregcm.controllers.SecureStorageController;
|
||||||
|
import org.whispersystems.textsecuregcm.experiment.ExperimentEnrollmentManager;
|
||||||
|
import org.whispersystems.textsecuregcm.push.ClientPresenceManager;
|
||||||
|
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster;
|
||||||
|
import org.whispersystems.textsecuregcm.securebackup.SecureBackupClient;
|
||||||
|
import org.whispersystems.textsecuregcm.securestorage.SecureStorageClient;
|
||||||
|
import org.whispersystems.textsecuregcm.sqs.DirectoryQueue;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.Accounts;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.DeletedAccounts;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.DeletedAccountsManager;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.Keys;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.MessagesCache;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.MessagesDynamoDb;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.MessagesManager;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.PhoneNumberIdentifiers;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.Profiles;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.ProfilesManager;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.RegistrationRecoveryPasswords;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.RegistrationRecoveryPasswordsManager;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.ReportMessageDynamoDb;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.ReportMessageManager;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.StoredVerificationCodeManager;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.VerificationCodeStore;
|
||||||
|
import org.whispersystems.textsecuregcm.util.DynamoDbFromConfig;
|
||||||
|
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
|
||||||
|
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct utilities commonly used by worker commands
|
||||||
|
*/
|
||||||
|
record CommandDependencies(
|
||||||
|
AccountsManager accountsManager,
|
||||||
|
ProfilesManager profilesManager,
|
||||||
|
ReportMessageManager reportMessageManager,
|
||||||
|
MessagesManager messagesManager,
|
||||||
|
DeletedAccountsManager deletedAccountsManager,
|
||||||
|
StoredVerificationCodeManager pendingAccountsManager,
|
||||||
|
ClientPresenceManager clientPresenceManager,
|
||||||
|
Keys keys) {
|
||||||
|
|
||||||
|
static CommandDependencies build(
|
||||||
|
final String name,
|
||||||
|
final Environment environment,
|
||||||
|
final WhisperServerConfiguration configuration) throws IOException, CertificateException {
|
||||||
|
Clock clock = Clock.systemUTC();
|
||||||
|
|
||||||
|
environment.getObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
|
|
||||||
|
ClientResources redisClusterClientResources = ClientResources.builder().build();
|
||||||
|
|
||||||
|
FaultTolerantRedisCluster cacheCluster = new FaultTolerantRedisCluster("main_cache_cluster",
|
||||||
|
configuration.getCacheClusterConfiguration(), redisClusterClientResources);
|
||||||
|
|
||||||
|
ExecutorService keyspaceNotificationDispatchExecutor = environment.lifecycle()
|
||||||
|
.executorService(name(name, "keyspaceNotification-%d")).maxThreads(4).build();
|
||||||
|
ExecutorService messageDeletionExecutor = environment.lifecycle()
|
||||||
|
.executorService(name(name, "messageDeletion-%d")).maxThreads(4).build();
|
||||||
|
ExecutorService backupServiceExecutor = environment.lifecycle()
|
||||||
|
.executorService(name(name, "backupService-%d")).maxThreads(8).minThreads(1).build();
|
||||||
|
ExecutorService storageServiceExecutor = environment.lifecycle()
|
||||||
|
.executorService(name(name, "storageService-%d")).maxThreads(8).minThreads(1).build();
|
||||||
|
|
||||||
|
ExternalServiceCredentialsGenerator backupCredentialsGenerator = SecureBackupController.credentialsGenerator(
|
||||||
|
configuration.getSecureBackupServiceConfiguration());
|
||||||
|
ExternalServiceCredentialsGenerator storageCredentialsGenerator = SecureStorageController.credentialsGenerator(
|
||||||
|
configuration.getSecureStorageServiceConfiguration());
|
||||||
|
|
||||||
|
DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager = new DynamicConfigurationManager<>(
|
||||||
|
configuration.getAppConfig().getApplication(), configuration.getAppConfig().getEnvironment(),
|
||||||
|
configuration.getAppConfig().getConfigurationName(), DynamicConfiguration.class);
|
||||||
|
dynamicConfigurationManager.start();
|
||||||
|
|
||||||
|
ExperimentEnrollmentManager experimentEnrollmentManager = new ExperimentEnrollmentManager(
|
||||||
|
dynamicConfigurationManager);
|
||||||
|
|
||||||
|
DynamoDbAsyncClient dynamoDbAsyncClient = DynamoDbFromConfig.asyncClient(
|
||||||
|
configuration.getDynamoDbClientConfiguration(),
|
||||||
|
software.amazon.awssdk.auth.credentials.InstanceProfileCredentialsProvider.create());
|
||||||
|
|
||||||
|
DynamoDbClient dynamoDbClient = DynamoDbFromConfig.client(
|
||||||
|
configuration.getDynamoDbClientConfiguration(),
|
||||||
|
software.amazon.awssdk.auth.credentials.InstanceProfileCredentialsProvider.create());
|
||||||
|
|
||||||
|
AmazonDynamoDB deletedAccountsLockDynamoDbClient = AmazonDynamoDBClientBuilder.standard()
|
||||||
|
.withRegion(configuration.getDynamoDbClientConfiguration().getRegion())
|
||||||
|
.withClientConfiguration(new ClientConfiguration().withClientExecutionTimeout(
|
||||||
|
((int) configuration.getDynamoDbClientConfiguration().getClientExecutionTimeout()
|
||||||
|
.toMillis()))
|
||||||
|
.withRequestTimeout(
|
||||||
|
(int) configuration.getDynamoDbClientConfiguration().getClientRequestTimeout()
|
||||||
|
.toMillis()))
|
||||||
|
.withCredentials(InstanceProfileCredentialsProvider.getInstance())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
DeletedAccounts deletedAccounts = new DeletedAccounts(dynamoDbClient,
|
||||||
|
configuration.getDynamoDbTables().getDeletedAccounts().getTableName(),
|
||||||
|
configuration.getDynamoDbTables().getDeletedAccounts().getNeedsReconciliationIndexName());
|
||||||
|
VerificationCodeStore pendingAccounts = new VerificationCodeStore(dynamoDbClient,
|
||||||
|
configuration.getDynamoDbTables().getPendingAccounts().getTableName());
|
||||||
|
RegistrationRecoveryPasswords registrationRecoveryPasswords = new RegistrationRecoveryPasswords(
|
||||||
|
configuration.getDynamoDbTables().getRegistrationRecovery().getTableName(),
|
||||||
|
configuration.getDynamoDbTables().getRegistrationRecovery().getExpiration(),
|
||||||
|
dynamoDbClient,
|
||||||
|
dynamoDbAsyncClient
|
||||||
|
);
|
||||||
|
|
||||||
|
RegistrationRecoveryPasswordsManager registrationRecoveryPasswordsManager = new RegistrationRecoveryPasswordsManager(
|
||||||
|
registrationRecoveryPasswords);
|
||||||
|
|
||||||
|
Accounts accounts = new Accounts(
|
||||||
|
dynamoDbClient,
|
||||||
|
dynamoDbAsyncClient,
|
||||||
|
configuration.getDynamoDbTables().getAccounts().getTableName(),
|
||||||
|
configuration.getDynamoDbTables().getAccounts().getPhoneNumberTableName(),
|
||||||
|
configuration.getDynamoDbTables().getAccounts().getPhoneNumberIdentifierTableName(),
|
||||||
|
configuration.getDynamoDbTables().getAccounts().getUsernamesTableName(),
|
||||||
|
configuration.getDynamoDbTables().getAccounts().getScanPageSize());
|
||||||
|
PhoneNumberIdentifiers phoneNumberIdentifiers = new PhoneNumberIdentifiers(dynamoDbClient,
|
||||||
|
configuration.getDynamoDbTables().getPhoneNumberIdentifiers().getTableName());
|
||||||
|
Profiles profiles = new Profiles(dynamoDbClient, dynamoDbAsyncClient,
|
||||||
|
configuration.getDynamoDbTables().getProfiles().getTableName());
|
||||||
|
Keys keys = new Keys(dynamoDbClient,
|
||||||
|
configuration.getDynamoDbTables().getKeys().getTableName());
|
||||||
|
MessagesDynamoDb messagesDynamoDb = new MessagesDynamoDb(dynamoDbClient, dynamoDbAsyncClient,
|
||||||
|
configuration.getDynamoDbTables().getMessages().getTableName(),
|
||||||
|
configuration.getDynamoDbTables().getMessages().getExpiration(),
|
||||||
|
messageDeletionExecutor);
|
||||||
|
FaultTolerantRedisCluster messageInsertCacheCluster = new FaultTolerantRedisCluster("message_insert_cluster",
|
||||||
|
configuration.getMessageCacheConfiguration().getRedisClusterConfiguration(), redisClusterClientResources);
|
||||||
|
FaultTolerantRedisCluster messageReadDeleteCluster = new FaultTolerantRedisCluster("message_read_delete_cluster",
|
||||||
|
configuration.getMessageCacheConfiguration().getRedisClusterConfiguration(), redisClusterClientResources);
|
||||||
|
FaultTolerantRedisCluster clientPresenceCluster = new FaultTolerantRedisCluster("client_presence_cluster",
|
||||||
|
configuration.getClientPresenceClusterConfiguration(), redisClusterClientResources);
|
||||||
|
FaultTolerantRedisCluster rateLimitersCluster = new FaultTolerantRedisCluster("rate_limiters",
|
||||||
|
configuration.getRateLimitersCluster(), redisClusterClientResources);
|
||||||
|
SecureBackupClient secureBackupClient = new SecureBackupClient(backupCredentialsGenerator, backupServiceExecutor,
|
||||||
|
configuration.getSecureBackupServiceConfiguration());
|
||||||
|
SecureStorageClient secureStorageClient = new SecureStorageClient(storageCredentialsGenerator,
|
||||||
|
storageServiceExecutor, configuration.getSecureStorageServiceConfiguration());
|
||||||
|
ClientPresenceManager clientPresenceManager = new ClientPresenceManager(clientPresenceCluster,
|
||||||
|
Executors.newSingleThreadScheduledExecutor(), keyspaceNotificationDispatchExecutor);
|
||||||
|
MessagesCache messagesCache = new MessagesCache(messageInsertCacheCluster, messageReadDeleteCluster,
|
||||||
|
Clock.systemUTC(), keyspaceNotificationDispatchExecutor, messageDeletionExecutor);
|
||||||
|
DirectoryQueue directoryQueue = new DirectoryQueue(
|
||||||
|
configuration.getDirectoryConfiguration().getSqsConfiguration());
|
||||||
|
ProfilesManager profilesManager = new ProfilesManager(profiles, cacheCluster);
|
||||||
|
ReportMessageDynamoDb reportMessageDynamoDb = new ReportMessageDynamoDb(dynamoDbClient,
|
||||||
|
configuration.getDynamoDbTables().getReportMessage().getTableName(),
|
||||||
|
configuration.getReportMessageConfiguration().getReportTtl());
|
||||||
|
ReportMessageManager reportMessageManager = new ReportMessageManager(reportMessageDynamoDb, rateLimitersCluster,
|
||||||
|
configuration.getReportMessageConfiguration().getCounterTtl());
|
||||||
|
MessagesManager messagesManager = new MessagesManager(messagesDynamoDb, messagesCache,
|
||||||
|
reportMessageManager, messageDeletionExecutor);
|
||||||
|
DeletedAccountsManager deletedAccountsManager = new DeletedAccountsManager(deletedAccounts,
|
||||||
|
deletedAccountsLockDynamoDbClient,
|
||||||
|
configuration.getDynamoDbTables().getDeletedAccountsLock().getTableName());
|
||||||
|
StoredVerificationCodeManager pendingAccountsManager = new StoredVerificationCodeManager(pendingAccounts);
|
||||||
|
AccountsManager accountsManager = new AccountsManager(accounts, phoneNumberIdentifiers, cacheCluster,
|
||||||
|
deletedAccountsManager, directoryQueue, keys, messagesManager, profilesManager,
|
||||||
|
pendingAccountsManager, secureStorageClient, secureBackupClient, clientPresenceManager,
|
||||||
|
experimentEnrollmentManager, registrationRecoveryPasswordsManager, clock);
|
||||||
|
|
||||||
|
return new CommandDependencies(
|
||||||
|
accountsManager,
|
||||||
|
profilesManager,
|
||||||
|
reportMessageManager,
|
||||||
|
messagesManager,
|
||||||
|
deletedAccountsManager,
|
||||||
|
pendingAccountsManager,
|
||||||
|
clientPresenceManager,
|
||||||
|
keys
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -5,60 +5,19 @@
|
||||||
|
|
||||||
package org.whispersystems.textsecuregcm.workers;
|
package org.whispersystems.textsecuregcm.workers;
|
||||||
|
|
||||||
import static com.codahale.metrics.MetricRegistry.name;
|
|
||||||
|
|
||||||
import com.amazonaws.ClientConfiguration;
|
|
||||||
import com.amazonaws.auth.InstanceProfileCredentialsProvider;
|
|
||||||
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
|
|
||||||
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
|
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
import io.dropwizard.Application;
|
import io.dropwizard.Application;
|
||||||
import io.dropwizard.cli.EnvironmentCommand;
|
import io.dropwizard.cli.EnvironmentCommand;
|
||||||
import io.dropwizard.setup.Environment;
|
import io.dropwizard.setup.Environment;
|
||||||
import io.lettuce.core.resource.ClientResources;
|
|
||||||
import java.time.Clock;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import net.sourceforge.argparse4j.inf.Namespace;
|
import net.sourceforge.argparse4j.inf.Namespace;
|
||||||
import net.sourceforge.argparse4j.inf.Subparser;
|
import net.sourceforge.argparse4j.inf.Subparser;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.whispersystems.textsecuregcm.WhisperServerConfiguration;
|
import org.whispersystems.textsecuregcm.WhisperServerConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
|
||||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
|
||||||
import org.whispersystems.textsecuregcm.controllers.SecureBackupController;
|
|
||||||
import org.whispersystems.textsecuregcm.controllers.SecureStorageController;
|
|
||||||
import org.whispersystems.textsecuregcm.experiment.ExperimentEnrollmentManager;
|
|
||||||
import org.whispersystems.textsecuregcm.push.ClientPresenceManager;
|
|
||||||
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster;
|
|
||||||
import org.whispersystems.textsecuregcm.securebackup.SecureBackupClient;
|
|
||||||
import org.whispersystems.textsecuregcm.securestorage.SecureStorageClient;
|
|
||||||
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.AccountsManager;
|
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||||
import org.whispersystems.textsecuregcm.storage.AccountsManager.DeletionReason;
|
import org.whispersystems.textsecuregcm.storage.AccountsManager.DeletionReason;
|
||||||
import org.whispersystems.textsecuregcm.storage.DeletedAccounts;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.DeletedAccountsManager;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.Keys;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.MessagesCache;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.MessagesDynamoDb;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.MessagesManager;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.PhoneNumberIdentifiers;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.Profiles;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.ProfilesManager;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.ProhibitedUsernames;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.RegistrationRecoveryPasswords;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.RegistrationRecoveryPasswordsManager;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.ReportMessageDynamoDb;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.ReportMessageManager;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.StoredVerificationCodeManager;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.VerificationCodeStore;
|
|
||||||
import org.whispersystems.textsecuregcm.util.DynamoDbFromConfig;
|
|
||||||
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
|
|
||||||
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
|
|
||||||
|
|
||||||
public class DeleteUserCommand extends EnvironmentCommand<WhisperServerConfiguration> {
|
public class DeleteUserCommand extends EnvironmentCommand<WhisperServerConfiguration> {
|
||||||
|
|
||||||
|
@ -84,130 +43,16 @@ public class DeleteUserCommand extends EnvironmentCommand<WhisperServerConfigura
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void run(Environment environment, Namespace namespace,
|
protected void run(Environment environment, Namespace namespace, WhisperServerConfiguration configuration)
|
||||||
WhisperServerConfiguration configuration)
|
|
||||||
throws Exception
|
throws Exception
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
Clock clock = Clock.systemUTC();
|
|
||||||
String[] users = namespace.getString("user").split(",");
|
String[] users = namespace.getString("user").split(",");
|
||||||
|
|
||||||
environment.getObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
environment.getObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
|
|
||||||
ClientResources redisClusterClientResources = ClientResources.builder().build();
|
final CommandDependencies deps = CommandDependencies.build("rmuser", environment, configuration);
|
||||||
|
|
||||||
FaultTolerantRedisCluster cacheCluster = new FaultTolerantRedisCluster("main_cache_cluster",
|
AccountsManager accountsManager = deps.accountsManager();
|
||||||
configuration.getCacheClusterConfiguration(), redisClusterClientResources);
|
|
||||||
|
|
||||||
ExecutorService keyspaceNotificationDispatchExecutor = environment.lifecycle()
|
|
||||||
.executorService(name(getClass(), "keyspaceNotification-%d")).maxThreads(4).build();
|
|
||||||
ExecutorService messageDeletionExecutor = environment.lifecycle()
|
|
||||||
.executorService(name(getClass(), "messageDeletion-%d")).maxThreads(4).build();
|
|
||||||
ExecutorService backupServiceExecutor = environment.lifecycle()
|
|
||||||
.executorService(name(getClass(), "backupService-%d")).maxThreads(8).minThreads(1).build();
|
|
||||||
ExecutorService storageServiceExecutor = environment.lifecycle()
|
|
||||||
.executorService(name(getClass(), "storageService-%d")).maxThreads(8).minThreads(1).build();
|
|
||||||
|
|
||||||
ExternalServiceCredentialsGenerator backupCredentialsGenerator = SecureBackupController.credentialsGenerator(
|
|
||||||
configuration.getSecureBackupServiceConfiguration());
|
|
||||||
ExternalServiceCredentialsGenerator storageCredentialsGenerator = SecureStorageController.credentialsGenerator(
|
|
||||||
configuration.getSecureStorageServiceConfiguration());
|
|
||||||
|
|
||||||
DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager = new DynamicConfigurationManager<>(
|
|
||||||
configuration.getAppConfig().getApplication(), configuration.getAppConfig().getEnvironment(),
|
|
||||||
configuration.getAppConfig().getConfigurationName(), DynamicConfiguration.class);
|
|
||||||
dynamicConfigurationManager.start();
|
|
||||||
|
|
||||||
ExperimentEnrollmentManager experimentEnrollmentManager = new ExperimentEnrollmentManager(
|
|
||||||
dynamicConfigurationManager);
|
|
||||||
|
|
||||||
DynamoDbAsyncClient dynamoDbAsyncClient = DynamoDbFromConfig.asyncClient(
|
|
||||||
configuration.getDynamoDbClientConfiguration(),
|
|
||||||
software.amazon.awssdk.auth.credentials.InstanceProfileCredentialsProvider.create());
|
|
||||||
|
|
||||||
DynamoDbClient dynamoDbClient = DynamoDbFromConfig.client(
|
|
||||||
configuration.getDynamoDbClientConfiguration(),
|
|
||||||
software.amazon.awssdk.auth.credentials.InstanceProfileCredentialsProvider.create());
|
|
||||||
|
|
||||||
AmazonDynamoDB deletedAccountsLockDynamoDbClient = AmazonDynamoDBClientBuilder.standard()
|
|
||||||
.withRegion(configuration.getDynamoDbClientConfiguration().getRegion())
|
|
||||||
.withClientConfiguration(new ClientConfiguration().withClientExecutionTimeout(
|
|
||||||
((int) configuration.getDynamoDbClientConfiguration().getClientExecutionTimeout()
|
|
||||||
.toMillis()))
|
|
||||||
.withRequestTimeout(
|
|
||||||
(int) configuration.getDynamoDbClientConfiguration().getClientRequestTimeout()
|
|
||||||
.toMillis()))
|
|
||||||
.withCredentials(InstanceProfileCredentialsProvider.getInstance())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
DeletedAccounts deletedAccounts = new DeletedAccounts(dynamoDbClient,
|
|
||||||
configuration.getDynamoDbTables().getDeletedAccounts().getTableName(),
|
|
||||||
configuration.getDynamoDbTables().getDeletedAccounts().getNeedsReconciliationIndexName());
|
|
||||||
VerificationCodeStore pendingAccounts = new VerificationCodeStore(dynamoDbClient,
|
|
||||||
configuration.getDynamoDbTables().getPendingAccounts().getTableName());
|
|
||||||
RegistrationRecoveryPasswords registrationRecoveryPasswords = new RegistrationRecoveryPasswords(
|
|
||||||
configuration.getDynamoDbTables().getRegistrationRecovery().getTableName(),
|
|
||||||
configuration.getDynamoDbTables().getRegistrationRecovery().getExpiration(),
|
|
||||||
dynamoDbClient,
|
|
||||||
dynamoDbAsyncClient
|
|
||||||
);
|
|
||||||
|
|
||||||
RegistrationRecoveryPasswordsManager registrationRecoveryPasswordsManager = new RegistrationRecoveryPasswordsManager(registrationRecoveryPasswords);
|
|
||||||
|
|
||||||
Accounts accounts = new Accounts(
|
|
||||||
dynamoDbClient,
|
|
||||||
dynamoDbAsyncClient,
|
|
||||||
configuration.getDynamoDbTables().getAccounts().getTableName(),
|
|
||||||
configuration.getDynamoDbTables().getAccounts().getPhoneNumberTableName(),
|
|
||||||
configuration.getDynamoDbTables().getAccounts().getPhoneNumberIdentifierTableName(),
|
|
||||||
configuration.getDynamoDbTables().getAccounts().getUsernamesTableName(),
|
|
||||||
configuration.getDynamoDbTables().getAccounts().getScanPageSize());
|
|
||||||
PhoneNumberIdentifiers phoneNumberIdentifiers = new PhoneNumberIdentifiers(dynamoDbClient,
|
|
||||||
configuration.getDynamoDbTables().getPhoneNumberIdentifiers().getTableName());
|
|
||||||
Profiles profiles = new Profiles(dynamoDbClient, dynamoDbAsyncClient,
|
|
||||||
configuration.getDynamoDbTables().getProfiles().getTableName());
|
|
||||||
ProhibitedUsernames prohibitedUsernames = new ProhibitedUsernames(dynamoDbClient,
|
|
||||||
configuration.getDynamoDbTables().getReservedUsernames().getTableName());
|
|
||||||
Keys keys = new Keys(dynamoDbClient,
|
|
||||||
configuration.getDynamoDbTables().getKeys().getTableName());
|
|
||||||
MessagesDynamoDb messagesDynamoDb = new MessagesDynamoDb(dynamoDbClient, dynamoDbAsyncClient,
|
|
||||||
configuration.getDynamoDbTables().getMessages().getTableName(),
|
|
||||||
configuration.getDynamoDbTables().getMessages().getExpiration(),
|
|
||||||
messageDeletionExecutor);
|
|
||||||
FaultTolerantRedisCluster messageInsertCacheCluster = new FaultTolerantRedisCluster("message_insert_cluster",
|
|
||||||
configuration.getMessageCacheConfiguration().getRedisClusterConfiguration(), redisClusterClientResources);
|
|
||||||
FaultTolerantRedisCluster messageReadDeleteCluster = new FaultTolerantRedisCluster("message_read_delete_cluster",
|
|
||||||
configuration.getMessageCacheConfiguration().getRedisClusterConfiguration(), redisClusterClientResources);
|
|
||||||
FaultTolerantRedisCluster clientPresenceCluster = new FaultTolerantRedisCluster("client_presence_cluster",
|
|
||||||
configuration.getClientPresenceClusterConfiguration(), redisClusterClientResources);
|
|
||||||
FaultTolerantRedisCluster rateLimitersCluster = new FaultTolerantRedisCluster("rate_limiters",
|
|
||||||
configuration.getRateLimitersCluster(), redisClusterClientResources);
|
|
||||||
SecureBackupClient secureBackupClient = new SecureBackupClient(backupCredentialsGenerator, backupServiceExecutor,
|
|
||||||
configuration.getSecureBackupServiceConfiguration());
|
|
||||||
SecureStorageClient secureStorageClient = new SecureStorageClient(storageCredentialsGenerator,
|
|
||||||
storageServiceExecutor, configuration.getSecureStorageServiceConfiguration());
|
|
||||||
ClientPresenceManager clientPresenceManager = new ClientPresenceManager(clientPresenceCluster,
|
|
||||||
Executors.newSingleThreadScheduledExecutor(), keyspaceNotificationDispatchExecutor);
|
|
||||||
MessagesCache messagesCache = new MessagesCache(messageInsertCacheCluster, messageReadDeleteCluster,
|
|
||||||
Clock.systemUTC(), keyspaceNotificationDispatchExecutor, messageDeletionExecutor);
|
|
||||||
DirectoryQueue directoryQueue = new DirectoryQueue(
|
|
||||||
configuration.getDirectoryConfiguration().getSqsConfiguration());
|
|
||||||
ProfilesManager profilesManager = new ProfilesManager(profiles, cacheCluster);
|
|
||||||
ReportMessageDynamoDb reportMessageDynamoDb = new ReportMessageDynamoDb(dynamoDbClient,
|
|
||||||
configuration.getDynamoDbTables().getReportMessage().getTableName(),
|
|
||||||
configuration.getReportMessageConfiguration().getReportTtl());
|
|
||||||
ReportMessageManager reportMessageManager = new ReportMessageManager(reportMessageDynamoDb, rateLimitersCluster,
|
|
||||||
configuration.getReportMessageConfiguration().getCounterTtl());
|
|
||||||
MessagesManager messagesManager = new MessagesManager(messagesDynamoDb, messagesCache,
|
|
||||||
reportMessageManager, messageDeletionExecutor);
|
|
||||||
DeletedAccountsManager deletedAccountsManager = new DeletedAccountsManager(deletedAccounts,
|
|
||||||
deletedAccountsLockDynamoDbClient,
|
|
||||||
configuration.getDynamoDbTables().getDeletedAccountsLock().getTableName());
|
|
||||||
StoredVerificationCodeManager pendingAccountsManager = new StoredVerificationCodeManager(pendingAccounts);
|
|
||||||
AccountsManager accountsManager = new AccountsManager(accounts, phoneNumberIdentifiers, cacheCluster,
|
|
||||||
deletedAccountsManager, directoryQueue, keys, messagesManager, profilesManager,
|
|
||||||
pendingAccountsManager, secureStorageClient, secureBackupClient, clientPresenceManager,
|
|
||||||
experimentEnrollmentManager, registrationRecoveryPasswordsManager, clock);
|
|
||||||
|
|
||||||
for (String user : users) {
|
for (String user : users) {
|
||||||
Optional<Account> account = accountsManager.getByE164(user);
|
Optional<Account> account = accountsManager.getByE164(user);
|
||||||
|
|
|
@ -5,58 +5,17 @@
|
||||||
|
|
||||||
package org.whispersystems.textsecuregcm.workers;
|
package org.whispersystems.textsecuregcm.workers;
|
||||||
|
|
||||||
import static com.codahale.metrics.MetricRegistry.name;
|
|
||||||
|
|
||||||
import com.amazonaws.ClientConfiguration;
|
|
||||||
import com.amazonaws.auth.InstanceProfileCredentialsProvider;
|
|
||||||
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
|
|
||||||
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
|
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
import io.dropwizard.Application;
|
import io.dropwizard.Application;
|
||||||
import io.dropwizard.cli.EnvironmentCommand;
|
import io.dropwizard.cli.EnvironmentCommand;
|
||||||
import io.dropwizard.setup.Environment;
|
import io.dropwizard.setup.Environment;
|
||||||
import io.lettuce.core.resource.ClientResources;
|
|
||||||
import java.time.Clock;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import net.sourceforge.argparse4j.inf.Namespace;
|
import net.sourceforge.argparse4j.inf.Namespace;
|
||||||
import net.sourceforge.argparse4j.inf.Subparser;
|
import net.sourceforge.argparse4j.inf.Subparser;
|
||||||
import org.whispersystems.textsecuregcm.WhisperServerConfiguration;
|
import org.whispersystems.textsecuregcm.WhisperServerConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
|
||||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
|
||||||
import org.whispersystems.textsecuregcm.controllers.SecureBackupController;
|
|
||||||
import org.whispersystems.textsecuregcm.controllers.SecureStorageController;
|
|
||||||
import org.whispersystems.textsecuregcm.experiment.ExperimentEnrollmentManager;
|
|
||||||
import org.whispersystems.textsecuregcm.push.ClientPresenceManager;
|
|
||||||
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster;
|
|
||||||
import org.whispersystems.textsecuregcm.securebackup.SecureBackupClient;
|
|
||||||
import org.whispersystems.textsecuregcm.securestorage.SecureStorageClient;
|
|
||||||
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.AccountsManager;
|
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||||
import org.whispersystems.textsecuregcm.storage.DeletedAccounts;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.DeletedAccountsManager;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.Keys;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.MessagesCache;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.MessagesDynamoDb;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.MessagesManager;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.PhoneNumberIdentifiers;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.Profiles;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.ProfilesManager;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.ProhibitedUsernames;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.RegistrationRecoveryPasswords;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.RegistrationRecoveryPasswordsManager;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.ReportMessageDynamoDb;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.ReportMessageManager;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.StoredVerificationCodeManager;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.VerificationCodeStore;
|
|
||||||
import org.whispersystems.textsecuregcm.util.DynamoDbFromConfig;
|
|
||||||
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
|
|
||||||
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
|
|
||||||
|
|
||||||
public class SetUserDiscoverabilityCommand extends EnvironmentCommand<WhisperServerConfiguration> {
|
public class SetUserDiscoverabilityCommand extends EnvironmentCommand<WhisperServerConfiguration> {
|
||||||
|
|
||||||
|
@ -92,124 +51,10 @@ public class SetUserDiscoverabilityCommand extends EnvironmentCommand<WhisperSer
|
||||||
final WhisperServerConfiguration configuration) throws Exception {
|
final WhisperServerConfiguration configuration) throws Exception {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Clock clock = Clock.systemUTC();
|
|
||||||
environment.getObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
environment.getObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
|
|
||||||
ClientResources redisClusterClientResources = ClientResources.builder().build();
|
final CommandDependencies deps = CommandDependencies.build("set-discoverability", environment, configuration);
|
||||||
|
final AccountsManager accountsManager = deps.accountsManager();
|
||||||
FaultTolerantRedisCluster cacheCluster = new FaultTolerantRedisCluster("main_cache_cluster",
|
|
||||||
configuration.getCacheClusterConfiguration(), redisClusterClientResources);
|
|
||||||
FaultTolerantRedisCluster rateLimitersCluster = new FaultTolerantRedisCluster("rate_limiters",
|
|
||||||
configuration.getRateLimitersCluster(), redisClusterClientResources);
|
|
||||||
|
|
||||||
ExecutorService keyspaceNotificationDispatchExecutor = environment.lifecycle()
|
|
||||||
.executorService(name(getClass(), "keyspaceNotification-%d")).maxThreads(4).build();
|
|
||||||
ExecutorService messageDeletionExecutor = environment.lifecycle()
|
|
||||||
.executorService(name(getClass(), "messageDeletion-%d")).maxThreads(4).build();
|
|
||||||
ExecutorService backupServiceExecutor = environment.lifecycle()
|
|
||||||
.executorService(name(getClass(), "backupService-%d")).maxThreads(8).minThreads(1).build();
|
|
||||||
ExecutorService storageServiceExecutor = environment.lifecycle()
|
|
||||||
.executorService(name(getClass(), "storageService-%d")).maxThreads(8).minThreads(1).build();
|
|
||||||
|
|
||||||
ExternalServiceCredentialsGenerator backupCredentialsGenerator = SecureBackupController.credentialsGenerator(
|
|
||||||
configuration.getSecureBackupServiceConfiguration());
|
|
||||||
ExternalServiceCredentialsGenerator storageCredentialsGenerator = SecureStorageController.credentialsGenerator(
|
|
||||||
configuration.getSecureStorageServiceConfiguration());
|
|
||||||
|
|
||||||
DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager = new DynamicConfigurationManager<>(
|
|
||||||
configuration.getAppConfig().getApplication(), configuration.getAppConfig().getEnvironment(),
|
|
||||||
configuration.getAppConfig().getConfigurationName(), DynamicConfiguration.class);
|
|
||||||
dynamicConfigurationManager.start();
|
|
||||||
|
|
||||||
ExperimentEnrollmentManager experimentEnrollmentManager = new ExperimentEnrollmentManager(
|
|
||||||
dynamicConfigurationManager);
|
|
||||||
|
|
||||||
DynamoDbAsyncClient dynamoDbAsyncClient = DynamoDbFromConfig.asyncClient(
|
|
||||||
configuration.getDynamoDbClientConfiguration(),
|
|
||||||
software.amazon.awssdk.auth.credentials.InstanceProfileCredentialsProvider.create());
|
|
||||||
|
|
||||||
DynamoDbClient dynamoDbClient = DynamoDbFromConfig.client(
|
|
||||||
configuration.getDynamoDbClientConfiguration(),
|
|
||||||
software.amazon.awssdk.auth.credentials.InstanceProfileCredentialsProvider.create());
|
|
||||||
|
|
||||||
AmazonDynamoDB deletedAccountsLockDynamoDbClient = AmazonDynamoDBClientBuilder.standard()
|
|
||||||
.withRegion(configuration.getDynamoDbClientConfiguration().getRegion())
|
|
||||||
.withClientConfiguration(new ClientConfiguration().withClientExecutionTimeout(
|
|
||||||
((int) configuration.getDynamoDbClientConfiguration().getClientExecutionTimeout()
|
|
||||||
.toMillis()))
|
|
||||||
.withRequestTimeout(
|
|
||||||
(int) configuration.getDynamoDbClientConfiguration().getClientRequestTimeout()
|
|
||||||
.toMillis()))
|
|
||||||
.withCredentials(InstanceProfileCredentialsProvider.getInstance())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
DeletedAccounts deletedAccounts = new DeletedAccounts(dynamoDbClient,
|
|
||||||
configuration.getDynamoDbTables().getDeletedAccounts().getTableName(),
|
|
||||||
configuration.getDynamoDbTables().getDeletedAccounts().getNeedsReconciliationIndexName());
|
|
||||||
VerificationCodeStore pendingAccounts = new VerificationCodeStore(dynamoDbClient,
|
|
||||||
configuration.getDynamoDbTables().getPendingAccounts().getTableName());
|
|
||||||
RegistrationRecoveryPasswords registrationRecoveryPasswords = new RegistrationRecoveryPasswords(
|
|
||||||
configuration.getDynamoDbTables().getRegistrationRecovery().getTableName(),
|
|
||||||
configuration.getDynamoDbTables().getRegistrationRecovery().getExpiration(),
|
|
||||||
dynamoDbClient,
|
|
||||||
dynamoDbAsyncClient
|
|
||||||
);
|
|
||||||
|
|
||||||
RegistrationRecoveryPasswordsManager registrationRecoveryPasswordsManager = new RegistrationRecoveryPasswordsManager(registrationRecoveryPasswords);
|
|
||||||
|
|
||||||
Accounts accounts = new Accounts(
|
|
||||||
dynamoDbClient,
|
|
||||||
dynamoDbAsyncClient,
|
|
||||||
configuration.getDynamoDbTables().getAccounts().getTableName(),
|
|
||||||
configuration.getDynamoDbTables().getAccounts().getPhoneNumberTableName(),
|
|
||||||
configuration.getDynamoDbTables().getAccounts().getPhoneNumberIdentifierTableName(),
|
|
||||||
configuration.getDynamoDbTables().getAccounts().getUsernamesTableName(),
|
|
||||||
configuration.getDynamoDbTables().getAccounts().getScanPageSize());
|
|
||||||
PhoneNumberIdentifiers phoneNumberIdentifiers = new PhoneNumberIdentifiers(dynamoDbClient,
|
|
||||||
configuration.getDynamoDbTables().getPhoneNumberIdentifiers().getTableName());
|
|
||||||
Profiles profiles = new Profiles(dynamoDbClient, dynamoDbAsyncClient,
|
|
||||||
configuration.getDynamoDbTables().getProfiles().getTableName());
|
|
||||||
ProhibitedUsernames prohibitedUsernames = new ProhibitedUsernames(dynamoDbClient,
|
|
||||||
configuration.getDynamoDbTables().getReservedUsernames().getTableName());
|
|
||||||
Keys keys = new Keys(dynamoDbClient,
|
|
||||||
configuration.getDynamoDbTables().getKeys().getTableName());
|
|
||||||
MessagesDynamoDb messagesDynamoDb = new MessagesDynamoDb(dynamoDbClient, dynamoDbAsyncClient,
|
|
||||||
configuration.getDynamoDbTables().getMessages().getTableName(),
|
|
||||||
configuration.getDynamoDbTables().getMessages().getExpiration(),
|
|
||||||
messageDeletionExecutor);
|
|
||||||
FaultTolerantRedisCluster messageInsertCacheCluster = new FaultTolerantRedisCluster("message_insert_cluster",
|
|
||||||
configuration.getMessageCacheConfiguration().getRedisClusterConfiguration(), redisClusterClientResources);
|
|
||||||
FaultTolerantRedisCluster messageReadDeleteCluster = new FaultTolerantRedisCluster("message_read_delete_cluster",
|
|
||||||
configuration.getMessageCacheConfiguration().getRedisClusterConfiguration(), redisClusterClientResources);
|
|
||||||
FaultTolerantRedisCluster clientPresenceCluster = new FaultTolerantRedisCluster("client_presence",
|
|
||||||
configuration.getClientPresenceClusterConfiguration(), redisClusterClientResources);
|
|
||||||
SecureBackupClient secureBackupClient = new SecureBackupClient(backupCredentialsGenerator, backupServiceExecutor,
|
|
||||||
configuration.getSecureBackupServiceConfiguration());
|
|
||||||
SecureStorageClient secureStorageClient = new SecureStorageClient(storageCredentialsGenerator,
|
|
||||||
storageServiceExecutor, configuration.getSecureStorageServiceConfiguration());
|
|
||||||
ClientPresenceManager clientPresenceManager = new ClientPresenceManager(clientPresenceCluster,
|
|
||||||
Executors.newSingleThreadScheduledExecutor(), keyspaceNotificationDispatchExecutor);
|
|
||||||
MessagesCache messagesCache = new MessagesCache(messageInsertCacheCluster, messageReadDeleteCluster,
|
|
||||||
Clock.systemUTC(), keyspaceNotificationDispatchExecutor, messageDeletionExecutor);
|
|
||||||
DirectoryQueue directoryQueue = new DirectoryQueue(
|
|
||||||
configuration.getDirectoryConfiguration().getSqsConfiguration());
|
|
||||||
ProfilesManager profilesManager = new ProfilesManager(profiles, cacheCluster);
|
|
||||||
ReportMessageDynamoDb reportMessageDynamoDb = new ReportMessageDynamoDb(dynamoDbClient,
|
|
||||||
configuration.getDynamoDbTables().getReportMessage().getTableName(),
|
|
||||||
configuration.getReportMessageConfiguration().getReportTtl());
|
|
||||||
ReportMessageManager reportMessageManager = new ReportMessageManager(reportMessageDynamoDb, rateLimitersCluster,
|
|
||||||
configuration.getReportMessageConfiguration().getCounterTtl());
|
|
||||||
MessagesManager messagesManager = new MessagesManager(messagesDynamoDb, messagesCache,
|
|
||||||
reportMessageManager, messageDeletionExecutor);
|
|
||||||
DeletedAccountsManager deletedAccountsManager = new DeletedAccountsManager(deletedAccounts,
|
|
||||||
deletedAccountsLockDynamoDbClient,
|
|
||||||
configuration.getDynamoDbTables().getDeletedAccountsLock().getTableName());
|
|
||||||
StoredVerificationCodeManager pendingAccountsManager = new StoredVerificationCodeManager(pendingAccounts);
|
|
||||||
AccountsManager accountsManager = new AccountsManager(accounts, phoneNumberIdentifiers, cacheCluster,
|
|
||||||
deletedAccountsManager, directoryQueue, keys, messagesManager, profilesManager,
|
|
||||||
pendingAccountsManager, secureStorageClient, secureBackupClient, clientPresenceManager,
|
|
||||||
experimentEnrollmentManager, registrationRecoveryPasswordsManager, clock);
|
|
||||||
|
|
||||||
Optional<Account> maybeAccount;
|
Optional<Account> maybeAccount;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013-2021 Signal Messenger, LLC
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.whispersystems.textsecuregcm.workers;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
|
import io.dropwizard.Application;
|
||||||
|
import io.dropwizard.cli.EnvironmentCommand;
|
||||||
|
import io.dropwizard.setup.Environment;
|
||||||
|
import java.util.UUID;
|
||||||
|
import net.sourceforge.argparse4j.inf.Namespace;
|
||||||
|
import net.sourceforge.argparse4j.inf.Subparser;
|
||||||
|
import org.whispersystems.textsecuregcm.WhisperServerConfiguration;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.Account;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.Device;
|
||||||
|
|
||||||
|
public class UnlinkDeviceCommand extends EnvironmentCommand<WhisperServerConfiguration> {
|
||||||
|
|
||||||
|
public UnlinkDeviceCommand() {
|
||||||
|
super(new Application<>() {
|
||||||
|
@Override
|
||||||
|
public void run(WhisperServerConfiguration configuration, Environment environment) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}, "unlink-device", "Unlink a device and clear messages");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configure(final Subparser subparser) {
|
||||||
|
super.configure(subparser);
|
||||||
|
|
||||||
|
subparser.addArgument("-d", "--deviceId")
|
||||||
|
.dest("deviceId")
|
||||||
|
.type(Long.class)
|
||||||
|
.required(true);
|
||||||
|
|
||||||
|
subparser.addArgument("-u", "--uuid")
|
||||||
|
.help("the UUID of the account to modify")
|
||||||
|
.dest("uuid")
|
||||||
|
.type(String.class)
|
||||||
|
.required(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void run(final Environment environment, final Namespace namespace,
|
||||||
|
final WhisperServerConfiguration configuration) throws Exception {
|
||||||
|
environment.getObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
|
|
||||||
|
final UUID aci = UUID.fromString(namespace.getString("uuid").trim());
|
||||||
|
final long deviceId = namespace.getLong("deviceId");
|
||||||
|
|
||||||
|
final CommandDependencies deps = CommandDependencies.build("unlink-device", environment, configuration);
|
||||||
|
|
||||||
|
Account account = deps.accountsManager().getByAccountIdentifier(aci)
|
||||||
|
.orElseThrow(() -> new IllegalArgumentException("account id " + aci +" does not exist"));
|
||||||
|
|
||||||
|
if (deviceId == Device.MASTER_ID) {
|
||||||
|
throw new IllegalArgumentException("cannot delete primary device");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** see {@link org.whispersystems.textsecuregcm.controllers.DeviceController#removeDevice} */
|
||||||
|
System.out.format("Removing device %s::%d\n", aci, deviceId);
|
||||||
|
account = deps.accountsManager().update(account, a -> a.removeDevice(deviceId));
|
||||||
|
|
||||||
|
System.out.format("Removing keys for device %s::%d\n", aci, deviceId);
|
||||||
|
deps.keys().delete(account.getUuid(), deviceId);
|
||||||
|
|
||||||
|
System.out.format("Clearing additional messages for %s::%d\n", aci, deviceId);
|
||||||
|
deps.messagesManager().clear(account.getUuid(), deviceId);
|
||||||
|
|
||||||
|
System.out.format("Clearing presence state for %s::%d\n", aci, deviceId);
|
||||||
|
deps.clientPresenceManager().disconnectPresence(aci, deviceId);
|
||||||
|
|
||||||
|
System.out.format("Device %s::%d successfully removed\n", aci, deviceId);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue