chibenwa commented on code in PR #2445: URL: https://github.com/apache/james-project/pull/2445#discussion_r1811216233
########## protocols/imap/src/main/java/org/apache/james/imap/main/PathConverter.java: ########## @@ -21,80 +21,230 @@ import java.util.List; +import org.apache.james.core.Domain; import org.apache.james.core.Username; +import org.apache.james.imap.api.display.ModifiedUtf7; import org.apache.james.imap.api.process.ImapSession; +import org.apache.james.mailbox.MailboxSession; import org.apache.james.mailbox.model.MailboxConstants; import org.apache.james.mailbox.model.MailboxPath; +import org.apache.james.mailbox.model.search.MailboxQuery; +import org.apache.james.mailbox.model.search.PrefixedRegex; +import org.apache.james.mailbox.model.search.Wildcard; import com.google.common.base.Joiner; 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 class PathConverter { +public interface PathConverter { + interface Factory { + PathConverter.Factory DEFAULT = new PathConverter.Factory.Default(); - private static final int NAMESPACE = 0; + class Default implements Factory { + public PathConverter forSession(ImapSession session) { + return new PathConverter.Default(session.getMailboxSession()); + } - public static PathConverter forSession(ImapSession session) { - return new PathConverter(session); - } + public PathConverter forSession(MailboxSession session) { + return new PathConverter.Default(session); + } + } - private final ImapSession session; + PathConverter forSession(ImapSession session); - private PathConverter(ImapSession session) { - this.session = session; + PathConverter forSession(MailboxSession session); } - public MailboxPath buildFullPath(String mailboxName) { - if (Strings.isNullOrEmpty(mailboxName)) { - return buildRelativePath(""); + 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 MailboxSession mailboxSession; + + private Default(MailboxSession mailboxSession) { + this.mailboxSession = mailboxSession; } - if (isAbsolute(mailboxName)) { - return buildAbsolutePath(mailboxName); - } else { - return buildRelativePath(mailboxName); + + public MailboxPath buildFullPath(String mailboxName) { + if (Strings.isNullOrEmpty(mailboxName)) { + return buildRelativePath(""); + } + if (isAbsolute(mailboxName)) { + return buildAbsolutePath(mailboxName); + } else { + return buildRelativePath(mailboxName); + } } - } - private boolean isAbsolute(String mailboxName) { - Preconditions.checkArgument(!Strings.isNullOrEmpty(mailboxName)); - return mailboxName.charAt(0) == MailboxConstants.NAMESPACE_PREFIX_CHAR; - } + private boolean isAbsolute(String mailboxName) { + Preconditions.checkArgument(!Strings.isNullOrEmpty(mailboxName)); + return mailboxName.charAt(0) == MailboxConstants.NAMESPACE_PREFIX_CHAR; + } - private MailboxPath buildRelativePath(String mailboxName) { - return buildMailboxPath(MailboxConstants.USER_NAMESPACE, session.getUserName(), mailboxName); - } + private MailboxPath buildRelativePath(String mailboxName) { + return new MailboxPath(MailboxConstants.USER_NAMESPACE, mailboxSession.getUser(), 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); - } + private MailboxPath buildAbsolutePath(String absolutePath) { + return asMailboxPath(Splitter.on(mailboxSession.getPathDelimiter()).splitToList(absolutePath), mailboxSession); + } - private Username retrieveUserName(String namespace) { - if (namespace.equals(MailboxConstants.USER_NAMESPACE)) { - return session.getUserName(); + 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")) { + if (mailboxPathParts.size() == 1) { + // May be generated by some List commands. + String mailboxName = Joiner.on(session.getPathDelimiter()).join(Iterables.skip(mailboxPathParts, 1)); + return new MailboxPath(MailboxConstants.USER_NAMESPACE, null, sanitizeMailboxName(mailboxName)); + } + String username = mailboxPathParts.get(USER); + 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)); + + } else { + throw new DeniedAccessOnSharedMailboxException(); + } } - throw new DeniedAccessOnSharedMailboxException(); - } - private MailboxPath buildMailboxPath(String namespace, Username user, String mailboxName) { - if (!namespace.equals(MailboxConstants.USER_NAMESPACE)) { - throw new DeniedAccessOnSharedMailboxException(); + private String sanitizeMailboxName(String mailboxName) { + // use uppercase for INBOX + // See IMAP-349 + if (mailboxName.equalsIgnoreCase(MailboxConstants.INBOX)) { + return MailboxConstants.INBOX; + } + return mailboxName; } - return new MailboxPath(namespace, user, sanitizeMailboxName(mailboxName)); - } - private String sanitizeMailboxName(String mailboxName) { - // use uppercase for INBOX - // See IMAP-349 - if (mailboxName.equalsIgnoreCase(MailboxConstants.INBOX)) { - return MailboxConstants.INBOX; + /** + * Joins the elements of a mailboxPath together and returns them as a string + */ + private String joinMailboxPath(MailboxPath mailboxPath, MailboxSession session) { + StringBuilder sb = new StringBuilder(); + if (mailboxPath.getNamespace() != null && !mailboxPath.getNamespace().isEmpty()) { + if (mailboxPath.getNamespace().equalsIgnoreCase(MailboxConstants.USER_NAMESPACE) + && !mailboxPath.belongsTo(session)) { + sb.append("#user"); + } else { + sb.append(mailboxPath.getNamespace()); + } + } + if (mailboxPath.getUser() != null) { + if (!mailboxPath.belongsTo(session)) { + if (!sb.isEmpty()) { + sb.append(session.getPathDelimiter()); + } + + sb.append(USERNAME_ESCAPER.escape(mailboxPath.getUser().getLocalPart())); + } + } + if (mailboxPath.getName() != null && !mailboxPath.getName().isEmpty()) { + if (!sb.isEmpty()) { + sb.append(session.getPathDelimiter()); + } + sb.append(mailboxPath.getName()); + } + return sb.toString(); + } + + public String mailboxName(boolean relative, MailboxPath path, MailboxSession session) { + if (relative && path.belongsTo(session)) { + return path.getName(); + } else { + return joinMailboxPath(path, session); + } + } + + public MailboxQuery mailboxQuery(String finalReferencename, String mailboxName, ImapSession session) { + MailboxSession mailboxSession = session.getMailboxSession(); + String decodedMailboxName = ModifiedUtf7.decodeModifiedUTF7(mailboxName); + if (finalReferencename.isEmpty()) { + if (mailboxName.equals("*")) { + return MailboxQuery.builder() + .matchesAllMailboxNames() + .build(); + } + return MailboxQuery.builder() + .expression(new PrefixedRegex( + "", + decodedMailboxName, + mailboxSession.getPathDelimiter())) + .build(); + } + + MailboxPath basePath = computeBasePath(session, finalReferencename); + if (basePath.getNamespace().equals(MailboxConstants.USER_NAMESPACE) + && basePath.getUser() == null) { + + int separatorPosition = decodedMailboxName.indexOf(mailboxSession.getPathDelimiter()); + if (separatorPosition >= 0) { + // interpret first part as the user Review Comment: :-1: split underneath uses a regex which obfuscate code, expose to complications like REDOS, and behaves pourly in what is here a critical path. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: notifications-unsubscr...@james.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@james.apache.org For additional commands, e-mail: notifications-h...@james.apache.org