diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java index 406491ee2..730a98364 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java @@ -639,7 +639,7 @@ public class MessageController { // spam report token is optional, but if provided ensure it is valid base64. final Optional maybeSpamReportToken = - spamReport != null ? Optional.of(spamReport.token()) : Optional.empty(); + spamReport != null ? Optional.ofNullable(spamReport.token()) : Optional.empty(); reportMessageManager.report(sourceNumber, sourceAci, sourcePni, messageGuid, spamReporterUuid, maybeSpamReportToken, userAgent); diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/entities/SpamReport.java b/service/src/main/java/org/whispersystems/textsecuregcm/entities/SpamReport.java index 7dec41ef8..185abbff6 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/entities/SpamReport.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/entities/SpamReport.java @@ -4,9 +4,10 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import org.whispersystems.textsecuregcm.util.ByteArrayAdapter; +import javax.annotation.Nullable; import javax.validation.Valid; import javax.validation.constraints.NotEmpty; public record SpamReport(@JsonSerialize(using = ByteArrayAdapter.Serializing.class) @JsonDeserialize(using = ByteArrayAdapter.Deserializing.class) - @NotEmpty byte[] token) {} + @Nullable byte[] token) {} diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/MessageControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/MessageControllerTest.java index 538ca603c..a96c8c221 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/MessageControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/MessageControllerTest.java @@ -7,6 +7,7 @@ package org.whispersystems.textsecuregcm.controllers; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -58,6 +59,8 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.glassfish.jersey.server.ServerProperties; import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory; +import org.hamcrest.CoreMatchers; +import org.hamcrest.Matcher; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -759,6 +762,50 @@ class MessageControllerTest { any()); } + @ParameterizedTest + @MethodSource + void testReportMessageByAciWithNullSpamReportToken(Entity entity, boolean expectOk) { + + final String senderNumber = "+12125550001"; + final UUID senderAci = UUID.randomUUID(); + final UUID senderPni = UUID.randomUUID(); + UUID messageGuid = UUID.randomUUID(); + + final Account account = mock(Account.class); + when(account.getUuid()).thenReturn(senderAci); + when(account.getNumber()).thenReturn(senderNumber); + when(account.getPhoneNumberIdentifier()).thenReturn(senderPni); + + when(accountsManager.getByAccountIdentifier(senderAci)).thenReturn(Optional.of(account)); + when(deletedAccountsManager.findDeletedAccountE164(senderAci)).thenReturn(Optional.of(senderNumber)); + when(accountsManager.getPhoneNumberIdentifier(senderNumber)).thenReturn(senderPni); + + Response response = + resources.getJerseyTest() + .target(String.format("/v1/messages/report/%s/%s", senderAci, messageGuid)) + .request() + .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) + .post(entity); + + Matcher matcher = expectOk ? is(equalTo(202)) : not(equalTo(202)); + assertThat(response.getStatus(), matcher); + } + + private static Stream testReportMessageByAciWithNullSpamReportToken() { + return Stream.of( + Arguments.of(Entity.json(new SpamReport(new byte[5])), true), + Arguments.of(Entity.json("{\"token\":\"AAAAAAA\"}"), true), + Arguments.of(Entity.json(new SpamReport(new byte[0])), true), + Arguments.of(Entity.json(new SpamReport(null)), true), + Arguments.of(Entity.json("{\"token\": \"\"}"), true), + Arguments.of(Entity.json("{\"token\": null}"), true), + Arguments.of(Entity.json("null"), true), + Arguments.of(Entity.json("{\"weird\": 123}"), true), + Arguments.of(Entity.json("\"weirder\""), false), + Arguments.of(Entity.json("weirdest"), false) + ); + } + @Test void testValidateContentLength() throws Exception { final int contentLength = Math.toIntExact(MessageController.MAX_MESSAGE_SIZE + 1);