diff --git a/integration-tests/src/main/java/org/signal/integration/TestUser.java b/integration-tests/src/main/java/org/signal/integration/TestUser.java index 8a7dbeff5..07be08071 100644 --- a/integration-tests/src/main/java/org/signal/integration/TestUser.java +++ b/integration-tests/src/main/java/org/signal/integration/TestUser.java @@ -10,7 +10,6 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import java.security.SecureRandom; -import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.List; import java.util.Map; @@ -126,7 +125,7 @@ public UUID pniUuid() { } public AccountAttributes accountAttributes() { - return new AccountAttributes(true, registrationId, pniRegistrationId, "".getBytes(StandardCharsets.UTF_8), "", true, new Device.DeviceCapabilities(false, false, false, false)) + return new AccountAttributes(true, registrationId, pniRegistrationId, "", "", true, new Device.DeviceCapabilities(false, false, false, false)) .withUnidentifiedAccessKey(unidentifiedAccessKey) .withRecoveryPassword(registrationPassword); } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/entities/AccountAttributes.java b/service/src/main/java/org/whispersystems/textsecuregcm/entities/AccountAttributes.java index 5ed0c95c9..2236b3572 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/entities/AccountAttributes.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/entities/AccountAttributes.java @@ -8,7 +8,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.google.common.annotations.VisibleForTesting; import java.util.Optional; import javax.annotation.Nullable; @@ -31,10 +30,8 @@ public class AccountAttributes { private int phoneNumberIdentityRegistrationId; @JsonProperty - @JsonSerialize(using = ByteArrayAdapter.Serializing.class) - @JsonDeserialize(using = ByteArrayAdapter.Deserializing.class) - @Size(max = 225) - private byte[] name; + @Size(max = 204, message = "This field must be less than 50 characters") + private String name; @JsonProperty private String registrationLock; @@ -65,7 +62,7 @@ public AccountAttributes( final boolean fetchesMessages, final int registrationId, final int phoneNumberIdentifierRegistrationId, - final byte[] name, + final String name, final String registrationLock, final boolean discoverableByPhoneNumber, final DeviceCapabilities capabilities) { @@ -90,7 +87,7 @@ public int getPhoneNumberIdentityRegistrationId() { return phoneNumberIdentityRegistrationId; } - public byte[] getName() { + public String getName() { return name; } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/entities/DeviceInfo.java b/service/src/main/java/org/whispersystems/textsecuregcm/entities/DeviceInfo.java index da66df7d6..189a0b39b 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/entities/DeviceInfo.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/entities/DeviceInfo.java @@ -5,16 +5,5 @@ package org.whispersystems.textsecuregcm.entities; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import org.whispersystems.textsecuregcm.util.ByteArrayAdapter; - -public record DeviceInfo(long id, - - @JsonSerialize(using = ByteArrayAdapter.Serializing.class) - @JsonDeserialize(using = ByteArrayAdapter.Deserializing.class) - byte[] name, - - long lastSeen, - long created) { +public record DeviceInfo(long id, String name, long lastSeen, long created) { } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/entities/DeviceName.java b/service/src/main/java/org/whispersystems/textsecuregcm/entities/DeviceName.java index ebebc1335..498c4032b 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/entities/DeviceName.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/entities/DeviceName.java @@ -6,24 +6,19 @@ 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 org.whispersystems.textsecuregcm.util.ByteArrayAdapter; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.Size; public class DeviceName { @JsonProperty - @JsonSerialize(using = ByteArrayAdapter.Serializing.class) - @JsonDeserialize(using = ByteArrayAdapter.Deserializing.class) @NotEmpty - @Size(max = 225) - private byte[] deviceName; + @Size(max = 300, message = "This field must be less than 300 characters") + private String deviceName; public DeviceName() {} - public byte[] getDeviceName() { + public String getDeviceName() { return deviceName; } } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/grpc/DevicesGrpcService.java b/service/src/main/java/org/whispersystems/textsecuregcm/grpc/DevicesGrpcService.java index fa67e1ff1..ea726f92e 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/grpc/DevicesGrpcService.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/grpc/DevicesGrpcService.java @@ -60,8 +60,8 @@ public Mono getDevices(final GetDevicesRequest request) { .reduce(GetDevicesResponse.newBuilder(), (builder, device) -> { final GetDevicesResponse.LinkedDevice.Builder linkedDeviceBuilder = GetDevicesResponse.LinkedDevice.newBuilder(); - if (device.getName() != null) { - linkedDeviceBuilder.setName(ByteString.copyFrom(device.getName())); + if (StringUtils.isNotBlank(device.getName())) { + linkedDeviceBuilder.setName(ByteString.copyFrom(Base64.getDecoder().decode(device.getName()))); } return builder.addDevices(linkedDeviceBuilder @@ -105,7 +105,7 @@ public Mono setDeviceName(final SetDeviceNameRequest requ return Mono.fromFuture(() -> accountsManager.getByAccountIdentifierAsync(authenticatedDevice.accountIdentifier())) .map(maybeAccount -> maybeAccount.orElseThrow(Status.UNAUTHENTICATED::asRuntimeException)) .flatMap(account -> Mono.fromFuture(() -> accountsManager.updateDeviceAsync(account, authenticatedDevice.deviceId(), - device -> device.setName(request.getName().toByteArray())))) + device -> device.setName(Base64.getEncoder().encodeToString(request.getName().toByteArray()))))) .thenReturn(SetDeviceNameResponse.newBuilder().build()); } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/storage/Device.java b/service/src/main/java/org/whispersystems/textsecuregcm/storage/Device.java index 790bce398..ad66fb7b4 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/storage/Device.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/storage/Device.java @@ -7,7 +7,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; import java.util.List; import java.util.OptionalInt; import java.util.concurrent.TimeUnit; @@ -18,7 +17,6 @@ import org.whispersystems.textsecuregcm.auth.SaltedTokenHash; import org.whispersystems.textsecuregcm.entities.ECSignedPreKey; import org.whispersystems.textsecuregcm.identity.IdentityType; -import org.whispersystems.textsecuregcm.util.DeviceNameByteArrayAdapter; public class Device { @@ -33,9 +31,7 @@ public class Device { private byte id; @JsonProperty - @JsonSerialize(using = DeviceNameByteArrayAdapter.Serializer.class) - @JsonDeserialize(using = DeviceNameByteArrayAdapter.Deserializer.class) - private byte[] name; + private String name; @JsonProperty private String authToken; @@ -150,11 +146,11 @@ public void setId(byte id) { this.id = id; } - public byte[] getName() { + public String getName() { return name; } - public void setName(byte[] name) { + public void setName(String name) { this.name = name; } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/util/DeviceNameByteArrayAdapter.java b/service/src/main/java/org/whispersystems/textsecuregcm/util/DeviceNameByteArrayAdapter.java deleted file mode 100644 index a0758ddc4..000000000 --- a/service/src/main/java/org/whispersystems/textsecuregcm/util/DeviceNameByteArrayAdapter.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.whispersystems.textsecuregcm.util; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonDeserializer; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.SerializerProvider; -import io.micrometer.core.instrument.Counter; -import io.micrometer.core.instrument.Metrics; -import org.whispersystems.textsecuregcm.metrics.MetricsUtil; -import java.io.IOException; -import java.util.Base64; - -/** - * Serializes a byte array as a standard Base64-encoded string and deserializes Base64-encoded strings to byte arrays, - * but treats any string that cannot be parsed as Base64 to {@code null}. - *

- * Historically, device names were passed around as weakly-typed strings with the expectation that clients would provide - * Base64 strings, but nothing in the server ever verified that was the case. In the absence of strict validation, some - * third-party clients started submitting unencrypted names for devices, and so device names in persistent storage are a - * mix of Base64-encoded device name ciphertexts from first-party clients and plaintext device names from third-party - * clients. This adapter will discard the latter. - */ -public class DeviceNameByteArrayAdapter { - - private static final Counter UNPARSEABLE_DEVICE_NAME_COUNTER = - Metrics.counter(MetricsUtil.name(DeviceNameByteArrayAdapter.class, "unparseableDeviceName")); - - public static class Serializer extends JsonSerializer { - @Override - public void serialize(final byte[] bytes, - final JsonGenerator jsonGenerator, - final SerializerProvider serializerProvider) throws IOException { - - jsonGenerator.writeString(Base64.getEncoder().encodeToString(bytes)); - } - } - - public static class Deserializer extends JsonDeserializer { - @Override - public byte[] deserialize(final JsonParser jsonParser, - final DeserializationContext deserializationContext) throws IOException { - - try { - return Base64.getDecoder().decode(jsonParser.getValueAsString()); - } catch (final IllegalArgumentException e) { - UNPARSEABLE_DEVICE_NAME_COUNTER.increment(); - return null; - } - } - } -} diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/auth/AuthEnablementRefreshRequirementProviderTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/auth/AuthEnablementRefreshRequirementProviderTest.java index 21a865c58..b96d80bed 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/auth/AuthEnablementRefreshRequirementProviderTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/auth/AuthEnablementRefreshRequirementProviderTest.java @@ -221,10 +221,7 @@ void testDeviceAdded() { final int initialDeviceCount = account.getDevices().size(); - final List addedDeviceNames = List.of( - Base64.getEncoder().encodeToString("newDevice1".getBytes(StandardCharsets.UTF_8)), - Base64.getEncoder().encodeToString("newDevice2".getBytes(StandardCharsets.UTF_8))); - + final List addedDeviceNames = List.of("newDevice1", "newDevice2"); final Response response = resources.getJerseyTest() .target("/v1/test/account/devices") .request() @@ -453,7 +450,7 @@ public String setEnabled(@Auth TestPrincipal principal, Map devic @PUT @Path("/account/devices") @ChangesDeviceEnabledState - public String addDevices(@Auth TestPrincipal auth, List deviceNames) { + public String addDevices(@Auth TestPrincipal auth, List deviceNames) { deviceNames.forEach(name -> { final Device device = DevicesHelper.createDevice(auth.getAccount().getNextDeviceId()); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/DeviceControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/DeviceControllerTest.java index a2e52ddf5..029e78db0 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/DeviceControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/DeviceControllerTest.java @@ -712,10 +712,11 @@ void longNameTest() { .request() .header("Authorization", AuthHelper.getProvisioningAuthHeader(AuthHelper.VALID_NUMBER, "password1")) .put(Entity.entity(new AccountAttributes(false, 1234, 5678, - TestRandomUtil.nextBytes(226), null, true, null), + "this is a really long name that is longer than 80 characters it's so long that it's even longer than 204 characters. that's a lot of characters. we're talking lots and lots and lots of characters. 12345678", + null, true, null), MediaType.APPLICATION_JSON_TYPE)); - assertEquals(422, response.getStatus()); + assertEquals(response.getStatus(), 422); verifyNoMoreInteractions(messagesManager); } diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/RegistrationControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/RegistrationControllerTest.java index 388981350..34c774bfb 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/RegistrationControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/RegistrationControllerTest.java @@ -477,10 +477,10 @@ static Stream atomicAccountCreationConflictingChannel() { } final AccountAttributes fetchesMessagesAccountAttributes = - new AccountAttributes(true, 1, 1, "test".getBytes(StandardCharsets.UTF_8), null, true, new Device.DeviceCapabilities(false, false, false, false)); + new AccountAttributes(true, 1, 1, "test", null, true, new Device.DeviceCapabilities(false, false, false, false)); final AccountAttributes pushAccountAttributes = - new AccountAttributes(false, 1, 1, "test".getBytes(StandardCharsets.UTF_8), null, true, new Device.DeviceCapabilities(false, false, false, false)); + new AccountAttributes(false, 1, 1, "test", null, true, new Device.DeviceCapabilities(false, false, false, false)); return Stream.of( // "Fetches messages" is true, but an APNs token is provided @@ -566,7 +566,7 @@ static Stream atomicAccountCreationPartialSignedPreKeys() { } final AccountAttributes accountAttributes = - new AccountAttributes(true, 1, 1, "test".getBytes(StandardCharsets.UTF_8), null, true, new Device.DeviceCapabilities(false, false, false, false)); + new AccountAttributes(true, 1, 1, "test", null, true, new Device.DeviceCapabilities(false, false, false, false)); return Stream.of( // Signed PNI EC pre-key is missing @@ -719,7 +719,7 @@ private static boolean accountAttributesEqual(final AccountAttributes a, final A && a.isUnrestrictedUnidentifiedAccess() == b.isUnrestrictedUnidentifiedAccess() && a.isDiscoverableByPhoneNumber() == b.isDiscoverableByPhoneNumber() && Objects.equals(a.getPhoneNumberIdentityRegistrationId(), b.getPhoneNumberIdentityRegistrationId()) - && Arrays.equals(a.getName(), b.getName()) + && Objects.equals(a.getName(), b.getName()) && Objects.equals(a.getRegistrationLock(), b.getRegistrationLock()) && Arrays.equals(a.getUnidentifiedAccessKey(), b.getUnidentifiedAccessKey()) && Objects.equals(a.getCapabilities(), b.getCapabilities()) @@ -746,10 +746,10 @@ private static Stream atomicAccountCreationSuccess() { } final AccountAttributes fetchesMessagesAccountAttributes = - new AccountAttributes(true, 1, 1, "test".getBytes(StandardCharsets.UTF_8), null, true, new Device.DeviceCapabilities(false, false, false, false)); + new AccountAttributes(true, 1, 1, "test", null, true, new Device.DeviceCapabilities(false, false, false, false)); final AccountAttributes pushAccountAttributes = - new AccountAttributes(false, 1, 1, "test".getBytes(StandardCharsets.UTF_8), null, true, new Device.DeviceCapabilities(false, false, false, false)); + new AccountAttributes(false, 1, 1, "test", null, true, new Device.DeviceCapabilities(false, false, false, false)); final String apnsToken = "apns-token"; final String apnsVoipToken = "apns-voip-token"; @@ -861,7 +861,7 @@ private static String requestJson(final String sessionId, final IdentityKey aciIdentityKey = new IdentityKey(aciIdentityKeyPair.getPublicKey()); final IdentityKey pniIdentityKey = new IdentityKey(pniIdentityKeyPair.getPublicKey()); - final AccountAttributes accountAttributes = new AccountAttributes(true, registrationId, pniRegistrationId, "name".getBytes(StandardCharsets.UTF_8), "reglock", + final AccountAttributes accountAttributes = new AccountAttributes(true, registrationId, pniRegistrationId, "name", "reglock", true, new Device.DeviceCapabilities(true, true, true, true)); final RegistrationRequest request = new RegistrationRequest( diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/grpc/DevicesGrpcServiceTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/grpc/DevicesGrpcServiceTest.java index 1d38fb9d7..679a49652 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/grpc/DevicesGrpcServiceTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/grpc/DevicesGrpcServiceTest.java @@ -10,6 +10,7 @@ import static org.mockito.ArgumentMatchers.anyByte; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.whispersystems.textsecuregcm.grpc.GrpcTestUtils.assertStatusException; @@ -20,6 +21,7 @@ import java.time.Duration; import java.time.Instant; import java.time.temporal.ChronoUnit; +import java.util.Base64; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; @@ -121,7 +123,8 @@ void getDevices() { when(linkedDevice.getId()).thenReturn((byte) (Device.PRIMARY_ID + 1)); when(linkedDevice.getCreated()).thenReturn(linkedDeviceCreated.toEpochMilli()); when(linkedDevice.getLastSeen()).thenReturn(linkedDeviceLastSeen.toEpochMilli()); - when(linkedDevice.getName()).thenReturn(linkedDeviceName.getBytes(StandardCharsets.UTF_8)); + when(linkedDevice.getName()) + .thenReturn(Base64.getEncoder().encodeToString(linkedDeviceName.getBytes(StandardCharsets.UTF_8))); when(authenticatedAccount.getDevices()).thenReturn(List.of(primaryDevice, linkedDevice)); @@ -189,7 +192,7 @@ void setDeviceName(final byte deviceId) { .setName(ByteString.copyFrom(deviceName)) .build()); - verify(device).setName(deviceName); + verify(device).setName(Base64.getEncoder().encodeToString(deviceName)); } @ParameterizedTest diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountCreationIntegrationTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountCreationIntegrationTest.java index c581d47cc..ddbb78784 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountCreationIntegrationTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountCreationIntegrationTest.java @@ -1,6 +1,5 @@ package org.whispersystems.textsecuregcm.storage; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -9,7 +8,6 @@ import static org.mockito.Mockito.when; import com.google.i18n.phonenumbers.PhoneNumberUtil; -import java.nio.charset.StandardCharsets; import java.time.Clock; import java.time.Duration; import java.time.Instant; @@ -172,7 +170,7 @@ void createAccount(final DeliveryChannels deliveryChannels, final String signalAgent = RandomStringUtils.randomAlphabetic(3); final int registrationId = ThreadLocalRandom.current().nextInt(Device.MAX_REGISTRATION_ID); final int pniRegistrationId = ThreadLocalRandom.current().nextInt(Device.MAX_REGISTRATION_ID); - final byte[] deviceName = RandomStringUtils.randomAlphabetic(16).getBytes(StandardCharsets.UTF_8); + final String deviceName = RandomStringUtils.randomAlphabetic(16); final String registrationLockSecret = RandomStringUtils.randomAlphanumeric(16); final Device.DeviceCapabilities deviceCapabilities = new Device.DeviceCapabilities( @@ -266,7 +264,7 @@ void reregisterAccount(final DeliveryChannels deliveryChannels, final Account originalAccount = accountsManager.create(number, RandomStringUtils.randomAlphanumeric(16), "OWI", - new AccountAttributes(true, 1, 1, "name".getBytes(StandardCharsets.UTF_8), "registration-lock", false, new Device.DeviceCapabilities(false, false, false, false)), + new AccountAttributes(true, 1, 1, "name", "registration-lock", false, new Device.DeviceCapabilities(false, false, false, false)), Collections.emptyList(), new IdentityKey(aciKeyPair.getPublicKey()), new IdentityKey(pniKeyPair.getPublicKey()), @@ -284,7 +282,7 @@ void reregisterAccount(final DeliveryChannels deliveryChannels, final String signalAgent = RandomStringUtils.randomAlphabetic(3); final int registrationId = ThreadLocalRandom.current().nextInt(Device.MAX_REGISTRATION_ID); final int pniRegistrationId = ThreadLocalRandom.current().nextInt(Device.MAX_REGISTRATION_ID); - final byte[] deviceName = RandomStringUtils.randomAlphabetic(16).getBytes(StandardCharsets.UTF_8); + final String deviceName = RandomStringUtils.randomAlphabetic(16); final String registrationLockSecret = RandomStringUtils.randomAlphanumeric(16); final Device.DeviceCapabilities deviceCapabilities = new Device.DeviceCapabilities( @@ -381,7 +379,7 @@ private void assertExpectedStoredAccount(final Account account, final DeliveryChannels deliveryChannels, final int registrationId, final int pniRegistrationId, - final byte[] deviceName, + final String deviceName, final boolean discoverableByPhoneNumber, final Device.DeviceCapabilities deviceCapabilities, final List badges, @@ -400,7 +398,7 @@ private void assertExpectedStoredAccount(final Account account, assertEquals(deliveryChannels.fetchesMessages(), primaryDevice.getFetchesMessages()); assertEquals(registrationId, primaryDevice.getRegistrationId()); assertEquals(pniRegistrationId, primaryDevice.getPhoneNumberIdentityRegistrationId().orElseThrow()); - assertArrayEquals(deviceName, primaryDevice.getName()); + assertEquals(deviceName, primaryDevice.getName()); assertEquals(discoverableByPhoneNumber, account.isDiscoverableByPhoneNumber()); assertEquals(deviceCapabilities, primaryDevice.getCapabilities()); assertEquals(badges, account.getBadges()); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsManagerChangeNumberIntegrationTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsManagerChangeNumberIntegrationTest.java index 8025b9052..dd9692cca 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsManagerChangeNumberIntegrationTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsManagerChangeNumberIntegrationTest.java @@ -13,7 +13,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import java.nio.charset.StandardCharsets; import java.time.Clock; import java.util.Map; import java.util.Optional; @@ -186,7 +185,7 @@ void testChangeNumberWithPniExtensions() throws InterruptedException, Mismatched final int rotatedPniRegistrationId = 17; final ECKeyPair rotatedPniIdentityKeyPair = Curve.generateKeyPair(); final ECSignedPreKey rotatedSignedPreKey = KeysHelper.signedECPreKey(1L, rotatedPniIdentityKeyPair); - final AccountAttributes accountAttributes = new AccountAttributes(true, rotatedPniRegistrationId + 1, rotatedPniRegistrationId, "test".getBytes(StandardCharsets.UTF_8), null, true, new Device.DeviceCapabilities(false, false, false, false)); + final AccountAttributes accountAttributes = new AccountAttributes(true, rotatedPniRegistrationId + 1, rotatedPniRegistrationId, "test", null, true, new Device.DeviceCapabilities(false, false, false, false)); final Account account = AccountsHelper.createAccount(accountsManager, originalNumber, accountAttributes); account.getPrimaryDevice().setSignedPreKey(KeysHelper.signedECPreKey(1, rotatedPniIdentityKeyPair)); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsManagerConcurrentModificationIntegrationTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsManagerConcurrentModificationIntegrationTest.java index 6dbc936f4..971755fb9 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsManagerConcurrentModificationIntegrationTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsManagerConcurrentModificationIntegrationTest.java @@ -20,7 +20,6 @@ import io.lettuce.core.cluster.api.sync.RedisAdvancedClusterCommands; import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.time.Clock; import java.time.Instant; import java.util.ArrayList; @@ -196,7 +195,7 @@ void testConcurrentUpdate() throws IOException, InterruptedException { modifyAccount(uuid, account -> account.setRegistrationLock(credentials.hash(), credentials.salt())), modifyAccount(uuid, account -> account.setUnrestrictedUnidentifiedAccess(unrestrictedUnidentifiedAccess)), modifyDevice(uuid, Device.PRIMARY_ID, device -> device.setLastSeen(lastSeen)), - modifyDevice(uuid, Device.PRIMARY_ID, device -> device.setName("deviceName".getBytes(StandardCharsets.UTF_8))) + modifyDevice(uuid, Device.PRIMARY_ID, device -> device.setName("deviceName")) ).join(); final Account managerAccount = accountsManager.getByAccountIdentifier(uuid).orElseThrow(); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsManagerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsManagerTest.java index 2457e8ca8..d16c0b8c8 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsManagerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsManagerTest.java @@ -900,9 +900,9 @@ void testUpdateDevice() { @SuppressWarnings("unchecked") Consumer unknownDeviceUpdater = mock(Consumer.class); account = accountsManager.updateDevice(account, deviceId, deviceUpdater); - account = accountsManager.updateDevice(account, deviceId, d -> d.setName("deviceName".getBytes(StandardCharsets.UTF_8))); + account = accountsManager.updateDevice(account, deviceId, d -> d.setName("deviceName")); - assertArrayEquals("deviceName".getBytes(StandardCharsets.UTF_8), account.getDevice(deviceId).orElseThrow().getName()); + assertEquals("deviceName", account.getDevice(deviceId).orElseThrow().getName()); verify(deviceUpdater, times(1)).accept(any(Device.class)); @@ -933,9 +933,9 @@ void testUpdateDeviceAsync() { @SuppressWarnings("unchecked") Consumer unknownDeviceUpdater = mock(Consumer.class); account = accountsManager.updateDeviceAsync(account, deviceId, deviceUpdater).join(); - account = accountsManager.updateDeviceAsync(account, deviceId, d -> d.setName("deviceName".getBytes(StandardCharsets.UTF_8))).join(); + account = accountsManager.updateDeviceAsync(account, deviceId, d -> d.setName("deviceName")).join(); - assertArrayEquals("deviceName".getBytes(StandardCharsets.UTF_8), account.getDevice(deviceId).orElseThrow().getName()); + assertEquals("deviceName", account.getDevice(deviceId).orElseThrow().getName()); verify(deviceUpdater, times(1)).accept(any(Device.class)); 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 7128c9360..ea135c0b7 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountsTest.java @@ -499,7 +499,7 @@ void testUpdate() { assertPhoneNumberConstraintExists("+14151112222", account.getUuid()); assertPhoneNumberIdentifierConstraintExists(account.getPhoneNumberIdentifier(), account.getUuid()); - device.setName("foobar".getBytes(StandardCharsets.UTF_8)); + device.setName("foobar"); accounts.update(account); @@ -567,7 +567,7 @@ void testUpdateTransactionally() { final Account account = generateAccount("+14151112222", UUID.randomUUID(), UUID.randomUUID()); createAccount(account); - final byte[] deviceName = "device-name".getBytes(StandardCharsets.UTF_8); + final String deviceName = "device-name"; assertNotEquals(deviceName, accounts.getByAccountIdentifier(account.getUuid()).orElseThrow().getPrimaryDevice().getName()); @@ -593,7 +593,7 @@ void testUpdateTransactionally() { .build()) .build())).toCompletableFuture().join(); - assertArrayEquals(deviceName, + assertEquals(deviceName, accounts.getByAccountIdentifier(account.getUuid()).orElseThrow().getPrimaryDevice().getName()); assertTrue(DYNAMO_DB_EXTENSION.getDynamoDbClient().getItem(GetItemRequest.builder() diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/util/DeviceNameByteArrayAdapterTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/util/DeviceNameByteArrayAdapterTest.java deleted file mode 100644 index 062cebe1b..000000000 --- a/service/src/test/java/org/whispersystems/textsecuregcm/util/DeviceNameByteArrayAdapterTest.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.whispersystems.textsecuregcm.util; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.SerializerProvider; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import java.io.IOException; -import java.util.Base64; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -class DeviceNameByteArrayAdapterTest { - - @Test - void serialize() throws IOException { - final byte[] deviceName = TestRandomUtil.nextBytes(16); - final JsonGenerator jsonGenerator = mock(JsonGenerator.class); - - new DeviceNameByteArrayAdapter.Serializer().serialize(deviceName, jsonGenerator, mock(SerializerProvider.class)); - - verify(jsonGenerator).writeString(Base64.getEncoder().encodeToString(deviceName)); - } - - @ParameterizedTest - @MethodSource - void deserialize(final String encodedString, final byte[] expectedBytes) throws IOException { - final JsonParser jsonParser = mock(JsonParser.class); - when(jsonParser.getValueAsString()).thenReturn(encodedString); - - assertArrayEquals(expectedBytes, - new DeviceNameByteArrayAdapter.Deserializer().deserialize(jsonParser, mock(DeserializationContext.class))); - } - - private static List deserialize() { - final byte[] deviceName = TestRandomUtil.nextBytes(16); - - return List.of( - Arguments.of(Base64.getEncoder().encodeToString(deviceName), deviceName), - Arguments.of("This is not a valid Base64 string", null) - ); - } -}