Add phone-number-sharing field to versioned profile
Co-authored-by: Katherine <katherine@signal.org>
This commit is contained in:
		
							parent
							
								
									3b509bf820
								
							
						
					
					
						commit
						9d3d4a3698
					
				|  | @ -163,9 +163,9 @@ public class ProfileController { | |||
|   public Response setProfile(@Auth AuthenticatedAccount auth, @NotNull @Valid CreateProfileRequest request) { | ||||
| 
 | ||||
|     final Optional<VersionedProfile> currentProfile = profilesManager.get(auth.getAccount().getUuid(), | ||||
|         request.getVersion()); | ||||
|         request.version()); | ||||
| 
 | ||||
|     if (request.getPaymentAddress() != null && request.getPaymentAddress().length != 0) { | ||||
|     if (request.paymentAddress() != null && request.paymentAddress().length != 0) { | ||||
|       final boolean hasDisallowedPrefix = | ||||
|           dynamicConfigurationManager.getConfiguration().getPaymentsConfiguration().getDisallowedPrefixes().stream() | ||||
|               .anyMatch(prefix -> auth.getAccount().getNumber().startsWith(prefix)); | ||||
|  | @ -189,13 +189,14 @@ public class ProfileController { | |||
| 
 | ||||
|     profilesManager.set(auth.getAccount().getUuid(), | ||||
|         new VersionedProfile( | ||||
|             request.getVersion(), | ||||
|             request.getName(), | ||||
|             request.version(), | ||||
|             request.name(), | ||||
|             avatar, | ||||
|             request.getAboutEmoji(), | ||||
|             request.getAbout(), | ||||
|             request.getPaymentAddress(), | ||||
|             request.getCommitment().serialize())); | ||||
|             request.aboutEmoji(), | ||||
|             request.about(), | ||||
|             request.paymentAddress(), | ||||
|             request.phoneNumberSharing(), | ||||
|             request.commitment().serialize())); | ||||
| 
 | ||||
|     if (request.getAvatarChange() != CreateProfileRequest.AvatarChange.UNCHANGED) { | ||||
|       currentAvatar.ifPresent(s -> s3client.deleteObject(DeleteObjectRequest.builder() | ||||
|  | @ -204,13 +205,13 @@ public class ProfileController { | |||
|           .build())); | ||||
|     } | ||||
| 
 | ||||
|     final List<AccountBadge> updatedBadges = request.getBadges() | ||||
|     final List<AccountBadge> updatedBadges = request.badges() | ||||
|         .map(badges -> ProfileHelper.mergeBadgeIdsWithExistingAccountBadges(clock, badgeConfigurationMap, badges, auth.getAccount().getBadges())) | ||||
|         .orElseGet(() -> auth.getAccount().getBadges()); | ||||
| 
 | ||||
|     accountsManager.update(auth.getAccount(), a -> { | ||||
|       a.setBadges(clock, updatedBadges); | ||||
|       a.setCurrentProfileVersion(request.getVersion()); | ||||
|       a.setCurrentProfileVersion(request.version()); | ||||
|     }); | ||||
| 
 | ||||
|     if (request.getAvatarChange() == CreateProfileRequest.AvatarChange.UPDATE) { | ||||
|  | @ -411,6 +412,7 @@ public class ProfileController { | |||
|     final byte[] about = maybeProfile.map(VersionedProfile::about).orElse(null); | ||||
|     final byte[] aboutEmoji = maybeProfile.map(VersionedProfile::aboutEmoji).orElse(null); | ||||
|     final String avatar = maybeProfile.map(VersionedProfile::avatar).orElse(null); | ||||
|     final byte[] phoneNumberSharing = maybeProfile.map(VersionedProfile::phoneNumberSharing).orElse(null); | ||||
| 
 | ||||
|     // Allow requests where either the version matches the latest version on Account or the latest version on Account | ||||
|     // is empty to read the payment address. | ||||
|  | @ -421,7 +423,7 @@ public class ProfileController { | |||
| 
 | ||||
|     return new VersionedProfileResponse( | ||||
|         buildBaseProfileResponseForAccountIdentity(account, isSelf, containerRequestContext), | ||||
|         name, about, aboutEmoji, avatar, paymentAddress); | ||||
|         name, about, aboutEmoji, avatar, paymentAddress, phoneNumberSharing); | ||||
|   } | ||||
| 
 | ||||
|   private BaseProfileResponse buildBaseProfileResponseForAccountIdentity(final Account account, | ||||
|  |  | |||
|  | @ -10,91 +10,62 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; | |||
| import com.fasterxml.jackson.databind.annotation.JsonSerialize; | ||||
| import java.util.List; | ||||
| import java.util.Optional; | ||||
| import javax.annotation.Nullable; | ||||
| import javax.validation.constraints.NotEmpty; | ||||
| import javax.validation.constraints.NotNull; | ||||
| import org.signal.libsignal.zkgroup.profiles.ProfileKeyCommitment; | ||||
| import org.whispersystems.textsecuregcm.util.ByteArrayBase64WithPaddingAdapter; | ||||
| import org.whispersystems.textsecuregcm.util.ExactlySize; | ||||
| 
 | ||||
| public class CreateProfileRequest { | ||||
| public record CreateProfileRequest( | ||||
|   @JsonProperty | ||||
|   @NotNull | ||||
|   @JsonDeserialize(using = ProfileKeyCommitmentAdapter.Deserializing.class) | ||||
|   @JsonSerialize(using = ProfileKeyCommitmentAdapter.Serializing.class) | ||||
|   ProfileKeyCommitment commitment, | ||||
| 
 | ||||
|   @JsonProperty | ||||
|   @NotEmpty | ||||
|   private String version; | ||||
|   String version, | ||||
| 
 | ||||
|   @JsonProperty | ||||
|   @JsonSerialize(using = ByteArrayBase64WithPaddingAdapter.Serializing.class) | ||||
|   @JsonDeserialize(using = ByteArrayBase64WithPaddingAdapter.Deserializing.class) | ||||
|   @ExactlySize({81, 285}) | ||||
|   private byte[] name; | ||||
| 
 | ||||
|   @JsonProperty | ||||
|   private boolean avatar; | ||||
| 
 | ||||
|   @JsonProperty | ||||
|   private boolean sameAvatar; | ||||
|   byte[] name, | ||||
| 
 | ||||
|   @JsonProperty | ||||
|   @JsonSerialize(using = ByteArrayBase64WithPaddingAdapter.Serializing.class) | ||||
|   @JsonDeserialize(using = ByteArrayBase64WithPaddingAdapter.Deserializing.class) | ||||
|   @ExactlySize({0, 60}) | ||||
|   private byte[] aboutEmoji; | ||||
|   byte[] aboutEmoji, | ||||
| 
 | ||||
|   @JsonProperty | ||||
|   @JsonSerialize(using = ByteArrayBase64WithPaddingAdapter.Serializing.class) | ||||
|   @JsonDeserialize(using = ByteArrayBase64WithPaddingAdapter.Deserializing.class) | ||||
|   @ExactlySize({0, 156, 282, 540}) | ||||
|   private byte[] about; | ||||
|   byte[] about, | ||||
| 
 | ||||
|   @JsonProperty | ||||
|   @JsonSerialize(using = ByteArrayBase64WithPaddingAdapter.Serializing.class) | ||||
|   @JsonDeserialize(using = ByteArrayBase64WithPaddingAdapter.Deserializing.class) | ||||
|   @ExactlySize({0, 582}) | ||||
|   private byte[] paymentAddress; | ||||
|   byte[] paymentAddress, | ||||
| 
 | ||||
|   @JsonProperty("avatar") | ||||
|   boolean hasAvatar, | ||||
| 
 | ||||
|   @JsonProperty | ||||
|   @Nullable | ||||
|   private List<String> badgeIds; | ||||
|   boolean sameAvatar, | ||||
| 
 | ||||
|   @JsonProperty("badgeIds") | ||||
|   Optional<List<String>> badges, | ||||
| 
 | ||||
|   @JsonProperty | ||||
|   @NotNull | ||||
|   @JsonDeserialize(using = ProfileKeyCommitmentAdapter.Deserializing.class) | ||||
|   @JsonSerialize(using = ProfileKeyCommitmentAdapter.Serializing.class) | ||||
|   private ProfileKeyCommitment commitment; | ||||
| 
 | ||||
|   public CreateProfileRequest() { | ||||
|   } | ||||
| 
 | ||||
|   public CreateProfileRequest( | ||||
|       final ProfileKeyCommitment commitment, final String version, final byte[] name, final byte[] aboutEmoji, final byte[] about, | ||||
|       final byte[] paymentAddress, final boolean wantsAvatar, final boolean sameAvatar, final List<String> badgeIds) { | ||||
|     this.commitment = commitment; | ||||
|     this.version = version; | ||||
|     this.name = name; | ||||
|     this.aboutEmoji = aboutEmoji; | ||||
|     this.about = about; | ||||
|     this.paymentAddress = paymentAddress; | ||||
|     this.avatar = wantsAvatar; | ||||
|     this.sameAvatar = sameAvatar; | ||||
|     this.badgeIds = badgeIds; | ||||
|   } | ||||
| 
 | ||||
|   public ProfileKeyCommitment getCommitment() { | ||||
|     return commitment; | ||||
|   } | ||||
| 
 | ||||
|   public String getVersion() { | ||||
|     return version; | ||||
|   } | ||||
| 
 | ||||
|   public byte[] getName() { | ||||
|     return name; | ||||
|   } | ||||
| 
 | ||||
|   public boolean hasAvatar() { | ||||
|     return avatar; | ||||
|   } | ||||
|   @JsonSerialize(using = ByteArrayBase64WithPaddingAdapter.Serializing.class) | ||||
|   @JsonDeserialize(using = ByteArrayBase64WithPaddingAdapter.Deserializing.class) | ||||
|   @ExactlySize({0, 29}) | ||||
|   byte[] phoneNumberSharing | ||||
| ) { | ||||
| 
 | ||||
|   public enum AvatarChange { | ||||
|     UNCHANGED, | ||||
|  | @ -112,19 +83,4 @@ public class CreateProfileRequest { | |||
|     return AvatarChange.UNCHANGED; | ||||
|   } | ||||
| 
 | ||||
|   public byte[] getAboutEmoji() { | ||||
|     return aboutEmoji; | ||||
|   } | ||||
| 
 | ||||
|   public byte[] getAbout() { | ||||
|     return about; | ||||
|   } | ||||
| 
 | ||||
|   public byte[] getPaymentAddress() { | ||||
|     return paymentAddress; | ||||
|   } | ||||
| 
 | ||||
|   public Optional<List<String>> getBadges() { | ||||
|     return Optional.ofNullable(badgeIds); | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -11,6 +11,8 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; | |||
| import com.fasterxml.jackson.databind.annotation.JsonSerialize; | ||||
| import org.whispersystems.textsecuregcm.util.ByteArrayBase64WithPaddingAdapter; | ||||
| 
 | ||||
| // Note, this class cannot be converted into a record because @JsonUnwrapped does not work with records. | ||||
| // https://github.com/FasterXML/jackson-databind/issues/1467 | ||||
| public class VersionedProfileResponse { | ||||
| 
 | ||||
|   @JsonUnwrapped | ||||
|  | @ -39,6 +41,11 @@ public class VersionedProfileResponse { | |||
|   @JsonDeserialize(using = ByteArrayBase64WithPaddingAdapter.Deserializing.class) | ||||
|   private byte[] paymentAddress; | ||||
| 
 | ||||
|   @JsonProperty | ||||
|   @JsonSerialize(using = ByteArrayBase64WithPaddingAdapter.Serializing.class) | ||||
|   @JsonDeserialize(using = ByteArrayBase64WithPaddingAdapter.Deserializing.class) | ||||
|   private byte[] phoneNumberSharing; | ||||
| 
 | ||||
|   public VersionedProfileResponse() { | ||||
|   } | ||||
| 
 | ||||
|  | @ -47,7 +54,8 @@ public class VersionedProfileResponse { | |||
|       final byte[] about, | ||||
|       final byte[] aboutEmoji, | ||||
|       final String avatar, | ||||
|       final byte[] paymentAddress) { | ||||
|       final byte[] paymentAddress, | ||||
|       final byte[] phoneNumberSharing) { | ||||
| 
 | ||||
|     this.baseProfileResponse = baseProfileResponse; | ||||
|     this.name = name; | ||||
|  | @ -55,6 +63,7 @@ public class VersionedProfileResponse { | |||
|     this.aboutEmoji = aboutEmoji; | ||||
|     this.avatar = avatar; | ||||
|     this.paymentAddress = paymentAddress; | ||||
|     this.phoneNumberSharing = phoneNumberSharing; | ||||
|   } | ||||
| 
 | ||||
|   public BaseProfileResponse getBaseProfileResponse() { | ||||
|  | @ -80,4 +89,8 @@ public class VersionedProfileResponse { | |||
|   public byte[] getPaymentAddress() { | ||||
|     return paymentAddress; | ||||
|   } | ||||
| 
 | ||||
|   public byte[] getPhoneNumberSharing() { | ||||
|     return phoneNumberSharing; | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -48,6 +48,7 @@ public class ProfileGrpcHelper { | |||
|           maybeProfile.map(VersionedProfile::about).map(ByteString::copyFrom).ifPresent(responseBuilder::setAbout); | ||||
|           maybeProfile.map(VersionedProfile::aboutEmoji).map(ByteString::copyFrom).ifPresent(responseBuilder::setAboutEmoji); | ||||
|           maybeProfile.map(VersionedProfile::avatar).ifPresent(responseBuilder::setAvatar); | ||||
|           maybeProfile.map(VersionedProfile::phoneNumberSharing).map(ByteString::copyFrom).ifPresent(responseBuilder::setPhoneNumberSharing); | ||||
| 
 | ||||
|           // Allow requests where either the version matches the latest version on Account or the latest version on Account | ||||
|           // is empty to read the payment address. | ||||
|  |  | |||
|  | @ -141,6 +141,7 @@ public class ProfileGrpcService extends ReactorProfileGrpc.ProfileImplBase { | |||
|                   request.getAboutEmoji().toByteArray(), | ||||
|                   request.getAbout().toByteArray(), | ||||
|                   request.getPaymentAddress().toByteArray(), | ||||
|                   request.getPhoneNumberSharing().toByteArray(), | ||||
|                   request.getCommitment().toByteArray()))); | ||||
| 
 | ||||
|           final List<Mono<?>> updates = new ArrayList<>(2); | ||||
|  |  | |||
|  | @ -62,6 +62,9 @@ public class Profiles { | |||
|   // Payment address; byte array | ||||
|   private static final String ATTR_PAYMENT_ADDRESS = "P"; | ||||
| 
 | ||||
|   // Phone number sharing setting; byte array | ||||
|   private static final String ATTR_PHONE_NUMBER_SHARING = "S"; | ||||
| 
 | ||||
|   // Commitment; byte array | ||||
|   private static final String ATTR_COMMITMENT = "C"; | ||||
| 
 | ||||
|  | @ -71,7 +74,8 @@ public class Profiles { | |||
|       "#avatar", ATTR_AVATAR, | ||||
|       "#about", ATTR_ABOUT, | ||||
|       "#aboutEmoji", ATTR_EMOJI, | ||||
|       "#paymentAddress", ATTR_PAYMENT_ADDRESS); | ||||
|       "#paymentAddress", ATTR_PAYMENT_ADDRESS, | ||||
|       "#phoneNumberSharing", ATTR_PHONE_NUMBER_SHARING); | ||||
| 
 | ||||
|   private static final Timer SET_PROFILES_TIMER = Metrics.timer(name(Profiles.class, "set")); | ||||
|   private static final Timer GET_PROFILE_TIMER = Metrics.timer(name(Profiles.class, "get")); | ||||
|  | @ -154,6 +158,12 @@ public class Profiles { | |||
|       deletedAttributes.add("paymentAddress"); | ||||
|     } | ||||
| 
 | ||||
|     if (profile.phoneNumberSharing() != null) { | ||||
|       updatedAttributes.add("phoneNumberSharing"); | ||||
|     } else { | ||||
|       deletedAttributes.add("phoneNumberSharing"); | ||||
|     } | ||||
| 
 | ||||
|     final StringBuilder updateExpressionBuilder = new StringBuilder( | ||||
|         "SET #commitment = if_not_exists(#commitment, :commitment)"); | ||||
| 
 | ||||
|  | @ -201,6 +211,9 @@ public class Profiles { | |||
|       expressionValues.put(":paymentAddress", AttributeValues.fromByteArray(profile.paymentAddress())); | ||||
|     } | ||||
|      | ||||
|     if (profile.phoneNumberSharing() != null) { | ||||
|       expressionValues.put(":phoneNumberSharing", AttributeValues.fromByteArray(profile.phoneNumberSharing())); | ||||
|     } | ||||
|     return expressionValues; | ||||
|   } | ||||
| 
 | ||||
|  | @ -235,6 +248,7 @@ public class Profiles { | |||
|         getBytes(item, ATTR_EMOJI), | ||||
|         getBytes(item, ATTR_ABOUT), | ||||
|         getBytes(item, ATTR_PAYMENT_ADDRESS), | ||||
|         getBytes(item, ATTR_PHONE_NUMBER_SHARING), | ||||
|         AttributeValues.getByteArray(item, ATTR_COMMITMENT, null)); | ||||
|   } | ||||
| 
 | ||||
|  |  | |||
|  | @ -5,14 +5,10 @@ | |||
| 
 | ||||
| package org.whispersystems.textsecuregcm.storage; | ||||
| 
 | ||||
| import com.fasterxml.jackson.annotation.JsonCreator; | ||||
| 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 org.whispersystems.textsecuregcm.util.ByteArrayBase64WithPaddingAdapter; | ||||
| import java.util.Arrays; | ||||
| import java.util.Objects; | ||||
| 
 | ||||
| public record VersionedProfile (String version, | ||||
|                                 @JsonSerialize(using = ByteArrayBase64WithPaddingAdapter.Serializing.class) | ||||
|  | @ -33,6 +29,10 @@ public record VersionedProfile (String version, | |||
|                                 @JsonDeserialize(using = ByteArrayBase64WithPaddingAdapter.Deserializing.class) | ||||
|                                 byte[] paymentAddress, | ||||
| 
 | ||||
|                                 @JsonSerialize(using = ByteArrayAdapter.Serializing.class) | ||||
|                                 @JsonDeserialize(using = ByteArrayAdapter.Deserializing.class) | ||||
|                                 byte[] phoneNumberSharing, | ||||
| 
 | ||||
|                                 @JsonSerialize(using = ByteArrayAdapter.Serializing.class) | ||||
|                                 @JsonDeserialize(using = ByteArrayAdapter.Deserializing.class) | ||||
|                                 byte[] commitment) {} | ||||
|  |  | |||
|  | @ -132,6 +132,10 @@ message SetProfileRequest { | |||
|    * A list of badge IDs associated with the profile. | ||||
|    */ | ||||
|   repeated string badge_ids = 7; | ||||
|   /** | ||||
|    * The ciphertext of the phone-number sharing setting on the profile. 29-byte encrypted boolean. | ||||
|    */ | ||||
|   bytes phone_number_sharing = 8; | ||||
|   /** | ||||
|    * The profile key commitment. Used to issue a profile key credential response. | ||||
|    * Must be set on the request. | ||||
|  | @ -189,6 +193,10 @@ message GetVersionedProfileResponse { | |||
|    * The ciphertext of the MobileCoin wallet ID on the profile. | ||||
|    */ | ||||
|   bytes payment_address = 5; | ||||
|   /** | ||||
|    * The ciphertext of the phone-number sharing setting on the profile. | ||||
|    */ | ||||
|   bytes phone_number_sharing = 6; | ||||
| } | ||||
| 
 | ||||
| message GetUnversionedProfileRequest { | ||||
|  |  | |||
|  | @ -227,10 +227,11 @@ class ProfileControllerTest { | |||
|     final byte[] name = TestRandomUtil.nextBytes(81); | ||||
|     final byte[] emoji = TestRandomUtil.nextBytes(60); | ||||
|     final byte[] about = TestRandomUtil.nextBytes(156); | ||||
|     final byte[] phoneNumberSharing = TestRandomUtil.nextBytes(29); | ||||
| 
 | ||||
|     when(profilesManager.get(eq(AuthHelper.VALID_UUID), eq("someversion"))).thenReturn(Optional.empty()); | ||||
|     when(profilesManager.get(eq(AuthHelper.VALID_UUID_TWO), eq("validversion"))).thenReturn(Optional.of(new VersionedProfile( | ||||
|         "validversion", name, "profiles/validavatar", emoji, about, null, "validcommitmnet".getBytes()))); | ||||
|         "validversion", name, "profiles/validavatar", emoji, about, null, phoneNumberSharing, "validcommitment".getBytes()))); | ||||
| 
 | ||||
|     clearInvocations(rateLimiter); | ||||
|     clearInvocations(accountsManager); | ||||
|  | @ -419,7 +420,7 @@ class ProfileControllerTest { | |||
|         .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) | ||||
|         .put(Entity.entity(new CreateProfileRequest(commitment, "someversion", | ||||
|             name, null, null, | ||||
|             null, true, false, List.of()), MediaType.APPLICATION_JSON_TYPE), ProfileAvatarUploadAttributes.class); | ||||
|             null, true, false, Optional.of(List.of()), null), MediaType.APPLICATION_JSON_TYPE), ProfileAvatarUploadAttributes.class); | ||||
| 
 | ||||
|     final ArgumentCaptor<VersionedProfile> profileArgumentCaptor = ArgumentCaptor.forClass(VersionedProfile.class); | ||||
| 
 | ||||
|  | @ -446,7 +447,7 @@ class ProfileControllerTest { | |||
|         .request() | ||||
|         .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) | ||||
|         .put(Entity.entity(new CreateProfileRequest(commitment, "someversion", name, | ||||
|             null, null, null, true, false, List.of()), MediaType.APPLICATION_JSON_TYPE))) { | ||||
|             null, null, null, true, false, Optional.of(List.of()), null), MediaType.APPLICATION_JSON_TYPE))) { | ||||
| 
 | ||||
|       assertThat(response.getStatus()).isEqualTo(422); | ||||
|     } | ||||
|  | @ -456,6 +457,7 @@ class ProfileControllerTest { | |||
|   void testSetProfileWithoutAvatarUpload() throws InvalidInputException { | ||||
|     final ProfileKeyCommitment commitment = new ProfileKey(new byte[32]).getCommitment(new ServiceId.Aci(AuthHelper.VALID_UUID)); | ||||
|     final byte[] name = TestRandomUtil.nextBytes(81); | ||||
|     final byte[] phoneNumberSharing = TestRandomUtil.nextBytes(29); | ||||
| 
 | ||||
|     clearInvocations(AuthHelper.VALID_ACCOUNT_TWO); | ||||
| 
 | ||||
|  | @ -464,7 +466,7 @@ class ProfileControllerTest { | |||
|         .request() | ||||
|         .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO)) | ||||
|         .put(Entity.entity(new CreateProfileRequest(commitment, "anotherversion", name, null, null, | ||||
|             null, false, false, List.of()), MediaType.APPLICATION_JSON_TYPE))) { | ||||
|             null, false, false, Optional.of(List.of()), phoneNumberSharing), MediaType.APPLICATION_JSON_TYPE))) { | ||||
| 
 | ||||
|       assertThat(response.getStatus()).isEqualTo(200); | ||||
|       assertThat(response.hasEntity()).isFalse(); | ||||
|  | @ -482,6 +484,7 @@ class ProfileControllerTest { | |||
|       assertThat(profileArgumentCaptor.getValue().name()).isEqualTo(name); | ||||
|       assertThat(profileArgumentCaptor.getValue().aboutEmoji()).isNull(); | ||||
|       assertThat(profileArgumentCaptor.getValue().about()).isNull(); | ||||
|       assertThat(profileArgumentCaptor.getValue().phoneNumberSharing()).isEqualTo(phoneNumberSharing); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | @ -496,7 +499,7 @@ class ProfileControllerTest { | |||
|         .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO)) | ||||
|         .put(Entity.entity(new CreateProfileRequest(commitment, "validversion", | ||||
|             name, null, null, | ||||
|             null, true, false, List.of()), MediaType.APPLICATION_JSON_TYPE), ProfileAvatarUploadAttributes.class); | ||||
|             null, true, false, Optional.of(List.of()), null), MediaType.APPLICATION_JSON_TYPE), ProfileAvatarUploadAttributes.class); | ||||
| 
 | ||||
|     final ArgumentCaptor<VersionedProfile> profileArgumentCaptor = ArgumentCaptor.forClass(VersionedProfile.class); | ||||
| 
 | ||||
|  | @ -522,7 +525,7 @@ class ProfileControllerTest { | |||
|         .request() | ||||
|         .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO)) | ||||
|         .put(Entity.entity(new CreateProfileRequest(commitment, "validversion", name, | ||||
|             null, null, null, false, false, List.of()), MediaType.APPLICATION_JSON_TYPE))) { | ||||
|             null, null, null, false, false, Optional.of(List.of()), null), MediaType.APPLICATION_JSON_TYPE))) { | ||||
| 
 | ||||
|       assertThat(response.getStatus()).isEqualTo(200); | ||||
|       assertThat(response.hasEntity()).isFalse(); | ||||
|  | @ -552,7 +555,7 @@ class ProfileControllerTest { | |||
|         .request() | ||||
|         .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO)) | ||||
|         .put(Entity.entity(new CreateProfileRequest(commitment, "validversion", name, | ||||
|             null, null, null, true, true, List.of()), MediaType.APPLICATION_JSON_TYPE))) { | ||||
|             null, null, null, true, true, Optional.of(List.of()), null), MediaType.APPLICATION_JSON_TYPE))) { | ||||
| 
 | ||||
|       assertThat(response.getStatus()).isEqualTo(200); | ||||
|       assertThat(response.hasEntity()).isFalse(); | ||||
|  | @ -583,7 +586,7 @@ class ProfileControllerTest { | |||
|         .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO)) | ||||
|         .put(Entity.entity(new CreateProfileRequest(commitment, "validversion", name, | ||||
|             null, null, | ||||
|             null, false, true, List.of()), MediaType.APPLICATION_JSON_TYPE))) { | ||||
|             null, false, true, Optional.of(List.of()), null), MediaType.APPLICATION_JSON_TYPE))) { | ||||
| 
 | ||||
|       final ArgumentCaptor<VersionedProfile> profileArgumentCaptor = ArgumentCaptor.forClass(VersionedProfile.class); | ||||
| 
 | ||||
|  | @ -610,7 +613,7 @@ class ProfileControllerTest { | |||
|         .request() | ||||
|         .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) | ||||
|         .put(Entity.entity(new CreateProfileRequest(commitment, "validversion", name, | ||||
|             null, null, null, true, true, List.of()), MediaType.APPLICATION_JSON_TYPE))) { | ||||
|             null, null, null, true, true, Optional.of(List.of()), null), MediaType.APPLICATION_JSON_TYPE))) { | ||||
| 
 | ||||
|       assertThat(response.getStatus()).isEqualTo(200); | ||||
|       assertThat(response.hasEntity()).isFalse(); | ||||
|  | @ -642,7 +645,7 @@ class ProfileControllerTest { | |||
|         .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO)) | ||||
|         .put(Entity.entity( | ||||
|             new CreateProfileRequest(commitment, "validversion", name, | ||||
|                 null, null, null, true, false, List.of()), | ||||
|                 null, null, null, true, false, Optional.of(List.of()), null), | ||||
|             MediaType.APPLICATION_JSON_TYPE), ProfileAvatarUploadAttributes.class); | ||||
| 
 | ||||
|     final ArgumentCaptor<VersionedProfile> profileArgumentCaptor = ArgumentCaptor.forClass(VersionedProfile.class); | ||||
|  | @ -675,7 +678,7 @@ class ProfileControllerTest { | |||
|         .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO)) | ||||
|         .put(Entity.entity( | ||||
|             new CreateProfileRequest(commitment, "anotherversion", name, emoji, about, null, | ||||
|                 false, false, List.of()), | ||||
|                 false, false, Optional.of(List.of()), null), | ||||
|             MediaType.APPLICATION_JSON_TYPE))) { | ||||
| 
 | ||||
|       assertThat(response.getStatus()).isEqualTo(200); | ||||
|  | @ -715,7 +718,7 @@ class ProfileControllerTest { | |||
|         .put(Entity.entity( | ||||
|             new CreateProfileRequest(commitment, "yetanotherversion", name, | ||||
|                 null, null, paymentAddress, false, false, | ||||
|                 List.of()), MediaType.APPLICATION_JSON_TYPE))) { | ||||
|                 Optional.of(List.of()), null), MediaType.APPLICATION_JSON_TYPE))) { | ||||
| 
 | ||||
|       assertThat(response.getStatus()).isEqualTo(200); | ||||
|       assertThat(response.hasEntity()).isFalse(); | ||||
|  | @ -757,7 +760,7 @@ class ProfileControllerTest { | |||
|         .put(Entity.entity( | ||||
|             new CreateProfileRequest(commitment, "yetanotherversion", name, | ||||
|                 null, null, paymentAddress, false, false, | ||||
|                 List.of()), MediaType.APPLICATION_JSON_TYPE))) { | ||||
|                 Optional.of(List.of()), null), MediaType.APPLICATION_JSON_TYPE))) { | ||||
| 
 | ||||
|       assertThat(response.getStatus()).isEqualTo(403); | ||||
|       assertThat(response.hasEntity()).isFalse(); | ||||
|  | @ -776,6 +779,7 @@ class ProfileControllerTest { | |||
|     final ProfileKeyCommitment commitment = new ProfileKey(new byte[32]).getCommitment(new ServiceId.Aci(AuthHelper.VALID_UUID)); | ||||
|     final byte[] name = TestRandomUtil.nextBytes(81); | ||||
|     final byte[] paymentAddress = TestRandomUtil.nextBytes(582); | ||||
|     final byte[] phoneNumberSharing = TestRandomUtil.nextBytes(29); | ||||
| 
 | ||||
|     clearInvocations(AuthHelper.VALID_ACCOUNT_TWO); | ||||
| 
 | ||||
|  | @ -783,6 +787,7 @@ class ProfileControllerTest { | |||
|         .thenReturn(Optional.of( | ||||
|             new VersionedProfile("1", name, null, null, null, | ||||
|                 existingPaymentAddressOnProfile ? TestRandomUtil.nextBytes(582) : null, | ||||
|                 phoneNumberSharing, | ||||
|                 commitment.serialize()))); | ||||
| 
 | ||||
| 
 | ||||
|  | @ -793,7 +798,7 @@ class ProfileControllerTest { | |||
|         .put(Entity.entity( | ||||
|             new CreateProfileRequest(commitment, "yetanotherversion", name, | ||||
|                 null, null, paymentAddress, false, false, | ||||
|                 List.of()), MediaType.APPLICATION_JSON_TYPE))) { | ||||
|                 Optional.of(List.of()), null), MediaType.APPLICATION_JSON_TYPE))) { | ||||
| 
 | ||||
|       if (existingPaymentAddressOnProfile) { | ||||
|         assertThat(response.getStatus()).isEqualTo(200); | ||||
|  | @ -823,14 +828,49 @@ class ProfileControllerTest { | |||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @Test | ||||
|   void testSetProfilePhoneNumberSharing() throws Exception { | ||||
|     final ProfileKeyCommitment commitment = new ProfileKey(new byte[32]).getCommitment(new ServiceId.Aci(AuthHelper.VALID_UUID)); | ||||
|     final byte[] name = TestRandomUtil.nextBytes(81); | ||||
|     final byte[] phoneNumberSharing = TestRandomUtil.nextBytes(29); | ||||
| 
 | ||||
|     clearInvocations(AuthHelper.VALID_ACCOUNT_TWO); | ||||
| 
 | ||||
|     try (final Response response = resources.getJerseyTest() | ||||
|         .target("/v1/profile/") | ||||
|         .request() | ||||
|         .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO)) | ||||
|         .put(Entity.entity(new CreateProfileRequest(commitment, "anotherversion", name, null, null, | ||||
|             null, false, false, Optional.of(List.of()), phoneNumberSharing), MediaType.APPLICATION_JSON_TYPE))) { | ||||
| 
 | ||||
|       assertThat(response.getStatus()).isEqualTo(200); | ||||
|       assertThat(response.hasEntity()).isFalse(); | ||||
| 
 | ||||
|       final ArgumentCaptor<VersionedProfile> profileArgumentCaptor = ArgumentCaptor.forClass(VersionedProfile.class); | ||||
| 
 | ||||
|       verify(profilesManager, times(1)).get(eq(AuthHelper.VALID_UUID_TWO), eq("anotherversion")); | ||||
|       verify(profilesManager, times(1)).set(eq(AuthHelper.VALID_UUID_TWO), profileArgumentCaptor.capture()); | ||||
| 
 | ||||
|       verifyNoMoreInteractions(s3client); | ||||
| 
 | ||||
|       assertThat(profileArgumentCaptor.getValue().commitment()).isEqualTo(commitment.serialize()); | ||||
|       assertThat(profileArgumentCaptor.getValue().avatar()).isNull(); | ||||
|       assertThat(profileArgumentCaptor.getValue().version()).isEqualTo("anotherversion"); | ||||
|       assertThat(profileArgumentCaptor.getValue().name()).isEqualTo(name); | ||||
|       assertThat(profileArgumentCaptor.getValue().aboutEmoji()).isNull(); | ||||
|       assertThat(profileArgumentCaptor.getValue().about()).isNull(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @Test | ||||
|   void testGetProfileByVersion() throws RateLimitExceededException { | ||||
|     final byte[] name = TestRandomUtil.nextBytes(81); | ||||
|     final byte[] emoji = TestRandomUtil.nextBytes(60); | ||||
|     final byte[] about = TestRandomUtil.nextBytes(156); | ||||
|     final byte[] phoneNumberSharing = TestRandomUtil.nextBytes(29); | ||||
| 
 | ||||
|     when(profilesManager.get(eq(AuthHelper.VALID_UUID_TWO), eq("validversion"))).thenReturn(Optional.of(new VersionedProfile( | ||||
|         "validversion", name, "profiles/validavatar", emoji, about, null, "validcommitmnet".getBytes()))); | ||||
|         "validversion", name, "profiles/validavatar", emoji, about, null, phoneNumberSharing, "validcommitment".getBytes()))); | ||||
| 
 | ||||
|     final VersionedProfileResponse profile = resources.getJerseyTest() | ||||
|         .target("/v1/profile/" + AuthHelper.VALID_UUID_TWO + "/validversion") | ||||
|  | @ -843,6 +883,7 @@ class ProfileControllerTest { | |||
|     assertThat(profile.getAbout()).containsExactly(about); | ||||
|     assertThat(profile.getAboutEmoji()).containsExactly(emoji); | ||||
|     assertThat(profile.getAvatar()).isEqualTo("profiles/validavatar"); | ||||
|     assertThat(profile.getPhoneNumberSharing()).containsExactly(phoneNumberSharing); | ||||
|     assertThat(profile.getBaseProfileResponse().getCapabilities().gv1Migration()).isTrue(); | ||||
|     assertThat(profile.getBaseProfileResponse().getUuid()).isEqualTo(new AciServiceIdentifier(AuthHelper.VALID_UUID_TWO)); | ||||
|     assertThat(profile.getBaseProfileResponse().getBadges()).hasSize(1).element(0).has(new Condition<>( | ||||
|  | @ -869,7 +910,7 @@ class ProfileControllerTest { | |||
|         .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO)) | ||||
|         .put(Entity.entity( | ||||
|             new CreateProfileRequest(commitment, "someversion", name, null, null, paymentAddress, false, false, | ||||
|                 List.of()), MediaType.APPLICATION_JSON_TYPE))) { | ||||
|                 Optional.of(List.of()), null), MediaType.APPLICATION_JSON_TYPE))) { | ||||
| 
 | ||||
|       assertThat(response.getStatus()).isEqualTo(200); | ||||
|       assertThat(response.hasEntity()).isFalse(); | ||||
|  | @ -882,7 +923,7 @@ class ProfileControllerTest { | |||
|   void testGetProfileReturnsNoPaymentAddressIfCurrentVersionMismatch() { | ||||
|     final byte[] paymentAddress = TestRandomUtil.nextBytes(582); | ||||
|     when(profilesManager.get(AuthHelper.VALID_UUID_TWO, "validversion")).thenReturn( | ||||
|         Optional.of(new VersionedProfile(null, null, null, null, null, paymentAddress, null))); | ||||
|         Optional.of(new VersionedProfile(null, null, null, null, null, paymentAddress, null, null))); | ||||
| 
 | ||||
|     { | ||||
|       final VersionedProfileResponse profile = resources.getJerseyTest() | ||||
|  | @ -959,7 +1000,7 @@ class ProfileControllerTest { | |||
|         .request() | ||||
|         .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO)) | ||||
|         .put(Entity.entity(new CreateProfileRequest(commitment, "anotherversion", name, emoji, about, null, false, false, | ||||
|             List.of("TEST2")), MediaType.APPLICATION_JSON_TYPE))) { | ||||
|             Optional.of(List.of("TEST2")), null), MediaType.APPLICATION_JSON_TYPE))) { | ||||
| 
 | ||||
|       assertThat(response.getStatus()).isEqualTo(200); | ||||
|       assertThat(response.hasEntity()).isFalse(); | ||||
|  | @ -982,7 +1023,7 @@ class ProfileControllerTest { | |||
|         .request() | ||||
|         .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO)) | ||||
|         .put(Entity.entity(new CreateProfileRequest(commitment, "anotherversion", name, emoji, about, null, false, false, | ||||
|             List.of("TEST3", "TEST2")), MediaType.APPLICATION_JSON_TYPE))) { | ||||
|             Optional.of(List.of("TEST3", "TEST2")), null), MediaType.APPLICATION_JSON_TYPE))) { | ||||
| 
 | ||||
|       assertThat(response.getStatus()).isEqualTo(200); | ||||
|       assertThat(response.hasEntity()).isFalse(); | ||||
|  | @ -1008,7 +1049,7 @@ class ProfileControllerTest { | |||
|         .request() | ||||
|         .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO)) | ||||
|         .put(Entity.entity(new CreateProfileRequest(commitment, "anotherversion", name, emoji, about, null, false, false, | ||||
|             List.of("TEST2", "TEST3")), MediaType.APPLICATION_JSON_TYPE))) { | ||||
|             Optional.of(List.of("TEST2", "TEST3")), null), MediaType.APPLICATION_JSON_TYPE))) { | ||||
| 
 | ||||
|       assertThat(response.getStatus()).isEqualTo(200); | ||||
|       assertThat(response.hasEntity()).isFalse(); | ||||
|  | @ -1034,7 +1075,7 @@ class ProfileControllerTest { | |||
|         .request() | ||||
|         .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO)) | ||||
|         .put(Entity.entity(new CreateProfileRequest(commitment, "anotherversion", name, emoji, about, null, false, false, | ||||
|             List.of("TEST1")), MediaType.APPLICATION_JSON_TYPE))) { | ||||
|             Optional.of(List.of("TEST1")), null), MediaType.APPLICATION_JSON_TYPE))) { | ||||
| 
 | ||||
|       assertThat(response.getStatus()).isEqualTo(200); | ||||
|       assertThat(response.hasEntity()).isFalse(); | ||||
|  |  | |||
|  | @ -218,6 +218,7 @@ public class ProfileGrpcServiceTest extends SimpleBaseGrpcTest<ProfileGrpcServic | |||
|     final byte[] validAboutEmoji = new byte[60]; | ||||
|     final byte[] validAbout = new byte[540]; | ||||
|     final byte[] validPaymentAddress = new byte[582]; | ||||
|     final byte[] validPhoneNumberSharing = new byte[29]; | ||||
| 
 | ||||
|     final SetProfileRequest request = SetProfileRequest.newBuilder() | ||||
|         .setVersion(VERSION) | ||||
|  | @ -226,6 +227,7 @@ public class ProfileGrpcServiceTest extends SimpleBaseGrpcTest<ProfileGrpcServic | |||
|         .setAboutEmoji(ByteString.copyFrom(validAboutEmoji)) | ||||
|         .setAbout(ByteString.copyFrom(validAbout)) | ||||
|         .setPaymentAddress(ByteString.copyFrom(validPaymentAddress)) | ||||
|         .setPhoneNumberSharing(ByteString.copyFrom(validPhoneNumberSharing)) | ||||
|         .setCommitment(ByteString.copyFrom(commitment)) | ||||
|         .build(); | ||||
| 
 | ||||
|  | @ -244,6 +246,7 @@ public class ProfileGrpcServiceTest extends SimpleBaseGrpcTest<ProfileGrpcServic | |||
|     assertThat(profile.aboutEmoji()).isEqualTo(validAboutEmoji); | ||||
|     assertThat(profile.about()).isEqualTo(validAbout); | ||||
|     assertThat(profile.paymentAddress()).isEqualTo(validPaymentAddress); | ||||
|     assertThat(profile.phoneNumberSharing()).isEqualTo(validPhoneNumberSharing); | ||||
|   } | ||||
| 
 | ||||
|   @ParameterizedTest | ||||
|  |  | |||
|  | @ -110,7 +110,7 @@ public class ProfilesManagerTest { | |||
|     final UUID uuid = UUID.randomUUID(); | ||||
|     final byte[] name = TestRandomUtil.nextBytes(81); | ||||
|     final VersionedProfile profile = new VersionedProfile("someversion", name, "someavatar", null, null, | ||||
|         null, "somecommitment".getBytes()); | ||||
|         null, null, "somecommitment".getBytes()); | ||||
| 
 | ||||
|     when(commands.hget(eq("profiles::" + uuid), eq("someversion"))).thenReturn(null); | ||||
|     when(profiles.get(eq(uuid), eq("someversion"))).thenReturn(Optional.of(profile)); | ||||
|  | @ -133,7 +133,7 @@ public class ProfilesManagerTest { | |||
|     final UUID uuid = UUID.randomUUID(); | ||||
|     final byte[] name = TestRandomUtil.nextBytes(81); | ||||
|     final VersionedProfile profile = new VersionedProfile("someversion", name, "someavatar", null, null, | ||||
|         null, "somecommitment".getBytes()); | ||||
|         null, null, "somecommitment".getBytes()); | ||||
| 
 | ||||
|     when(asyncCommands.hget(eq("profiles::" + uuid), eq("someversion"))).thenReturn(MockRedisFuture.completedFuture(null)); | ||||
|     when(asyncCommands.hset(eq("profiles::" + uuid), eq("someversion"), anyString())).thenReturn(MockRedisFuture.completedFuture(null)); | ||||
|  | @ -157,7 +157,7 @@ public class ProfilesManagerTest { | |||
|     final UUID uuid = UUID.randomUUID(); | ||||
|     final byte[] name = TestRandomUtil.nextBytes(81); | ||||
|     final VersionedProfile profile = new VersionedProfile("someversion", name, "someavatar", null, null, | ||||
|         null, "somecommitment".getBytes()); | ||||
|         null, null, "somecommitment".getBytes()); | ||||
| 
 | ||||
|     when(commands.hget(eq("profiles::" + uuid), eq("someversion"))).thenThrow(new RedisException("Connection lost")); | ||||
|     when(profiles.get(eq(uuid), eq("someversion"))).thenReturn(Optional.of(profile)); | ||||
|  | @ -180,7 +180,7 @@ public class ProfilesManagerTest { | |||
|     final UUID uuid = UUID.randomUUID(); | ||||
|     final byte[] name = TestRandomUtil.nextBytes(81); | ||||
|     final VersionedProfile profile = new VersionedProfile("someversion", name, "someavatar", null, null, | ||||
|         null, "somecommitment".getBytes()); | ||||
|         null, null, "somecommitment".getBytes()); | ||||
| 
 | ||||
|     when(asyncCommands.hget(eq("profiles::" + uuid), eq("someversion"))).thenReturn(MockRedisFuture.failedFuture(new RedisException("Connection lost"))); | ||||
|     when(asyncCommands.hset(eq("profiles::" + uuid), eq("someversion"), anyString())).thenReturn(MockRedisFuture.completedFuture(null)); | ||||
|  | @ -204,7 +204,7 @@ public class ProfilesManagerTest { | |||
|     final UUID uuid = UUID.randomUUID(); | ||||
|     final byte[] name = TestRandomUtil.nextBytes(81); | ||||
|     final VersionedProfile profile = new VersionedProfile("someversion", name, "someavatar", null, null, | ||||
|         null, "somecommitment".getBytes()); | ||||
|         null, null, "somecommitment".getBytes()); | ||||
| 
 | ||||
|     profilesManager.set(uuid, profile); | ||||
| 
 | ||||
|  | @ -220,7 +220,7 @@ public class ProfilesManagerTest { | |||
|     final UUID uuid = UUID.randomUUID(); | ||||
|     final byte[] name = TestRandomUtil.nextBytes(81); | ||||
|     final VersionedProfile profile = new VersionedProfile("someversion", name, "someavatar", null, null, | ||||
|         null, "somecommitment".getBytes()); | ||||
|         null, null, "somecommitment".getBytes()); | ||||
| 
 | ||||
|     when(asyncCommands.hset(eq("profiles::" + uuid), eq("someversion"), anyString())).thenReturn(MockRedisFuture.completedFuture(null)); | ||||
|     when(profiles.setAsync(eq(uuid), eq(profile))).thenReturn(CompletableFuture.completedFuture(null)); | ||||
|  |  | |||
|  | @ -48,8 +48,9 @@ public class ProfilesTest { | |||
|     final byte[] validAboutEmoji = TestRandomUtil.nextBytes(60); | ||||
|     final byte[] validAbout = TestRandomUtil.nextBytes(156); | ||||
|     final String avatar = "profiles/" + ProfileTestHelper.generateRandomBase64FromByteArray(16); | ||||
|     final byte[] phoneNumberSharing = TestRandomUtil.nextBytes(29); | ||||
| 
 | ||||
|     validProfile = new VersionedProfile(version, name, avatar, validAboutEmoji, validAbout, null, commitment); | ||||
|     validProfile = new VersionedProfile(version, name, avatar, validAboutEmoji, validAbout, null, phoneNumberSharing, commitment); | ||||
|   } | ||||
| 
 | ||||
|   @Test | ||||
|  | @ -92,10 +93,11 @@ public class ProfilesTest { | |||
|     final byte[] differentEmoji = TestRandomUtil.nextBytes(60); | ||||
|     final byte[] differentAbout = TestRandomUtil.nextBytes(156); | ||||
|     final byte[] paymentAddress = TestRandomUtil.nextBytes(582); | ||||
|     final byte[] phoneNumberSharing = TestRandomUtil.nextBytes(29); | ||||
|     final byte[] commitment = new ProfileKey(TestRandomUtil.nextBytes(32)).getCommitment(new ServiceId.Aci(ACI)).serialize(); | ||||
| 
 | ||||
|     VersionedProfile updatedProfile = new VersionedProfile(version, name, differentAvatar, | ||||
|         differentEmoji, differentAbout, paymentAddress, commitment); | ||||
|         differentEmoji, differentAbout, paymentAddress, phoneNumberSharing, commitment); | ||||
| 
 | ||||
|     profiles.set(ACI, updatedProfile); | ||||
| 
 | ||||
|  | @ -115,7 +117,7 @@ public class ProfilesTest { | |||
|     final byte[] name = TestRandomUtil.nextBytes(81); | ||||
|     final byte[] commitment = new ProfileKey(TestRandomUtil.nextBytes(32)).getCommitment(new ServiceId.Aci(ACI)).serialize(); | ||||
| 
 | ||||
|     VersionedProfile profile = new VersionedProfile(version, name, null, null, null, null, | ||||
|     VersionedProfile profile = new VersionedProfile(version, name, null, null, null, null, null, | ||||
|         commitment); | ||||
|     profiles.set(ACI, profile); | ||||
| 
 | ||||
|  | @ -147,10 +149,11 @@ public class ProfilesTest { | |||
|     final byte[] differentEmoji = TestRandomUtil.nextBytes(60); | ||||
|     final byte[] differentAbout = TestRandomUtil.nextBytes(156); | ||||
|     final String differentAvatar = "profiles/" + ProfileTestHelper.generateRandomBase64FromByteArray(16); | ||||
|     final byte[] differentPhoneNumberSharing = TestRandomUtil.nextBytes(29); | ||||
|     final byte[] differentCommitment = new ProfileKey(TestRandomUtil.nextBytes(32)).getCommitment(new ServiceId.Aci(ACI)).serialize(); | ||||
| 
 | ||||
|     VersionedProfile updated = new VersionedProfile(validProfile.version(), differentName, differentAvatar, differentEmoji, differentAbout, null, | ||||
|         differentCommitment); | ||||
|         differentPhoneNumberSharing, differentCommitment); | ||||
|     profiles.set(ACI, updated); | ||||
| 
 | ||||
|     retrieved = profiles.get(ACI, updated.version()); | ||||
|  | @ -160,6 +163,7 @@ public class ProfilesTest { | |||
|     assertThat(retrieved.get().about()).isEqualTo(updated.about()); | ||||
|     assertThat(retrieved.get().aboutEmoji()).isEqualTo(updated.aboutEmoji()); | ||||
|     assertThat(retrieved.get().avatar()).isEqualTo(updated.avatar()); | ||||
|     assertThat(retrieved.get().phoneNumberSharing()).isEqualTo(updated.phoneNumberSharing()); | ||||
| 
 | ||||
|     // Commitment should be unchanged after an overwrite | ||||
|     assertThat(retrieved.get().commitment()).isEqualTo(validProfile.commitment()); | ||||
|  | @ -183,8 +187,8 @@ public class ProfilesTest { | |||
|     final byte[] commitmentTwo = new ProfileKey(TestRandomUtil.nextBytes(32)).getCommitment(new ServiceId.Aci(ACI)).serialize(); | ||||
| 
 | ||||
|     VersionedProfile profileOne = new VersionedProfile(versionOne, nameOne, avatarOne, null, null, | ||||
|         null, commitmentOne); | ||||
|     VersionedProfile profileTwo = new VersionedProfile(versionTwo, nameTwo, avatarTwo, aboutEmoji, about, null, commitmentTwo); | ||||
|         null, null, commitmentOne); | ||||
|     VersionedProfile profileTwo = new VersionedProfile(versionTwo, nameTwo, avatarTwo, aboutEmoji, about, null, null, commitmentTwo); | ||||
| 
 | ||||
|     profiles.set(ACI, profileOne); | ||||
|     profiles.set(ACI, profileTwo); | ||||
|  | @ -236,8 +240,8 @@ public class ProfilesTest { | |||
|     final byte[] commitmentTwo = new ProfileKey(TestRandomUtil.nextBytes(32)).getCommitment(new ServiceId.Aci(ACI)).serialize(); | ||||
| 
 | ||||
|     VersionedProfile profileOne = new VersionedProfile(versionOne, nameOne, avatarOne, null, null, | ||||
|         null, commitmentOne); | ||||
|     VersionedProfile profileTwo = new VersionedProfile(versionTwo, nameTwo, avatarTwo, aboutEmoji, about, null, commitmentTwo); | ||||
|         null, null, commitmentOne); | ||||
|     VersionedProfile profileTwo = new VersionedProfile(versionTwo, nameTwo, avatarTwo, aboutEmoji, about, null, null, commitmentTwo); | ||||
| 
 | ||||
|     profiles.set(ACI, profileOne); | ||||
|     profiles.set(ACI, profileTwo); | ||||
|  | @ -266,32 +270,37 @@ public class ProfilesTest { | |||
|     final byte[] emoji = TestRandomUtil.nextBytes(60); | ||||
|     final byte[] about = TestRandomUtil.nextBytes(156); | ||||
|     final byte[] paymentAddress = TestRandomUtil.nextBytes(582); | ||||
|     final byte[] phoneNumberSharing = TestRandomUtil.nextBytes(29); | ||||
|     final byte[] commitment = new ProfileKey(TestRandomUtil.nextBytes(32)).getCommitment(new ServiceId.Aci(ACI)).serialize(); | ||||
| 
 | ||||
|     return Stream.of( | ||||
|         Arguments.of( | ||||
|             new VersionedProfile(version, name, avatar, emoji, about, paymentAddress, commitment), | ||||
|             "SET #commitment = if_not_exists(#commitment, :commitment), #name = :name, #avatar = :avatar, #about = :about, #aboutEmoji = :aboutEmoji, #paymentAddress = :paymentAddress"), | ||||
|             new VersionedProfile(version, name, avatar, emoji, about, paymentAddress, phoneNumberSharing, commitment), | ||||
|             "SET #commitment = if_not_exists(#commitment, :commitment), #name = :name, #avatar = :avatar, #about = :about, #aboutEmoji = :aboutEmoji, #paymentAddress = :paymentAddress, #phoneNumberSharing = :phoneNumberSharing"), | ||||
| 
 | ||||
|         Arguments.of( | ||||
|             new VersionedProfile(version, name, avatar, emoji, about, null, commitment), | ||||
|             "SET #commitment = if_not_exists(#commitment, :commitment), #name = :name, #avatar = :avatar, #about = :about, #aboutEmoji = :aboutEmoji REMOVE #paymentAddress"), | ||||
|             new VersionedProfile(version, name, avatar, emoji, about, paymentAddress, null, commitment), | ||||
|             "SET #commitment = if_not_exists(#commitment, :commitment), #name = :name, #avatar = :avatar, #about = :about, #aboutEmoji = :aboutEmoji, #paymentAddress = :paymentAddress REMOVE #phoneNumberSharing"), | ||||
| 
 | ||||
|         Arguments.of( | ||||
|             new VersionedProfile(version, name, avatar, emoji, null, null, commitment), | ||||
|             "SET #commitment = if_not_exists(#commitment, :commitment), #name = :name, #avatar = :avatar, #aboutEmoji = :aboutEmoji REMOVE #about, #paymentAddress"), | ||||
|             new VersionedProfile(version, name, avatar, emoji, about, null, null, commitment), | ||||
|             "SET #commitment = if_not_exists(#commitment, :commitment), #name = :name, #avatar = :avatar, #about = :about, #aboutEmoji = :aboutEmoji REMOVE #paymentAddress, #phoneNumberSharing"), | ||||
| 
 | ||||
|         Arguments.of( | ||||
|             new VersionedProfile(version, name, avatar, null, null, null, commitment), | ||||
|             "SET #commitment = if_not_exists(#commitment, :commitment), #name = :name, #avatar = :avatar REMOVE #about, #aboutEmoji, #paymentAddress"), | ||||
|             new VersionedProfile(version, name, avatar, emoji, null, null, null, commitment), | ||||
|             "SET #commitment = if_not_exists(#commitment, :commitment), #name = :name, #avatar = :avatar, #aboutEmoji = :aboutEmoji REMOVE #about, #paymentAddress, #phoneNumberSharing"), | ||||
| 
 | ||||
|         Arguments.of( | ||||
|             new VersionedProfile(version, name, null, null, null, null, commitment), | ||||
|             "SET #commitment = if_not_exists(#commitment, :commitment), #name = :name REMOVE #avatar, #about, #aboutEmoji, #paymentAddress"), | ||||
|             new VersionedProfile(version, name, avatar, null, null, null, null, commitment), | ||||
|             "SET #commitment = if_not_exists(#commitment, :commitment), #name = :name, #avatar = :avatar REMOVE #about, #aboutEmoji, #paymentAddress, #phoneNumberSharing"), | ||||
| 
 | ||||
|         Arguments.of( | ||||
|             new VersionedProfile(version, null, null, null, null, null, commitment), | ||||
|             "SET #commitment = if_not_exists(#commitment, :commitment) REMOVE #name, #avatar, #about, #aboutEmoji, #paymentAddress") | ||||
|             new VersionedProfile(version, name, null, null, null, null, null, commitment), | ||||
|             "SET #commitment = if_not_exists(#commitment, :commitment), #name = :name REMOVE #avatar, #about, #aboutEmoji, #paymentAddress, #phoneNumberSharing"), | ||||
| 
 | ||||
|         Arguments.of( | ||||
|             new VersionedProfile(version, null, null, null, null, null, null, commitment), | ||||
|             "SET #commitment = if_not_exists(#commitment, :commitment) REMOVE #name, #avatar, #about, #aboutEmoji, #paymentAddress, #phoneNumberSharing") | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|  | @ -308,11 +317,23 @@ public class ProfilesTest { | |||
|     final byte[] emoji = TestRandomUtil.nextBytes(60); | ||||
|     final byte[] about = TestRandomUtil.nextBytes(156); | ||||
|     final byte[] paymentAddress = TestRandomUtil.nextBytes(582); | ||||
|     final byte[] phoneNumberSharing = TestRandomUtil.nextBytes(29); | ||||
|     final byte[] commitment = new ProfileKey(TestRandomUtil.nextBytes(32)).getCommitment(new ServiceId.Aci(ACI)).serialize(); | ||||
| 
 | ||||
|     return Stream.of( | ||||
|         Arguments.of( | ||||
|             new VersionedProfile(version, name, avatar, emoji, about, paymentAddress, commitment), | ||||
|             new VersionedProfile(version, name, avatar, emoji, about, paymentAddress, phoneNumberSharing, commitment), | ||||
|             Map.of( | ||||
|                 ":commitment", AttributeValues.fromByteArray(commitment), | ||||
|                 ":name", AttributeValues.fromByteArray(name), | ||||
|                 ":avatar", AttributeValues.fromString(avatar), | ||||
|                 ":aboutEmoji", AttributeValues.fromByteArray(emoji), | ||||
|                 ":about", AttributeValues.fromByteArray(about), | ||||
|                 ":paymentAddress", AttributeValues.fromByteArray(paymentAddress), | ||||
|                 ":phoneNumberSharing", AttributeValues.fromByteArray(phoneNumberSharing))), | ||||
| 
 | ||||
|         Arguments.of( | ||||
|             new VersionedProfile(version, name, avatar, emoji, about, paymentAddress, null, commitment), | ||||
|             Map.of( | ||||
|                 ":commitment", AttributeValues.fromByteArray(commitment), | ||||
|                 ":name", AttributeValues.fromByteArray(name), | ||||
|  | @ -322,7 +343,7 @@ public class ProfilesTest { | |||
|                 ":paymentAddress", AttributeValues.fromByteArray(paymentAddress))), | ||||
| 
 | ||||
|         Arguments.of( | ||||
|             new VersionedProfile(version, name, avatar, emoji, about, null, commitment), | ||||
|             new VersionedProfile(version, name, avatar, emoji, about, null, null, commitment), | ||||
|             Map.of( | ||||
|                 ":commitment", AttributeValues.fromByteArray(commitment), | ||||
|                 ":name", AttributeValues.fromByteArray(name), | ||||
|  | @ -331,7 +352,7 @@ public class ProfilesTest { | |||
|                 ":about", AttributeValues.fromByteArray(about))), | ||||
| 
 | ||||
|         Arguments.of( | ||||
|             new VersionedProfile(version, name, avatar, emoji, null, null, commitment), | ||||
|             new VersionedProfile(version, name, avatar, emoji, null, null, null, commitment), | ||||
|             Map.of( | ||||
|                 ":commitment", AttributeValues.fromByteArray(commitment), | ||||
|                 ":name",AttributeValues.fromByteArray(name), | ||||
|  | @ -339,20 +360,20 @@ public class ProfilesTest { | |||
|                 ":aboutEmoji", AttributeValues.fromByteArray(emoji))), | ||||
| 
 | ||||
|         Arguments.of( | ||||
|             new VersionedProfile(version, name, avatar, null, null, null, commitment), | ||||
|             new VersionedProfile(version, name, avatar, null, null, null, null, commitment), | ||||
|             Map.of( | ||||
|                 ":commitment", AttributeValues.fromByteArray(commitment), | ||||
|                 ":name", AttributeValues.fromByteArray(name), | ||||
|                 ":avatar", AttributeValues.fromString(avatar))), | ||||
| 
 | ||||
|         Arguments.of( | ||||
|             new VersionedProfile(version, name, null, null, null, null, commitment), | ||||
|             new VersionedProfile(version, name, null, null, null, null, null, commitment), | ||||
|             Map.of( | ||||
|                 ":commitment", AttributeValues.fromByteArray(commitment), | ||||
|                 ":name", AttributeValues.fromByteArray(name))), | ||||
| 
 | ||||
|         Arguments.of( | ||||
|             new VersionedProfile(version, null, null, null, null, null, commitment), | ||||
|             new VersionedProfile(version, null, null, null, null, null, null, commitment), | ||||
|             Map.of(":commitment", AttributeValues.fromByteArray(commitment))) | ||||
|     ); | ||||
|   } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Jonathan Klabunde Tomer
						Jonathan Klabunde Tomer