Disallow sync messages to PNIs
This commit is contained in:
parent
20392a567b
commit
4f42c10d60
|
@ -87,6 +87,7 @@ import org.whispersystems.textsecuregcm.entities.SendMultiRecipientMessageRespon
|
||||||
import org.whispersystems.textsecuregcm.entities.SpamReport;
|
import org.whispersystems.textsecuregcm.entities.SpamReport;
|
||||||
import org.whispersystems.textsecuregcm.entities.StaleDevices;
|
import org.whispersystems.textsecuregcm.entities.StaleDevices;
|
||||||
import org.whispersystems.textsecuregcm.identity.AciServiceIdentifier;
|
import org.whispersystems.textsecuregcm.identity.AciServiceIdentifier;
|
||||||
|
import org.whispersystems.textsecuregcm.identity.IdentityType;
|
||||||
import org.whispersystems.textsecuregcm.identity.ServiceIdentifier;
|
import org.whispersystems.textsecuregcm.identity.ServiceIdentifier;
|
||||||
import org.whispersystems.textsecuregcm.limits.CardinalityEstimator;
|
import org.whispersystems.textsecuregcm.limits.CardinalityEstimator;
|
||||||
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||||
|
@ -138,7 +139,6 @@ public class MessageController {
|
||||||
private static final String CONTENT_SIZE_DISTRIBUTION_NAME = name(MessageController.class, "messageContentSize");
|
private static final String CONTENT_SIZE_DISTRIBUTION_NAME = name(MessageController.class, "messageContentSize");
|
||||||
private static final String OUTGOING_MESSAGE_LIST_SIZE_BYTES_DISTRIBUTION_NAME = name(MessageController.class, "outgoingMessageListSizeBytes");
|
private static final String OUTGOING_MESSAGE_LIST_SIZE_BYTES_DISTRIBUTION_NAME = name(MessageController.class, "outgoingMessageListSizeBytes");
|
||||||
private static final String RATE_LIMITED_MESSAGE_COUNTER_NAME = name(MessageController.class, "rateLimitedMessage");
|
private static final String RATE_LIMITED_MESSAGE_COUNTER_NAME = name(MessageController.class, "rateLimitedMessage");
|
||||||
private static final String RATE_LIMITED_STORIES_COUNTER_NAME = name(MessageController.class, "rateLimitedStory");
|
|
||||||
|
|
||||||
private static final String REJECT_INVALID_ENVELOPE_TYPE = name(MessageController.class, "rejectInvalidEnvelopeType");
|
private static final String REJECT_INVALID_ENVELOPE_TYPE = name(MessageController.class, "rejectInvalidEnvelopeType");
|
||||||
|
|
||||||
|
@ -248,6 +248,10 @@ public class MessageController {
|
||||||
try {
|
try {
|
||||||
boolean isSyncMessage = source.isPresent() && source.get().getAccount().isIdentifiedBy(destinationIdentifier);
|
boolean isSyncMessage = source.isPresent() && source.get().getAccount().isIdentifiedBy(destinationIdentifier);
|
||||||
|
|
||||||
|
if (isSyncMessage && destinationIdentifier.identityType() == IdentityType.PNI) {
|
||||||
|
throw new WebApplicationException(Status.FORBIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
Optional<Account> destination;
|
Optional<Account> destination;
|
||||||
|
|
||||||
if (!isSyncMessage) {
|
if (!isSyncMessage) {
|
||||||
|
|
|
@ -297,6 +297,26 @@ class MessageControllerTest {
|
||||||
assertTrue(captor.getValue().getUrgent());
|
assertTrue(captor.getValue().getUrgent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@ValueSource(booleans = {true, false})
|
||||||
|
void testSingleDeviceSync(final boolean sendToPni) throws Exception {
|
||||||
|
final ServiceIdentifier serviceIdentifier = sendToPni
|
||||||
|
? new PniServiceIdentifier(AuthHelper.VALID_PNI_3)
|
||||||
|
: new AciServiceIdentifier(AuthHelper.VALID_UUID_3);
|
||||||
|
|
||||||
|
try (final Response response =
|
||||||
|
resources.getJerseyTest()
|
||||||
|
.target(String.format("/v1/messages/%s", serviceIdentifier.toServiceIdentifierString()))
|
||||||
|
.request()
|
||||||
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_3, AuthHelper.VALID_PASSWORD_3_PRIMARY))
|
||||||
|
.put(Entity.entity(SystemMapper.jsonMapper().readValue(jsonFixture("fixtures/current_message_sync.json"),
|
||||||
|
IncomingMessageList.class),
|
||||||
|
MediaType.APPLICATION_JSON_TYPE))) {
|
||||||
|
|
||||||
|
assertThat(response.getStatus(), is(equalTo(sendToPni ? 403 : 200)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testSingleDeviceCurrentNotUrgent() throws Exception {
|
void testSingleDeviceCurrentNotUrgent() throws Exception {
|
||||||
Response response =
|
Response response =
|
||||||
|
|
|
@ -119,6 +119,7 @@ public class AccountsHelper {
|
||||||
switch (stubbing.getInvocation().getMethod().getName()) {
|
switch (stubbing.getInvocation().getMethod().getName()) {
|
||||||
case "getUuid" -> when(updatedAccount.getUuid()).thenAnswer(stubbing);
|
case "getUuid" -> when(updatedAccount.getUuid()).thenAnswer(stubbing);
|
||||||
case "getPhoneNumberIdentifier" -> when(updatedAccount.getPhoneNumberIdentifier()).thenAnswer(stubbing);
|
case "getPhoneNumberIdentifier" -> when(updatedAccount.getPhoneNumberIdentifier()).thenAnswer(stubbing);
|
||||||
|
case "isIdentifiedBy" -> when(updatedAccount.isIdentifiedBy(stubbing.getInvocation().getArgument(0))).thenAnswer(stubbing);
|
||||||
case "getNumber" -> when(updatedAccount.getNumber()).thenAnswer(stubbing);
|
case "getNumber" -> when(updatedAccount.getNumber()).thenAnswer(stubbing);
|
||||||
case "getUsername" -> when(updatedAccount.getUsernameHash()).thenAnswer(stubbing);
|
case "getUsername" -> when(updatedAccount.getUsernameHash()).thenAnswer(stubbing);
|
||||||
case "getUsernameHash" -> when(updatedAccount.getUsernameHash()).thenAnswer(stubbing);
|
case "getUsernameHash" -> when(updatedAccount.getUsernameHash()).thenAnswer(stubbing);
|
||||||
|
|
|
@ -22,6 +22,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
@ -34,7 +35,9 @@ import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAccountAuthenticator;
|
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAccountAuthenticator;
|
||||||
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount;
|
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.SaltedTokenHash;
|
import org.whispersystems.textsecuregcm.auth.SaltedTokenHash;
|
||||||
|
import org.whispersystems.textsecuregcm.identity.AciServiceIdentifier;
|
||||||
import org.whispersystems.textsecuregcm.identity.IdentityType;
|
import org.whispersystems.textsecuregcm.identity.IdentityType;
|
||||||
|
import org.whispersystems.textsecuregcm.identity.PniServiceIdentifier;
|
||||||
import org.whispersystems.textsecuregcm.storage.Account;
|
import org.whispersystems.textsecuregcm.storage.Account;
|
||||||
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||||
import org.whispersystems.textsecuregcm.storage.Device;
|
import org.whispersystems.textsecuregcm.storage.Device;
|
||||||
|
@ -147,6 +150,12 @@ public class AuthHelper {
|
||||||
when(VALID_ACCOUNT_3.getPrimaryDevice()).thenReturn(Optional.of(VALID_DEVICE_3_PRIMARY));
|
when(VALID_ACCOUNT_3.getPrimaryDevice()).thenReturn(Optional.of(VALID_DEVICE_3_PRIMARY));
|
||||||
when(VALID_ACCOUNT_3.getDevice((byte) 2)).thenReturn(Optional.of(VALID_DEVICE_3_LINKED));
|
when(VALID_ACCOUNT_3.getDevice((byte) 2)).thenReturn(Optional.of(VALID_DEVICE_3_LINKED));
|
||||||
|
|
||||||
|
when(VALID_ACCOUNT.getDevices()).thenReturn(List.of(VALID_DEVICE));
|
||||||
|
when(VALID_ACCOUNT_TWO.getDevices()).thenReturn(List.of(VALID_DEVICE_TWO));
|
||||||
|
when(DISABLED_ACCOUNT.getDevices()).thenReturn(List.of(DISABLED_DEVICE));
|
||||||
|
when(UNDISCOVERABLE_ACCOUNT.getDevices()).thenReturn(List.of(UNDISCOVERABLE_DEVICE));
|
||||||
|
when(VALID_ACCOUNT_3.getDevices()).thenReturn(List.of(VALID_DEVICE_3_PRIMARY, VALID_DEVICE_3_LINKED));
|
||||||
|
|
||||||
when(VALID_ACCOUNT_TWO.hasEnabledLinkedDevice()).thenReturn(true);
|
when(VALID_ACCOUNT_TWO.hasEnabledLinkedDevice()).thenReturn(true);
|
||||||
|
|
||||||
when(VALID_ACCOUNT.getNumber()).thenReturn(VALID_NUMBER);
|
when(VALID_ACCOUNT.getNumber()).thenReturn(VALID_NUMBER);
|
||||||
|
@ -175,6 +184,15 @@ public class AuthHelper {
|
||||||
when(UNDISCOVERABLE_ACCOUNT.isDiscoverableByPhoneNumber()).thenReturn(false);
|
when(UNDISCOVERABLE_ACCOUNT.isDiscoverableByPhoneNumber()).thenReturn(false);
|
||||||
when(VALID_ACCOUNT_3.isDiscoverableByPhoneNumber()).thenReturn(true);
|
when(VALID_ACCOUNT_3.isDiscoverableByPhoneNumber()).thenReturn(true);
|
||||||
|
|
||||||
|
when(VALID_ACCOUNT.isIdentifiedBy(new AciServiceIdentifier(VALID_UUID))).thenReturn(true);
|
||||||
|
when(VALID_ACCOUNT.isIdentifiedBy(new PniServiceIdentifier(VALID_PNI))).thenReturn(true);
|
||||||
|
when(VALID_ACCOUNT_TWO.isIdentifiedBy(new AciServiceIdentifier(VALID_UUID_TWO))).thenReturn(true);
|
||||||
|
when(VALID_ACCOUNT_TWO.isIdentifiedBy(new PniServiceIdentifier(VALID_PNI_TWO))).thenReturn(true);
|
||||||
|
when(DISABLED_ACCOUNT.isIdentifiedBy(new AciServiceIdentifier(DISABLED_UUID))).thenReturn(true);
|
||||||
|
when(UNDISCOVERABLE_ACCOUNT.isIdentifiedBy(new AciServiceIdentifier(UNDISCOVERABLE_UUID))).thenReturn(true);
|
||||||
|
when(VALID_ACCOUNT_3.isIdentifiedBy(new AciServiceIdentifier(VALID_UUID_3))).thenReturn(true);
|
||||||
|
when(VALID_ACCOUNT_3.isIdentifiedBy(new PniServiceIdentifier(VALID_PNI_3))).thenReturn(true);
|
||||||
|
|
||||||
when(VALID_ACCOUNT.getIdentityKey(IdentityType.ACI)).thenReturn(VALID_IDENTITY);
|
when(VALID_ACCOUNT.getIdentityKey(IdentityType.ACI)).thenReturn(VALID_IDENTITY);
|
||||||
|
|
||||||
reset(ACCOUNTS_MANAGER);
|
reset(ACCOUNTS_MANAGER);
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"messages" : [{
|
||||||
|
"type" : 1,
|
||||||
|
"destinationDeviceId" : 2,
|
||||||
|
"content" : "Zm9vYmFyego",
|
||||||
|
"timestamp" : 1234
|
||||||
|
}]
|
||||||
|
}
|
Loading…
Reference in New Issue