From f9bf07d64302f43e333f0eba11d75dcad9e8a8b6 Mon Sep 17 00:00:00 2001 From: JeremyEastham <34139712+JeremyEastham@users.noreply.github.com> Date: Fri, 8 Apr 2022 00:05:51 -0500 Subject: [PATCH 1/3] Add support for environment variables in config.yaml --- .../java/io/supertokens/config/Config.java | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/supertokens/config/Config.java b/src/main/java/io/supertokens/config/Config.java index 33fa93aef..60b42a92c 100644 --- a/src/main/java/io/supertokens/config/Config.java +++ b/src/main/java/io/supertokens/config/Config.java @@ -24,7 +24,12 @@ import io.supertokens.output.Logging; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.nio.file.Files; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class Config extends ResourceDistributor.SingletonResource { @@ -32,6 +37,10 @@ public class Config extends ResourceDistributor.SingletonResource { private final Main main; private final CoreConfig core; + private static final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); + private static final Pattern envPattern = Pattern.compile("(?:^|[^\\\\])\\$\\{([^}]*)}"); // (?:^|[^\\])\$\{([^}]*)} + private static final Pattern escEnvPattern = Pattern.compile("\\\\\\$\\{([^}]*)}"); // \\\$\{([^}]*)} + private Config(Main main, String configFilePath) { this.main = main; try { @@ -59,10 +68,34 @@ public static CoreConfig getConfig(Main main) { return getInstance(main).core; } + private String preprocessConfig(String configFilePath) throws IOException + { + List content = Files.readAllLines(new File(configFilePath).toPath()); + StringBuilder processed = new StringBuilder(); + for(int i = 0; i < content.size(); i++ ) { + String line = content.get(i); + Matcher matcher = envPattern.matcher(line); + final int lineNum = i + 1; // Make final for use in lambda + String processedLine = matcher.replaceAll(match -> { + String envVarName = match.group(1).trim(); + String envVar = System.getenv(envVarName); + if(envVar == null) + throw new QuitProgramException("Environment variable \"" + envVarName + "\" does not exist." + + " (Line " + lineNum + " of \"" + configFilePath + "\")" + + "\nUse \"\\${" + envVarName + "}\" if you are not inserting an environment variable here."); + return envVar; + }); + matcher = escEnvPattern.matcher(processedLine); + processedLine = matcher.replaceAll(match -> match.group().substring(1)); + processed.append(processedLine); + } + return processed.toString(); + } + private CoreConfig loadCoreConfig(String configFilePath) throws IOException { Logging.info(main, "Loading supertokens config."); - final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); - CoreConfig config = mapper.readValue(new File(configFilePath), CoreConfig.class); + String configFileContent = preprocessConfig(configFilePath); + CoreConfig config = mapper.readValue(configFileContent, CoreConfig.class); config.validateAndInitialise(main); return config; } From 00d1e1f99ce4c99833010c25fc10557acf4b5c7b Mon Sep 17 00:00:00 2001 From: JeremyEastham <34139712+JeremyEastham@users.noreply.github.com> Date: Mon, 11 Apr 2022 02:37:06 -0500 Subject: [PATCH 2/3] Create ConfigPreprocessor.java --- .../config/ConfigPreprocessor.java | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 src/main/java/io/supertokens/config/ConfigPreprocessor.java diff --git a/src/main/java/io/supertokens/config/ConfigPreprocessor.java b/src/main/java/io/supertokens/config/ConfigPreprocessor.java new file mode 100644 index 000000000..e913518fc --- /dev/null +++ b/src/main/java/io/supertokens/config/ConfigPreprocessor.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2022, VRAI Labs and/or its affiliates. All rights reserved. + * + * This software is licensed under the Apache License, Version 2.0 (the + * "License") as published by the Apache Software Foundation. + * + * You may not use this file except in compliance with the License. You may + * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +package io.supertokens.config; + +import io.supertokens.exceptions.QuitProgramException; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.regex.Pattern; + +public class ConfigPreprocessor { + private static final Pattern commentPattern = Pattern.compile("(?:^|[^\\\\])#(.*)"); // (?:^|[^\\])#(.*) + private static final Pattern envPattern = Pattern.compile("(?:^|[^\\\\])\\$\\{([^}]*)}"); // (?:^|[^\\])\$\{([^}]*)} + private static final Pattern escEnvPattern = Pattern.compile("\\\\\\$\\{([^}]*)}"); // \\\$\{([^}]*)} + + private final String config; + private String processedConfig; + + public ConfigPreprocessor(String config) { + this.config = config; + this.processedConfig = null; + } + + private String removeComments(String str) { + return commentPattern.matcher(str).replaceAll(match -> match.group().substring(0, match.start(1))); + } + + private String substituteEnvironmentVariables(String str) { + return envPattern.matcher(str).replaceAll(match -> { + String envVarName = match.group(1).trim(); + String envVar = System.getenv(envVarName); + if (envVar == null) + throw new QuitProgramException("Environment variable \"" + envVarName + "\" does not exist." + + "\nUse \"\\${" + envVarName + "}\" if you are not inserting an environment variable here."); + return envVar; + }); + } + + private String unescapeEscapedEnvironmentVariables(String str) { + return escEnvPattern.matcher(str).replaceAll(match -> match.group().substring(1)); + } + + public String getProcessedConfig() { + if (processedConfig == null) { + processedConfig = removeComments(config); + processedConfig = substituteEnvironmentVariables(processedConfig); + processedConfig = unescapeEscapedEnvironmentVariables(processedConfig); + } + return processedConfig; + } + + public static ConfigPreprocessor loadFromFile(String configFilePath) throws IOException { + return new ConfigPreprocessor(Files.readString(new File(configFilePath).toPath())); + } +} From 364d1131ae0e3712060157afb0a0e1fbc3551496 Mon Sep 17 00:00:00 2001 From: JeremyEastham <34139712+JeremyEastham@users.noreply.github.com> Date: Mon, 11 Apr 2022 16:50:07 -0500 Subject: [PATCH 3/3] Update Config.java to use ConfigPreprocessor.java --- .../java/io/supertokens/config/Config.java | 34 +------------------ 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/src/main/java/io/supertokens/config/Config.java b/src/main/java/io/supertokens/config/Config.java index 60b42a92c..ea6260954 100644 --- a/src/main/java/io/supertokens/config/Config.java +++ b/src/main/java/io/supertokens/config/Config.java @@ -23,13 +23,7 @@ import io.supertokens.exceptions.QuitProgramException; import io.supertokens.output.Logging; -import java.io.File; -import java.io.FileInputStream; import java.io.IOException; -import java.nio.file.Files; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; public class Config extends ResourceDistributor.SingletonResource { @@ -38,8 +32,6 @@ public class Config extends ResourceDistributor.SingletonResource { private final CoreConfig core; private static final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); - private static final Pattern envPattern = Pattern.compile("(?:^|[^\\\\])\\$\\{([^}]*)}"); // (?:^|[^\\])\$\{([^}]*)} - private static final Pattern escEnvPattern = Pattern.compile("\\\\\\$\\{([^}]*)}"); // \\\$\{([^}]*)} private Config(Main main, String configFilePath) { this.main = main; @@ -68,33 +60,9 @@ public static CoreConfig getConfig(Main main) { return getInstance(main).core; } - private String preprocessConfig(String configFilePath) throws IOException - { - List content = Files.readAllLines(new File(configFilePath).toPath()); - StringBuilder processed = new StringBuilder(); - for(int i = 0; i < content.size(); i++ ) { - String line = content.get(i); - Matcher matcher = envPattern.matcher(line); - final int lineNum = i + 1; // Make final for use in lambda - String processedLine = matcher.replaceAll(match -> { - String envVarName = match.group(1).trim(); - String envVar = System.getenv(envVarName); - if(envVar == null) - throw new QuitProgramException("Environment variable \"" + envVarName + "\" does not exist." + - " (Line " + lineNum + " of \"" + configFilePath + "\")" + - "\nUse \"\\${" + envVarName + "}\" if you are not inserting an environment variable here."); - return envVar; - }); - matcher = escEnvPattern.matcher(processedLine); - processedLine = matcher.replaceAll(match -> match.group().substring(1)); - processed.append(processedLine); - } - return processed.toString(); - } - private CoreConfig loadCoreConfig(String configFilePath) throws IOException { Logging.info(main, "Loading supertokens config."); - String configFileContent = preprocessConfig(configFilePath); + String configFileContent = ConfigPreprocessor.loadFromFile(configFilePath).getProcessedConfig(); CoreConfig config = mapper.readValue(configFileContent, CoreConfig.class); config.validateAndInitialise(main); return config;