This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 6d18bde689800ad2b4b24e228f5d09bd757c45e7
Author: LanKhuat <[email protected]>
AuthorDate: Wed Nov 18 15:15:50 2020 +0700

    JAMES-3450 Email/query reject invalid FilterOperator
---
 .../contract/EmailQueryMethodContract.scala        | 100 +++++++++++++++++++++
 .../james/jmap/json/EmailQuerySerializer.scala     |   3 +-
 2 files changed, 102 insertions(+), 1 deletion(-)

diff --git 
a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailQueryMethodContract.scala
 
b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailQueryMethodContract.scala
index ff8ec97..69297ed 100644
--- 
a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailQueryMethodContract.scala
+++ 
b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailQueryMethodContract.scala
@@ -5496,6 +5496,106 @@ trait EmailQueryMethodContract {
   }
 
   @Test
+  def emailQueryShouldRejectFilterOperatorWithExtraFields(server: 
GuiceJamesServer): Unit = {
+    val mailboxId = 
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.inbox(BOB))
+    val requestDate = ZonedDateTime.now().minusDays(1)
+
+    val request =
+      s"""{
+         |  "using": [
+         |    "urn:ietf:params:jmap:core",
+         |    "urn:ietf:params:jmap:mail"],
+         |  "methodCalls": [[
+         |    "Email/query",
+         |    {
+         |      "accountId": 
"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |      "filter" : {
+         |        "inMailbox": "${mailboxId.serialize}",
+         |        "before": 
"${UTCDate(requestDate.plusHours(1)).asUTC.format(UTC_DATE_FORMAT)}",
+         |        "operator": "AND",
+         |        "conditions": [
+         |          { "hasKeyword": "custom" }, { "hasKeyword": 
"another_custom" }
+         |        ]
+         |      }
+         |    },
+         |    "c1"]]
+         |}""".stripMargin
+
+    val response = `given`
+      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+      .body(request)
+    .when
+      .post
+    .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .isEqualTo(s"""{
+                    |    "sessionState": "75128aab4b1b",
+                    |    "methodResponses": [
+                    |        [
+                    |            "error",
+                    |            {
+                    |                "type": "invalidArguments",
+                    |                "description": 
"{\\"errors\\":[{\\"path\\":\\"obj.filter\\",\\"messages\\":[\\"Expecting 
filterOperator to contain only operator and conditions\\"]}]}"
+                    |            },
+                    |            "c1"
+                    |        ]
+                    |    ]
+                    |}""".stripMargin)
+  }
+
+  @Test
+  def emailQueryShouldRejectOperatorWithoutCondition(server: 
GuiceJamesServer): Unit = {
+    val request =
+      s"""{
+         |  "using": [
+         |    "urn:ietf:params:jmap:core",
+         |    "urn:ietf:params:jmap:mail"],
+         |  "methodCalls": [[
+         |    "Email/query",
+         |    {
+         |      "accountId": 
"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |      "filter" : {
+         |        "operator": "AND"
+         |      }
+         |    },
+         |    "c1"]]
+         |}""".stripMargin
+
+    val response = `given`
+      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+      .body(request)
+    .when
+      .post
+    .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .isEqualTo(s"""{
+                    |    "sessionState": "75128aab4b1b",
+                    |    "methodResponses": [
+                    |        [
+                    |            "error",
+                    |            {
+                    |                "type": "invalidArguments",
+                    |                "description": 
"{\\"errors\\":[{\\"path\\":\\"obj.filter\\",\\"messages\\":[\\"Expecting 
filterOperator to contain only operator and conditions\\"]}]}"
+                    |            },
+                    |            "c1"
+                    |        ]
+                    |    ]
+                    |}""".stripMargin)
+  }
+
+  @Test
   def inMailboxShouldBeRejectedWhenInOperator(server: GuiceJamesServer): Unit 
= {
     val message: Message = buildTestMessage
     val mailboxId = 
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.inbox(BOB))
diff --git 
a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailQuerySerializer.scala
 
b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailQuerySerializer.scala
index 7a12c2b..11ff719 100644
--- 
a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailQuerySerializer.scala
+++ 
b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailQuerySerializer.scala
@@ -101,7 +101,8 @@ class EmailQuerySerializer @Inject()(mailboxIdFactory: 
MailboxId.Factory) {
   private implicit val filterOperatorReads: Reads[FilterOperator] = 
Json.reads[FilterOperator]
 
   private implicit def filterQueryReads: Reads[FilterQuery] = {
-    case jsValue@JsObject(underlying) if underlying.contains("operator") => 
filterOperatorReads.reads(jsValue)
+    case JsObject(underlying) if underlying.contains("operator") && 
(!underlying.contains("conditions") || underlying.contains("conditions") && 
underlying.size > 2) => JsError("Expecting filterOperator to contain only 
operator and conditions")
+    case jsValue@JsObject(underlying) if underlying.contains("operator") && 
underlying.contains("conditions") && underlying.size.equals(2) => 
filterOperatorReads.reads(jsValue)
     case jsValue => filterConditionReads.reads(jsValue)
   }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to