This is an automated email from the ASF dual-hosted git repository. rcordier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit b4723b0f0218c7239eadcb5ae0d4021f59c7ce01 Author: Benoit TELLIER <btell...@linagora.com> AuthorDate: Wed Oct 9 14:32:21 2024 +0200 JAMES-2182 PathConverter: handle encoding for mailboxes belonging to others --- .../james/imap/scripts/ListWithSharedMailbox.test | 2 +- .../org/apache/james/imap/scripts/Namespace.test | 2 +- .../org/apache/james/imap/main/PathConverter.java | 53 +++++++++++++--------- .../james/imap/processor/NamespaceSupplier.java | 2 +- .../apache/james/imap/main/PathConverterTest.java | 18 ++++++-- 5 files changed, 49 insertions(+), 28 deletions(-) diff --git a/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/ListWithSharedMailbox.test b/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/ListWithSharedMailbox.test index 2d01957135..eba7f0dd17 100644 --- a/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/ListWithSharedMailbox.test +++ b/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/ListWithSharedMailbox.test @@ -24,7 +24,7 @@ S: \* LIST \(\\HasNoChildren\) \"\.\" \"INBOX\" S: a0 OK LIST completed. C: a1 LIST "#private" "%" -S: \* LIST \(\\HasNoChildren\) \"\.\" \"#private.imapuser.INBOX\" +S: \* LIST \(\\HasNoChildren\) \"\.\" \"#private.INBOX\" S: a1 OK LIST completed. C: a3 LIST "#private" sharedMailbox* diff --git a/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/Namespace.test b/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/Namespace.test index 42cc371ccb..bb67da2bca 100644 --- a/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/Namespace.test +++ b/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/Namespace.test @@ -17,6 +17,6 @@ # under the License. # ################################################################ C: A001 NAMESPACE -S: \* NAMESPACE \(\((\"\"|\"#private\.\") \".\"\)\) NIL NIL +S: \* NAMESPACE \(\((\"\"|\"#private\.\") \".\"\)\) \(\(\"#user.\" \".\"\)\) NIL S: A001 OK NAMESPACE completed. diff --git a/protocols/imap/src/main/java/org/apache/james/imap/main/PathConverter.java b/protocols/imap/src/main/java/org/apache/james/imap/main/PathConverter.java index 09702031d1..151e503f39 100644 --- a/protocols/imap/src/main/java/org/apache/james/imap/main/PathConverter.java +++ b/protocols/imap/src/main/java/org/apache/james/imap/main/PathConverter.java @@ -21,6 +21,7 @@ package org.apache.james.imap.main; import java.util.List; +import org.apache.james.core.Domain; import org.apache.james.core.Username; import org.apache.james.imap.api.process.ImapSession; import org.apache.james.mailbox.MailboxSession; @@ -48,6 +49,7 @@ public interface PathConverter { class Default implements PathConverter{ private static final int NAMESPACE = 0; + private static final int USER = 1; private final ImapSession session; @@ -72,29 +74,29 @@ public interface PathConverter { } private MailboxPath buildRelativePath(String mailboxName) { - return buildMailboxPath(MailboxConstants.USER_NAMESPACE, session.getUserName(), mailboxName); + return new MailboxPath(MailboxConstants.USER_NAMESPACE, session.getUserName(), sanitizeMailboxName(mailboxName)); } private MailboxPath buildAbsolutePath(String absolutePath) { - char pathDelimiter = session.getMailboxSession().getPathDelimiter(); - List<String> mailboxPathParts = Splitter.on(pathDelimiter).splitToList(absolutePath); - String namespace = mailboxPathParts.get(NAMESPACE); - String mailboxName = Joiner.on(pathDelimiter).join(Iterables.skip(mailboxPathParts, 1)); - return buildMailboxPath(namespace, retrieveUserName(namespace), mailboxName); + MailboxSession mailboxSession = session.getMailboxSession(); + return asMailboxPath(Splitter.on(mailboxSession.getPathDelimiter()).splitToList(absolutePath), mailboxSession); } - private Username retrieveUserName(String namespace) { - if (namespace.equals(MailboxConstants.USER_NAMESPACE)) { - return session.getUserName(); - } - throw new DeniedAccessOnSharedMailboxException(); - } + private MailboxPath asMailboxPath(List<String> mailboxPathParts, MailboxSession session) { + String namespace = mailboxPathParts.get(NAMESPACE); + if (namespace.equalsIgnoreCase("#private")) { + String mailboxName = Joiner.on(session.getPathDelimiter()).join(Iterables.skip(mailboxPathParts, 1)); + return new MailboxPath(MailboxConstants.USER_NAMESPACE, session.getUser(), sanitizeMailboxName(mailboxName)); + } else if (namespace.equalsIgnoreCase("#user")) { + Preconditions.checkArgument(mailboxPathParts.size() > 2, "Expecting at least 2 parts"); + String username = mailboxPathParts.get(USER); + Username user = Username.from(username, session.getUser().getDomainPart().map(Domain::asString)); + String mailboxName = Joiner.on(session.getPathDelimiter()).join(Iterables.skip(mailboxPathParts, 2)); + return new MailboxPath(MailboxConstants.USER_NAMESPACE, user, sanitizeMailboxName(mailboxName)); - private MailboxPath buildMailboxPath(String namespace, Username user, String mailboxName) { - if (!namespace.equals(MailboxConstants.USER_NAMESPACE)) { + } else { throw new DeniedAccessOnSharedMailboxException(); } - return new MailboxPath(namespace, user, sanitizeMailboxName(mailboxName)); } private String sanitizeMailboxName(String mailboxName) { @@ -109,20 +111,27 @@ public interface PathConverter { /** * Joins the elements of a mailboxPath together and returns them as a string */ - private String joinMailboxPath(MailboxPath mailboxPath, char delimiter) { + private String joinMailboxPath(MailboxPath mailboxPath, MailboxSession session) { StringBuilder sb = new StringBuilder(); if (mailboxPath.getNamespace() != null && !mailboxPath.getNamespace().equals("")) { - sb.append(mailboxPath.getNamespace()); + if (mailboxPath.getNamespace().equalsIgnoreCase(MailboxConstants.USER_NAMESPACE) + && !mailboxPath.belongsTo(session)) { + sb.append("#user"); + } else { + sb.append(mailboxPath.getNamespace()); + } } if (mailboxPath.getUser() != null && !mailboxPath.getUser().equals("")) { - if (sb.length() > 0) { - sb.append(delimiter); + if (!mailboxPath.belongsTo(session)) { + if (sb.length() > 0) { + sb.append(session.getPathDelimiter()); + } + sb.append(mailboxPath.getUser().asString()); } - sb.append(mailboxPath.getUser().asString()); } if (mailboxPath.getName() != null && !mailboxPath.getName().equals("")) { if (sb.length() > 0) { - sb.append(delimiter); + sb.append(session.getPathDelimiter()); } sb.append(mailboxPath.getName()); } @@ -133,7 +142,7 @@ public interface PathConverter { if (relative && path.belongsTo(session)) { return path.getName(); } else { - return joinMailboxPath(path, session.getPathDelimiter()); + return joinMailboxPath(path, session); } } } diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/NamespaceSupplier.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/NamespaceSupplier.java index 90fe3c91ad..c706266cef 100644 --- a/protocols/imap/src/main/java/org/apache/james/imap/processor/NamespaceSupplier.java +++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/NamespaceSupplier.java @@ -19,7 +19,7 @@ public interface NamespaceSupplier { @Override public Collection<Namespace> otherUsersNamespaces(MailboxSession session) { - return ImmutableList.of(); + return ImmutableList.of(new NamespaceResponse.Namespace("#user", session.getPathDelimiter())); } @Override diff --git a/protocols/imap/src/test/java/org/apache/james/imap/main/PathConverterTest.java b/protocols/imap/src/test/java/org/apache/james/imap/main/PathConverterTest.java index b98c995532..eedc447b97 100644 --- a/protocols/imap/src/test/java/org/apache/james/imap/main/PathConverterTest.java +++ b/protocols/imap/src/test/java/org/apache/james/imap/main/PathConverterTest.java @@ -102,6 +102,18 @@ class PathConverterTest { .isEqualTo(MailboxPath.forUser(USERNAME, mailboxName)); } + @Test + void buildFullPathShouldAcceptAbsoluteOtherUserPath() { + assertThat(pathConverter.buildFullPath("#user.username2.abc")) + .isEqualTo(MailboxPath.forUser(USERNAME2, "abc")); + } + + @Test + void buildFullPathShouldAcceptAbsoluteOtherUserPathWithSubfolder() { + assertThat(pathConverter.buildFullPath("#user.username2.abc.def")) + .isEqualTo(MailboxPath.forUser(USERNAME2, "abc.def")); + } + @Test void buildFullPathShouldDenyMailboxPathNotBelongingToTheUser() { assertThatThrownBy(() -> pathConverter.buildFullPath("#any")) @@ -117,7 +129,7 @@ class PathConverterTest { @Test void mailboxNameShouldReturnFQDNWhenRelativeAndOtherUserMailbox() { assertThat(pathConverter.mailboxName(RELATIVE, MailboxPath.forUser(USERNAME2, "abc"), mailboxSession)) - .isEqualTo("#private.username2.abc"); + .isEqualTo("#user.username2.abc"); } @Test @@ -129,13 +141,13 @@ class PathConverterTest { @Test void mailboxNameShouldReturnFQDNWhenNotRelativeAndUserMailbox() { assertThat(pathConverter.mailboxName(!RELATIVE, MailboxPath.forUser(USERNAME, "abc"), mailboxSession)) - .isEqualTo("#private.username.abc"); + .isEqualTo("#private.abc"); } @Test void mailboxNameShouldReturnFQDNWhenNotRelativeAndOtherUserMailbox() { assertThat(pathConverter.mailboxName(!RELATIVE, MailboxPath.forUser(USERNAME2, "abc"), mailboxSession)) - .isEqualTo("#private.username2.abc"); + .isEqualTo("#user.username2.abc"); } @Test --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@james.apache.org For additional commands, e-mail: notifications-h...@james.apache.org