All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.codacy.scoobydoo.configuration.Configuration Maven / Gradle / Ivy

There is a newer version: 3.30.0
Show newest version
package com.codacy.scoobydoo.configuration;

import com.codacy.scoobydoo.Constant.Key;
import com.codacy.scoobydoo.Constant.Status;
import com.codacy.scoobydoo.Decryptor;
import com.codacy.scoobydoo.LoggingHelper;
import software.amazon.awssdk.services.ssm.model.ParameterNotFoundException;
import software.amazon.awssdk.services.sts.model.ExpiredTokenException;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Properties;

public class Configuration {

    public static class Timeout {

        public Duration DEFAULT_TIMEOUT;
        public Duration DEFAULT_POLLING;
        public Duration ENDPOINT_MEDIUM_WAIT;
        public Duration ENDPOINT_HIGH_WAIT;
        public Duration ENDPOINT_MAX_WAIT;
        public Duration FIND_ELEMENT_WAIT_TIMEOUT;
        public Duration LONG_POLLING;
        public Duration LONG_WAIT_TIMEOUT;
        public Duration PAGE_LOAD_TIMEOUT;
        public Duration SCRIPT_TIMEOUT;

        public Timeout(Properties properties) {

            final List timeoutConfigKeys = Arrays.asList(
                    Key.TIMEOUT_DEFAULT,
                    Key.TIMEOUT_POLLING_DEFAULT,
                    Key.TIMEOUT_ENDPOINT_MEDIUM_WAIT,
                    Key.TIMEOUT_ENDPOINT_HIGH_WAIT,
                    Key.TIMEOUT_ENDPOINT_MAX_WAIT,
                    Key.TIMEOUT_FIND_ELEMENT_WAIT,
                    Key.TIMEOUT_LONG_POLLING,
                    Key.TIMEOUT_LONG_WAIT,
                    Key.TIMEOUT_PAGE_LOAD,
                    Key.TIMEOUT_SCRIPT);

            timeoutConfigKeys.forEach(key -> {
                String value = Objects.requireNonNull(properties.getProperty(key),
                        "Value for key [" + key + "] was not found.");
                Duration duration = Duration.ofSeconds(Long.parseLong(value));
                switch (key) {
                    case Key.TIMEOUT_DEFAULT                -> DEFAULT_TIMEOUT = duration;
                    case Key.TIMEOUT_POLLING_DEFAULT        -> DEFAULT_POLLING = duration;
                    case Key.TIMEOUT_ENDPOINT_MEDIUM_WAIT   -> ENDPOINT_MEDIUM_WAIT = duration;
                    case Key.TIMEOUT_ENDPOINT_HIGH_WAIT     -> ENDPOINT_HIGH_WAIT = duration;
                    case Key.TIMEOUT_ENDPOINT_MAX_WAIT      -> ENDPOINT_MAX_WAIT = duration;
                    case Key.TIMEOUT_FIND_ELEMENT_WAIT      -> FIND_ELEMENT_WAIT_TIMEOUT = duration;
                    case Key.TIMEOUT_LONG_POLLING           -> LONG_POLLING = duration;
                    case Key.TIMEOUT_LONG_WAIT              -> LONG_WAIT_TIMEOUT = duration;
                    case Key.TIMEOUT_PAGE_LOAD              -> PAGE_LOAD_TIMEOUT = duration;
                    case Key.TIMEOUT_SCRIPT                 -> SCRIPT_TIMEOUT = duration;
                    default                                 -> {
                        final String errorMessage = "Key [" + key + "] was not expected.";
                        IllegalArgumentException exception = new IllegalArgumentException(errorMessage);
                        LoggingHelper.error(errorMessage, exception);
                        throw exception;
                    }
                }
            });
        }
    }

    private final Decryptor decryptor;
    private final Properties properties;
    private SsmClientWrapper ssmClientWrapper;
    private final Timeout timeout;

    public Configuration(String environment, String aws) {

        Objects.requireNonNull(environment);
        Objects.requireNonNull(aws);

        properties = loadProperties(environment);
        timeout = new Timeout(properties);
        decryptor = new Decryptor(getEnvironmentVariableRawValue("ENCRYPTION_KEY", false));
        setAWSConfiguration(aws);
        setRateLimitCookieProperty();
        setHeadlessModeValue();
    }

    public void addProperty(String key, String value) {
        if (key == null || value == null || key.isEmpty() || value.isEmpty()) {
            IllegalArgumentException illegalArgumentException = new IllegalArgumentException("Key or value is empty.");
            LoggingHelper.error("Error adding property.", illegalArgumentException);
            throw illegalArgumentException;
        } else {
            properties.setProperty(key, value);
        }
    }

    public Properties getConfiguration() {
        return properties;
    }

    public String getData(String key) {
        return getData(key, false);
    }

    public String getEncryptedData(String key) {
        return getData(key, true);
    }

    // Use this instead of getEncryptedData to improve speed when you already know that the value you're looking for is
    // loaded in the Properties object.
    public String getEncryptedProperty(String key) {
        return getDecryptedValue(properties.getProperty(key), true);
    }

    // Use this instead of getData to improve speed when you already know that the value you're looking for is
    // loaded in the Properties object.
    public String getProperty(String key) {
        return properties.getProperty(key);
    }

    public String getSsmParameter(String key, Boolean encrypted) {
        assertSsmClientIsDefined();
        return ssmClientWrapper.getParameter(key, encrypted, true);
    }

    public Timeout getTimeout() {
        return timeout;
    }

    // use this to retrieve properties values that only accept "enabled" and "disabled" values (like an on/off
    // switch), converting them to boolean values, and ensuring that they are properly set.
    public boolean isSwitchConfigValueOn(String parameterName) {
        return isSwitchConfigValueOn(getData(parameterName), parameterName);
    }

    public void setAWSConfiguration(String aws) {

        String awsParameterStoreConfiguration = getEnvironmentVariableValue("AWS_PARAMETER_STORE", false);
        if (awsParameterStoreConfiguration == null) {
            awsParameterStoreConfiguration = Status.ENABLED;
        }

        boolean awsConfigIsEnabled = isSwitchConfigValueOn(aws, "aws");
        boolean awsParameterStorConfigurationIsEnabled = isSwitchConfigValueOn(awsParameterStoreConfiguration, "awsParameterStoreConfiguration");

        if (awsConfigIsEnabled && awsParameterStorConfigurationIsEnabled) {
            this.addProperty("awsParameterStore", Status.ENABLED);
            this.ssmClientWrapper = getSsmClient();
            assertAWSTokenHasNotExpired();
        } else {
            this.addProperty("awsParameterStore", Status.DISABLED);
        }
    }

    public void setRateLimitCookieProperty() {
        try {
            String cookieRateLimit = "cookieratelimit=" + getData("cookieRateLimitSsm");
            this.addProperty("cookieRateLimit", cookieRateLimit);
        } catch (IllegalArgumentException ignored) {
            LoggingHelper.info("Cookie Rate Limit was not found in the configuration file and will not be set.");
        }
    }

    public void setSsmParameter(String key, String value, Boolean secure) {
        assertSsmClientIsDefined();
        ssmClientWrapper.putParameter(key, value, secure);
    }



    private void assertAWSTokenHasNotExpired() {
        try {
            ssmClientWrapper.getParameter("justToTestIfTokenHasExpired", false, true);
        } catch(ExpiredTokenException e) {
            LoggingHelper.error("The AWS token has expired. Login (or re-login) in AWS and try again.", e);
            throw e;
        } catch(ParameterNotFoundException ignored) {}
    }

    private void assertSsmClientIsDefined() {
        if(ssmClientWrapper == null) {
            final String errorMessage = "The SSM Client wrapper was not configured and therefore it does not exist, so no SSM operations are possible.";
            IllegalStateException exception = new IllegalStateException(errorMessage);
            LoggingHelper.error(errorMessage, exception);
            throw exception;
        }
    }

    private String getData(String key, boolean isEncrypted) {

        String valueFromEnvFile = getEnvironmentVariableValue(key, isEncrypted);
        if (valueFromEnvFile != null) {
            return valueFromEnvFile;
        } else {
            return getDataFromConfigurationFile(key, isEncrypted);
        }
    }

    private String getDataFromConfigurationFile(String key, boolean isEncrypted) {

        Object value = properties.get(key);
        if (value == null) {
            IllegalArgumentException illegalArgumentException =
                    new IllegalArgumentException("Property [" + key + "] is not defined on the properties file.");
            LoggingHelper.error("Error getting key." + key, illegalArgumentException);
            throw illegalArgumentException;

        } else {
            String valueStr = value.toString();
            String[] valueSpliced = valueStr.split(":");
            String outputValue;
            if (valueSpliced[0].equals("ssm")) {
                outputValue = getSsmParameter(valueSpliced[1], isEncrypted);
                if(outputValue == null || outputValue.isEmpty()) {
                    final String errorMessage = "SSM value for key [" + key + "] was empty.";
                    RuntimeException exception = new RuntimeException(errorMessage);
                    LoggingHelper.error(errorMessage, exception);
                    throw exception;
                }
            } else {
                outputValue = getDecryptedValue(valueStr, isEncrypted);
                if(outputValue == null || outputValue.isEmpty()) {
                    final String errorMessage = "Value for key [" + key + "] was empty.";
                    RuntimeException exception = new RuntimeException(errorMessage);
                    LoggingHelper.error(errorMessage, exception);
                    throw exception;
                }
            }
            return outputValue;
        }
    }

    private String getDecryptedValue(String value, boolean isEncrypted) {
        if (isEncrypted) {
            return decryptor.decrypt(value);
        } else {
            return value;
        }
    }

    private String getEnv(String key) {
        return System.getenv(key.toUpperCase());
    }

    private String getEnvironmentVariableRawValue(String key, boolean canBeNull) {

        String value = getEnv(key);
        if (!canBeNull && value == null) {
            final String errorMessage = "Environment Variable [" + key + "] is not defined.";
            IllegalArgumentException exception = new IllegalArgumentException(errorMessage);
            LoggingHelper.error("Error getting environment variable.", exception);
            throw exception;
        } else {
            return value;
        }
    }

    private String getEnvironmentVariableValue(String key, boolean isEncrypted) {

        String value = getEnvironmentVariableRawValue(key, true);
        if (value == null) {
            LoggingHelper.debug("No environment variable found for value [" + key + "]. Going to search for it on the configuration file.");
            return null;
        } else {
            return getDecryptedValue(value, isEncrypted);
        }
    }

    private SsmClientWrapper getSsmClient() {
        return new SsmClientWrapper(getEnvironmentVariableRawValue("AWS_PROFILE", false));
    }

    private boolean isSwitchConfigValueOn(String value, String valueName) {

        if(value == null) {
            throw new IllegalArgumentException("No value was found for parameter [" + valueName + "].");

        } else if(!value.equals(Status.ENABLED) && !value.equals(Status.DISABLED)) {
            throw new IllegalArgumentException(
                    "Invalid value [" + value + "] for parameter [" + valueName + "]. It should be ["
                            + Status.ENABLED + "] or [" + Status.DISABLED + "] (case-sensitive).");

        } else {
            return value.equals(Status.ENABLED);
        }
    }

    private Properties loadProperties(String environment) {

        InputStream input;
        try {
            input = Files.newInputStream(Paths.get("src/test/resources/" + environment + ".properties"));
            Properties properties = new Properties();
            properties.load(input);
            return properties;

        } catch (IOException e) {
            final String errorMessage = "Failed to load properties file for environment ["
                    + environment + "]. Check if the target environment and corresponding file exist.";
            LoggingHelper.error(errorMessage, e);
            throw new IllegalArgumentException(errorMessage, e);
        }
    }

    private void setHeadlessModeValue() {
        String headlessMode = getEnvironmentVariableValue("HEADLESS_MODE", false);
        String status = (headlessMode != null && headlessMode.equals(Status.ENABLED)) ? Status.ENABLED : Status.DISABLED;
        properties.setProperty("headlessMode", status);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy