mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-21 09:10:35 +01:00
Create accounts transactionally
This commit is contained in:
committed by
Jon Chambers
parent
07c04006df
commit
c8033f875d
@@ -342,8 +342,8 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
||||
config.getDynamoDbTables().getPhoneNumberIdentifiers().getTableName());
|
||||
Profiles profiles = new Profiles(dynamoDbClient, dynamoDbAsyncClient,
|
||||
config.getDynamoDbTables().getProfiles().getTableName());
|
||||
KeysManager keys = new KeysManager(
|
||||
dynamoDbAsyncClient,
|
||||
KeysManager keysManager = new KeysManager(
|
||||
dynamoDbAsyncClient,
|
||||
config.getDynamoDbTables().getEcKeys().getTableName(),
|
||||
config.getDynamoDbTables().getKemKeys().getTableName(),
|
||||
config.getDynamoDbTables().getEcSignedPreKeys().getTableName(),
|
||||
@@ -525,7 +525,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
||||
AccountLockManager accountLockManager = new AccountLockManager(dynamoDbClient,
|
||||
config.getDynamoDbTables().getDeletedAccountsLock().getTableName());
|
||||
AccountsManager accountsManager = new AccountsManager(accounts, phoneNumberIdentifiers, cacheCluster,
|
||||
accountLockManager, keys, messagesManager, profilesManager,
|
||||
accountLockManager, keysManager, messagesManager, profilesManager,
|
||||
secureStorageClient, secureValueRecovery2Client,
|
||||
clientPresenceManager,
|
||||
experimentEnrollmentManager, registrationRecoveryPasswordsManager, accountLockExecutor, clock);
|
||||
@@ -669,8 +669,8 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
||||
.addService(new AccountsAnonymousGrpcService(accountsManager, rateLimiters))
|
||||
.addService(ExternalServiceCredentialsGrpcService.createForAllExternalServices(config, rateLimiters))
|
||||
.addService(ExternalServiceCredentialsAnonymousGrpcService.create(accountsManager, config))
|
||||
.addService(ServerInterceptors.intercept(new KeysGrpcService(accountsManager, keys, rateLimiters), basicCredentialAuthenticationInterceptor))
|
||||
.addService(new KeysAnonymousGrpcService(accountsManager, keys))
|
||||
.addService(ServerInterceptors.intercept(new KeysGrpcService(accountsManager, keysManager, rateLimiters), basicCredentialAuthenticationInterceptor))
|
||||
.addService(new KeysAnonymousGrpcService(accountsManager, keysManager))
|
||||
.addService(new PaymentsGrpcService(currencyManager))
|
||||
.addService(ServerInterceptors.intercept(new ProfileGrpcService(clock, accountsManager, profilesManager, dynamicConfigurationManager,
|
||||
config.getBadges(), asyncCdnS3Client, profileCdnPolicyGenerator, profileCdnPolicySigner, profileBadgeConverter, rateLimiters, zkProfileOperations, config.getCdnConfiguration().bucket()), basicCredentialAuthenticationInterceptor))
|
||||
@@ -725,7 +725,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
||||
turnTokenGenerator,
|
||||
registrationRecoveryPasswordsManager, usernameHashZkProofVerifier));
|
||||
|
||||
environment.jersey().register(new KeysController(rateLimiters, keys, accountsManager));
|
||||
environment.jersey().register(new KeysController(rateLimiters, keysManager, accountsManager));
|
||||
|
||||
boolean registeredSpamFilter = false;
|
||||
ReportSpamTokenProvider reportSpamTokenProvider = null;
|
||||
@@ -784,7 +784,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
||||
new CallLinkController(rateLimiters, callingGenericZkSecretParams),
|
||||
new CertificateController(new CertificateGenerator(config.getDeliveryCertificate().certificate().value(), config.getDeliveryCertificate().ecPrivateKey(), config.getDeliveryCertificate().expiresDays()), zkAuthOperations, callingGenericZkSecretParams, clock),
|
||||
new ChallengeController(rateLimitChallengeManager),
|
||||
new DeviceController(config.getLinkDeviceSecretConfiguration().secret().value(), accountsManager, messagesManager, keys, rateLimiters,
|
||||
new DeviceController(config.getLinkDeviceSecretConfiguration().secret().value(), accountsManager, messagesManager, keysManager, rateLimiters,
|
||||
rateLimitersCluster, config.getMaxDevices(), clock),
|
||||
new DirectoryV2Controller(directoryV2CredentialsGenerator),
|
||||
new DonationController(clock, zkReceiptOperations, redeemedReceiptsManager, accountsManager, config.getBadges(),
|
||||
@@ -799,7 +799,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
||||
config.getCdnConfiguration().bucket(), zkProfileOperations, batchIdentityCheckExecutor),
|
||||
new ProvisioningController(rateLimiters, provisioningManager),
|
||||
new RegistrationController(accountsManager, phoneVerificationTokenManager, registrationLockVerificationManager,
|
||||
keys, rateLimiters),
|
||||
rateLimiters),
|
||||
new RemoteConfigController(remoteConfigsManager, adminEventLogger,
|
||||
config.getRemoteConfigConfiguration().authorizedUsers(),
|
||||
config.getRemoteConfigConfiguration().requiredHostedDomain(),
|
||||
|
||||
@@ -20,9 +20,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.ws.rs.Consumes;
|
||||
@@ -45,8 +43,6 @@ import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||
import org.whispersystems.textsecuregcm.metrics.UserAgentTagUtil;
|
||||
import org.whispersystems.textsecuregcm.storage.Account;
|
||||
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||
import org.whispersystems.textsecuregcm.storage.Device;
|
||||
import org.whispersystems.textsecuregcm.storage.KeysManager;
|
||||
import org.whispersystems.textsecuregcm.util.HeaderUtils;
|
||||
import org.whispersystems.textsecuregcm.util.Util;
|
||||
|
||||
@@ -69,18 +65,16 @@ public class RegistrationController {
|
||||
private final AccountsManager accounts;
|
||||
private final PhoneVerificationTokenManager phoneVerificationTokenManager;
|
||||
private final RegistrationLockVerificationManager registrationLockVerificationManager;
|
||||
private final KeysManager keysManager;
|
||||
private final RateLimiters rateLimiters;
|
||||
|
||||
public RegistrationController(final AccountsManager accounts,
|
||||
final PhoneVerificationTokenManager phoneVerificationTokenManager,
|
||||
final RegistrationLockVerificationManager registrationLockVerificationManager,
|
||||
final KeysManager keysManager,
|
||||
final RateLimiters rateLimiters) {
|
||||
|
||||
this.accounts = accounts;
|
||||
this.phoneVerificationTokenManager = phoneVerificationTokenManager;
|
||||
this.registrationLockVerificationManager = registrationLockVerificationManager;
|
||||
this.keysManager = keysManager;
|
||||
this.rateLimiters = rateLimiters;
|
||||
}
|
||||
|
||||
@@ -141,37 +135,19 @@ public class RegistrationController {
|
||||
userAgent, RegistrationLockVerificationManager.Flow.REGISTRATION, verificationType);
|
||||
}
|
||||
|
||||
Account account = accounts.create(number, password, signalAgent, registrationRequest.accountAttributes(),
|
||||
existingAccount.map(Account::getBadges).orElseGet(ArrayList::new));
|
||||
|
||||
account = accounts.update(account, a -> {
|
||||
a.setIdentityKey(registrationRequest.aciIdentityKey());
|
||||
a.setPhoneNumberIdentityKey(registrationRequest.pniIdentityKey());
|
||||
|
||||
final Device device = a.getPrimaryDevice().orElseThrow();
|
||||
|
||||
device.setSignedPreKey(registrationRequest.deviceActivationRequest().aciSignedPreKey());
|
||||
device.setPhoneNumberIdentitySignedPreKey(registrationRequest.deviceActivationRequest().pniSignedPreKey());
|
||||
|
||||
registrationRequest.deviceActivationRequest().apnToken().ifPresent(apnRegistrationId -> {
|
||||
device.setApnId(apnRegistrationId.apnRegistrationId());
|
||||
device.setVoipApnId(apnRegistrationId.voipRegistrationId());
|
||||
});
|
||||
|
||||
registrationRequest.deviceActivationRequest().gcmToken().ifPresent(gcmRegistrationId ->
|
||||
device.setGcmId(gcmRegistrationId.gcmRegistrationId()));
|
||||
|
||||
CompletableFuture.allOf(
|
||||
keysManager.storeEcSignedPreKeys(a.getUuid(),
|
||||
Map.of(Device.PRIMARY_ID, registrationRequest.deviceActivationRequest().aciSignedPreKey())),
|
||||
keysManager.storePqLastResort(a.getUuid(),
|
||||
Map.of(Device.PRIMARY_ID, registrationRequest.deviceActivationRequest().aciPqLastResortPreKey())),
|
||||
keysManager.storeEcSignedPreKeys(a.getPhoneNumberIdentifier(),
|
||||
Map.of(Device.PRIMARY_ID, registrationRequest.deviceActivationRequest().pniSignedPreKey())),
|
||||
keysManager.storePqLastResort(a.getPhoneNumberIdentifier(),
|
||||
Map.of(Device.PRIMARY_ID, registrationRequest.deviceActivationRequest().pniPqLastResortPreKey())))
|
||||
.join();
|
||||
});
|
||||
final Account account = accounts.create(number,
|
||||
password,
|
||||
signalAgent,
|
||||
registrationRequest.accountAttributes(),
|
||||
existingAccount.map(Account::getBadges).orElseGet(ArrayList::new),
|
||||
registrationRequest.aciIdentityKey(),
|
||||
registrationRequest.pniIdentityKey(),
|
||||
registrationRequest.deviceActivationRequest().aciSignedPreKey(),
|
||||
registrationRequest.deviceActivationRequest().pniSignedPreKey(),
|
||||
registrationRequest.deviceActivationRequest().aciPqLastResortPreKey(),
|
||||
registrationRequest.deviceActivationRequest().pniPqLastResortPreKey(),
|
||||
registrationRequest.deviceActivationRequest().apnToken(),
|
||||
registrationRequest.deviceActivationRequest().gcmToken());
|
||||
|
||||
Metrics.counter(ACCOUNT_CREATED_COUNTER_NAME, Tags.of(UserAgentTagUtil.getPlatformTag(userAgent),
|
||||
Tag.of(COUNTRY_CODE_TAG_NAME, Util.getCountryCode(number)),
|
||||
|
||||
@@ -19,6 +19,7 @@ import java.time.Clock;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -28,6 +29,7 @@ import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Nonnull;
|
||||
@@ -157,6 +159,7 @@ public class Accounts extends AbstractDynamoDbStore {
|
||||
final String phoneNumberIdentifierConstraintTableName,
|
||||
final String usernamesConstraintTableName,
|
||||
final String deletedAccountsTableName) {
|
||||
|
||||
super(client);
|
||||
this.clock = clock;
|
||||
this.asyncClient = asyncClient;
|
||||
@@ -175,12 +178,14 @@ public class Accounts extends AbstractDynamoDbStore {
|
||||
final String phoneNumberIdentifierConstraintTableName,
|
||||
final String usernamesConstraintTableName,
|
||||
final String deletedAccountsTableName) {
|
||||
|
||||
this(Clock.systemUTC(), client, asyncClient, accountsTableName,
|
||||
phoneNumberConstraintTableName, phoneNumberIdentifierConstraintTableName, usernamesConstraintTableName,
|
||||
deletedAccountsTableName);
|
||||
}
|
||||
|
||||
public boolean create(final Account account) {
|
||||
public boolean create(final Account account, final Function<Account, Collection<TransactWriteItem>> additionalWriteItemsFunction) {
|
||||
|
||||
return CREATE_TIMER.record(() -> {
|
||||
try {
|
||||
final AttributeValue uuidAttr = AttributeValues.fromUUID(account.getUuid());
|
||||
@@ -199,8 +204,13 @@ public class Accounts extends AbstractDynamoDbStore {
|
||||
// the newly-created account.
|
||||
final TransactWriteItem deletedAccountDelete = buildRemoveDeletedAccount(account.getNumber());
|
||||
|
||||
final Collection<TransactWriteItem> writeItems = new ArrayList<>(
|
||||
List.of(phoneNumberConstraintPut, phoneNumberIdentifierConstraintPut, accountPut, deletedAccountDelete));
|
||||
|
||||
writeItems.addAll(additionalWriteItemsFunction.apply(account));
|
||||
|
||||
final TransactWriteItemsRequest request = TransactWriteItemsRequest.builder()
|
||||
.transactItems(phoneNumberConstraintPut, phoneNumberIdentifierConstraintPut, accountPut, deletedAccountDelete)
|
||||
.transactItems(writeItems)
|
||||
.build();
|
||||
|
||||
try {
|
||||
@@ -229,7 +239,8 @@ public class Accounts extends AbstractDynamoDbStore {
|
||||
account.setUuid(UUIDUtil.fromByteBuffer(actualAccountUuid));
|
||||
final Account existingAccount = getByAccountIdentifier(account.getUuid()).orElseThrow();
|
||||
account.setNumber(existingAccount.getNumber(), existingAccount.getPhoneNumberIdentifier());
|
||||
joinAndUnwrapUpdateFuture(reclaimAccount(existingAccount, account));
|
||||
joinAndUnwrapUpdateFuture(reclaimAccount(existingAccount, account, additionalWriteItemsFunction.apply(account)));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -254,7 +265,7 @@ public class Accounts extends AbstractDynamoDbStore {
|
||||
* @param existingAccount the existing account in the accounts table
|
||||
* @param accountToCreate a new account, with the same number and identifier as existingAccount
|
||||
*/
|
||||
private CompletionStage<Void> reclaimAccount(final Account existingAccount, final Account accountToCreate) {
|
||||
private CompletionStage<Void> reclaimAccount(final Account existingAccount, final Account accountToCreate, final Collection<TransactWriteItem> additionalWriteItems) {
|
||||
if (!existingAccount.getUuid().equals(accountToCreate.getUuid()) ||
|
||||
!existingAccount.getNumber().equals(accountToCreate.getNumber())) {
|
||||
throw new IllegalArgumentException("reclaimed accounts must match");
|
||||
@@ -310,6 +321,7 @@ public class Accounts extends AbstractDynamoDbStore {
|
||||
.build());
|
||||
}
|
||||
writeItems.add(UpdateAccountSpec.forAccount(accountsTableName, accountToCreate).transactItem());
|
||||
writeItems.addAll(additionalWriteItems);
|
||||
|
||||
return asyncClient.transactWriteItems(TransactWriteItemsRequest.builder().transactItems(writeItems).build())
|
||||
.thenApply(response -> {
|
||||
|
||||
@@ -53,7 +53,9 @@ import org.slf4j.LoggerFactory;
|
||||
import org.whispersystems.textsecuregcm.auth.SaltedTokenHash;
|
||||
import org.whispersystems.textsecuregcm.controllers.MismatchedDevicesException;
|
||||
import org.whispersystems.textsecuregcm.entities.AccountAttributes;
|
||||
import org.whispersystems.textsecuregcm.entities.ApnRegistrationId;
|
||||
import org.whispersystems.textsecuregcm.entities.ECSignedPreKey;
|
||||
import org.whispersystems.textsecuregcm.entities.GcmRegistrationId;
|
||||
import org.whispersystems.textsecuregcm.entities.KEMSignedPreKey;
|
||||
import org.whispersystems.textsecuregcm.experiment.ExperimentEnrollmentManager;
|
||||
import org.whispersystems.textsecuregcm.identity.IdentityType;
|
||||
@@ -175,17 +177,26 @@ public class AccountsManager {
|
||||
this.clock = requireNonNull(clock);
|
||||
}
|
||||
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
public Account create(final String number,
|
||||
final String password,
|
||||
final String signalAgent,
|
||||
final AccountAttributes accountAttributes,
|
||||
final List<AccountBadge> accountBadges) throws InterruptedException {
|
||||
final List<AccountBadge> accountBadges,
|
||||
final IdentityKey aciIdentityKey,
|
||||
final IdentityKey pniIdentityKey,
|
||||
final ECSignedPreKey aciSignedPreKey,
|
||||
final ECSignedPreKey pniSignedPreKey,
|
||||
final KEMSignedPreKey aciPqLastResortPreKey,
|
||||
final KEMSignedPreKey pniPqLastResortPreKey,
|
||||
final Optional<ApnRegistrationId> maybeApnRegistrationId,
|
||||
final Optional<GcmRegistrationId> maybeGcmRegistrationId) throws InterruptedException {
|
||||
|
||||
try (Timer.Context ignored = createTimer.time()) {
|
||||
final Account account = new Account();
|
||||
|
||||
accountLockManager.withLock(List.of(number), () -> {
|
||||
Device device = new Device();
|
||||
final Device device = new Device();
|
||||
device.setId(Device.PRIMARY_ID);
|
||||
device.setAuthTokenHash(SaltedTokenHash.generateFor(password));
|
||||
device.setFetchesMessages(accountAttributes.getFetchesMessages());
|
||||
@@ -196,6 +207,16 @@ public class AccountsManager {
|
||||
device.setCreated(System.currentTimeMillis());
|
||||
device.setLastSeen(Util.todayInMillis());
|
||||
device.setUserAgent(signalAgent);
|
||||
device.setSignedPreKey(aciSignedPreKey);
|
||||
device.setPhoneNumberIdentitySignedPreKey(pniSignedPreKey);
|
||||
|
||||
maybeApnRegistrationId.ifPresent(apnRegistrationId -> {
|
||||
device.setApnId(apnRegistrationId.apnRegistrationId());
|
||||
device.setVoipApnId(apnRegistrationId.voipRegistrationId());
|
||||
});
|
||||
|
||||
maybeGcmRegistrationId.ifPresent(gcmRegistrationId ->
|
||||
device.setGcmId(gcmRegistrationId.gcmRegistrationId()));
|
||||
|
||||
account.setNumber(number, phoneNumberIdentifiers.getPhoneNumberIdentifier(number));
|
||||
|
||||
@@ -205,6 +226,8 @@ public class AccountsManager {
|
||||
// Reuse the ACI from any recently-deleted account with this number to cover cases where somebody is
|
||||
// re-registering.
|
||||
account.setUuid(maybeRecentlyDeletedAccountIdentifier.orElseGet(UUID::randomUUID));
|
||||
account.setIdentityKey(aciIdentityKey);
|
||||
account.setPhoneNumberIdentityKey(pniIdentityKey);
|
||||
account.addDevice(device);
|
||||
account.setRegistrationLockFromAttributes(accountAttributes);
|
||||
account.setUnidentifiedAccessKey(accountAttributes.getUnidentifiedAccessKey());
|
||||
@@ -214,7 +237,14 @@ public class AccountsManager {
|
||||
|
||||
final UUID originalUuid = account.getUuid();
|
||||
|
||||
boolean freshUser = accounts.create(account);
|
||||
final boolean freshUser = accounts.create(account,
|
||||
a -> keysManager.buildWriteItemsForRepeatedUseKeys(a.getIdentifier(IdentityType.ACI),
|
||||
a.getIdentifier(IdentityType.PNI),
|
||||
Device.PRIMARY_ID,
|
||||
aciSignedPreKey,
|
||||
pniSignedPreKey,
|
||||
aciPqLastResortPreKey,
|
||||
pniPqLastResortPreKey));
|
||||
|
||||
// create() sometimes updates the UUID, if there was a number conflict.
|
||||
// for metrics, we want secondary to run with the same original UUID
|
||||
@@ -235,9 +265,11 @@ public class AccountsManager {
|
||||
// confident that everything has already been deleted. In the second case, though, we're taking over an existing
|
||||
// account and need to clear out messages and keys that may have been stored for the old account.
|
||||
if (!originalUuid.equals(actualUuid)) {
|
||||
// We exclude the primary device's repeated-use keys from deletion because new keys were provided as part of
|
||||
// the account creation process, and we don't want to delete the keys that just got added.
|
||||
final CompletableFuture<Void> deleteKeysFuture = CompletableFuture.allOf(
|
||||
keysManager.delete(actualUuid),
|
||||
keysManager.delete(account.getPhoneNumberIdentifier()));
|
||||
keysManager.delete(actualUuid, true),
|
||||
keysManager.delete(account.getPhoneNumberIdentifier(), true));
|
||||
|
||||
messagesManager.clear(actualUuid).join();
|
||||
profilesManager.deleteAll(actualUuid).join();
|
||||
|
||||
@@ -18,6 +18,7 @@ import org.whispersystems.textsecuregcm.entities.ECPreKey;
|
||||
import org.whispersystems.textsecuregcm.entities.ECSignedPreKey;
|
||||
import org.whispersystems.textsecuregcm.entities.KEMSignedPreKey;
|
||||
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
|
||||
import software.amazon.awssdk.services.dynamodb.model.TransactWriteItem;
|
||||
|
||||
public class KeysManager {
|
||||
|
||||
@@ -75,6 +76,20 @@ public class KeysManager {
|
||||
return CompletableFuture.allOf(storeFutures.toArray(new CompletableFuture[0]));
|
||||
}
|
||||
|
||||
public List<TransactWriteItem> buildWriteItemsForRepeatedUseKeys(final UUID accountIdentifier,
|
||||
final UUID phoneNumberIdentifier,
|
||||
final byte deviceId,
|
||||
final ECSignedPreKey aciSignedPreKey,
|
||||
final ECSignedPreKey pniSignedPreKey,
|
||||
final KEMSignedPreKey aciPqLastResortPreKey,
|
||||
final KEMSignedPreKey pniLastResortPreKey) {
|
||||
|
||||
return List.of(ecSignedPreKeys.buildTransactWriteItem(accountIdentifier, deviceId, aciSignedPreKey),
|
||||
ecSignedPreKeys.buildTransactWriteItem(phoneNumberIdentifier, deviceId, pniSignedPreKey),
|
||||
pqLastResortKeys.buildTransactWriteItem(accountIdentifier, deviceId, aciPqLastResortPreKey),
|
||||
pqLastResortKeys.buildTransactWriteItem(phoneNumberIdentifier, deviceId, pniLastResortPreKey));
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> storeEcSignedPreKeys(final UUID identifier, final Map<Byte, ECSignedPreKey> keys) {
|
||||
if (dynamicConfigurationManager.getConfiguration().getEcPreKeyMigrationConfiguration().storeEcSignedPreKeys()) {
|
||||
return ecSignedPreKeys.store(identifier, keys);
|
||||
@@ -134,14 +149,18 @@ public class KeysManager {
|
||||
return pqPreKeys.getCount(identifier, deviceId);
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> delete(final UUID accountUuid) {
|
||||
public CompletableFuture<Void> delete(final UUID identifier) {
|
||||
return delete(identifier, false);
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> delete(final UUID identifier, final boolean excludePrimaryDevice) {
|
||||
return CompletableFuture.allOf(
|
||||
ecPreKeys.delete(accountUuid),
|
||||
pqPreKeys.delete(accountUuid),
|
||||
dynamicConfigurationManager.getConfiguration().getEcPreKeyMigrationConfiguration().deleteEcSignedPreKeys()
|
||||
? ecSignedPreKeys.delete(accountUuid)
|
||||
: CompletableFuture.completedFuture(null),
|
||||
pqLastResortKeys.delete(accountUuid));
|
||||
ecPreKeys.delete(identifier),
|
||||
pqPreKeys.delete(identifier),
|
||||
dynamicConfigurationManager.getConfiguration().getEcPreKeyMigrationConfiguration().deleteEcSignedPreKeys()
|
||||
? ecSignedPreKeys.delete(identifier, excludePrimaryDevice)
|
||||
: CompletableFuture.completedFuture(null),
|
||||
pqLastResortKeys.delete(identifier, excludePrimaryDevice));
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> delete(final UUID accountUuid, final byte deviceId) {
|
||||
|
||||
@@ -112,6 +112,15 @@ public abstract class RepeatedUseSignedPreKeyStore<K extends SignedPreKey<?>> {
|
||||
.thenRun(() -> sample.stop(storeKeyBatchTimer));
|
||||
}
|
||||
|
||||
TransactWriteItem buildTransactWriteItem(final UUID identifier, final byte deviceId, final K preKey) {
|
||||
return TransactWriteItem.builder()
|
||||
.put(Put.builder()
|
||||
.tableName(tableName)
|
||||
.item(getItemFromPreKey(identifier, deviceId, preKey))
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a repeated-use pre-key for a specific device.
|
||||
*
|
||||
@@ -142,14 +151,19 @@ public abstract class RepeatedUseSignedPreKeyStore<K extends SignedPreKey<?>> {
|
||||
* Clears all repeated-use pre-keys associated with the given account/identity.
|
||||
*
|
||||
* @param identifier the identifier for the account/identity for which to clear repeated-use pre-keys
|
||||
* @param excludePrimaryDevice whether to exclude the primary device from repeated-use key deletion; this is intended
|
||||
* for cases when a user "re-registers" and displaces an existing account record and has
|
||||
* provided new repeated-use keys for the primary device in the process of creating the
|
||||
* new account
|
||||
*
|
||||
* @return a future that completes once repeated-use pre-keys have been cleared from all devices associated with the
|
||||
* target account/identity
|
||||
*/
|
||||
public CompletableFuture<Void> delete(final UUID identifier) {
|
||||
public CompletableFuture<Void> delete(final UUID identifier, final boolean excludePrimaryDevice) {
|
||||
final Timer.Sample sample = Timer.start();
|
||||
|
||||
return getDeviceIdsWithKeys(identifier)
|
||||
.filter(deviceId -> deviceId != Device.PRIMARY_ID || !excludePrimaryDevice)
|
||||
.map(deviceId -> DeleteItemRequest.builder()
|
||||
.tableName(tableName)
|
||||
.key(getPrimaryKey(identifier, deviceId))
|
||||
|
||||
Reference in New Issue
Block a user