You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2020/08/27 02:24:40 UTC
[james-project] 08/14: JAMES-3359 Mailbox/set parentId updates:
prevent loops
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 746efffb4e8b905b5155ec49e6e2bfe6d17ed288
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Thu Aug 20 14:59:10 2020 +0700
JAMES-3359 Mailbox/set parentId updates: prevent loops
We apply the same strategy than in Draft: preventing changing parentId of a mailbox having childs
respects the mailbox tree structure.
---
.../contract/MailboxSetMethodContract.scala | 59 ++++++++++++++++++++++
.../james/jmap/method/MailboxSetMethod.scala | 14 +++--
2 files changed, 68 insertions(+), 5 deletions(-)
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/MailboxSetMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxSetMethodContract.scala
index 765675d..355e3d5 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxSetMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxSetMethodContract.scala
@@ -6969,4 +6969,63 @@ trait MailboxSetMethodContract {
| ]
|}""".stripMargin)
}
+
+ @Test
+ def updatingParentIdShouldFailWhenMailboxHasAChild(server: GuiceJamesServer): Unit = {
+ val mailboxProbe = server.getProbe(classOf[MailboxProbeImpl])
+ val mailboxId: MailboxId = mailboxProbe.createMailbox(MailboxPath.forUser(BOB, "mailbox"))
+ mailboxProbe.createMailbox(MailboxPath.forUser(BOB, "mailbox.child"))
+ val parentId: MailboxId = mailboxProbe.createMailbox(MailboxPath.forUser(BOB, "parent"))
+
+ val request = s"""
+ |{
+ | "using": [ "urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail" ],
+ | "methodCalls": [
+ | [
+ | "Mailbox/set",
+ | {
+ | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+ | "update": {
+ | "${mailboxId.serialize()}": {
+ | "/parentId": "${parentId.serialize()}"
+ | }
+ | }
+ | },
+ | "c1"
+ | ]
+ | ]
+ |}
+ |""".stripMargin
+
+ val response = `given`
+ .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+ .body(request)
+ .when
+ .post
+ .`then`
+ .log().ifValidationFails()
+ .statusCode(SC_OK)
+ .contentType(JSON)
+ .extract
+ .body
+ .asString
+
+ assertThatJson(response).isEqualTo(
+ s"""{
+ | "sessionState": "75128aab4b1b",
+ | "methodResponses": [
+ | ["Mailbox/set", {
+ | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+ | "newState": "000001",
+ | "notUpdated": {
+ | "1": {
+ | "type": "invalidArguments",
+ | "description": "1 parentId property cannot be updated as this mailbox has child mailboxes",
+ | "properties": ["parentId"]
+ | }
+ | }
+ | }, "c1"]
+ | ]
+ |}""".stripMargin)
+ }
}
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetMethod.scala
index ba022f4..a412f8a 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetMethod.scala
@@ -122,6 +122,7 @@ case class UpdateFailure(mailboxId: UnparsedMailboxId, exception: Throwable, pat
case e: InvalidPatchException => MailboxSetError.invalidPatch(Some(SetErrorDescription(s"${e.cause}")))
case e: SystemMailboxChangeException => MailboxSetError.invalidArgument(Some(SetErrorDescription("Invalid change to a system mailbox")), filter(Properties(List("/name", "parentId"))))
case e: InsufficientRightsException => MailboxSetError.invalidArgument(Some(SetErrorDescription("Invalid change to a delegated mailbox")), None)
+ case e: MailboxHasChildException => MailboxSetError.invalidArgument(Some(SetErrorDescription(s"${e.mailboxId.serialize()} parentId property cannot be updated as this mailbox has child mailboxes")), Some(Properties(List("parentId"))))
case _ => MailboxSetError.serverFail(Some(SetErrorDescription(exception.getMessage)), None)
}
}
@@ -216,8 +217,8 @@ class MailboxSetMethod @Inject()(serializer: Serializer,
throw SystemMailboxChangeException(mailboxId)
}
val oldPath = mailbox.getMailboxPath
- val newPath = applyNameUpdate(validatedPatch.nameUpdate, mailboxSession)
- .andThen(applyParentIdUpdate(validatedPatch.parentIdUpdate, mailboxSession))
+ val newPath = applyParentIdUpdate(mailboxId, validatedPatch.parentIdUpdate, mailboxSession)
+ .andThen(applyNameUpdate(validatedPatch.nameUpdate, mailboxSession))
.apply(oldPath)
if (!oldPath.equals(newPath)) {
mailboxManager.renameMailbox(mailboxId,
@@ -236,8 +237,8 @@ class MailboxSetMethod @Inject()(serializer: Serializer,
}
}
- private def applyParentIdUpdate(maybeParentIdUpdate: Option[ParentIdUpdate], mailboxSession: MailboxSession): MailboxPath => MailboxPath = {
- maybeParentIdUpdate.map(parentIdUpdate => applyParentIdUpdate(parentIdUpdate, mailboxSession))
+ private def applyParentIdUpdate(mailboxId: MailboxId, maybeParentIdUpdate: Option[ParentIdUpdate], mailboxSession: MailboxSession): MailboxPath => MailboxPath = {
+ maybeParentIdUpdate.map(parentIdUpdate => applyParentIdUpdate(mailboxId, parentIdUpdate, mailboxSession))
.getOrElse(x => x)
}
@@ -253,11 +254,14 @@ class MailboxSetMethod @Inject()(serializer: Serializer,
}).getOrElse(originalPath)
}
- private def applyParentIdUpdate(parentIdUpdate: ParentIdUpdate, mailboxSession: MailboxSession): MailboxPath => MailboxPath = {
+ private def applyParentIdUpdate(mailboxId: MailboxId, parentIdUpdate: ParentIdUpdate, mailboxSession: MailboxSession): MailboxPath => MailboxPath = {
originalPath => {
val currentName = originalPath.getName(mailboxSession.getPathDelimiter)
parentIdUpdate.newId
.map(id => {
+ if (mailboxManager.hasChildren(originalPath, mailboxSession)) {
+ throw MailboxHasChildException(mailboxId)
+ }
val parentPath = mailboxManager.getMailbox(id, mailboxSession).getMailboxPath
parentPath.child(currentName, mailboxSession.getPathDelimiter)
})
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org