Add versioned profiles feature flag.
This commit is contained in:
parent
28bd245b96
commit
289f7aba63
11 changed files with 67 additions and 48 deletions
|
@ -53,7 +53,7 @@ public final class ProfileUploadJob extends BaseJob {
|
|||
String avatarPath = null;
|
||||
|
||||
try (StreamDetails avatar = AvatarHelper.getSelfProfileAvatarStream(context)) {
|
||||
if (FeatureFlags.VERSIONED_PROFILES) {
|
||||
if (FeatureFlags.versionedProfiles()) {
|
||||
avatarPath = accountManager.setVersionedProfile(Recipient.self().getUuid().get(), profileKey, profileName.serialize(), avatar).orNull();
|
||||
} else {
|
||||
accountManager.setProfileName(profileKey, profileName.serialize());
|
||||
|
|
|
@ -93,7 +93,7 @@ public class RefreshOwnProfileJob extends BaseJob {
|
|||
}
|
||||
|
||||
private static SignalServiceProfile.RequestType getRequestType(@NonNull Recipient recipient) {
|
||||
return FeatureFlags.VERSIONED_PROFILES && !recipient.hasProfileKeyCredential()
|
||||
return FeatureFlags.versionedProfiles() && !recipient.hasProfileKeyCredential()
|
||||
? SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL
|
||||
: SignalServiceProfile.RequestType.PROFILE;
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@ public class RetrieveProfileJob extends BaseJob {
|
|||
}
|
||||
|
||||
private static SignalServiceProfile.RequestType getRequestType(@NonNull Recipient recipient) {
|
||||
return FeatureFlags.VERSIONED_PROFILES && !recipient.hasProfileKeyCredential()
|
||||
return FeatureFlags.versionedProfiles() && !recipient.hasProfileKeyCredential()
|
||||
? SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL
|
||||
: SignalServiceProfile.RequestType.PROFILE;
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ public class RotateProfileKeyJob extends BaseJob {
|
|||
recipientDatabase.setProfileKey(self.getId(), profileKey);
|
||||
|
||||
try (StreamDetails avatarStream = AvatarHelper.getSelfProfileAvatarStream(context)) {
|
||||
if (FeatureFlags.VERSIONED_PROFILES) {
|
||||
if (FeatureFlags.versionedProfiles()) {
|
||||
accountManager.setVersionedProfile(self.getUuid().get(),
|
||||
profileKey,
|
||||
Recipient.self().getProfileName().serialize(),
|
||||
|
|
|
@ -11,6 +11,7 @@ import com.google.android.collect.Sets;
|
|||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.jobs.ProfileUploadJob;
|
||||
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob;
|
||||
import org.thoughtcrime.securesms.jobs.RemoteConfigRefreshJob;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
|
@ -59,8 +60,9 @@ public final class FeatureFlags {
|
|||
private static final String REMOTE_DELETE = "android.remoteDelete";
|
||||
private static final String PROFILE_FOR_CALLING = "android.profileForCalling";
|
||||
private static final String CALLING_PIP = "android.callingPip";
|
||||
private static final String NEW_GROUP_UI = "android.newGroupUI";
|
||||
private static final String REACT_WITH_ANY_EMOJI = "android.reactWithAnyEmoji";
|
||||
private static final String NEW_GROUP_UI = "android.newGroupUI";
|
||||
private static final String VERSIONED_PROFILES = "android.versionedProfiles";
|
||||
private static final String GROUPS_V2 = "android.groupsv2";
|
||||
private static final String GROUPS_V2_CREATE = "android.groupsv2.create";
|
||||
|
||||
|
@ -81,7 +83,8 @@ public final class FeatureFlags {
|
|||
PROFILE_FOR_CALLING,
|
||||
CALLING_PIP,
|
||||
NEW_GROUP_UI,
|
||||
REACT_WITH_ANY_EMOJI
|
||||
REACT_WITH_ANY_EMOJI,
|
||||
VERSIONED_PROFILES
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -113,6 +116,7 @@ public final class FeatureFlags {
|
|||
private static final Set<String> STICKY = Sets.newHashSet(
|
||||
PINS_FOR_ALL_LEGACY,
|
||||
PINS_FOR_ALL,
|
||||
VERSIONED_PROFILES,
|
||||
GROUPS_V2
|
||||
);
|
||||
|
||||
|
@ -128,8 +132,9 @@ public final class FeatureFlags {
|
|||
* desired test state.
|
||||
*/
|
||||
private static final Map<String, OnFlagChange> FLAG_CHANGE_LISTENERS = new HashMap<String, OnFlagChange>() {{
|
||||
put(MESSAGE_REQUESTS, (change) -> SignalStore.setMessageRequestEnableTime(change == Change.ENABLED ? System.currentTimeMillis() : 0));
|
||||
put(GROUPS_V2, (change) -> ApplicationDependencies.getJobManager().add(new RefreshAttributesJob()));
|
||||
put(MESSAGE_REQUESTS, (change) -> SignalStore.setMessageRequestEnableTime(change == Change.ENABLED ? System.currentTimeMillis() : 0));
|
||||
put(VERSIONED_PROFILES, (change) -> ApplicationDependencies.getJobManager().add(new ProfileUploadJob()));
|
||||
put(GROUPS_V2, (change) -> ApplicationDependencies.getJobManager().add(new RefreshAttributesJob()));
|
||||
}};
|
||||
|
||||
private static final Map<String, Object> REMOTE_VALUES = new TreeMap<>();
|
||||
|
@ -260,9 +265,14 @@ public final class FeatureFlags {
|
|||
return getBoolean(REACT_WITH_ANY_EMOJI, false);
|
||||
}
|
||||
|
||||
/** Read and write versioned profile information. */
|
||||
public static boolean versionedProfiles() {
|
||||
return getBoolean(VERSIONED_PROFILES, false);
|
||||
}
|
||||
|
||||
/** Groups v2 send and receive. */
|
||||
public static boolean groupsV2() {
|
||||
return getBoolean(GROUPS_V2, false);
|
||||
return versionedProfiles() && getBoolean(GROUPS_V2, false);
|
||||
}
|
||||
|
||||
/** Groups v2 send and receive. */
|
||||
|
@ -504,7 +514,4 @@ public final class FeatureFlags {
|
|||
enum Change {
|
||||
ENABLED, DISABLED, CHANGED, REMOVED
|
||||
}
|
||||
|
||||
/** Read and write versioned profile information. */
|
||||
public static final boolean VERSIONED_PROFILES = org.whispersystems.signalservice.FeatureFlags.VERSIONED_PROFILES;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,6 @@ package org.whispersystems.signalservice;
|
|||
*/
|
||||
public final class FeatureFlags {
|
||||
|
||||
/** Read and write versioned profile information. */
|
||||
public static final boolean VERSIONED_PROFILES = false;
|
||||
/** Prevent usage of non-versioned profile endpoints. */
|
||||
public static final boolean DISALLOW_OLD_PROFILE_SETTING = false;
|
||||
}
|
||||
|
|
|
@ -648,7 +648,7 @@ public class SignalServiceAccountManager {
|
|||
public void setProfileName(ProfileKey key, String name)
|
||||
throws IOException
|
||||
{
|
||||
if (FeatureFlags.VERSIONED_PROFILES) {
|
||||
if (FeatureFlags.DISALLOW_OLD_PROFILE_SETTING) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
|
@ -662,7 +662,7 @@ public class SignalServiceAccountManager {
|
|||
public Optional<String> setProfileAvatar(ProfileKey key, StreamDetails avatar)
|
||||
throws IOException
|
||||
{
|
||||
if (FeatureFlags.VERSIONED_PROFILES) {
|
||||
if (FeatureFlags.DISALLOW_OLD_PROFILE_SETTING) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
|
@ -684,10 +684,6 @@ public class SignalServiceAccountManager {
|
|||
public Optional<String> setVersionedProfile(UUID uuid, ProfileKey profileKey, String name, StreamDetails avatar)
|
||||
throws IOException
|
||||
{
|
||||
if (!FeatureFlags.VERSIONED_PROFILES) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
if (name == null) name = "";
|
||||
|
||||
byte[] ciphertextName = new ProfileCipher(profileKey).encryptName(name.getBytes(StandardCharsets.UTF_8), ProfileCipher.NAME_PADDED_LENGTH);
|
||||
|
@ -711,7 +707,7 @@ public class SignalServiceAccountManager {
|
|||
public Optional<ProfileKeyCredential> resolveProfileKeyCredential(UUID uuid, ProfileKey profileKey)
|
||||
throws NonSuccessfulResponseCodeException, PushNetworkException, VerificationFailedException
|
||||
{
|
||||
return this.pushServiceSocket.retrieveProfile(uuid, profileKey, Optional.absent()).getProfileKeyCredential();
|
||||
return this.pushServiceSocket.retrieveVersionedProfileAndCredential(uuid, profileKey, Optional.absent()).getProfileKeyCredential();
|
||||
}
|
||||
|
||||
public void setUsername(String username) throws IOException {
|
||||
|
|
|
@ -19,7 +19,6 @@ import org.whispersystems.libsignal.InvalidVersionException;
|
|||
import org.whispersystems.libsignal.util.Hex;
|
||||
import org.whispersystems.libsignal.util.Pair;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.FeatureFlags;
|
||||
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
||||
import org.whispersystems.signalservice.api.profiles.ProfileAndCredential;
|
||||
|
@ -187,16 +186,21 @@ public class SignalServiceMessagePipe {
|
|||
.setVerb("GET")
|
||||
.addAllHeaders(headers);
|
||||
|
||||
if (FeatureFlags.VERSIONED_PROFILES && requestType == SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL && uuid.isPresent() && profileKey.isPresent()) {
|
||||
UUID target = uuid.get();
|
||||
ProfileKeyVersion profileKeyIdentifier = profileKey.get().getProfileKeyVersion(target);
|
||||
requestContext = clientZkProfile.createProfileKeyCredentialRequestContext(random, target, profileKey.get());
|
||||
ProfileKeyCredentialRequest request = requestContext.getRequest();
|
||||
if (uuid.isPresent() && profileKey.isPresent()) {
|
||||
UUID target = uuid.get();
|
||||
ProfileKeyVersion profileKeyIdentifier = profileKey.get().getProfileKeyVersion(target);
|
||||
String version = profileKeyIdentifier.serialize();
|
||||
|
||||
String version = profileKeyIdentifier.serialize();
|
||||
String credentialRequest = Hex.toStringCondensed(request.serialize());
|
||||
if (requestType == SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL) {
|
||||
requestContext = clientZkProfile.createProfileKeyCredentialRequestContext(random, target, profileKey.get());
|
||||
|
||||
builder.setPath(String.format("/v1/profile/%s/%s/%s", target, version, credentialRequest));
|
||||
ProfileKeyCredentialRequest request = requestContext.getRequest();
|
||||
String credentialRequest = Hex.toStringCondensed(request.serialize());
|
||||
|
||||
builder.setPath(String.format("/v1/profile/%s/%s/%s", target, version, credentialRequest));
|
||||
} else {
|
||||
builder.setPath(String.format("/v1/profile/%s/%s", target, version));
|
||||
}
|
||||
} else {
|
||||
builder.setPath(String.format("/v1/profile/%s", address.getIdentifier()));
|
||||
}
|
||||
|
|
|
@ -9,10 +9,8 @@ package org.whispersystems.signalservice.api;
|
|||
import org.signal.zkgroup.VerificationFailedException;
|
||||
import org.signal.zkgroup.profiles.ClientZkProfileOperations;
|
||||
import org.signal.zkgroup.profiles.ProfileKey;
|
||||
import org.signal.zkgroup.profiles.ProfileKeyCredential;
|
||||
import org.whispersystems.libsignal.InvalidMessageException;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.FeatureFlags;
|
||||
import org.whispersystems.signalservice.api.crypto.AttachmentCipherInputStream;
|
||||
import org.whispersystems.signalservice.api.crypto.ProfileCipherInputStream;
|
||||
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess;
|
||||
|
@ -130,12 +128,18 @@ public class SignalServiceMessageReceiver {
|
|||
{
|
||||
Optional<UUID> uuid = address.getUuid();
|
||||
|
||||
if (FeatureFlags.VERSIONED_PROFILES && requestType == SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL && uuid.isPresent() && profileKey.isPresent()) {
|
||||
return socket.retrieveProfile(uuid.get(), profileKey.get(), unidentifiedAccess);
|
||||
if (uuid.isPresent() && profileKey.isPresent()) {
|
||||
if (requestType == SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL) {
|
||||
return socket.retrieveVersionedProfileAndCredential(uuid.get(), profileKey.get(), unidentifiedAccess);
|
||||
} else {
|
||||
return new ProfileAndCredential(socket.retrieveVersionedProfile(uuid.get(), profileKey.get(), unidentifiedAccess),
|
||||
SignalServiceProfile.RequestType.PROFILE,
|
||||
Optional.absent());
|
||||
}
|
||||
} else {
|
||||
return new ProfileAndCredential(socket.retrieveProfile(address, unidentifiedAccess),
|
||||
SignalServiceProfile.RequestType.PROFILE,
|
||||
Optional.<ProfileKeyCredential>absent());
|
||||
Optional.absent());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -131,8 +131,6 @@ public class SignalServiceProfile {
|
|||
}
|
||||
|
||||
public ProfileKeyCredentialResponse getProfileKeyCredentialResponse() {
|
||||
if (!FeatureFlags.VERSIONED_PROFILES) return null;
|
||||
|
||||
if (credential == null) return null;
|
||||
|
||||
try {
|
||||
|
|
|
@ -595,13 +595,9 @@ public class PushServiceSocket {
|
|||
}
|
||||
}
|
||||
|
||||
public ProfileAndCredential retrieveProfile(UUID target, ProfileKey profileKey, Optional<UnidentifiedAccess> unidentifiedAccess)
|
||||
public ProfileAndCredential retrieveVersionedProfileAndCredential(UUID target, ProfileKey profileKey, Optional<UnidentifiedAccess> unidentifiedAccess)
|
||||
throws NonSuccessfulResponseCodeException, PushNetworkException, VerificationFailedException
|
||||
{
|
||||
if (!FeatureFlags.VERSIONED_PROFILES) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
ProfileKeyVersion profileKeyIdentifier = profileKey.getProfileKeyVersion(target);
|
||||
ProfileKeyCredentialRequestContext requestContext = clientZkProfileOperations.createProfileKeyCredentialRequestContext(random, target, profileKey);
|
||||
ProfileKeyCredentialRequest request = requestContext.getRequest();
|
||||
|
@ -626,6 +622,24 @@ public class PushServiceSocket {
|
|||
}
|
||||
}
|
||||
|
||||
public SignalServiceProfile retrieveVersionedProfile(UUID target, ProfileKey profileKey, Optional<UnidentifiedAccess> unidentifiedAccess)
|
||||
throws NonSuccessfulResponseCodeException, PushNetworkException
|
||||
{
|
||||
ProfileKeyVersion profileKeyIdentifier = profileKey.getProfileKeyVersion(target);
|
||||
|
||||
String version = profileKeyIdentifier.serialize();
|
||||
String subPath = String.format("%s/%s", target, version);
|
||||
|
||||
String response = makeServiceRequest(String.format(PROFILE_PATH, subPath), "GET", null, NO_HEADERS, unidentifiedAccess);
|
||||
|
||||
try {
|
||||
return JsonUtil.fromJson(response, SignalServiceProfile.class);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
throw new NonSuccessfulResponseCodeException("Unable to parse entity");
|
||||
}
|
||||
}
|
||||
|
||||
public void retrieveProfileAvatar(String path, File destination, long maxSizeBytes)
|
||||
throws NonSuccessfulResponseCodeException, PushNetworkException {
|
||||
try {
|
||||
|
@ -636,7 +650,7 @@ public class PushServiceSocket {
|
|||
}
|
||||
|
||||
public void setProfileName(String name) throws NonSuccessfulResponseCodeException, PushNetworkException {
|
||||
if (FeatureFlags.VERSIONED_PROFILES) {
|
||||
if (FeatureFlags.DISALLOW_OLD_PROFILE_SETTING) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
|
@ -646,7 +660,7 @@ public class PushServiceSocket {
|
|||
public Optional<String> setProfileAvatar(ProfileAvatarData profileAvatar)
|
||||
throws NonSuccessfulResponseCodeException, PushNetworkException
|
||||
{
|
||||
if (FeatureFlags.VERSIONED_PROFILES) {
|
||||
if (FeatureFlags.DISALLOW_OLD_PROFILE_SETTING) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
|
@ -680,10 +694,6 @@ public class PushServiceSocket {
|
|||
public Optional<String> writeProfile(SignalServiceProfileWrite signalServiceProfileWrite, ProfileAvatarData profileAvatar)
|
||||
throws NonSuccessfulResponseCodeException, PushNetworkException
|
||||
{
|
||||
if (!FeatureFlags.VERSIONED_PROFILES) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
String requestBody = JsonUtil.toJson(signalServiceProfileWrite);
|
||||
ProfileAvatarUploadAttributes formAttributes;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue