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