Use ProfileHelper.isPaymentAddressUpdateForbidden for both REST and gRPC

This commit is contained in:
Chris Eager 2026-06-09 10:04:31 -05:00 committed by Chris Eager
parent 32befd7c9a
commit d6c7c5e7bf
5 changed files with 38 additions and 26 deletions

View File

@ -181,14 +181,8 @@ public class ProfileController {
final Optional<VersionedProfileV1> currentProfile =
profilesManager.getV1(auth.accountIdentifier(), request.version());
if (request.paymentAddress() != null && request.paymentAddress().length != 0) {
final boolean hasDisallowedPrefix =
dynamicConfigurationManager.getConfiguration().getPaymentsConfiguration().getDisallowedPrefixes().stream()
.anyMatch(prefix -> account.getNumber().startsWith(prefix));
if (hasDisallowedPrefix && currentProfile.map(VersionedProfileV1::paymentAddress).isEmpty()) {
return Response.status(Response.Status.FORBIDDEN).build();
}
if (request.paymentAddress() != null && request.paymentAddress().length != 0 && ProfileHelper.isPaymentAddressUpdateForbidden(account, Optional.empty(), currentProfile, dynamicConfigurationManager)) {
return Response.status(Response.Status.FORBIDDEN).build();
}
final Optional<String> currentAvatar = ProfileHelper.getCurrentAvatar(currentProfile);

View File

@ -152,7 +152,7 @@ public class ProfileGrpcService extends SimpleProfileGrpc.ProfileImplBase {
avatarData.finalAvatar().orElse(null),
request.getV1Request().getAboutEmoji().toByteArray(),
request.getV1Request().getAbout().toByteArray(),
request.getPaymentAddress().toByteArray(),
request.getPaymentAddress().isEmpty() ? null : request.getPaymentAddress().toByteArray(),
request.getV1Request().getPhoneNumberSharing().toByteArray(),
commitment);

View File

@ -114,7 +114,7 @@ public class ProfileHelper {
.getDisallowedPrefixes().stream()
.anyMatch(prefix -> account.getNumber().startsWith(prefix));
return hasDisallowedPrefix && currentPaymentAddress.isEmpty();
return hasDisallowedPrefix && currentPaymentAddress.filter(a -> a.length != 0).isEmpty();
}
@Nullable

View File

@ -41,6 +41,7 @@ import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collection;
import java.util.Collections;
import java.util.HexFormat;
import java.util.List;
@ -50,6 +51,7 @@ import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import org.assertj.core.api.Condition;
import org.glassfish.jersey.server.ServerProperties;
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
@ -818,15 +820,14 @@ class ProfileControllerTest {
}
@ParameterizedTest
@ValueSource(booleans = {true, false})
@MethodSource
void testSetProfilePaymentAddressCountryNotAllowedExistingPaymentAddress(
final boolean existingPaymentAddressOnProfile) throws InvalidInputException {
@Nullable final byte[] existingPaymentAddressOnProfile, final byte[] requestPaymentAddress, final boolean expectAllowed) throws InvalidInputException {
when(dynamicPaymentsConfiguration.getDisallowedPrefixes())
.thenReturn(List.of(AuthHelper.VALID_NUMBER_TWO.substring(0, 3)));
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);
@ -834,7 +835,7 @@ class ProfileControllerTest {
when(profilesManager.getV1(eq(AuthHelper.VALID_UUID_TWO), any()))
.thenReturn(Optional.of(
new VersionedProfileV1("1", name, null, null, null,
existingPaymentAddressOnProfile ? TestRandomUtil.nextBytes(582) : null,
existingPaymentAddressOnProfile,
phoneNumberSharing,
commitment.serialize())));
@ -845,10 +846,10 @@ class ProfileControllerTest {
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO))
.put(Entity.entity(
new CreateProfileRequest(commitment, version, name,
null, null, paymentAddress, false, false,
null, null, requestPaymentAddress, false, false,
Optional.of(List.of()), null), MediaType.APPLICATION_JSON_TYPE))) {
if (existingPaymentAddressOnProfile) {
if (expectAllowed) {
assertThat(response.getStatus()).isEqualTo(200);
assertThat(response.hasEntity()).isFalse();
@ -866,7 +867,7 @@ class ProfileControllerTest {
assertThat(profile.name()).isEqualTo(name);
assertThat(profile.aboutEmoji()).isNull();
assertThat(profile.about()).isNull();
assertThat(profile.paymentAddress()).isEqualTo(paymentAddress);
assertThat(profile.paymentAddress()).isEqualTo(requestPaymentAddress);
} else {
assertThat(response.getStatus()).isEqualTo(403);
assertThat(response.hasEntity()).isFalse();
@ -876,6 +877,16 @@ class ProfileControllerTest {
}
}
static Collection<Arguments> testSetProfilePaymentAddressCountryNotAllowedExistingPaymentAddress() {
return List.of(
Arguments.argumentSet("null existing payment address, empty new", null, new byte[0], true),
Arguments.argumentSet("null existing payment address", null, TestRandomUtil.nextBytes(582), false),
Arguments.argumentSet("empty existing payment address, empty new", new byte[0], new byte[0], true),
Arguments.argumentSet("empty existing payment address", new byte[0], TestRandomUtil.nextBytes(582), false),
Arguments.argumentSet("valid existing payment address", TestRandomUtil.nextBytes(582), TestRandomUtil.nextBytes(582), true)
);
}
@Test
void testSetProfilePhoneNumberSharing() throws Exception {
final ProfileKeyCommitment commitment = new ProfileKey(new byte[32]).getCommitment(new ServiceId.Aci(AuthHelper.VALID_UUID));

View File

@ -496,20 +496,17 @@ public class ProfileGrpcServiceTest extends SimpleBaseGrpcTest<ProfileGrpcServic
}
@ParameterizedTest
@ValueSource(booleans = {true, false})
void setPaymentAddressDisallowedCountry(final boolean hasExistingPaymentAddress) throws InvalidInputException {
@MethodSource
void setPaymentAddressDisallowedCountry(@Nullable final byte[] existingPaymentAddress, final byte[] requestPaymentAddress, final boolean expectAllowed) throws InvalidInputException {
final Phonenumber.PhoneNumber disallowedPhoneNumber = PhoneNumberUtil.getInstance().getExampleNumber("CU");
final byte[] commitment = new ProfileKey(new byte[32]).getCommitment(new ServiceId.Aci(AUTHENTICATED_ACI)).serialize();
final byte[] validPaymentAddress = new byte[582];
if (hasExistingPaymentAddress) {
when(profile.paymentAddress()).thenReturn(validPaymentAddress);
}
when(profile.paymentAddress()).thenReturn(existingPaymentAddress);
final SetProfileRequest request = SetProfileRequest.newBuilder()
.setVersion(ByteString.copyFrom(VERSION))
.setData(ByteString.copyFrom(VALID_DATA))
.setPaymentAddress(ByteString.copyFrom(validPaymentAddress))
.setPaymentAddress(ByteString.copyFrom(requestPaymentAddress))
.setCommitment(ByteString.copyFrom(commitment))
.setV1Request(V1_REQUEST)
.build();
@ -522,13 +519,23 @@ public class ProfileGrpcServiceTest extends SimpleBaseGrpcTest<ProfileGrpcServic
final SetProfileResponse response = authenticatedServiceStub().setProfile(request);
if (hasExistingPaymentAddress) {
assertTrue(response.hasResult(), "Payment address changes in disallowed countries should still be allowed if the account already has a valid payment address");
if (expectAllowed) {
assertTrue(response.hasResult());
} else {
assertTrue(response.hasPaymentsForbiddenInRegion());
}
}
static Collection<Arguments> setPaymentAddressDisallowedCountry() {
return List.of(
Arguments.argumentSet("null existing address, zero-length new", null, new byte[0], true),
Arguments.argumentSet("null existing address", null, TestRandomUtil.nextBytes(582), false),
Arguments.argumentSet("zero-length existing address, zero-length new", new byte[0], new byte[0], true),
Arguments.argumentSet("zero-length existing address", new byte[0], TestRandomUtil.nextBytes(582), false),
Arguments.argumentSet("valid existing address", TestRandomUtil.nextBytes(582), TestRandomUtil.nextBytes(582), true)
);
}
@Test
void setProfileBadges() throws Exception {