diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/AccountController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/AccountController.java index 9384c2ffa..53516a2e1 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/AccountController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/AccountController.java @@ -274,7 +274,6 @@ public class AccountController { @ApiResponse(responseCode = "204", description = "Username successfully deleted.", useReturnTypeSchema = true) @ApiResponse(responseCode = "401", description = "Account authentication check failed.") public CompletableFuture deleteUsernameHash(@Auth final AuthenticatedAccount auth) { - clearUsernameLink(auth.getAccount()); return accounts.clearUsernameHash(auth.getAccount()) .thenRun(Util.NOOP); } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/storage/Accounts.java b/service/src/main/java/org/whispersystems/textsecuregcm/storage/Accounts.java index 9ea0d9e61..2b67c1972 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/storage/Accounts.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/storage/Accounts.java @@ -537,22 +537,27 @@ public class Accounts extends AbstractDynamoDbStore { return account.getUsernameHash().map(usernameHash -> { final Timer.Sample sample = Timer.start(); + @Nullable final UUID originalLinkHandle = account.getUsernameLinkHandle(); + @Nullable final byte[] originalEncryptedUsername = account.getEncryptedUsername().orElse(null); + final TransactWriteItemsRequest request; try { final List writeItems = new ArrayList<>(); account.setUsernameHash(null); + account.setUsernameLinkDetails(null, null); writeItems.add( TransactWriteItem.builder() .update(Update.builder() .tableName(accountsTableName) .key(Map.of(KEY_ACCOUNT_UUID, AttributeValues.fromUUID(account.getUuid()))) - .updateExpression("SET #data = :data REMOVE #username_hash ADD #version :version_increment") + .updateExpression("SET #data = :data REMOVE #username_hash, #username_link ADD #version :version_increment") .conditionExpression("#version = :version") .expressionAttributeNames(Map.of("#data", ATTR_ACCOUNT_DATA, "#username_hash", ATTR_USERNAME_HASH, + "#username_link", ATTR_USERNAME_LINK_UUID, "#version", ATTR_VERSION)) .expressionAttributeValues(Map.of( ":data", accountDataAttributeValue(account), @@ -570,11 +575,14 @@ public class Accounts extends AbstractDynamoDbStore { throw new IllegalArgumentException(e); } finally { account.setUsernameHash(usernameHash); + account.setUsernameLinkDetails(originalLinkHandle, originalEncryptedUsername); } return asyncClient.transactWriteItems(request) .thenAccept(ignored -> { account.setUsernameHash(null); + account.setUsernameLinkDetails(null, null); + account.setVersion(account.getVersion() + 1); }) .exceptionally(throwable -> { diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsTest.java index d943b3409..0b5973bca 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsTest.java @@ -837,7 +837,11 @@ class AccountsTest { assertThat(accounts.getByUsernameHash(USERNAME_HASH_1).join()).isEmpty(); assertThat(accounts.getByAccountIdentifier(account.getUuid())) - .hasValueSatisfying(clearedAccount -> assertThat(clearedAccount.getUsernameHash()).isEmpty()); + .hasValueSatisfying(clearedAccount -> { + assertThat(clearedAccount.getUsernameHash()).isEmpty(); + assertThat(clearedAccount.getUsernameLinkHandle()).isNull(); + assertThat(clearedAccount.getEncryptedUsername().isEmpty()); + }); } @Test