1 /*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License").
5 * You may not use this file except in compliance with the License.
6 * A copy of the License is located at
7 *
8 * http://aws.amazon.com/apache2.0
9 *
10 * or in the "license" file accompanying this file. This file is distributed
11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 * express or implied. See the License for the specific language governing
13 * permissions and limitations under the License.
14 */
15
16 package software.amazon.awssdk.profiles;
17
18 import java.nio.file.FileSystems;
19 import java.nio.file.Files;
20 import java.nio.file.Path;
21 import java.nio.file.Paths;
22 import java.util.Optional;
23 import java.util.regex.Pattern;
24 import software.amazon.awssdk.annotations.SdkInternalApi;
25 import software.amazon.awssdk.annotations.SdkPublicApi;
26 import software.amazon.awssdk.utils.JavaSystemSetting;
27 import software.amazon.awssdk.utils.StringUtils;
28
29 /**
30 * A collection of static methods for loading the location for configuration and credentials files.
31 */
32 @SdkPublicApi
33 public final class ProfileFileLocation {
34 private static final Pattern HOME_DIRECTORY_PATTERN =
35 Pattern.compile("^~(/|" + Pattern.quote(FileSystems.getDefault().getSeparator()) + ").*$");
36
37 private ProfileFileLocation() {
38 }
39
40
41 /**
42 * Resolve the path for the configuration file, regardless of whether it exists or not.
43 *
44 * @see #configurationFileLocation()
45 */
46 public static Path configurationFilePath() {
47 return resolveProfileFilePath(
48 ProfileFileSystemSetting.AWS_CONFIG_FILE.getStringValue()
49 .orElse(Paths.get(ProfileFileLocation.userHomeDirectory(),
50 ".aws", "config").toString()));
51 }
52
53 /**
54 * Resolve the location for the credentials file, regardless of whether it exists or not.
55 *
56 * @see #credentialsFileLocation()
57 */
58 public static Path credentialsFilePath() {
59 return resolveProfileFilePath(
60 ProfileFileSystemSetting.AWS_SHARED_CREDENTIALS_FILE.getStringValue()
61 .orElse(Paths.get(userHomeDirectory(),
62 ".aws", "credentials").toString()));
63 }
64
65 /**
66 * Load the location for the configuration file, usually ~/.aws/config unless it's overridden using an environment variable
67 * or system property.
68 */
69 public static Optional<Path> configurationFileLocation() {
70 return resolveIfExists(configurationFilePath());
71 }
72
73 /**
74 * Load the location for the credentials file, usually ~/.aws/credentials unless it's overridden using an environment variable
75 * or system property.
76 */
77 public static Optional<Path> credentialsFileLocation() {
78 return resolveIfExists(credentialsFilePath());
79 }
80
81 /**
82 * Load the home directory that should be used for the profile file. This will check the same environment variables as the CLI
83 * to identify the location of home, before falling back to java-specific resolution.
84 */
85 @SdkInternalApi
86 static String userHomeDirectory() {
87 boolean isWindows = JavaSystemSetting.OS_NAME.getStringValue()
88 .map(s -> StringUtils.lowerCase(s).startsWith("windows"))
89 .orElse(false);
90
91 // To match the logic of the CLI we have to consult environment variables directly.
92 // CHECKSTYLE:OFF
93 String home = System.getenv("HOME");
94
95 if (home != null) {
96 return home;
97 }
98
99 if (isWindows) {
100 String userProfile = System.getenv("USERPROFILE");
101
102 if (userProfile != null) {
103 return userProfile;
104 }
105
106 String homeDrive = System.getenv("HOMEDRIVE");
107 String homePath = System.getenv("HOMEPATH");
108
109 if (homeDrive != null && homePath != null) {
110 return homeDrive + homePath;
111 }
112 }
113
114 return JavaSystemSetting.USER_HOME.getStringValueOrThrow();
115 // CHECKSTYLE:ON
116 }
117
118 private static Path resolveProfileFilePath(String path) {
119 // Resolve ~ using the CLI's logic, not whatever Java decides to do with it.
120 if (HOME_DIRECTORY_PATTERN.matcher(path).matches()) {
121 path = userHomeDirectory() + path.substring(1);
122 }
123
124 return Paths.get(path);
125 }
126
127 private static Optional<Path> resolveIfExists(Path path) {
128 return Optional.ofNullable(path).filter(Files::isRegularFile).filter(Files::isReadable);
129 }
130 }
131