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

Mutations

211

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

219

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

228

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

239

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

240

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

243

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

246

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

251

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

262

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

266

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

283

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

305

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

306

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

308

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)
replaced boolean return with true for com/renomad/minum/state/Constants::equals → 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)
negated conditional → 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

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

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

313

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