Block attempts to set wallet addresses from unsupported countries.

This commit is contained in:
Jon Chambers 2021-03-26 11:53:57 -04:00 committed by Jon Chambers
parent 5965f0fd22
commit 7e29ed1cc7
3 changed files with 74 additions and 11 deletions

View File

@ -409,7 +409,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
AttachmentControllerV3 attachmentControllerV3 = new AttachmentControllerV3(rateLimiters, config.getGcpAttachmentsConfiguration().getDomain(), config.getGcpAttachmentsConfiguration().getEmail(), config.getGcpAttachmentsConfiguration().getMaxSizeInBytes(), config.getGcpAttachmentsConfiguration().getPathPrefix(), config.getGcpAttachmentsConfiguration().getRsaSigningKey());
KeysController keysController = new KeysController(rateLimiters, keysDynamoDb, accountsManager, directoryQueue);
MessageController messageController = new MessageController(rateLimiters, messageSender, receiptSender, accountsManager, messagesManager, apnFallbackManager, dynamicConfigurationManager, metricsCluster, declinedMessageReceiptExecutor);
ProfileController profileController = new ProfileController(rateLimiters, accountsManager, profilesManager, usernamesManager, cdnS3Client, profileCdnPolicyGenerator, profileCdnPolicySigner, config.getCdnConfiguration().getBucket(), zkProfileOperations, isZkEnabled);
ProfileController profileController = new ProfileController(rateLimiters, accountsManager, profilesManager, usernamesManager, dynamicConfigurationManager, cdnS3Client, profileCdnPolicyGenerator, profileCdnPolicySigner, config.getCdnConfiguration().getBucket(), zkProfileOperations, isZkEnabled);
StickerController stickerController = new StickerController(rateLimiters, config.getCdnConfiguration().getAccessKey(), config.getCdnConfiguration().getAccessSecret(), config.getCdnConfiguration().getRegion(), config.getCdnConfiguration().getBucket());
RemoteConfigController remoteConfigController = new RemoteConfigController(remoteConfigsManager, config.getRemoteConfigConfiguration().getAuthorizedTokens(), config.getRemoteConfigConfiguration().getGlobalConfig());

View File

@ -12,6 +12,7 @@ import java.security.SecureRandom;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import javax.validation.Valid;
import javax.validation.valueextraction.Unwrapping;
@ -26,9 +27,11 @@ import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import org.signal.zkgroup.InvalidInputException;
import org.signal.zkgroup.VerificationFailedException;
import org.signal.zkgroup.profiles.ProfileKeyCommitment;
@ -50,11 +53,13 @@ import org.whispersystems.textsecuregcm.s3.PolicySigner;
import org.whispersystems.textsecuregcm.s3.PostPolicyGenerator;
import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
import org.whispersystems.textsecuregcm.storage.ProfilesManager;
import org.whispersystems.textsecuregcm.storage.UsernamesManager;
import org.whispersystems.textsecuregcm.storage.VersionedProfile;
import org.whispersystems.textsecuregcm.util.ExactlySize;
import org.whispersystems.textsecuregcm.util.Pair;
import org.whispersystems.textsecuregcm.util.Util;
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@Path("/v1/profile")
@ -66,6 +71,7 @@ public class ProfileController {
private final ProfilesManager profilesManager;
private final AccountsManager accountsManager;
private final UsernamesManager usernamesManager;
private final DynamicConfigurationManager dynamicConfigurationManager;
private final PolicySigner policySigner;
private final PostPolicyGenerator policyGenerator;
@ -76,20 +82,22 @@ public class ProfileController {
private final String bucket;
public ProfileController(RateLimiters rateLimiters,
AccountsManager accountsManager,
ProfilesManager profilesManager,
UsernamesManager usernamesManager,
AmazonS3 s3client,
PostPolicyGenerator policyGenerator,
PolicySigner policySigner,
String bucket,
ServerZkProfileOperations zkProfileOperations,
boolean isZkEnabled)
AccountsManager accountsManager,
ProfilesManager profilesManager,
UsernamesManager usernamesManager,
DynamicConfigurationManager dynamicConfigurationManager,
AmazonS3 s3client,
PostPolicyGenerator policyGenerator,
PolicySigner policySigner,
String bucket,
ServerZkProfileOperations zkProfileOperations,
boolean isZkEnabled)
{
this.rateLimiters = rateLimiters;
this.accountsManager = accountsManager;
this.profilesManager = profilesManager;
this.usernamesManager = usernamesManager;
this.dynamicConfigurationManager = dynamicConfigurationManager;
this.zkProfileOperations = zkProfileOperations;
this.bucket = bucket;
this.s3client = s3client;
@ -105,6 +113,15 @@ public class ProfileController {
public Response setProfile(@Auth Account account, @Valid CreateProfileRequest request) {
if (!isZkEnabled) throw new WebApplicationException(Response.Status.NOT_FOUND);
final Set<String> allowedPaymentsCountryCodes =
dynamicConfigurationManager.getConfiguration().getPaymentsConfiguration().getAllowedCountryCodes();
if (StringUtils.isNotBlank(request.getPaymentAddress()) &&
!allowedPaymentsCountryCodes.contains(Util.getCountryCode(account.getNumber()))) {
return Response.status(Status.FORBIDDEN).build();
}
Optional<VersionedProfile> currentProfile = profilesManager.get(account.getUuid(), request.getVersion());
String avatar = request.isAvatar() ? generateAvatarObjectName() : null;
Optional<ProfileAvatarUploadAttributes> response = Optional.empty();

View File

@ -11,6 +11,7 @@ import static org.mockito.Mockito.argThat;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@ -21,7 +22,9 @@ import com.amazonaws.services.s3.AmazonS3;
import com.google.common.collect.ImmutableSet;
import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider;
import io.dropwizard.testing.junit.ResourceTestRule;
import java.util.Collections;
import java.util.Optional;
import java.util.Set;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@ -38,6 +41,8 @@ import org.signal.zkgroup.profiles.ProfileKeyCommitment;
import org.signal.zkgroup.profiles.ServerZkProfileOperations;
import org.whispersystems.textsecuregcm.auth.AmbiguousIdentifier;
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAccount;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicPaymentsConfiguration;
import org.whispersystems.textsecuregcm.controllers.ProfileController;
import org.whispersystems.textsecuregcm.controllers.RateLimitExceededException;
import org.whispersystems.textsecuregcm.entities.CreateProfileRequest;
@ -49,11 +54,13 @@ import org.whispersystems.textsecuregcm.s3.PolicySigner;
import org.whispersystems.textsecuregcm.s3.PostPolicyGenerator;
import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
import org.whispersystems.textsecuregcm.storage.ProfilesManager;
import org.whispersystems.textsecuregcm.storage.UsernamesManager;
import org.whispersystems.textsecuregcm.storage.VersionedProfile;
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
import org.whispersystems.textsecuregcm.util.SystemMapper;
import org.whispersystems.textsecuregcm.util.Util;
public class ProfileControllerTest {
@ -69,6 +76,9 @@ public class ProfileControllerTest {
private static PolicySigner policySigner = new PolicySigner("accessSecret", "us-west-1");
private static ServerZkProfileOperations zkProfileOperations = mock(ServerZkProfileOperations.class);
private static DynamicConfigurationManager dynamicConfigurationManager = mock(DynamicConfigurationManager.class);
private DynamicPaymentsConfiguration dynamicPaymentsConfiguration;
private Account profileAccount;
@ -82,6 +92,7 @@ public class ProfileControllerTest {
accountsManager,
profilesManager,
usernamesManager,
dynamicConfigurationManager,
s3client,
postPolicyGenerator,
policySigner,
@ -94,6 +105,13 @@ public class ProfileControllerTest {
public void setup() throws Exception {
reset(s3client);
dynamicPaymentsConfiguration = mock(DynamicPaymentsConfiguration.class);
final DynamicConfiguration dynamicConfiguration = mock(DynamicConfiguration.class);
when(dynamicConfigurationManager.getConfiguration()).thenReturn(dynamicConfiguration);
when(dynamicConfiguration.getPaymentsConfiguration()).thenReturn(dynamicPaymentsConfiguration);
when(dynamicPaymentsConfiguration.getAllowedCountryCodes()).thenReturn(Collections.emptySet());
when(rateLimiters.getProfileLimiter()).thenReturn(rateLimiter);
when(rateLimiters.getUsernameLookupLimiter()).thenReturn(usernameRateLimiter);
@ -365,7 +383,8 @@ public class ProfileControllerTest {
assertThat(profileArgumentCaptor.getValue().getVersion()).isEqualTo("anotherversion");
assertThat(profileArgumentCaptor.getValue().getName()).isEqualTo("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678");
assertThat(profileArgumentCaptor.getValue().getAboutEmoji()).isNull();
assertThat(profileArgumentCaptor.getValue().getAbout()).isNull(); }
assertThat(profileArgumentCaptor.getValue().getAbout()).isNull();
}
@Test
public void testSetProfileWithAvatarUploadAndPreviousAvatar() throws InvalidInputException {
@ -458,6 +477,9 @@ public class ProfileControllerTest {
@Test
public void testSetProfilePaymentAddress() throws InvalidInputException {
when(dynamicPaymentsConfiguration.getAllowedCountryCodes())
.thenReturn(Set.of(Util.getCountryCode(AuthHelper.VALID_NUMBER_TWO)));
ProfileKeyCommitment commitment = new ProfileKey(new byte[32]).getCommitment(AuthHelper.VALID_UUID);
clearInvocations(AuthHelper.VALID_ACCOUNT_TWO);
@ -494,6 +516,27 @@ public class ProfileControllerTest {
assertThat(profile.getPaymentAddress()).isEqualTo(paymentAddress);
}
@Test
public void testSetProfilePaymentAddressCountryNotAllowed() throws InvalidInputException {
ProfileKeyCommitment commitment = new ProfileKey(new byte[32]).getCommitment(AuthHelper.VALID_UUID);
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, "yetanotherversion", name, null, null, paymentAddress, false), MediaType.APPLICATION_JSON_TYPE));
assertThat(response.getStatus()).isEqualTo(403);
assertThat(response.hasEntity()).isFalse();
verify(profilesManager, never()).set(any(), any());
}
@Test
public void testGetProfileByVersion() throws RateLimitExceededException {
Profile profile = resources.getJerseyTest()
@ -521,6 +564,9 @@ public class ProfileControllerTest {
@Test
public void testSetProfileUpdatesAccountCurrentVersion() throws InvalidInputException {
when(dynamicPaymentsConfiguration.getAllowedCountryCodes())
.thenReturn(Set.of(Util.getCountryCode(AuthHelper.VALID_NUMBER_TWO)));
ProfileKeyCommitment commitment = new ProfileKey(new byte[32]).getCommitment(AuthHelper.VALID_UUID_TWO);
clearInvocations(AuthHelper.VALID_ACCOUNT_TWO);