From 5dbde869df47fcacdf716733b0bce07853b37bbd Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Sun, 29 Jan 2017 20:02:36 -0800 Subject: [PATCH] staging command // FREEBIE --- .../textsecuregcm/WhisperServerService.java | 2 + .../workers/DeleteUserCommand.java | 110 ++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 src/main/java/org/whispersystems/textsecuregcm/workers/DeleteUserCommand.java diff --git a/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java b/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java index 15614ce7a..efdfe2b2b 100644 --- a/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java +++ b/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java @@ -87,6 +87,7 @@ import org.whispersystems.textsecuregcm.websocket.AuthenticatedConnectListener; import org.whispersystems.textsecuregcm.websocket.DeadLetterHandler; import org.whispersystems.textsecuregcm.websocket.ProvisioningConnectListener; import org.whispersystems.textsecuregcm.websocket.WebSocketAccountAuthenticator; +import org.whispersystems.textsecuregcm.workers.DeleteUserCommand; import org.whispersystems.textsecuregcm.workers.DirectoryCommand; import org.whispersystems.textsecuregcm.workers.PeriodicStatsCommand; import org.whispersystems.textsecuregcm.workers.TrimMessagesCommand; @@ -122,6 +123,7 @@ public class WhisperServerService extends Application("accountdb", "accountsdb.xml") { @Override public DataSourceFactory getDataSourceFactory(WhisperServerConfiguration configuration) { diff --git a/src/main/java/org/whispersystems/textsecuregcm/workers/DeleteUserCommand.java b/src/main/java/org/whispersystems/textsecuregcm/workers/DeleteUserCommand.java new file mode 100644 index 000000000..0cc8bfbf0 --- /dev/null +++ b/src/main/java/org/whispersystems/textsecuregcm/workers/DeleteUserCommand.java @@ -0,0 +1,110 @@ +package org.whispersystems.textsecuregcm.workers; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.google.common.base.Optional; +import net.sourceforge.argparse4j.inf.Namespace; +import net.sourceforge.argparse4j.inf.Subparser; +import org.skife.jdbi.v2.DBI; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.whispersystems.textsecuregcm.WhisperServerConfiguration; +import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials; +import org.whispersystems.textsecuregcm.providers.RedisClientFactory; +import org.whispersystems.textsecuregcm.storage.Account; +import org.whispersystems.textsecuregcm.storage.Accounts; +import org.whispersystems.textsecuregcm.storage.AccountsManager; +import org.whispersystems.textsecuregcm.storage.Device; +import org.whispersystems.textsecuregcm.storage.DirectoryManager; +import org.whispersystems.textsecuregcm.util.Base64; + +import java.security.SecureRandom; + +import io.dropwizard.Application; +import io.dropwizard.cli.EnvironmentCommand; +import io.dropwizard.db.DataSourceFactory; +import io.dropwizard.jdbi.ImmutableListContainerFactory; +import io.dropwizard.jdbi.ImmutableSetContainerFactory; +import io.dropwizard.jdbi.OptionalContainerFactory; +import io.dropwizard.jdbi.args.OptionalArgumentFactory; +import io.dropwizard.setup.Environment; +import redis.clients.jedis.JedisPool; + +public class DeleteUserCommand extends EnvironmentCommand { + + private final Logger logger = LoggerFactory.getLogger(DirectoryCommand.class); + + public DeleteUserCommand() { + super(new Application() { + @Override + public void run(WhisperServerConfiguration configuration, Environment environment) + throws Exception + { + + } + }, "rmuser", "remove user"); + } + + @Override + public void configure(Subparser subparser) { + super.configure(subparser); + subparser.addArgument("-u", "--user") + .dest("user") + .type(String.class) + .required(true) + .help("The user to remove"); + } + + @Override + protected void run(Environment environment, Namespace namespace, + WhisperServerConfiguration configuration) + throws Exception + { + try { + String[] users = namespace.getString("user").split(","); + + environment.getObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + DataSourceFactory dbConfig = configuration.getDataSourceFactory(); + DBI dbi = new DBI(dbConfig.getUrl(), dbConfig.getUser(), dbConfig.getPassword()); + + dbi.registerArgumentFactory(new OptionalArgumentFactory(dbConfig.getDriverClass())); + dbi.registerContainerFactory(new ImmutableListContainerFactory()); + dbi.registerContainerFactory(new ImmutableSetContainerFactory()); + dbi.registerContainerFactory(new OptionalContainerFactory()); + + Accounts accounts = dbi.onDemand(Accounts.class); + JedisPool cacheClient = new RedisClientFactory(configuration.getCacheConfiguration().getUrl()).getRedisClientPool(); + JedisPool redisClient = new RedisClientFactory(configuration.getDirectoryConfiguration().getUrl()).getRedisClientPool(); + DirectoryManager directory = new DirectoryManager(redisClient); + AccountsManager accountsManager = new AccountsManager(accounts, directory, cacheClient); + + for (String user: users) { + Optional account = accountsManager.get(user); + + if (account.isPresent()) { + Optional device = account.get().getDevice(1); + + if (device.isPresent()) { + byte[] random = new byte[16]; + SecureRandom.getInstance("SHA1PRNG").nextBytes(random); + + device.get().setGcmId(null); + device.get().setFetchesMessages(false); + device.get().setAuthenticationCredentials(new AuthenticationCredentials(Base64.encodeBytes(random))); + + accountsManager.update(account.get()); + + logger.warn("Removed " + account.get().getNumber()); + } else { + logger.warn("No primary device found..."); + } + } else { + logger.warn("Account not found..."); + } + } + } catch (Exception ex) { + logger.warn("Removal Exception", ex); + throw new RuntimeException(ex); + } + } +}