mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-19 16:58:04 +01:00
Remove from svrb on account deletion
This commit is contained in:
@@ -205,7 +205,7 @@ import org.whispersystems.textsecuregcm.registration.RegistrationServiceClient;
|
||||
import org.whispersystems.textsecuregcm.s3.PolicySigner;
|
||||
import org.whispersystems.textsecuregcm.s3.PostPolicyGenerator;
|
||||
import org.whispersystems.textsecuregcm.securestorage.SecureStorageClient;
|
||||
import org.whispersystems.textsecuregcm.securevaluerecovery.SecureValueRecovery2Client;
|
||||
import org.whispersystems.textsecuregcm.securevaluerecovery.SecureValueRecoveryClient;
|
||||
import org.whispersystems.textsecuregcm.spam.ChallengeConstraintChecker;
|
||||
import org.whispersystems.textsecuregcm.spam.RegistrationFraudChecker;
|
||||
import org.whispersystems.textsecuregcm.spam.RegistrationRecoveryChecker;
|
||||
@@ -508,8 +508,8 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
||||
.maxThreads(1).minThreads(1).build();
|
||||
ExecutorService fcmSenderExecutor = environment.lifecycle().executorService(name(getClass(), "fcmSender-%d"))
|
||||
.maxThreads(32).minThreads(32).workQueue(fcmSenderQueue).build();
|
||||
ExecutorService secureValueRecovery2ServiceExecutor = environment.lifecycle()
|
||||
.executorService(name(getClass(), "secureValueRecoveryService2-%d")).maxThreads(1).minThreads(1).build();
|
||||
ExecutorService secureValueRecoveryServiceExecutor = environment.lifecycle()
|
||||
.executorService(name(getClass(), "secureValueRecoveryService-%d")).maxThreads(1).minThreads(1).build();
|
||||
ExecutorService storageServiceExecutor = environment.lifecycle()
|
||||
.executorService(name(getClass(), "storageService-%d")).maxThreads(1).minThreads(1).build();
|
||||
ExecutorService virtualThreadEventLoggerExecutor = environment.lifecycle()
|
||||
@@ -624,8 +624,18 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
||||
config.getKeyTransparencyServiceConfiguration().tlsCertificate(),
|
||||
config.getKeyTransparencyServiceConfiguration().clientCertificate(),
|
||||
config.getKeyTransparencyServiceConfiguration().clientPrivateKey().value());
|
||||
SecureValueRecovery2Client secureValueRecovery2Client = new SecureValueRecovery2Client(svr2CredentialsGenerator,
|
||||
secureValueRecovery2ServiceExecutor, secureValueRecoveryServiceRetryExecutor, config.getSvr2Configuration());
|
||||
SecureValueRecoveryClient secureValueRecovery2Client = new SecureValueRecoveryClient(
|
||||
svr2CredentialsGenerator,
|
||||
secureValueRecoveryServiceExecutor,
|
||||
secureValueRecoveryServiceRetryExecutor,
|
||||
config.getSvr2Configuration(),
|
||||
() -> dynamicConfigurationManager.getConfiguration().getSvr2StatusCodesToIgnoreForAccountDeletion());
|
||||
SecureValueRecoveryClient secureValueRecoveryBClient = new SecureValueRecoveryClient(
|
||||
svrbCredentialsGenerator,
|
||||
secureValueRecoveryServiceExecutor,
|
||||
secureValueRecoveryServiceRetryExecutor,
|
||||
config.getSvrbConfiguration(),
|
||||
() -> dynamicConfigurationManager.getConfiguration().getSvrbStatusCodesToIgnoreForAccountDeletion());
|
||||
SecureStorageClient secureStorageClient = new SecureStorageClient(storageCredentialsGenerator,
|
||||
storageServiceExecutor, storageServiceRetryExecutor, config.getSecureStorageServiceConfiguration());
|
||||
DisconnectionRequestManager disconnectionRequestManager = new DisconnectionRequestManager(pubsubClient, disconnectionRequestListenerExecutor);
|
||||
@@ -646,7 +656,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
||||
new ClientPublicKeysManager(clientPublicKeys, accountLockManager, accountLockExecutor);
|
||||
AccountsManager accountsManager = new AccountsManager(accounts, phoneNumberIdentifiers, cacheCluster,
|
||||
pubsubClient, accountLockManager, keysManager, messagesManager, profilesManager,
|
||||
secureStorageClient, secureValueRecovery2Client, disconnectionRequestManager,
|
||||
secureStorageClient, secureValueRecovery2Client, secureValueRecoveryBClient, disconnectionRequestManager,
|
||||
registrationRecoveryPasswordsManager, clientPublicKeysManager, accountLockExecutor, messagePollExecutor,
|
||||
clock, config.getLinkDeviceSecretConfiguration().secret().value(), dynamicConfigurationManager);
|
||||
RemoteConfigsManager remoteConfigsManager = new RemoteConfigsManager(remoteConfigs);
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
package org.whispersystems.textsecuregcm.configuration.dynamic;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.vdurmont.semver4j.Semver;
|
||||
import jakarta.validation.Valid;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@@ -14,7 +13,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import org.whispersystems.textsecuregcm.limits.RateLimiterConfig;
|
||||
import org.whispersystems.textsecuregcm.util.ua.ClientPlatform;
|
||||
|
||||
public class DynamicConfiguration {
|
||||
|
||||
@@ -60,7 +58,11 @@ public class DynamicConfiguration {
|
||||
|
||||
@JsonProperty
|
||||
@Valid
|
||||
List<String> svrStatusCodesToIgnoreForAccountDeletion = Collections.emptyList();
|
||||
List<Integer> svr2StatusCodesToIgnoreForAccountDeletion = Collections.emptyList();
|
||||
|
||||
@JsonProperty
|
||||
@Valid
|
||||
List<Integer> svrbStatusCodesToIgnoreForAccountDeletion = Collections.emptyList();
|
||||
|
||||
@JsonProperty
|
||||
@Valid
|
||||
@@ -108,8 +110,12 @@ public class DynamicConfiguration {
|
||||
return metricsConfiguration;
|
||||
}
|
||||
|
||||
public List<String> getSvrStatusCodesToIgnoreForAccountDeletion() {
|
||||
return svrStatusCodesToIgnoreForAccountDeletion;
|
||||
public List<Integer> getSvr2StatusCodesToIgnoreForAccountDeletion() {
|
||||
return svr2StatusCodesToIgnoreForAccountDeletion;
|
||||
}
|
||||
|
||||
public List<Integer> getSvrbStatusCodesToIgnoreForAccountDeletion() {
|
||||
return svrbStatusCodesToIgnoreForAccountDeletion;
|
||||
}
|
||||
|
||||
public DynamicRestDeprecationConfiguration restDeprecation() {
|
||||
|
||||
@@ -15,10 +15,14 @@ import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.function.Supplier;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
||||
import org.whispersystems.textsecuregcm.configuration.SecureValueRecoveryConfiguration;
|
||||
@@ -28,21 +32,26 @@ import org.whispersystems.textsecuregcm.util.HttpUtils;
|
||||
/**
|
||||
* A client for sending requests to Signal's secure value recovery v2 service on behalf of authenticated users.
|
||||
*/
|
||||
public class SecureValueRecovery2Client {
|
||||
public class SecureValueRecoveryClient {
|
||||
private static final Logger logger = LoggerFactory.getLogger(SecureValueRecoveryClient.class);
|
||||
|
||||
private final ExternalServiceCredentialsGenerator secureValueRecoveryCredentialsGenerator;
|
||||
private final URI deleteUri;
|
||||
private final Supplier<List<Integer>> allowedDeletionErrorStatusCodes;
|
||||
private final FaultTolerantHttpClient httpClient;
|
||||
|
||||
@VisibleForTesting
|
||||
static final String DELETE_PATH = "/v1/delete";
|
||||
|
||||
public SecureValueRecovery2Client(final ExternalServiceCredentialsGenerator secureValueRecoveryCredentialsGenerator,
|
||||
public SecureValueRecoveryClient(
|
||||
final ExternalServiceCredentialsGenerator secureValueRecoveryCredentialsGenerator,
|
||||
final Executor executor, final ScheduledExecutorService retryExecutor,
|
||||
final SecureValueRecoveryConfiguration configuration)
|
||||
final SecureValueRecoveryConfiguration configuration,
|
||||
Supplier<List<Integer>> allowedDeletionErrorStatusCodes)
|
||||
throws CertificateException {
|
||||
this.secureValueRecoveryCredentialsGenerator = secureValueRecoveryCredentialsGenerator;
|
||||
this.deleteUri = URI.create(configuration.uri()).resolve(DELETE_PATH);
|
||||
this.allowedDeletionErrorStatusCodes = allowedDeletionErrorStatusCodes;
|
||||
this.httpClient = FaultTolerantHttpClient.newBuilder()
|
||||
.withCircuitBreaker(configuration.circuitBreaker())
|
||||
.withRetry(configuration.retry())
|
||||
@@ -57,7 +66,7 @@ public class SecureValueRecovery2Client {
|
||||
.build();
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> deleteBackups(final UUID accountUuid) {
|
||||
public CompletableFuture<Void> removeData(final UUID accountUuid) {
|
||||
|
||||
final ExternalServiceCredentials credentials = secureValueRecoveryCredentialsGenerator.generateForUuid(accountUuid);
|
||||
|
||||
@@ -72,6 +81,13 @@ public class SecureValueRecovery2Client {
|
||||
return null;
|
||||
}
|
||||
|
||||
final List<Integer> allowedErrors = allowedDeletionErrorStatusCodes.get();
|
||||
if (allowedErrors.contains(response.statusCode())) {
|
||||
logger.warn("Ignoring failure to delete svr entry for account {} with status {}",
|
||||
accountUuid, response.statusCode());
|
||||
return null;
|
||||
}
|
||||
logger.warn("Failed to delete svr entry for account {} with status {}", accountUuid, response.statusCode());
|
||||
throw new SecureValueRecoveryException("Failed to delete backup", String.valueOf(response.statusCode()));
|
||||
});
|
||||
}
|
||||
@@ -45,7 +45,6 @@ import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executor;
|
||||
@@ -84,8 +83,7 @@ import org.whispersystems.textsecuregcm.redis.FaultTolerantPubSubConnection;
|
||||
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisClient;
|
||||
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisClusterClient;
|
||||
import org.whispersystems.textsecuregcm.securestorage.SecureStorageClient;
|
||||
import org.whispersystems.textsecuregcm.securevaluerecovery.SecureValueRecovery2Client;
|
||||
import org.whispersystems.textsecuregcm.securevaluerecovery.SecureValueRecoveryException;
|
||||
import org.whispersystems.textsecuregcm.securevaluerecovery.SecureValueRecoveryClient;
|
||||
import org.whispersystems.textsecuregcm.util.ExceptionUtils;
|
||||
import org.whispersystems.textsecuregcm.util.Pair;
|
||||
import org.whispersystems.textsecuregcm.util.SystemMapper;
|
||||
@@ -126,8 +124,8 @@ public class AccountsManager extends RedisPubSubAdapter<String, String> implemen
|
||||
private final MessagesManager messagesManager;
|
||||
private final ProfilesManager profilesManager;
|
||||
private final SecureStorageClient secureStorageClient;
|
||||
private final SecureValueRecovery2Client secureValueRecovery2Client;
|
||||
|
||||
private final SecureValueRecoveryClient secureValueRecovery2Client;
|
||||
private final SecureValueRecoveryClient secureValueRecoveryBClient;
|
||||
private final DisconnectionRequestManager disconnectionRequestManager;
|
||||
private final RegistrationRecoveryPasswordsManager registrationRecoveryPasswordsManager;
|
||||
private final ClientPublicKeysManager clientPublicKeysManager;
|
||||
@@ -209,7 +207,8 @@ public class AccountsManager extends RedisPubSubAdapter<String, String> implemen
|
||||
final MessagesManager messagesManager,
|
||||
final ProfilesManager profilesManager,
|
||||
final SecureStorageClient secureStorageClient,
|
||||
final SecureValueRecovery2Client secureValueRecovery2Client,
|
||||
final SecureValueRecoveryClient secureValueRecovery2Client,
|
||||
final SecureValueRecoveryClient secureValueRecoveryBClient,
|
||||
final DisconnectionRequestManager disconnectionRequestManager,
|
||||
final RegistrationRecoveryPasswordsManager registrationRecoveryPasswordsManager,
|
||||
final ClientPublicKeysManager clientPublicKeysManager,
|
||||
@@ -228,6 +227,7 @@ public class AccountsManager extends RedisPubSubAdapter<String, String> implemen
|
||||
this.profilesManager = profilesManager;
|
||||
this.secureStorageClient = secureStorageClient;
|
||||
this.secureValueRecovery2Client = secureValueRecovery2Client;
|
||||
this.secureValueRecoveryBClient = secureValueRecoveryBClient;
|
||||
this.disconnectionRequestManager = disconnectionRequestManager;
|
||||
this.registrationRecoveryPasswordsManager = requireNonNull(registrationRecoveryPasswordsManager);
|
||||
this.clientPublicKeysManager = clientPublicKeysManager;
|
||||
@@ -1292,20 +1292,10 @@ public class AccountsManager extends RedisPubSubAdapter<String, String> implemen
|
||||
account.getIdentifier(IdentityType.ACI),
|
||||
device.getId())))
|
||||
.toList();
|
||||
final CompletableFuture<Void> svr2DeleteBackupFuture = secureValueRecovery2Client.deleteBackups(account.getUuid())
|
||||
.exceptionally(ExceptionUtils.exceptionallyHandler(SecureValueRecoveryException.class, exception -> {
|
||||
final List<String> svrStatusCodesToIgnore = dynamicConfigurationManager.getConfiguration().getSvrStatusCodesToIgnoreForAccountDeletion();
|
||||
if (svrStatusCodesToIgnore.contains(exception.getStatusCode())) {
|
||||
logger.warn("Ignoring failure to delete svr2 backup for account: " + account.getUuid(), exception);
|
||||
return null;
|
||||
}
|
||||
logger.warn("Failed to delete svr2 backup for account: " + account.getUuid(), exception);
|
||||
throw new CompletionException(exception);
|
||||
}));
|
||||
|
||||
return CompletableFuture.allOf(
|
||||
secureStorageClient.deleteStoredData(account.getUuid()),
|
||||
svr2DeleteBackupFuture,
|
||||
secureValueRecovery2Client.removeData(account.getUuid()),
|
||||
secureValueRecoveryBClient.removeData(account.getUuid()),
|
||||
keysManager.deleteSingleUsePreKeys(account.getUuid()),
|
||||
keysManager.deleteSingleUsePreKeys(account.getPhoneNumberIdentifier()),
|
||||
messagesManager.clear(account.getUuid()),
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfigurati
|
||||
import org.whispersystems.textsecuregcm.controllers.SecureStorageController;
|
||||
import org.whispersystems.textsecuregcm.controllers.SecureValueRecovery2Controller;
|
||||
import org.whispersystems.textsecuregcm.experiment.ExperimentEnrollmentManager;
|
||||
import org.whispersystems.textsecuregcm.controllers.SecureValueRecoveryBController;
|
||||
import org.whispersystems.textsecuregcm.experiment.PushNotificationExperimentSamples;
|
||||
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||
import org.whispersystems.textsecuregcm.metrics.MicrometerAwsSdkMetricPublisher;
|
||||
@@ -45,7 +46,7 @@ import org.whispersystems.textsecuregcm.push.WebSocketConnectionEventManager;
|
||||
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisClient;
|
||||
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisClusterClient;
|
||||
import org.whispersystems.textsecuregcm.securestorage.SecureStorageClient;
|
||||
import org.whispersystems.textsecuregcm.securevaluerecovery.SecureValueRecovery2Client;
|
||||
import org.whispersystems.textsecuregcm.securevaluerecovery.SecureValueRecoveryClient;
|
||||
import org.whispersystems.textsecuregcm.storage.AccountLockManager;
|
||||
import org.whispersystems.textsecuregcm.storage.Accounts;
|
||||
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||
@@ -173,6 +174,8 @@ record CommandDependencies(
|
||||
configuration.getSecureStorageServiceConfiguration());
|
||||
ExternalServiceCredentialsGenerator secureValueRecovery2CredentialsGenerator = SecureValueRecovery2Controller.credentialsGenerator(
|
||||
configuration.getSvr2Configuration());
|
||||
ExternalServiceCredentialsGenerator secureValueRecoveryBCredentialsGenerator = SecureValueRecoveryBController.credentialsGenerator(
|
||||
configuration.getSvrbConfiguration());
|
||||
|
||||
final ExecutorService awsSdkMetricsExecutor = environment.lifecycle()
|
||||
.virtualExecutorService(MetricRegistry.name(WhisperServerService.class, "awsSdkMetrics-%d"));
|
||||
@@ -238,10 +241,18 @@ record CommandDependencies(
|
||||
.getRedisClusterConfiguration().build("messages", redisClientResourcesBuilder);
|
||||
FaultTolerantRedisClusterClient rateLimitersCluster = configuration.getRateLimitersCluster().build("rate_limiters",
|
||||
redisClientResourcesBuilder);
|
||||
SecureValueRecovery2Client secureValueRecovery2Client = new SecureValueRecovery2Client(
|
||||
secureValueRecovery2CredentialsGenerator, secureValueRecoveryServiceExecutor,
|
||||
SecureValueRecoveryClient secureValueRecovery2Client = new SecureValueRecoveryClient(
|
||||
secureValueRecovery2CredentialsGenerator,
|
||||
secureValueRecoveryServiceExecutor,
|
||||
secureValueRecoveryServiceRetryExecutor,
|
||||
configuration.getSvr2Configuration());
|
||||
configuration.getSvr2Configuration(),
|
||||
() -> dynamicConfigurationManager.getConfiguration().getSvr2StatusCodesToIgnoreForAccountDeletion());
|
||||
SecureValueRecoveryClient secureValueRecoveryBClient = new SecureValueRecoveryClient(
|
||||
secureValueRecoveryBCredentialsGenerator,
|
||||
secureValueRecoveryServiceExecutor,
|
||||
secureValueRecoveryServiceRetryExecutor,
|
||||
configuration.getSvrbConfiguration(),
|
||||
() -> dynamicConfigurationManager.getConfiguration().getSvrbStatusCodesToIgnoreForAccountDeletion());
|
||||
SecureStorageClient secureStorageClient = new SecureStorageClient(storageCredentialsGenerator,
|
||||
storageServiceExecutor, storageServiceRetryExecutor, configuration.getSecureStorageServiceConfiguration());
|
||||
DisconnectionRequestManager disconnectionRequestManager = new DisconnectionRequestManager(pubsubClient, disconnectionRequestListenerExecutor);
|
||||
@@ -264,7 +275,7 @@ record CommandDependencies(
|
||||
new RegistrationRecoveryPasswordsManager(registrationRecoveryPasswords);
|
||||
AccountsManager accountsManager = new AccountsManager(accounts, phoneNumberIdentifiers, cacheCluster,
|
||||
pubsubClient, accountLockManager, keys, messagesManager, profilesManager,
|
||||
secureStorageClient, secureValueRecovery2Client, disconnectionRequestManager,
|
||||
secureStorageClient, secureValueRecovery2Client, secureValueRecoveryBClient, disconnectionRequestManager,
|
||||
registrationRecoveryPasswordsManager, clientPublicKeysManager, accountLockExecutor, messagePollExecutor,
|
||||
clock, configuration.getLinkDeviceSecretConfiguration().secret().value(), dynamicConfigurationManager);
|
||||
RateLimiters rateLimiters = RateLimiters.create(dynamicConfigurationManager, rateLimitersCluster);
|
||||
|
||||
Reference in New Issue
Block a user