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 a2557d58c96f938f3e89176870eedabaa1ebeda1 Author: Benoit TELLIER <btell...@linagora.com> AuthorDate: Wed Oct 9 14:53:43 2024 +0200 JAMES-2182 PathConverter: username escaping for dots This common character conflicts with the path delimiter of the mailbox name and thus needs to be escaped. --- .../org/apache/james/imap/main/PathConverter.java | 13 +++++++++-- .../apache/james/imap/main/PathConverterTest.java | 26 ++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) 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 3bbcbf469f..5ea5c5fe79 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 @@ -33,6 +33,8 @@ import com.google.common.base.Preconditions; import com.google.common.base.Splitter; import com.google.common.base.Strings; import com.google.common.collect.Iterables; +import com.google.common.escape.Escaper; +import com.google.common.escape.Escapers; public interface PathConverter { interface Factory { @@ -50,6 +52,10 @@ public interface PathConverter { class Default implements PathConverter{ private static final int NAMESPACE = 0; private static final int USER = 1; + public static final Escaper USERNAME_ESCAPER = Escapers.builder() + .addEscape('.', "__") + .addEscape('_', "_-") + .build(); private final ImapSession session; @@ -90,7 +96,9 @@ public interface PathConverter { } 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 unescapedUsername = username.replace("__", ".") + .replace("_-", "_"); + Username user = Username.from(unescapedUsername, 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)); @@ -126,7 +134,8 @@ public interface PathConverter { if (!sb.isEmpty()) { sb.append(session.getPathDelimiter()); } - sb.append(mailboxPath.getUser().getLocalPart()); + + sb.append(USERNAME_ESCAPER.escape(mailboxPath.getUser().getLocalPart())); } } if (mailboxPath.getName() != null && !mailboxPath.getName().isEmpty()) { 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 f314f32949..8d864b4b26 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 @@ -35,6 +35,8 @@ import org.junit.jupiter.api.Test; class PathConverterTest { private static final Username USERNAME = Username.of("username"); + private static final Username USERNAME_WITH_DOT = Username.of("username.with.dot"); + private static final Username USERNAME_WITH_UNDERSCORE = Username.of("username_with_underscore"); private static final Username USERNAME2 = Username.of("username2"); private static final Username USERNAME_WITH_MAIL = Username.of("usern...@apache.org"); @@ -112,6 +114,18 @@ class PathConverterTest { .isEqualTo(MailboxPath.forUser(USERNAME2, "abc")); } + @Test + void buildFullPathShouldAcceptAbsoluteOtherUserPathWithDot() { + assertThat(pathConverter.buildFullPath("#user.username__with__dot.abc")) + .isEqualTo(MailboxPath.forUser(USERNAME_WITH_DOT, "abc")); + } + + @Test + void buildFullPathShouldAcceptAbsoluteOtherUserPathWithUnderscore() { + assertThat(pathConverter.buildFullPath("#user.username_-with_-underscore.abc")) + .isEqualTo(MailboxPath.forUser(USERNAME_WITH_UNDERSCORE, "abc")); + } + @Test void buildFullPathShouldAcceptAbsoluteOtherUserPathWithSubfolder() { assertThat(pathConverter.buildFullPath("#user.username2.abc.def")) @@ -136,6 +150,18 @@ class PathConverterTest { .isEqualTo("#user.username2.abc"); } + @Test + void mailboxNameShouldEscapeDotInUsername() { + assertThat(pathConverter.mailboxName(RELATIVE, MailboxPath.forUser(USERNAME_WITH_DOT, "abc"), mailboxSession)) + .isEqualTo("#user.username__with__dot.abc"); + } + + @Test + void mailboxNameShouldEscapeUnderscoreInUsername() { + assertThat(pathConverter.mailboxName(RELATIVE, MailboxPath.forUser(USERNAME_WITH_UNDERSCORE, "abc"), mailboxSession)) + .isEqualTo("#user.username_-with_-underscore.abc"); + } + @Test void mailboxNameShouldReturnFQDNWhenRelativeAndSharedMailbox() { assertThat(pathConverter.mailboxName(RELATIVE, new MailboxPath("#Shared", Username.of("marketing"), "abc"), mailboxSession)) --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@james.apache.org For additional commands, e-mail: notifications-h...@james.apache.org