This is an automated email from the ASF dual-hosted git repository. lgoldstein pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mina-sshd.git
commit 7fefebb5356d02fb52965e1686b8497ade94fb53 Author: Lyor Goldstein <lgoldst...@apache.org> AuthorDate: Thu Feb 17 08:41:47 2022 +0200 [SSHD-1246] Moved user HOME directory detection and usage to PathUtils --- CHANGES.md | 4 ++ .../sshd/client/config/hosts/HostConfigEntry.java | 32 ++------- .../sshd/common/config/keys/IdentityUtils.java | 20 ------ .../sshd/common/config/keys/PublicKeyEntry.java | 3 +- .../org/apache/sshd/common/util/io/PathUtils.java | 73 ++++++++++++++++++++ .../apache/sshd/common/util/io/PathUtilsTest.java | 78 ++++++++++++++++++++++ .../java/org/apache/sshd/openpgp/PGPUtils.java | 4 +- 7 files changed, 163 insertions(+), 51 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 4571d35..894d234 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -57,6 +57,10 @@ to make sure the requested value does not exceed `Integer#MAX_VALUE` (sometimes or malformed packets. It is important to bear in mind that in the vast majority of the cases we do not want to be able to allocate arrays or lists having billions of elements as it would almost definitely cause out-of-memory issues. +## User HOME directory resolution and usage have been moved to *PathUtils* + +Was originally in *HostConfigEntry*. + ## Minor code helpers ## Behavioral changes and enhancements diff --git a/sshd-common/src/main/java/org/apache/sshd/client/config/hosts/HostConfigEntry.java b/sshd-common/src/main/java/org/apache/sshd/client/config/hosts/HostConfigEntry.java index 31a62c2..5f4d33d 100644 --- a/sshd-common/src/main/java/org/apache/sshd/client/config/hosts/HostConfigEntry.java +++ b/sshd-common/src/main/java/org/apache/sshd/client/config/hosts/HostConfigEntry.java @@ -48,7 +48,6 @@ import java.util.TreeMap; import org.apache.sshd.common.auth.MutableUserHolder; import org.apache.sshd.common.config.ConfigFileReaderSupport; -import org.apache.sshd.common.config.keys.IdentityUtils; import org.apache.sshd.common.config.keys.PublicKeyEntry; import org.apache.sshd.common.util.GenericUtils; import org.apache.sshd.common.util.MapEntryUtils; @@ -56,6 +55,7 @@ import org.apache.sshd.common.util.MapEntryUtils.NavigableMapBuilder; import org.apache.sshd.common.util.OsUtils; import org.apache.sshd.common.util.ValidateUtils; import org.apache.sshd.common.util.io.IoUtils; +import org.apache.sshd.common.util.io.PathUtils; import org.apache.sshd.common.util.io.input.NoCloseInputStream; import org.apache.sshd.common.util.io.input.NoCloseReader; import org.apache.sshd.common.util.io.output.NoCloseOutputStream; @@ -114,7 +114,6 @@ public class HostConfigEntry extends HostPatternsHolder implements MutableUserHo public static final String MULTI_VALUE_SEPARATORS = " ,"; - public static final char HOME_TILDE_CHAR = '~'; public static final char PATH_MACRO_CHAR = '%'; public static final char LOCAL_HOME_MACRO = 'd'; public static final char LOCAL_USER_MACRO = 'u'; @@ -1148,9 +1147,9 @@ public class HostConfigEntry extends HostPatternsHolder implements MutableUserHo for (int curPos = 0; curPos < elem.length(); curPos++) { char ch = elem.charAt(curPos); - if (ch == HOME_TILDE_CHAR) { + if (ch == PathUtils.HOME_TILDE_CHAR) { ValidateUtils.checkTrue((curPos == 0) && (index == 0), "Home tilde must be first: %s", id); - appendUserHome(sb); + PathUtils.appendUserHome(sb); } else if (ch == PATH_MACRO_CHAR) { curPos++; ValidateUtils.checkTrue(curPos < elem.length(), "Missing macro modifier in %s", id); @@ -1161,7 +1160,7 @@ public class HostConfigEntry extends HostPatternsHolder implements MutableUserHo break; case LOCAL_HOME_MACRO: ValidateUtils.checkTrue((curPos == 1) && (index == 0), "Home macro must be first: %s", id); - appendUserHome(sb); + PathUtils.appendUserHome(sb); break; case LOCAL_USER_MACRO: sb.append(ValidateUtils.checkNotNullAndNotEmpty(OsUtils.getCurrentUser(), @@ -1194,29 +1193,6 @@ public class HostConfigEntry extends HostPatternsHolder implements MutableUserHo return sb.toString(); } - public static StringBuilder appendUserHome(StringBuilder sb) { - return appendUserHome(sb, IdentityUtils.getUserHomeFolder()); - } - - public static StringBuilder appendUserHome(StringBuilder sb, Path userHome) { - return appendUserHome(sb, Objects.requireNonNull(userHome, "No user home folder").toString()); - } - - public static StringBuilder appendUserHome(StringBuilder sb, String userHome) { - if (GenericUtils.isEmpty(userHome)) { - return sb; - } - - sb.append(userHome); - // strip any ending separator since we add our own - int len = sb.length(); - if (sb.charAt(len - 1) == File.separatorChar) { - sb.setLength(len - 1); - } - - return sb; - } - /** * @return The default {@link Path} location of the OpenSSH hosts entries configuration file */ diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/IdentityUtils.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/IdentityUtils.java index b353dbc..f727165 100644 --- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/IdentityUtils.java +++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/IdentityUtils.java @@ -23,7 +23,6 @@ import java.io.IOException; import java.io.InputStream; import java.nio.file.OpenOption; import java.nio.file.Path; -import java.nio.file.Paths; import java.security.GeneralSecurityException; import java.security.KeyPair; import java.util.Collections; @@ -48,25 +47,6 @@ public final class IdentityUtils { throw new UnsupportedOperationException("No instance"); } - private static final class LazyDefaultUserHomeFolderHolder { - private static final Path PATH - = Paths.get(ValidateUtils.checkNotNullAndNotEmpty(System.getProperty("user.home"), "No user home")) - .toAbsolutePath() - .normalize(); - - private LazyDefaultUserHomeFolderHolder() { - throw new UnsupportedOperationException("No instance allowed"); - } - } - - /** - * @return The {@link Path} to the currently running user home - */ - @SuppressWarnings("synthetic-access") - public static Path getUserHomeFolder() { - return LazyDefaultUserHomeFolderHolder.PATH; - } - /** * @param prefix The file name prefix - ignored if {@code null}/empty * @param type The identity type - ignored if {@code null}/empty diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntry.java b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntry.java index 8dc634c..882daa7 100644 --- a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntry.java +++ b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntry.java @@ -42,6 +42,7 @@ import org.apache.sshd.common.session.SessionContext; import org.apache.sshd.common.util.GenericUtils; import org.apache.sshd.common.util.NumberUtils; import org.apache.sshd.common.util.ValidateUtils; +import org.apache.sshd.common.util.io.PathUtils; /** * <P> @@ -498,7 +499,7 @@ public class PublicKeyEntry implements Serializable, KeyTypeIndicator { } private static final class LazyDefaultKeysFolderHolder { - private static final Path PATH = IdentityUtils.getUserHomeFolder().resolve(STD_KEYFILE_FOLDER_NAME); + private static final Path PATH = PathUtils.getUserHomeFolder().resolve(STD_KEYFILE_FOLDER_NAME); private LazyDefaultKeysFolderHolder() { throw new UnsupportedOperationException("No instance allowed"); diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/io/PathUtils.java b/sshd-common/src/main/java/org/apache/sshd/common/util/io/PathUtils.java index 52fec23..cd9ab9c 100644 --- a/sshd-common/src/main/java/org/apache/sshd/common/util/io/PathUtils.java +++ b/sshd-common/src/main/java/org/apache/sshd/common/util/io/PathUtils.java @@ -19,11 +19,14 @@ package org.apache.sshd.common.util.io; +import java.io.File; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Comparator; import java.util.Objects; import org.apache.sshd.common.util.GenericUtils; +import org.apache.sshd.common.util.ValidateUtils; import org.apache.sshd.common.util.functors.UnaryEquator; /** @@ -43,6 +46,19 @@ public final class PathUtils { public static final UnaryEquator<Path> EQ_CASE_SENSITIVE_FILENAME = (p1, p2) -> BY_CASE_SENSITIVE_FILENAME.compare(p1, p2) == 0; + private static final class LazyDefaultUserHomeFolderHolder { + private static final Path PATH + = Paths.get(ValidateUtils.checkNotNullAndNotEmpty(System.getProperty("user.home"), "No user home")) + .toAbsolutePath() + .normalize(); + + private LazyDefaultUserHomeFolderHolder() { + throw new UnsupportedOperationException("No instance allowed"); + } + } + + public static final char HOME_TILDE_CHAR = '~'; + /** * Private Constructor */ @@ -73,4 +89,61 @@ public final class PathUtils { String n2 = Objects.toString(p2.getFileName(), null); return GenericUtils.safeCompare(n1, n2, caseSensitive); } + + /** + * <UL> + * <LI>Replaces <U>leading</U> '~' with user's HOME directory</LI> + * <LI>Replaces any forward slashes with the O/S directory separator</LI> + * </UL> + * + * @param path Input path - ignored if {@code null}/empty/blank + * @return Adjusted path + */ + public static String normalizePath(String path) { + if (GenericUtils.isBlank(path)) { + return path; + } + + if (path.charAt(0) == HOME_TILDE_CHAR) { + Path homeDir = Objects.requireNonNull(getUserHomeFolder(), "No user home folder available"); + if (path.length() > 1) { + path = homeDir + path.substring(1); + } else { + path = homeDir.toString(); + } + } + + return path.replace('/', File.separatorChar); + } + + /** + * @return The {@link Path} to the currently running user home + */ + @SuppressWarnings("synthetic-access") + public static Path getUserHomeFolder() { + return LazyDefaultUserHomeFolderHolder.PATH; + } + + public static StringBuilder appendUserHome(StringBuilder sb) { + return appendUserHome(sb, getUserHomeFolder()); + } + + public static StringBuilder appendUserHome(StringBuilder sb, Path userHome) { + return appendUserHome(sb, Objects.requireNonNull(userHome, "No user home folder").toString()); + } + + public static StringBuilder appendUserHome(StringBuilder sb, String userHome) { + if (GenericUtils.isEmpty(userHome)) { + return sb; + } + + sb.append(userHome); + // strip any ending separator since we add our own + int len = sb.length(); + if (sb.charAt(len - 1) == File.separatorChar) { + sb.setLength(len - 1); + } + + return sb; + } } diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/PathUtilsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/PathUtilsTest.java new file mode 100644 index 0000000..32c0480 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/PathUtilsTest.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.sshd.common.util.io; + +import java.io.File; +import java.nio.file.Path; + +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runners.MethodSorters; + +/** + * @author <a href="mailto:d...@mina.apache.org">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Category({ NoIoTestCase.class }) +public class PathUtilsTest extends JUnitTestSupport { + public PathUtilsTest() { + super(); + } + + @Test + public void testNormalizeUserHomeOnlyPath() { + Path expected = PathUtils.getUserHomeFolder(); + String actual = PathUtils.normalizePath(Character.toString(PathUtils.HOME_TILDE_CHAR)); + assertEquals(expected.toString(), actual); + } + + @Test + public void testNormalizeLeadingUserHomePath() { + Path expected = PathUtils.getUserHomeFolder() + .resolve(getClass().getSimpleName()) + .resolve(getCurrentTestName()) + ; + String actual = PathUtils.normalizePath(PathUtils.HOME_TILDE_CHAR + + File.separator + getClass().getSimpleName() + + File.separator + getCurrentTestName()); + assertEquals(expected.toString(), actual); + } + + @Test + public void testNormalizeStandardPath() { + String expected = detectTargetFolder().toString(); + String actual = PathUtils.normalizePath(expected); + assertSame(expected, actual); + } + + @Test + public void testNormalizeForwardSlash() { + String expected = detectTargetFolder().toString(); + String actual = PathUtils.normalizePath(expected.replace(File.separatorChar, '/')); + if (File.separatorChar == '/') { + assertSame(expected, actual); + } else { + assertEquals(expected, actual); + } + } +} diff --git a/sshd-openpgp/src/main/java/org/apache/sshd/openpgp/PGPUtils.java b/sshd-openpgp/src/main/java/org/apache/sshd/openpgp/PGPUtils.java index d061b6e..9159d79 100644 --- a/sshd-openpgp/src/main/java/org/apache/sshd/openpgp/PGPUtils.java +++ b/sshd-openpgp/src/main/java/org/apache/sshd/openpgp/PGPUtils.java @@ -28,10 +28,10 @@ import java.util.Set; import java.util.TreeMap; import org.apache.sshd.common.PropertyResolverUtils; -import org.apache.sshd.common.config.keys.IdentityUtils; import org.apache.sshd.common.util.GenericUtils; import org.apache.sshd.common.util.OsUtils; import org.apache.sshd.common.util.ValidateUtils; +import org.apache.sshd.common.util.io.PathUtils; import org.c02e.jpgpj.CompressionAlgorithm; import org.c02e.jpgpj.EncryptionAlgorithm; import org.c02e.jpgpj.Key; @@ -161,7 +161,7 @@ public final class PGPUtils { } private static final class LazyDefaultPgpKeysFolderHolder { - private static final Path PATH = IdentityUtils.getUserHomeFolder() + private static final Path PATH = PathUtils.getUserHomeFolder() .resolve(OsUtils.isUNIX() ? STD_LINUX_PGP_FOLDER_NAME : STD_WINDOWS_PGP_FOLDER_NAME); private LazyDefaultPgpKeysFolderHolder() {