Constants.java

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
Location : getProp
Killed by : com.renomad.minum.state.ConstantsTests.testCustomProps(com.renomad.minum.state.ConstantsTests)
replaced int return with 0 for com/renomad/minum/state/Constants::getProp → KILLED

204

1.1
Location : getProp
Killed by : com.renomad.minum.web.SocketWrapperTests.testSendingSingleByte(com.renomad.minum.web.SocketWrapperTests)
replaced boolean return with false for com/renomad/minum/state/Constants::getProp → KILLED

2.2
Location : getProp
Killed by : com.renomad.minum.web.SocketWrapperTests.testSendingSingleByte(com.renomad.minum.web.SocketWrapperTests)
replaced boolean return with true for com/renomad/minum/state/Constants::getProp → KILLED

213

1.1
Location : getProp
Killed by : com.renomad.minum.web.SocketWrapperTests.testSendingSingleByte(com.renomad.minum.web.SocketWrapperTests)
replaced return value with Collections.emptyList for com/renomad/minum/state/Constants::getProp → KILLED

224

1.1
Location : extractList
Killed by : com.renomad.minum.state.ConstantsTests.testGetProps_Array(com.renomad.minum.state.ConstantsTests)
negated conditional → KILLED

225

1.1
Location : extractList
Killed by : none
negated conditional → TIMED_OUT

228

1.1
Location : extractList
Killed by : com.renomad.minum.security.TheBrigTests
replaced return value with Collections.emptyList for com/renomad/minum/state/Constants::extractList → KILLED

231

1.1
Location : extractList
Killed by : com.renomad.minum.state.ConstantsTests.testGetProps_Array(com.renomad.minum.state.ConstantsTests)
replaced return value with Collections.emptyList for com/renomad/minum/state/Constants::extractList → KILLED

236

1.1
Location : getConfiguredProperties
Killed by : com.renomad.minum.logging.TestLoggerTests.test_TestLogger_MaxLines(com.renomad.minum.logging.TestLoggerTests)
replaced return value with null for com/renomad/minum/state/Constants::getConfiguredProperties → KILLED

247

1.1
Location : getConfiguredProperties
Killed by : com.renomad.minum.web.WebFrameworkTests.test_readStaticFile_IOException(com.renomad.minum.web.WebFrameworkTests)
removed call to java/util/Properties::load → KILLED

251

1.1
Location : getConfiguredProperties
Killed by : com.renomad.minum.state.ConstantsTests.testGettingConfiguredPropertiesFromFile_NothingFound(com.renomad.minum.state.ConstantsTests)
replaced return value with null for com/renomad/minum/state/Constants::getConfiguredProperties → KILLED

268

1.1
Location : convertLoggingStringsToEnums
Killed by : com.renomad.minum.state.ConstantsTests.test_convertLoggingStringsToEnums(com.renomad.minum.state.ConstantsTests)
replaced return value with Collections.emptyList for com/renomad/minum/state/Constants::convertLoggingStringsToEnums → KILLED

291

1.1
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
replaced boolean return with false for com/renomad/minum/state/Constants::equals → KILLED

2.2
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
negated conditional → KILLED

292

1.1
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
negated conditional → KILLED

2.2
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
negated conditional → KILLED

3.3
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
replaced boolean return with true for com/renomad/minum/state/Constants::equals → KILLED

294

1.1
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
negated conditional → KILLED

2.2
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
negated conditional → KILLED

3.3
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
negated conditional → KILLED

4.4
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
negated conditional → KILLED

5.5
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
negated conditional → KILLED

6.6
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
negated conditional → KILLED

7.7
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
negated conditional → KILLED

8.8
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
negated conditional → KILLED

9.9
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
negated conditional → KILLED

10.10
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
negated conditional → KILLED

11.11
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
negated conditional → KILLED

12.12
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
negated conditional → KILLED

13.13
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
negated conditional → KILLED

14.14
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
negated conditional → KILLED

15.15
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
negated conditional → KILLED

16.16
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
negated conditional → KILLED

17.17
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
negated conditional → KILLED

18.18
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
replaced boolean return with true for com/renomad/minum/state/Constants::equals → KILLED

19.19
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
negated conditional → KILLED

20.20
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
negated conditional → KILLED

21.21
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
negated conditional → KILLED

22.22
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
negated conditional → KILLED

23.23
Location : equals
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
negated conditional → KILLED

299

1.1
Location : hashCode
Killed by : com.renomad.minum.EqualsTests.equalsTest(com.renomad.minum.EqualsTests)
replaced int return with 0 for com/renomad/minum/state/Constants::hashCode → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.0