mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-21 16:28:05 +01:00
Enable case-sensitive usernames
This commit is contained in:
@@ -1496,32 +1496,32 @@ class AccountControllerTest {
|
||||
@Test
|
||||
void testSetUsername() throws UsernameNotAvailableException {
|
||||
Account account = mock(Account.class);
|
||||
when(account.getUsername()).thenReturn(Optional.of("n00bkiller.1234"));
|
||||
when(accountsManager.setUsername(any(), eq("n00bkiller"), isNull()))
|
||||
when(account.getUsername()).thenReturn(Optional.of("N00bkilleR.1234"));
|
||||
when(accountsManager.setUsername(any(), eq("N00bkilleR"), isNull()))
|
||||
.thenReturn(account);
|
||||
Response response =
|
||||
resources.getJerseyTest()
|
||||
.target("/v1/accounts/username")
|
||||
.request()
|
||||
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
|
||||
.put(Entity.json(new UsernameRequest("n00bkiller", null)));
|
||||
.put(Entity.json(new UsernameRequest("N00bkilleR", null)));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
assertThat(response.readEntity(UsernameResponse.class).username()).isEqualTo("n00bkiller.1234");
|
||||
assertThat(response.readEntity(UsernameResponse.class).username()).isEqualTo("N00bkilleR.1234");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testReserveUsername() throws UsernameNotAvailableException {
|
||||
when(accountsManager.reserveUsername(any(), eq("n00bkiller")))
|
||||
.thenReturn(new AccountsManager.UsernameReservation(null, "n00bkiller.1234", RESERVATION_TOKEN));
|
||||
when(accountsManager.reserveUsername(any(), eq("N00bkilleR")))
|
||||
.thenReturn(new AccountsManager.UsernameReservation(null, "N00bkilleR.1234", RESERVATION_TOKEN));
|
||||
Response response =
|
||||
resources.getJerseyTest()
|
||||
.target("/v1/accounts/username/reserved")
|
||||
.request()
|
||||
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
|
||||
.put(Entity.json(new ReserveUsernameRequest("n00bkiller")));
|
||||
.put(Entity.json(new ReserveUsernameRequest("N00bkilleR")));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
assertThat(response.readEntity(ReserveUsernameResponse.class))
|
||||
.satisfies(r -> r.username().equals("n00bkiller.1234"))
|
||||
.satisfies(r -> r.username().equals("N00bkilleR.1234"))
|
||||
.satisfies(r -> r.reservationToken().equals(RESERVATION_TOKEN));
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ import org.whispersystems.textsecuregcm.storage.Device.DeviceCapabilities;
|
||||
import org.whispersystems.textsecuregcm.tests.util.AccountsHelper;
|
||||
import org.whispersystems.textsecuregcm.tests.util.RedisClusterHelper;
|
||||
import org.whispersystems.textsecuregcm.util.UsernameGenerator;
|
||||
import org.whispersystems.textsecuregcm.util.UsernameNormalizer;
|
||||
|
||||
class AccountsManagerTest {
|
||||
|
||||
@@ -751,7 +752,7 @@ class AccountsManagerTest {
|
||||
@Test
|
||||
void testSetReservedUsername() throws UsernameNotAvailableException, UsernameReservationNotFoundException {
|
||||
final Account account = AccountsHelper.generateTestAccount("+18005551234", UUID.randomUUID(), UUID.randomUUID(), new ArrayList<>(), new byte[16]);
|
||||
final String reserved = "scooby.1234";
|
||||
final String reserved = "sCoObY.1234";
|
||||
setReservationHash(account, reserved);
|
||||
when(accounts.usernameAvailable(eq(Optional.of(RESERVATION_TOKEN)), eq(reserved))).thenReturn(true);
|
||||
accountsManager.confirmReservedUsername(account, reserved, RESERVATION_TOKEN);
|
||||
|
||||
@@ -43,6 +43,7 @@ import org.whispersystems.textsecuregcm.util.TestClock;
|
||||
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
|
||||
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ConditionalCheckFailedException;
|
||||
import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest;
|
||||
import software.amazon.awssdk.services.dynamodb.model.GetItemRequest;
|
||||
@@ -617,7 +618,7 @@ class AccountsTest {
|
||||
final Account account = generateAccount("+18005551234", UUID.randomUUID(), UUID.randomUUID());
|
||||
accounts.create(account);
|
||||
|
||||
final String username = "test";
|
||||
final String username = "TeST";
|
||||
|
||||
assertThat(accounts.getByUsername(username)).isEmpty();
|
||||
|
||||
@@ -638,6 +639,12 @@ class AccountsTest {
|
||||
accounts.setUsername(account, secondUsername);
|
||||
|
||||
assertThat(accounts.getByUsername(username)).isEmpty();
|
||||
assertThat(dynamoDbExtension.getDynamoDbClient()
|
||||
.getItem(GetItemRequest.builder()
|
||||
.tableName(USERNAME_CONSTRAINT_TABLE_NAME)
|
||||
.key(Map.of(Accounts.ATTR_USERNAME, AttributeValues.fromString("test")))
|
||||
.build())
|
||||
.item()).isEmpty();
|
||||
|
||||
{
|
||||
final Optional<Account> maybeAccount = accounts.getByUsername(secondUsername);
|
||||
@@ -688,7 +695,7 @@ class AccountsTest {
|
||||
final Account account = generateAccount("+18005551234", UUID.randomUUID(), UUID.randomUUID());
|
||||
accounts.create(account);
|
||||
|
||||
final String username = "test";
|
||||
final String username = "TeST";
|
||||
|
||||
accounts.setUsername(account, username);
|
||||
assertThat(accounts.getByUsername(username)).isPresent();
|
||||
@@ -731,29 +738,31 @@ class AccountsTest {
|
||||
final Account account2 = generateAccount("+18005552222", UUID.randomUUID(), UUID.randomUUID());
|
||||
accounts.create(account2);
|
||||
|
||||
final UUID token = accounts.reserveUsername(account1, "garfield", Duration.ofDays(1));
|
||||
assertThat(account1.getReservedUsernameHash()).get().isEqualTo(Accounts.reservedUsernameHash(account1.getUuid(), "garfield"));
|
||||
final UUID token = accounts.reserveUsername(account1, "GarfielD", Duration.ofDays(1));
|
||||
assertThat(account1.getReservedUsernameHash()).get().isEqualTo(Accounts.reservedUsernameHash(account1.getUuid(), "GarfielD"));
|
||||
assertThat(account1.getUsername()).isEmpty();
|
||||
|
||||
// account 2 shouldn't be able to reserve the username
|
||||
// account 2 shouldn't be able to reserve the username if it's the same when normalized
|
||||
assertThrows(ContestedOptimisticLockException.class,
|
||||
() -> accounts.reserveUsername(account2, "garfield", Duration.ofDays(1)));
|
||||
() -> accounts.reserveUsername(account2, "gARFIELd", Duration.ofDays(1)));
|
||||
assertThrows(ContestedOptimisticLockException.class,
|
||||
() -> accounts.confirmUsername(account2, "garfield", UUID.randomUUID()));
|
||||
assertThat(accounts.getByUsername("garfield")).isEmpty();
|
||||
() -> accounts.confirmUsername(account2, "gARFIELd", UUID.randomUUID()));
|
||||
assertThat(accounts.getByUsername("gARFIELd")).isEmpty();
|
||||
|
||||
accounts.confirmUsername(account1, "garfield", token);
|
||||
accounts.confirmUsername(account1, "GarfielD", token);
|
||||
assertThat(account1.getReservedUsernameHash()).isEmpty();
|
||||
assertThat(account1.getUsername()).get().isEqualTo("garfield");
|
||||
assertThat(accounts.getByUsername("garfield").get().getUuid()).isEqualTo(account1.getUuid());
|
||||
assertThat(account1.getUsername()).get().isEqualTo("GarfielD");
|
||||
assertThat(accounts.getByUsername("GarfielD").get().getUuid()).isEqualTo(account1.getUuid());
|
||||
|
||||
assertThat(dynamoDbExtension.getDynamoDbClient()
|
||||
final Map<String, AttributeValue> usernameConstraintRecord = dynamoDbExtension.getDynamoDbClient()
|
||||
.getItem(GetItemRequest.builder()
|
||||
.tableName(USERNAME_CONSTRAINT_TABLE_NAME)
|
||||
.key(Map.of(Accounts.ATTR_USERNAME, AttributeValues.fromString("garfield")))
|
||||
.build())
|
||||
.item())
|
||||
.doesNotContainKey(Accounts.ATTR_TTL);
|
||||
.item();
|
||||
|
||||
assertThat(usernameConstraintRecord).containsKey(Accounts.ATTR_USERNAME);
|
||||
assertThat(usernameConstraintRecord).doesNotContainKey(Accounts.ATTR_TTL);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -761,7 +770,7 @@ class AccountsTest {
|
||||
final Account account1 = generateAccount("+18005551111", UUID.randomUUID(), UUID.randomUUID());
|
||||
accounts.create(account1);
|
||||
|
||||
final String username = "unsinkablesam";
|
||||
final String username = "UnSinkaBlesam";
|
||||
|
||||
final UUID token = accounts.reserveUsername(account1, username, Duration.ofDays(1));
|
||||
assertThat(accounts.usernameAvailable(username)).isFalse();
|
||||
|
||||
@@ -28,8 +28,8 @@ public class UsernameGeneratorTest {
|
||||
|
||||
static Stream<Arguments> nicknameValidation() {
|
||||
return Stream.of(
|
||||
Arguments.of("Test", false, "upper case"),
|
||||
Arguments.of("tesT", false, "upper case"),
|
||||
Arguments.of("Test", true, "upper case"),
|
||||
Arguments.of("tesT", true, "upper case"),
|
||||
Arguments.of("te-st", false, "illegal character"),
|
||||
Arguments.of("ab\uD83D\uDC1B", false, "illegal character"),
|
||||
Arguments.of("1test", false, "illegal start"),
|
||||
@@ -55,7 +55,7 @@ public class UsernameGeneratorTest {
|
||||
|
||||
static Stream<Arguments> nonStandardUsernames() {
|
||||
return Stream.of(
|
||||
Arguments.of("Test.123", false),
|
||||
Arguments.of("Test.123", true),
|
||||
Arguments.of("test.-123", false),
|
||||
Arguments.of("test.0", false),
|
||||
Arguments.of("test.", false),
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.whispersystems.textsecuregcm.tests.util;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.whispersystems.textsecuregcm.util.UsernameNormalizer;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class UsernameNormalizerTest {
|
||||
|
||||
@Test
|
||||
public void usernameNormalization() {
|
||||
assertThat(UsernameNormalizer.normalize("TeST")).isEqualTo("test");
|
||||
assertThat(UsernameNormalizer.normalize("TeST_")).isEqualTo("test_");
|
||||
assertThat(UsernameNormalizer.normalize("TeST_.123")).isEqualTo("test_.123");
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user