add an option to replace username ciphertext without rotating the link handle

This commit is contained in:
Jonathan Klabunde Tomer
2023-11-13 09:01:54 -08:00
committed by GitHub
parent a4a4204762
commit a83378a44e
7 changed files with 69 additions and 11 deletions

View File

@@ -410,9 +410,8 @@ public class AccountController {
summary = "Set username link",
description = """
Authenticated endpoint. For the given encrypted username generates a username link handle.
Username link handle could be used to lookup the encrypted username.
An account can only have one username link at a time. Calling this endpoint will reset previously stored
encrypted username and deactivate previous link handle.
The username link handle can be used to lookup the encrypted username.
An account can only have one username link at a time; this endpoint overwrites the previous encrypted username if there was one.
"""
)
@ApiResponse(responseCode = "200", description = "Username Link updated successfully.", useReturnTypeSchema = true)
@@ -426,12 +425,19 @@ public class AccountController {
// check ratelimiter for username link operations
rateLimiters.forDescriptor(RateLimiters.For.USERNAME_LINK_OPERATION).validate(auth.getAccount().getUuid());
final Account account = auth.getAccount();
// check if username hash is set for the account
if (auth.getAccount().getUsernameHash().isEmpty()) {
if (account.getUsernameHash().isEmpty()) {
throw new WebApplicationException(Status.CONFLICT);
}
final UUID usernameLinkHandle = UUID.randomUUID();
final UUID usernameLinkHandle;
if (encryptedUsername.keepLinkHandle() && account.getUsernameLinkHandle() != null) {
usernameLinkHandle = account.getUsernameLinkHandle();
} else {
usernameLinkHandle = UUID.randomUUID();
}
updateUsernameLink(auth.getAccount(), usernameLinkHandle, encryptedUsername.usernameLinkEncryptedValue());
return new UsernameLinkHandle(usernameLinkHandle);
}

View File

@@ -5,6 +5,7 @@
package org.whispersystems.textsecuregcm.entities;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -18,7 +19,17 @@ public record EncryptedUsername(
@NotNull
@Size(min = 1, max = EncryptedUsername.MAX_SIZE)
@Schema(type = "string", description = "the URL-safe base64 encoding of the encrypted username")
byte[] usernameLinkEncryptedValue) {
byte[] usernameLinkEncryptedValue,
@JsonProperty
@Schema(type = "boolean", description = "if set and the account already has an encrypted-username link handle, reuse the same link handle rather than generating a new one. The response will still have the link handle.")
boolean keepLinkHandle
) {
public static final int MAX_SIZE = 128;
public EncryptedUsername(final byte[] usernameLinkEncryptedValue) {
this(usernameLinkEncryptedValue, false);
}
}

View File

@@ -267,7 +267,12 @@ public class AccountsGrpcService extends ReactorAccountsGrpc.AccountsImplBase {
.asRuntimeException());
}
final UUID linkHandle = UUID.randomUUID();
final UUID linkHandle;
if (request.getKeepLinkHandle() && account.getUsernameLinkHandle() != null) {
linkHandle = account.getUsernameLinkHandle();
} else {
linkHandle = UUID.randomUUID();
}
return Mono.fromFuture(() -> accountsManager.updateAsync(account, a -> a.setUsernameLinkDetails(linkHandle, request.getUsernameCiphertext().toByteArray())))
.thenReturn(linkHandle);