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