Clean up prohibited username references
This commit is contained in:
parent
8847cb92ac
commit
61af1ba029
|
@ -79,8 +79,6 @@ dynamoDbTables:
|
||||||
tableName: Example_RemoteConfig
|
tableName: Example_RemoteConfig
|
||||||
reportMessage:
|
reportMessage:
|
||||||
tableName: Example_ReportMessage
|
tableName: Example_ReportMessage
|
||||||
reservedUsernames:
|
|
||||||
tableName: Example_ReservedUsernames
|
|
||||||
subscriptions:
|
subscriptions:
|
||||||
tableName: Example_Subscriptions
|
tableName: Example_Subscriptions
|
||||||
verificationSessions:
|
verificationSessions:
|
||||||
|
|
|
@ -229,7 +229,6 @@ import org.whispersystems.textsecuregcm.workers.AssignUsernameCommand;
|
||||||
import org.whispersystems.textsecuregcm.workers.CertificateCommand;
|
import org.whispersystems.textsecuregcm.workers.CertificateCommand;
|
||||||
import org.whispersystems.textsecuregcm.workers.CheckDynamicConfigurationCommand;
|
import org.whispersystems.textsecuregcm.workers.CheckDynamicConfigurationCommand;
|
||||||
import org.whispersystems.textsecuregcm.workers.DeleteUserCommand;
|
import org.whispersystems.textsecuregcm.workers.DeleteUserCommand;
|
||||||
import org.whispersystems.textsecuregcm.workers.ReserveUsernameCommand;
|
|
||||||
import org.whispersystems.textsecuregcm.workers.ServerVersionCommand;
|
import org.whispersystems.textsecuregcm.workers.ServerVersionCommand;
|
||||||
import org.whispersystems.textsecuregcm.workers.SetCrawlerAccelerationTask;
|
import org.whispersystems.textsecuregcm.workers.SetCrawlerAccelerationTask;
|
||||||
import org.whispersystems.textsecuregcm.workers.SetRequestLoggingEnabledTask;
|
import org.whispersystems.textsecuregcm.workers.SetRequestLoggingEnabledTask;
|
||||||
|
@ -259,7 +258,6 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
||||||
bootstrap.addCommand(new ServerVersionCommand());
|
bootstrap.addCommand(new ServerVersionCommand());
|
||||||
bootstrap.addCommand(new CheckDynamicConfigurationCommand());
|
bootstrap.addCommand(new CheckDynamicConfigurationCommand());
|
||||||
bootstrap.addCommand(new SetUserDiscoverabilityCommand());
|
bootstrap.addCommand(new SetUserDiscoverabilityCommand());
|
||||||
bootstrap.addCommand(new ReserveUsernameCommand());
|
|
||||||
bootstrap.addCommand(new AssignUsernameCommand());
|
bootstrap.addCommand(new AssignUsernameCommand());
|
||||||
bootstrap.addCommand(new UnlinkDeviceCommand());
|
bootstrap.addCommand(new UnlinkDeviceCommand());
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,6 @@ public class DynamoDbTables {
|
||||||
private final TableWithExpiration registrationRecovery;
|
private final TableWithExpiration registrationRecovery;
|
||||||
private final Table remoteConfig;
|
private final Table remoteConfig;
|
||||||
private final Table reportMessage;
|
private final Table reportMessage;
|
||||||
private final Table reservedUsernames;
|
|
||||||
private final Table subscriptions;
|
private final Table subscriptions;
|
||||||
private final Table verificationSessions;
|
private final Table verificationSessions;
|
||||||
|
|
||||||
|
@ -81,7 +80,6 @@ public class DynamoDbTables {
|
||||||
@JsonProperty("registrationRecovery") final TableWithExpiration registrationRecovery,
|
@JsonProperty("registrationRecovery") final TableWithExpiration registrationRecovery,
|
||||||
@JsonProperty("remoteConfig") final Table remoteConfig,
|
@JsonProperty("remoteConfig") final Table remoteConfig,
|
||||||
@JsonProperty("reportMessage") final Table reportMessage,
|
@JsonProperty("reportMessage") final Table reportMessage,
|
||||||
@JsonProperty("reservedUsernames") final Table reservedUsernames,
|
|
||||||
@JsonProperty("subscriptions") final Table subscriptions,
|
@JsonProperty("subscriptions") final Table subscriptions,
|
||||||
@JsonProperty("verificationSessions") final Table verificationSessions) {
|
@JsonProperty("verificationSessions") final Table verificationSessions) {
|
||||||
|
|
||||||
|
@ -100,7 +98,6 @@ public class DynamoDbTables {
|
||||||
this.registrationRecovery = registrationRecovery;
|
this.registrationRecovery = registrationRecovery;
|
||||||
this.remoteConfig = remoteConfig;
|
this.remoteConfig = remoteConfig;
|
||||||
this.reportMessage = reportMessage;
|
this.reportMessage = reportMessage;
|
||||||
this.reservedUsernames = reservedUsernames;
|
|
||||||
this.subscriptions = subscriptions;
|
this.subscriptions = subscriptions;
|
||||||
this.verificationSessions = verificationSessions;
|
this.verificationSessions = verificationSessions;
|
||||||
}
|
}
|
||||||
|
@ -195,12 +192,6 @@ public class DynamoDbTables {
|
||||||
return reportMessage;
|
return reportMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Valid
|
|
||||||
public Table getReservedUsernames() {
|
|
||||||
return reservedUsernames;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Valid
|
@Valid
|
||||||
public Table getSubscriptions() {
|
public Table getSubscriptions() {
|
||||||
|
|
|
@ -1,97 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2013-2021 Signal Messenger, LLC
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.whispersystems.textsecuregcm.storage;
|
|
||||||
|
|
||||||
import static org.whispersystems.textsecuregcm.metrics.MetricsUtil.name;
|
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
|
||||||
import com.google.common.cache.CacheBuilder;
|
|
||||||
import com.google.common.cache.CacheLoader;
|
|
||||||
import com.google.common.cache.LoadingCache;
|
|
||||||
import io.micrometer.core.instrument.Metrics;
|
|
||||||
import io.micrometer.core.instrument.Timer;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.whispersystems.textsecuregcm.util.AttributeValues;
|
|
||||||
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
|
|
||||||
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
|
|
||||||
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
|
|
||||||
import software.amazon.awssdk.services.dynamodb.model.ScanRequest;
|
|
||||||
import software.amazon.awssdk.services.dynamodb.model.ScanResponse;
|
|
||||||
import software.amazon.awssdk.services.dynamodb.paginators.ScanIterable;
|
|
||||||
|
|
||||||
public class ProhibitedUsernames {
|
|
||||||
|
|
||||||
private final DynamoDbClient dynamoDbClient;
|
|
||||||
private final String tableName;
|
|
||||||
|
|
||||||
private final LoadingCache<String, Pattern> patternCache = CacheBuilder.newBuilder()
|
|
||||||
.maximumSize(1_000)
|
|
||||||
.build(new CacheLoader<>() {
|
|
||||||
@Override
|
|
||||||
public Pattern load(final String s) {
|
|
||||||
return Pattern.compile(s, Pattern.CASE_INSENSITIVE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
static final String KEY_PATTERN = "P";
|
|
||||||
private static final String ATTR_RESERVED_FOR_UUID = "U";
|
|
||||||
|
|
||||||
private static final Timer IS_PROHIBITED_TIMER = Metrics.timer(name(ProhibitedUsernames.class, "isProhibited"));
|
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(ProhibitedUsernames.class);
|
|
||||||
|
|
||||||
public ProhibitedUsernames(final DynamoDbClient dynamoDbClient, final String tableName) {
|
|
||||||
this.dynamoDbClient = dynamoDbClient;
|
|
||||||
this.tableName = tableName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isProhibited(final String nickname, final UUID accountIdentifier) {
|
|
||||||
return IS_PROHIBITED_TIMER.record(() -> {
|
|
||||||
final ScanIterable scanIterable = dynamoDbClient.scanPaginator(ScanRequest.builder()
|
|
||||||
.tableName(tableName)
|
|
||||||
.build());
|
|
||||||
|
|
||||||
for (final ScanResponse scanResponse : scanIterable) {
|
|
||||||
if (scanResponse.hasItems()) {
|
|
||||||
for (final Map<String, AttributeValue> item : scanResponse.items()) {
|
|
||||||
try {
|
|
||||||
final Pattern pattern = patternCache.get(item.get(KEY_PATTERN).s());
|
|
||||||
final UUID reservedFor = AttributeValues.getUUID(item, ATTR_RESERVED_FOR_UUID, null);
|
|
||||||
|
|
||||||
if (pattern.matcher(nickname).matches() && !accountIdentifier.equals(reservedFor)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch (final Exception e) {
|
|
||||||
log.error("Failed to load pattern from item: {}", item, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prohibits username except for all accounts except `reservedFor`
|
|
||||||
*
|
|
||||||
* @param pattern pattern to prohibit
|
|
||||||
* @param reservedFor an account that is allowed to use names in the pattern
|
|
||||||
*/
|
|
||||||
public void prohibitUsername(final String pattern, final UUID reservedFor) {
|
|
||||||
dynamoDbClient.putItem(PutItemRequest.builder()
|
|
||||||
.tableName(tableName)
|
|
||||||
.item(Map.of(
|
|
||||||
KEY_PATTERN, AttributeValues.fromString(pattern),
|
|
||||||
ATTR_RESERVED_FOR_UUID, AttributeValues.fromUUID(reservedFor)))
|
|
||||||
.build());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -50,7 +50,6 @@ import org.whispersystems.textsecuregcm.storage.MessagesManager;
|
||||||
import org.whispersystems.textsecuregcm.storage.PhoneNumberIdentifiers;
|
import org.whispersystems.textsecuregcm.storage.PhoneNumberIdentifiers;
|
||||||
import org.whispersystems.textsecuregcm.storage.Profiles;
|
import org.whispersystems.textsecuregcm.storage.Profiles;
|
||||||
import org.whispersystems.textsecuregcm.storage.ProfilesManager;
|
import org.whispersystems.textsecuregcm.storage.ProfilesManager;
|
||||||
import org.whispersystems.textsecuregcm.storage.ProhibitedUsernames;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.RegistrationRecoveryPasswords;
|
import org.whispersystems.textsecuregcm.storage.RegistrationRecoveryPasswords;
|
||||||
import org.whispersystems.textsecuregcm.storage.RegistrationRecoveryPasswordsManager;
|
import org.whispersystems.textsecuregcm.storage.RegistrationRecoveryPasswordsManager;
|
||||||
import org.whispersystems.textsecuregcm.storage.ReportMessageDynamoDb;
|
import org.whispersystems.textsecuregcm.storage.ReportMessageDynamoDb;
|
||||||
|
@ -176,8 +175,6 @@ public class AssignUsernameCommand extends EnvironmentCommand<WhisperServerConfi
|
||||||
configuration.getDynamoDbTables().getPhoneNumberIdentifiers().getTableName());
|
configuration.getDynamoDbTables().getPhoneNumberIdentifiers().getTableName());
|
||||||
Profiles profiles = new Profiles(dynamoDbClient, dynamoDbAsyncClient,
|
Profiles profiles = new Profiles(dynamoDbClient, dynamoDbAsyncClient,
|
||||||
configuration.getDynamoDbTables().getProfiles().getTableName());
|
configuration.getDynamoDbTables().getProfiles().getTableName());
|
||||||
ProhibitedUsernames prohibitedUsernames = new ProhibitedUsernames(dynamoDbClient,
|
|
||||||
configuration.getDynamoDbTables().getReservedUsernames().getTableName());
|
|
||||||
Keys keys = new Keys(dynamoDbClient,
|
Keys keys = new Keys(dynamoDbClient,
|
||||||
configuration.getDynamoDbTables().getKeys().getTableName());
|
configuration.getDynamoDbTables().getKeys().getTableName());
|
||||||
MessagesDynamoDb messagesDynamoDb = new MessagesDynamoDb(dynamoDbClient, dynamoDbAsyncClient,
|
MessagesDynamoDb messagesDynamoDb = new MessagesDynamoDb(dynamoDbClient, dynamoDbAsyncClient,
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2013-2021 Signal Messenger, LLC
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.whispersystems.textsecuregcm.workers;
|
|
||||||
|
|
||||||
import io.dropwizard.cli.ConfiguredCommand;
|
|
||||||
import io.dropwizard.setup.Bootstrap;
|
|
||||||
import net.sourceforge.argparse4j.inf.Namespace;
|
|
||||||
import net.sourceforge.argparse4j.inf.Subparser;
|
|
||||||
import org.whispersystems.textsecuregcm.WhisperServerConfiguration;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.ProhibitedUsernames;
|
|
||||||
import org.whispersystems.textsecuregcm.util.DynamoDbFromConfig;
|
|
||||||
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
public class ReserveUsernameCommand extends ConfiguredCommand<WhisperServerConfiguration> {
|
|
||||||
|
|
||||||
public ReserveUsernameCommand() {
|
|
||||||
super("reserve-username", "Reserve a username pattern for a specific account identifier");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void configure(final Subparser subparser) {
|
|
||||||
super.configure(subparser);
|
|
||||||
|
|
||||||
subparser.addArgument("-p", "--pattern")
|
|
||||||
.dest("pattern")
|
|
||||||
.type(String.class)
|
|
||||||
.required(true);
|
|
||||||
|
|
||||||
subparser.addArgument("-u", "--uuid")
|
|
||||||
.dest("uuid")
|
|
||||||
.type(String.class)
|
|
||||||
.required(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void run(final Bootstrap<WhisperServerConfiguration> bootstrap, final Namespace namespace,
|
|
||||||
final WhisperServerConfiguration config) throws Exception {
|
|
||||||
|
|
||||||
final DynamoDbClient dynamoDbClient = DynamoDbFromConfig.client(config.getDynamoDbClientConfiguration(),
|
|
||||||
software.amazon.awssdk.auth.credentials.InstanceProfileCredentialsProvider.create());
|
|
||||||
|
|
||||||
final ProhibitedUsernames prohibitedUsernames = new ProhibitedUsernames(dynamoDbClient,
|
|
||||||
config.getDynamoDbTables().getReservedUsernames().getTableName());
|
|
||||||
|
|
||||||
final String pattern = namespace.getString("pattern").trim();
|
|
||||||
|
|
||||||
try {
|
|
||||||
Pattern.compile(pattern);
|
|
||||||
} catch (final Exception e) {
|
|
||||||
throw new IllegalArgumentException("Bad pattern: " + pattern, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
final UUID aci = UUID.fromString(namespace.getString("uuid").trim());
|
|
||||||
|
|
||||||
prohibitedUsernames.prohibitUsername(pattern, aci);
|
|
||||||
|
|
||||||
System.out.format("Reserved %s for account %s\n", pattern, aci);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue