Only return payment address from latest profile (#408)
* Only return payment address from latest profile * Rename `currentVersionedProfile` to `currentProfileVersion` * Change return type to Optional * Update service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java Co-authored-by: Jon Chambers <63609320+jon-signal@users.noreply.github.com> * Fix broken test Co-authored-by: Jon Chambers <63609320+jon-signal@users.noreply.github.com>
This commit is contained in:
parent
fff8c72f42
commit
b5ade5dc12
|
@ -137,6 +137,7 @@ public class ProfileController {
|
||||||
|
|
||||||
account.setProfileName(request.getName());
|
account.setProfileName(request.getName());
|
||||||
account.setAvatar(avatar);
|
account.setAvatar(avatar);
|
||||||
|
account.setCurrentProfileVersion(request.getVersion());
|
||||||
accountsManager.update(account);
|
accountsManager.update(account);
|
||||||
|
|
||||||
if (response.isPresent()) return Response.ok(response).build();
|
if (response.isPresent()) return Response.ok(response).build();
|
||||||
|
@ -202,7 +203,14 @@ public class ProfileController {
|
||||||
String about = profile.map(VersionedProfile::getAbout).orElse(null);
|
String about = profile.map(VersionedProfile::getAbout).orElse(null);
|
||||||
String aboutEmoji = profile.map(VersionedProfile::getAboutEmoji).orElse(null);
|
String aboutEmoji = profile.map(VersionedProfile::getAboutEmoji).orElse(null);
|
||||||
String avatar = profile.map(VersionedProfile::getAvatar).orElse(accountProfile.get().getAvatar());
|
String avatar = profile.map(VersionedProfile::getAvatar).orElse(accountProfile.get().getAvatar());
|
||||||
String paymentAddress = profile.map(VersionedProfile::getPaymentAddress).orElse(null);
|
Optional<String> currentProfileVersion = accountProfile.get().getCurrentProfileVersion();
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
final String paymentAddress = profile
|
||||||
|
.filter(p -> currentProfileVersion.map(v -> v.equals(version)).orElse(true))
|
||||||
|
.map(VersionedProfile::getPaymentAddress)
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
Optional<ProfileKeyCredentialResponse> credential = getProfileCredential(credentialRequest, profile, uuid);
|
Optional<ProfileKeyCredentialResponse> credential = getProfileCredential(credentialRequest, profile, uuid);
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,9 @@ public class Account implements Principal {
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private String identityKey;
|
private String identityKey;
|
||||||
|
|
||||||
|
@JsonProperty("cpv")
|
||||||
|
private String currentProfileVersion;
|
||||||
|
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
@ -195,6 +198,14 @@ public class Account implements Principal {
|
||||||
return lastSeen;
|
return lastSeen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Optional<String> getCurrentProfileVersion() {
|
||||||
|
return Optional.ofNullable(currentProfileVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrentProfileVersion(String currentProfileVersion) {
|
||||||
|
this.currentProfileVersion = currentProfileVersion;
|
||||||
|
}
|
||||||
|
|
||||||
public String getProfileName() {
|
public String getProfileName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
@ -267,5 +278,4 @@ public class Account implements Principal {
|
||||||
public boolean implies(Subject subject) {
|
public boolean implies(Subject subject) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,8 @@ public class ProfileControllerTest {
|
||||||
private static PolicySigner policySigner = new PolicySigner("accessSecret", "us-west-1");
|
private static PolicySigner policySigner = new PolicySigner("accessSecret", "us-west-1");
|
||||||
private static ServerZkProfileOperations zkProfileOperations = mock(ServerZkProfileOperations.class);
|
private static ServerZkProfileOperations zkProfileOperations = mock(ServerZkProfileOperations.class);
|
||||||
|
|
||||||
|
private Account profileAccount;
|
||||||
|
|
||||||
|
|
||||||
@ClassRule
|
@ClassRule
|
||||||
public static final ResourceTestRule resources = ResourceTestRule.builder()
|
public static final ResourceTestRule resources = ResourceTestRule.builder()
|
||||||
|
@ -95,7 +97,7 @@ public class ProfileControllerTest {
|
||||||
when(rateLimiters.getProfileLimiter()).thenReturn(rateLimiter);
|
when(rateLimiters.getProfileLimiter()).thenReturn(rateLimiter);
|
||||||
when(rateLimiters.getUsernameLookupLimiter()).thenReturn(usernameRateLimiter);
|
when(rateLimiters.getUsernameLookupLimiter()).thenReturn(usernameRateLimiter);
|
||||||
|
|
||||||
Account profileAccount = mock(Account.class);
|
profileAccount = mock(Account.class);
|
||||||
|
|
||||||
when(profileAccount.getIdentityKey()).thenReturn("bar");
|
when(profileAccount.getIdentityKey()).thenReturn("bar");
|
||||||
when(profileAccount.getProfileName()).thenReturn("baz");
|
when(profileAccount.getProfileName()).thenReturn("baz");
|
||||||
|
@ -104,6 +106,7 @@ public class ProfileControllerTest {
|
||||||
when(profileAccount.isEnabled()).thenReturn(true);
|
when(profileAccount.isEnabled()).thenReturn(true);
|
||||||
when(profileAccount.isGroupsV2Supported()).thenReturn(false);
|
when(profileAccount.isGroupsV2Supported()).thenReturn(false);
|
||||||
when(profileAccount.isGv1MigrationSupported()).thenReturn(false);
|
when(profileAccount.isGv1MigrationSupported()).thenReturn(false);
|
||||||
|
when(profileAccount.getCurrentProfileVersion()).thenReturn(Optional.empty());
|
||||||
|
|
||||||
Account capabilitiesAccount = mock(Account.class);
|
Account capabilitiesAccount = mock(Account.class);
|
||||||
|
|
||||||
|
@ -125,8 +128,8 @@ public class ProfileControllerTest {
|
||||||
when(accountsManager.get(argThat((ArgumentMatcher<AmbiguousIdentifier>) identifier -> identifier != null && identifier.hasNumber() && identifier.getNumber().equals(AuthHelper.VALID_NUMBER)))).thenReturn(Optional.of(capabilitiesAccount));
|
when(accountsManager.get(argThat((ArgumentMatcher<AmbiguousIdentifier>) identifier -> identifier != null && identifier.hasNumber() && identifier.getNumber().equals(AuthHelper.VALID_NUMBER)))).thenReturn(Optional.of(capabilitiesAccount));
|
||||||
|
|
||||||
when(profilesManager.get(eq(AuthHelper.VALID_UUID), eq("someversion"))).thenReturn(Optional.empty());
|
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", "validname", "profiles/validavatar", "emoji", "about",
|
when(profilesManager.get(eq(AuthHelper.VALID_UUID_TWO), eq("validversion"))).thenReturn(Optional.of(new VersionedProfile(
|
||||||
null, "validcommitmnet".getBytes())));
|
"validversion", "validname", "profiles/validavatar", "emoji", "about", null, "validcommitmnet".getBytes())));
|
||||||
|
|
||||||
clearInvocations(rateLimiter);
|
clearInvocations(rateLimiter);
|
||||||
clearInvocations(accountsManager);
|
clearInvocations(accountsManager);
|
||||||
|
@ -194,7 +197,7 @@ public class ProfileControllerTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProfileGetUnauthorized() throws Exception {
|
public void testProfileGetUnauthorized() {
|
||||||
Response response = resources.getJerseyTest()
|
Response response = resources.getJerseyTest()
|
||||||
.target("/v1/profile/" + AuthHelper.VALID_NUMBER_TWO)
|
.target("/v1/profile/" + AuthHelper.VALID_NUMBER_TWO)
|
||||||
.request()
|
.request()
|
||||||
|
@ -204,7 +207,7 @@ public class ProfileControllerTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProfileGetByUsernameUnauthorized() throws Exception {
|
public void testProfileGetByUsernameUnauthorized() {
|
||||||
Response response = resources.getJerseyTest()
|
Response response = resources.getJerseyTest()
|
||||||
.target("/v1/profile/username/n00bkiller")
|
.target("/v1/profile/username/n00bkiller")
|
||||||
.request()
|
.request()
|
||||||
|
@ -230,7 +233,7 @@ public class ProfileControllerTest {
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProfileGetDisabled() throws Exception {
|
public void testProfileGetDisabled() {
|
||||||
Response response = resources.getJerseyTest()
|
Response response = resources.getJerseyTest()
|
||||||
.target("/v1/profile/" + AuthHelper.VALID_NUMBER_TWO)
|
.target("/v1/profile/" + AuthHelper.VALID_NUMBER_TWO)
|
||||||
.request()
|
.request()
|
||||||
|
@ -241,7 +244,7 @@ public class ProfileControllerTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProfileCapabilities() throws Exception {
|
public void testProfileCapabilities() {
|
||||||
Profile profile= resources.getJerseyTest()
|
Profile profile= resources.getJerseyTest()
|
||||||
.target("/v1/profile/" + AuthHelper.VALID_NUMBER)
|
.target("/v1/profile/" + AuthHelper.VALID_NUMBER)
|
||||||
.request()
|
.request()
|
||||||
|
@ -515,4 +518,53 @@ public class ProfileControllerTest {
|
||||||
|
|
||||||
verify(rateLimiter, times(1)).validate(eq(AuthHelper.VALID_NUMBER));
|
verify(rateLimiter, times(1)).validate(eq(AuthHelper.VALID_NUMBER));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetProfileUpdatesAccountCurrentVersion() throws InvalidInputException {
|
||||||
|
ProfileKeyCommitment commitment = new ProfileKey(new byte[32]).getCommitment(AuthHelper.VALID_UUID_TWO);
|
||||||
|
|
||||||
|
clearInvocations(AuthHelper.VALID_ACCOUNT_TWO);
|
||||||
|
|
||||||
|
final String name = RandomStringUtils.randomAlphabetic(380);
|
||||||
|
final String paymentAddress = RandomStringUtils.randomAlphanumeric(684);
|
||||||
|
|
||||||
|
Response response = resources.getJerseyTest()
|
||||||
|
.target("/v1/profile")
|
||||||
|
.request()
|
||||||
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER_TWO, AuthHelper.VALID_PASSWORD_TWO))
|
||||||
|
.put(Entity.entity(new CreateProfileRequest(commitment, "someversion", name, null, null, paymentAddress, false), MediaType.APPLICATION_JSON_TYPE));
|
||||||
|
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
assertThat(response.hasEntity()).isFalse();
|
||||||
|
|
||||||
|
verify(AuthHelper.VALID_ACCOUNT_TWO).setCurrentProfileVersion("someversion");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetProfileReturnsNoPaymentAddressIfCurrentVersionMismatch() {
|
||||||
|
when(profilesManager.get(AuthHelper.VALID_UUID_TWO, "validversion")).thenReturn(
|
||||||
|
Optional.of(new VersionedProfile(null, null, null, null, null, "paymentaddress", null)));
|
||||||
|
Profile profile = resources.getJerseyTest()
|
||||||
|
.target("/v1/profile/" + AuthHelper.VALID_UUID_TWO + "/validversion")
|
||||||
|
.request()
|
||||||
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
|
||||||
|
.get(Profile.class);
|
||||||
|
assertThat(profile.getPaymentAddress()).isEqualTo("paymentaddress");
|
||||||
|
|
||||||
|
when(profileAccount.getCurrentProfileVersion()).thenReturn(Optional.of("validversion"));
|
||||||
|
profile = resources.getJerseyTest()
|
||||||
|
.target("/v1/profile/" + AuthHelper.VALID_UUID_TWO + "/validversion")
|
||||||
|
.request()
|
||||||
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
|
||||||
|
.get(Profile.class);
|
||||||
|
assertThat(profile.getPaymentAddress()).isEqualTo("paymentaddress");
|
||||||
|
|
||||||
|
when(profileAccount.getCurrentProfileVersion()).thenReturn(Optional.of("someotherversion"));
|
||||||
|
profile = resources.getJerseyTest()
|
||||||
|
.target("/v1/profile/" + AuthHelper.VALID_UUID_TWO + "/validversion")
|
||||||
|
.request()
|
||||||
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
|
||||||
|
.get(Profile.class);
|
||||||
|
assertThat(profile.getPaymentAddress()).isNull();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue