1 | package com.renomad.minum.state; | |
2 | ||
3 | import com.renomad.minum.logging.LoggingLevel; | |
4 | import com.renomad.minum.utils.TimeUtils; | |
5 | ||
6 | import java.io.FileInputStream; | |
7 | import java.io.IOException; | |
8 | import java.util.*; | |
9 | ||
10 | /** | |
11 | * Very important system design decisions are made here. All | |
12 | * developers on this project should look through each of these. | |
13 | */ | |
14 | public final class Constants { | |
15 | ||
16 | private final Properties properties; | |
17 | ||
18 | public Constants() { | |
19 | this(null); | |
20 | } | |
21 | ||
22 | public Constants(Properties props) { | |
23 | properties = Objects.requireNonNullElseGet(props, Constants::getConfiguredProperties); | |
24 | ||
25 | serverPort = getProp("SERVER_PORT", 8080); | |
26 | secureServerPort = getProp("SSL_SERVER_PORT", 8443); | |
27 | hostName = properties.getProperty("HOST_NAME", "localhost"); | |
28 | dbDirectory = properties.getProperty("DB_DIRECTORY", "db"); | |
29 | staticFilesDirectory = properties.getProperty("STATIC_FILES_DIRECTORY", "static"); | |
30 | logLevels = convertLoggingStringsToEnums(getProp("LOG_LEVELS", "DEBUG,TRACE,ASYNC_ERROR,AUDIT")); | |
31 | keystorePath = properties.getProperty("KEYSTORE_PATH", ""); | |
32 | keystorePassword = properties.getProperty("KEYSTORE_PASSWORD", ""); | |
33 | maxReadSizeBytes = getProp("MAX_READ_SIZE_BYTES", 10 * 1024 * 1024); | |
34 | maxReadLineSizeBytes = getProp("MAX_READ_LINE_SIZE_BYTES", 1024); | |
35 | socketTimeoutMillis = getProp("SOCKET_TIMEOUT_MILLIS", 7 * 1000); | |
36 | keepAliveTimeoutSeconds = getProp("KEEP_ALIVE_TIMEOUT_SECONDS", 3); | |
37 | vulnSeekingJailDuration = getProp("VULN_SEEKING_JAIL_DURATION", 10 * 1000); | |
38 | isTheBrigEnabled = getProp("IS_THE_BRIG_ENABLED", true); | |
39 | suspiciousErrors = getProp("SUSPICIOUS_ERRORS", ""); | |
40 | suspiciousPaths = getProp("SUSPICIOUS_PATHS", ""); | |
41 | startTime = System.currentTimeMillis(); | |
42 | extraMimeMappings = getProp("EXTRA_MIME_MAPPINGS", ""); | |
43 | staticFileCacheTime = getProp("STATIC_FILE_CACHE_TIME", 60 * 5); | |
44 | useCacheForStaticFiles = getProp("USE_CACHE_FOR_STATIC_FILES", true); | |
45 | maxElementsLruCacheStaticFiles = getProp("MAX_ELEMENTS_LRU_CACHE_STATIC_FILES", 1000); | |
46 | } | |
47 | ||
48 | /** | |
49 | * The port for our regular, non-encrypted server | |
50 | */ | |
51 | public final int serverPort; | |
52 | ||
53 | /** | |
54 | * The port for our encrypted server | |
55 | */ | |
56 | public final int secureServerPort; | |
57 | ||
58 | /** | |
59 | * This is returned as the "host:" attribute in an HTTP request | |
60 | */ | |
61 | public final String hostName; | |
62 | ||
63 | /** | |
64 | * This is the root directory of our database | |
65 | */ | |
66 | public final String dbDirectory; | |
67 | ||
68 | /** | |
69 | * Root directory of static files | |
70 | */ | |
71 | public final String staticFilesDirectory; | |
72 | ||
73 | /** | |
74 | * The default logging levels | |
75 | */ | |
76 | public final List<LoggingLevel> logLevels; | |
77 | ||
78 | /** | |
79 | * The path to the keystore, required for encrypted TLS communication | |
80 | */ | |
81 | public final String keystorePath; | |
82 | ||
83 | /** | |
84 | * The password of the keystore, used for TLS | |
85 | */ | |
86 | public final String keystorePassword; | |
87 | ||
88 | /** | |
89 | * this is the most bytes we'll read while parsing the Request body | |
90 | */ | |
91 | public final int maxReadSizeBytes; | |
92 | ||
93 | /** | |
94 | * this is the most bytes we'll read on a single line, when reading by | |
95 | * line. This is especially relevant when reading headers and request lines, which | |
96 | * can bulk up with jwt's or query strings, respectively. | |
97 | */ | |
98 | public final int maxReadLineSizeBytes; | |
99 | ||
100 | /** | |
101 | * How long will we let a socket live before we crash it closed? | |
102 | * See {@link java.net.Socket#setSoTimeout(int)} | |
103 | */ | |
104 | public final int socketTimeoutMillis; | |
105 | ||
106 | /** | |
107 | * We include this value in the keep-alive header. It lets the | |
108 | * browser know how long to hold the socket open, in seconds, | |
109 | * before it decides we aren't sending anything else and closes it. | |
110 | */ | |
111 | public final int keepAliveTimeoutSeconds; | |
112 | ||
113 | /** | |
114 | * If a client does something that we consider an indicator for attacking, put them in | |
115 | * jail for a longer duration. | |
116 | */ | |
117 | public final int vulnSeekingJailDuration; | |
118 | ||
119 | /** | |
120 | * TheBrig is what puts client ip's in jail, if we feel they are attacking us. | |
121 | * If this is disabled, that functionality is removed. | |
122 | */ | |
123 | public final boolean isTheBrigEnabled; | |
124 | ||
125 | /** | |
126 | * These are a list of error messages that often indicate unusual behavior, maybe an attacker | |
127 | */ | |
128 | public final List<String> suspiciousErrors; | |
129 | ||
130 | /** | |
131 | * These are a list of paths that often indicate unusual behavior, maybe an attacker | |
132 | */ | |
133 | public final List<String> suspiciousPaths; | |
134 | ||
135 | /** | |
136 | * This value is the result of running System.currentTimeMillis() when this | |
137 | * class gets instantiated, and that is done at the very beginning. | |
138 | */ | |
139 | public final long startTime; | |
140 | ||
141 | /** | |
142 | * These are key-value pairs for mappings between a file | |
143 | * suffix and a mime type. | |
144 | * <p> | |
145 | * These are read by our system in the StaticFilesCache | |
146 | * as key-1,value-1,key-2,value-2,... and so on. | |
147 | * </p> | |
148 | * @see <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types">Basics of HTTP</a> | |
149 | * | |
150 | */ | |
151 | public final List<String> extraMimeMappings; | |
152 | ||
153 | /** | |
154 | * Length of time, in seconds, for static files to be cached, | |
155 | * per the provisions of the Cache-Control header, e.g. | |
156 | * <pre> | |
157 | * {@code Cache-Control: max-age=300} | |
158 | * </pre> | |
159 | */ | |
160 | public final long staticFileCacheTime; | |
161 | ||
162 | /** | |
163 | * Whether we will use caching for the static files. | |
164 | * <p> | |
165 | * When a user requests a path we don't recognize, we | |
166 | * go looking for it. | |
167 | * If we have already found it for someone else, it will | |
168 | * be in a cache. | |
169 | * </p> | |
170 | * <p> | |
171 | * However, if we are doing development, it helps to | |
172 | * not have caching enabled - it can confuse. | |
173 | * </p> | |
174 | */ | |
175 | public final boolean useCacheForStaticFiles; | |
176 | ||
177 | /** | |
178 | * This constant controls the maximum number of elements for the {@link com.renomad.minum.utils.LRUCache} | |
179 | * we create for use by {@link com.renomad.minum.utils.FileUtils}. As files are read | |
180 | * by FileUtil's methods, they will be stored in this cache, to avoid reading from | |
181 | * disk. However, caching can certainly complicate things, so if you would prefer | |
182 | * not to store these values in a cache, set {@link #useCacheForStaticFiles} to false. | |
183 | * <p> | |
184 | * The unit here is the number of elements to store in the cache. Be aware: elements | |
185 | * can be of any size, so two caches each having a max size of 1000 elements could be | |
186 | * drastically different sizes. | |
187 | * </p> | |
188 | */ | |
189 | public final int maxElementsLruCacheStaticFiles; | |
190 | ||
191 | /** | |
192 | * A helper method to remove some redundant boilerplate code for grabbing | |
193 | * configuration values from minum.config | |
194 | */ | |
195 | private int getProp(String propName, int propDefault) { | |
196 |
1
1. getProp : replaced int return with 0 for com/renomad/minum/state/Constants::getProp → KILLED |
return Integer.parseInt(properties.getProperty(propName, String.valueOf(propDefault))); |
197 | } | |
198 | ||
199 | /** | |
200 | * A helper method to remove some redundant boilerplate code for grabbing | |
201 | * configuration values from minum.config | |
202 | */ | |
203 | private boolean getProp(String propName, boolean propDefault) { | |
204 |
2
1. getProp : replaced boolean return with false for com/renomad/minum/state/Constants::getProp → KILLED 2. getProp : replaced boolean return with true for com/renomad/minum/state/Constants::getProp → KILLED |
return Boolean.parseBoolean(properties.getProperty(propName, String.valueOf(propDefault))); |
205 | } | |
206 | ||
207 | /** | |
208 | * A helper method to remove some redundant boilerplate code for grabbing | |
209 | * configuration values from minum.config | |
210 | */ | |
211 | private List<String> getProp(String propName, String propDefault) { | |
212 | String propValue = properties.getProperty(propName); | |
213 |
1
1. getProp : replaced return value with Collections.emptyList for com/renomad/minum/state/Constants::getProp → KILLED |
return extractList(propValue, propDefault); |
214 | } | |
215 | ||
216 | /** | |
217 | * Extract a list out of a comma-delimited string. | |
218 | * <br> | |
219 | * Example: a,b, c, d -> List.of("a","b","c","d") | |
220 | * @param propValue the value of a property | |
221 | * @param propDefault the default value to use, if the propValue is null | |
222 | */ | |
223 | static List<String> extractList(String propValue, String propDefault) { | |
224 |
1
1. extractList : negated conditional → KILLED |
if (propValue == null) { |
225 |
1
1. extractList : negated conditional → TIMED_OUT |
if (propDefault.isBlank()) { |
226 | return List.of(); | |
227 | } else { | |
228 |
1
1. extractList : replaced return value with Collections.emptyList for com/renomad/minum/state/Constants::extractList → KILLED |
return Arrays.asList(propDefault.trim().split("\\s*,\\s*")); |
229 | } | |
230 | } else { | |
231 |
1
1. extractList : replaced return value with Collections.emptyList for com/renomad/minum/state/Constants::extractList → KILLED |
return Arrays.asList(propValue.trim().split("\\s*,\\s*")); |
232 | } | |
233 | } | |
234 | ||
235 | public static Properties getConfiguredProperties() { | |
236 |
1
1. getConfiguredProperties : replaced return value with null for com/renomad/minum/state/Constants::getConfiguredProperties → KILLED |
return getConfiguredProperties("minum.config"); |
237 | } | |
238 | ||
239 | /** | |
240 | * Reads properties from minum.config | |
241 | */ | |
242 | static Properties getConfiguredProperties(String fileName) { | |
243 | var props = new Properties(); | |
244 | try (FileInputStream fis = new FileInputStream(fileName)) { | |
245 | System.out.println(TimeUtils.getTimestampIsoInstant() + | |
246 | " found properties file at ./minum.config. Loading properties"); | |
247 |
1
1. getConfiguredProperties : removed call to java/util/Properties::load → KILLED |
props.load(fis); |
248 | } catch (IOException ex) { | |
249 | System.out.println(CONFIG_ERROR_MESSAGE); | |
250 | } | |
251 |
1
1. getConfiguredProperties : replaced return value with null for com/renomad/minum/state/Constants::getConfiguredProperties → KILLED |
return props; |
252 | } | |
253 | ||
254 | ||
255 | /** | |
256 | * Given a list of strings representing logging levels, | |
257 | * convert it to a list of enums. Log levels are enumerated | |
258 | * in {@link LoggingLevel}. | |
259 | */ | |
260 | static List<LoggingLevel> convertLoggingStringsToEnums(List<String> logLevels) { | |
261 | List<String> logLevelStrings = logLevels.stream().map(String::toUpperCase).toList(); | |
262 | List<LoggingLevel> enabledLoggingLevels = new ArrayList<>(); | |
263 | for (LoggingLevel t : LoggingLevel.values()) { | |
264 | if (logLevelStrings.contains(t.name())) { | |
265 | enabledLoggingLevels.add(t); | |
266 | } | |
267 | } | |
268 |
1
1. convertLoggingStringsToEnums : replaced return value with Collections.emptyList for com/renomad/minum/state/Constants::convertLoggingStringsToEnums → KILLED |
return enabledLoggingLevels; |
269 | } | |
270 | ||
271 | private static final String CONFIG_ERROR_MESSAGE = """ | |
272 | | |
273 | | |
274 | | |
275 | ---------------------------------------------------------------- | |
276 | ----------------- System Configuration Missing ----------------- | |
277 | ---------------------------------------------------------------- | |
278 | | |
279 | No properties file found at ./minum.config | |
280 | | |
281 | Continuing, using defaults. See source code for Minum for an | |
282 | example minum.config, which will allow you to customize behavior. | |
283 | | |
284 | ---------------------------------------------------------------- | |
285 | ---------------------------------------------------------------- | |
286 | """; | |
287 | ||
288 | ||
289 | @Override | |
290 | public boolean equals(Object o) { | |
291 |
2
1. equals : replaced boolean return with false for com/renomad/minum/state/Constants::equals → KILLED 2. equals : negated conditional → KILLED |
if (this == o) return true; |
292 |
3
1. equals : negated conditional → KILLED 2. equals : negated conditional → KILLED 3. equals : replaced boolean return with true for com/renomad/minum/state/Constants::equals → KILLED |
if (o == null || getClass() != o.getClass()) return false; |
293 | Constants constants = (Constants) o; | |
294 |
23
1. equals : negated conditional → KILLED 2. equals : negated conditional → KILLED 3. equals : negated conditional → KILLED 4. equals : negated conditional → KILLED 5. equals : negated conditional → KILLED 6. equals : negated conditional → KILLED 7. equals : negated conditional → KILLED 8. equals : negated conditional → KILLED 9. equals : negated conditional → KILLED 10. equals : negated conditional → KILLED 11. equals : negated conditional → KILLED 12. equals : negated conditional → KILLED 13. equals : negated conditional → KILLED 14. equals : negated conditional → KILLED 15. equals : negated conditional → KILLED 16. equals : negated conditional → KILLED 17. equals : negated conditional → KILLED 18. equals : replaced boolean return with true for com/renomad/minum/state/Constants::equals → KILLED 19. equals : negated conditional → KILLED 20. equals : negated conditional → KILLED 21. equals : negated conditional → KILLED 22. equals : negated conditional → KILLED 23. equals : negated conditional → KILLED |
return serverPort == constants.serverPort && secureServerPort == constants.secureServerPort && maxReadSizeBytes == constants.maxReadSizeBytes && maxReadLineSizeBytes == constants.maxReadLineSizeBytes && socketTimeoutMillis == constants.socketTimeoutMillis && keepAliveTimeoutSeconds == constants.keepAliveTimeoutSeconds && vulnSeekingJailDuration == constants.vulnSeekingJailDuration && isTheBrigEnabled == constants.isTheBrigEnabled && startTime == constants.startTime && staticFileCacheTime == constants.staticFileCacheTime && useCacheForStaticFiles == constants.useCacheForStaticFiles && maxElementsLruCacheStaticFiles == constants.maxElementsLruCacheStaticFiles && Objects.equals(properties, constants.properties) && Objects.equals(hostName, constants.hostName) && Objects.equals(dbDirectory, constants.dbDirectory) && Objects.equals(staticFilesDirectory, constants.staticFilesDirectory) && Objects.equals(logLevels, constants.logLevels) && Objects.equals(keystorePath, constants.keystorePath) && Objects.equals(keystorePassword, constants.keystorePassword) && Objects.equals(suspiciousErrors, constants.suspiciousErrors) && Objects.equals(suspiciousPaths, constants.suspiciousPaths) && Objects.equals(extraMimeMappings, constants.extraMimeMappings); |
295 | } | |
296 | ||
297 | @Override | |
298 | public int hashCode() { | |
299 |
1
1. hashCode : replaced int return with 0 for com/renomad/minum/state/Constants::hashCode → KILLED |
return Objects.hash(properties, serverPort, secureServerPort, hostName, dbDirectory, staticFilesDirectory, logLevels, keystorePath, keystorePassword, maxReadSizeBytes, maxReadLineSizeBytes, socketTimeoutMillis, keepAliveTimeoutSeconds, vulnSeekingJailDuration, isTheBrigEnabled, suspiciousErrors, suspiciousPaths, startTime, extraMimeMappings, staticFileCacheTime, useCacheForStaticFiles, maxElementsLruCacheStaticFiles); |
300 | } | |
301 | } | |
302 | ||
303 | ||
304 | ||
Mutations | ||
196 |
1.1 |
|
204 |
1.1 2.2 |
|
213 |
1.1 |
|
224 |
1.1 |
|
225 |
1.1 |
|
228 |
1.1 |
|
231 |
1.1 |
|
236 |
1.1 |
|
247 |
1.1 |
|
251 |
1.1 |
|
268 |
1.1 |
|
291 |
1.1 2.2 |
|
292 |
1.1 2.2 3.3 |
|
294 |
1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 9.9 10.10 11.11 12.12 13.13 14.14 15.15 16.16 17.17 18.18 19.19 20.20 21.21 22.22 23.23 |
|
299 |
1.1 |