mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-20 22:28:05 +01:00
Add phone-number-sharing field to versioned profile
Co-authored-by: Katherine <katherine@signal.org>
This commit is contained in:
committed by
GitHub
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) {}
|
||||
|
||||
Reference in New Issue
Block a user