From d2e10e8a9a9d29c33e22e92c602fd41201e4cf9f Mon Sep 17 00:00:00 2001 From: Samuel Attwood Date: Thu, 25 Jan 2024 18:27:16 -0500 Subject: [PATCH] Update regex to handle quotes and variables --- pkg/natsreloader/natsreloader.go | 26 ++++- .../natsreloader_test.go | 106 ++++++++++++++++-- 2 files changed, 121 insertions(+), 11 deletions(-) rename pkg/natsreloader/{natsreloadertest => }/natsreloader_test.go (75%) diff --git a/pkg/natsreloader/natsreloader.go b/pkg/natsreloader/natsreloader.go index a09ef58c..31a6ee3d 100644 --- a/pkg/natsreloader/natsreloader.go +++ b/pkg/natsreloader/natsreloader.go @@ -426,7 +426,7 @@ func getIncludePaths(configFile string, checked map[string]interface{}) ([]strin checked[configFile] = nil parentDirectory := filepath.Dir(configFile) - includeRegex := regexp.MustCompile(`(?m)^\s*include\s+['"]?([^'"\n]*)`) + includeRegex := regexp.MustCompile(`(?m)^\s*include\s+(['"]?[^'";\n]*)`) content, err := os.ReadFile(configFile) if err != nil { @@ -435,8 +435,18 @@ func getIncludePaths(configFile string, checked map[string]interface{}) ([]strin includeMatches := includeRegex.FindAllStringSubmatch(string(content), -1) for _, match := range includeMatches { + matchStr := match[1] + if strings.HasPrefix(matchStr, "$") { + continue + } + + matchStr = strings.TrimPrefix(matchStr, "'") + matchStr = strings.TrimPrefix(matchStr, "\"") + + fmt.Println(matchStr) + // Include filepaths in NATS config are always relative - fullyQualifiedPath := filepath.Join(parentDirectory, match[1]) + fullyQualifiedPath := filepath.Join(parentDirectory, matchStr) fullyQualifiedPath = filepath.Clean(fullyQualifiedPath) if _, err := os.Stat(fullyQualifiedPath); os.IsNotExist(err) { @@ -458,7 +468,7 @@ func getIncludePaths(configFile string, checked map[string]interface{}) ([]strin func getCertPaths(configPaths []string) ([]string, error) { certPaths := []string{} - certRegex := regexp.MustCompile(`(?m)^\s*(cert_file|key_file|ca_file)\s*:\s*"?([^"\n]*)"?`) + certRegex := regexp.MustCompile(`(?m)^\s*(cert_file|key_file|ca_file)\s*:\s*(['"]?[^'";\n]*)"?`) for _, configPath := range configPaths { content, err := os.ReadFile(configPath) @@ -468,7 +478,15 @@ func getCertPaths(configPaths []string) ([]string, error) { certMatches := certRegex.FindAllStringSubmatch(string(content), -1) for _, match := range certMatches { - fullyQualifiedPath, err := filepath.Abs(match[2]) + matchStr := match[2] + if strings.HasPrefix(matchStr, "$") { + continue + } + + matchStr = strings.TrimPrefix(matchStr, "'") + matchStr = strings.TrimPrefix(matchStr, "\"") + + fullyQualifiedPath, err := filepath.Abs(matchStr) if err != nil { return nil, err } diff --git a/pkg/natsreloader/natsreloadertest/natsreloader_test.go b/pkg/natsreloader/natsreloader_test.go similarity index 75% rename from pkg/natsreloader/natsreloadertest/natsreloader_test.go rename to pkg/natsreloader/natsreloader_test.go index a61936e3..e8008f15 100644 --- a/pkg/natsreloader/natsreloadertest/natsreloader_test.go +++ b/pkg/natsreloader/natsreloader_test.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package natsreloadertest +package natsreloader import ( "context" @@ -27,8 +27,6 @@ import ( "syscall" "testing" "time" - - "github.com/nats-io/nack/pkg/natsreloader" ) const ( @@ -62,6 +60,31 @@ tls: { cert_file: "./test.pem" key_file: "./testkey.pem" } +` + includeTest_0 = ` +include nats_0.conf +include nats_1.conf; // semicolon terminated +include "nats_2.conf" // quoted +include "nats_3.conf"; // quoted and semicolon terminated +include 'nats_4.conf' // are single quotes valid in nats conf? if so also need this +include 'nats_5.conf'; // are single quotes valid in nats conf? if so also need this +include $NATS; // ignore, this is a variable. let's not worry about variable interpolation +include "$NATS_6.conf" // don't ignore, this is a string not a variable +include includeTest_1.conf +` + includeTest_1 = ` +tls: { + cert_file: ./nats_0.pem + key_file: 'nats_0.key' +} +tls: { + cert_file: "./nats_1.pem" + key_file: $test +} +tls: { + cert_file: "$nats_2.pem"; + key_file: 'nats_1.key'; +} ` ) @@ -85,7 +108,7 @@ func TestReloader(t *testing.T) { defer os.Remove(pidfile.Name()) // Create tempfile with contents, then update it - nconfig := &natsreloader.Config{ + nconfig := &Config{ PidFile: pidfile.Name(), WatchedFiles: []string{}, Signal: syscall.SIGHUP, @@ -106,7 +129,7 @@ func TestReloader(t *testing.T) { nconfig.WatchedFiles = append(nconfig.WatchedFiles, configFile.Name()) } - r, err := natsreloader.NewReloader(nconfig) + r, err := NewReloader(nconfig) if err != nil { t.Fatal(err) } @@ -173,6 +196,75 @@ func TestReloader(t *testing.T) { } } +func TestInclude(t *testing.T) { + directory, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + + dummyFiles := []string{ + "nats_0.conf", + "nats_1.conf", + "nats_2.conf", + "nats_3.conf", + "nats_4.conf", + "nats_5.conf", + "$NATS_6.conf", + "nats_0.pem", + "nats_1.pem", + "$nats_2.pem", + "nats_0.key", + "nats_1.key", + } + + for _, f := range dummyFiles { + p := filepath.Join(directory, f) + err = writeFile("", p) + defer os.Remove(p) + if err != nil { + t.Fatal(err) + } + } + + includeTestConf_0 := filepath.Join(directory, "includeTest_0.conf") + err = writeFile(includeTest_0, includeTestConf_0) + defer os.Remove(includeTestConf_0) + if err != nil { + t.Fatal(err) + } + + includeTestConf_1 := filepath.Join(directory, "includeTest_1.conf") + err = writeFile(includeTest_1, includeTestConf_1) + defer os.Remove(includeTestConf_1) + if err != nil { + t.Fatal(err) + } + + includes, err := getServerFiles("includeTest_0.conf") + if err != nil { + t.Fatal(err) + } + + includePaths := make([]string, 0) + for _, p := range includes { + includePaths = append(includePaths, filepath.Base(p)) + } + + dummyFiles = append(dummyFiles, "includeTest_0.conf") + dummyFiles = append(dummyFiles, "includeTest_1.conf") + + sort.Strings(dummyFiles) + sort.Strings(includePaths) + + for i, p := range dummyFiles { + if p != includePaths[i] { + fmt.Println(p, includePaths[i]) + t.Fatal("Expected include paths do not match") + } + } + +} + func TestFileFinder(t *testing.T) { directory, err := os.Getwd() if err != nil { @@ -218,13 +310,13 @@ func TestFileFinder(t *testing.T) { } defer os.Remove(pidFile) - nconfig := &natsreloader.Config{ + nconfig := &Config{ PidFile: pidFile, WatchedFiles: []string{filepath.Join(directory, "testConfig_0.conf")}, Signal: syscall.SIGHUP, } - r, err := natsreloader.NewReloader(nconfig) + r, err := NewReloader(nconfig) if err != nil { t.Fatal(err) }