From d9d7c904a7fdafce7b1c0f80e44e782761429e97 Mon Sep 17 00:00:00 2001 From: Johannes Drummer Date: Sat, 24 Aug 2024 17:38:07 +0200 Subject: [PATCH 1/3] fix: broken embedio on windows --- internal/io/embedio.go | 15 +++++++++++++++ internal/operators/from_file.go | 14 ++++++++------ internal/seclang/parser.go | 2 +- 3 files changed, 24 insertions(+), 7 deletions(-) create mode 100644 internal/io/embedio.go diff --git a/internal/io/embedio.go b/internal/io/embedio.go new file mode 100644 index 000000000..2886422ca --- /dev/null +++ b/internal/io/embedio.go @@ -0,0 +1,15 @@ +package io + +import ( + "io/fs" + "path/filepath" + "strings" +) + +// FSReadFile wraps fs.ReadFile supporting embedio on windows +func FSReadFile(fsys fs.FS, name string) ([]byte, error) { + if filepath.Separator != '/' { + name = strings.ReplaceAll(name, string(filepath.Separator), "/") + } + return fs.ReadFile(fsys, name) +} diff --git a/internal/operators/from_file.go b/internal/operators/from_file.go index 4d011c1af..f60736891 100644 --- a/internal/operators/from_file.go +++ b/internal/operators/from_file.go @@ -7,14 +7,16 @@ import ( "errors" "io/fs" "os" - "path" + "path/filepath" + + "github.com/corazawaf/coraza/v3/internal/io" ) var errEmptyDirs = errors.New("empty dirs") -func loadFromFile(filepath string, dirs []string, root fs.FS) ([]byte, error) { - if path.IsAbs(filepath) { - return fs.ReadFile(root, filepath) +func loadFromFile(filename string, dirs []string, root fs.FS) ([]byte, error) { + if filepath.IsAbs(filename) { + return io.FSReadFile(root, filename) } if len(dirs) == 0 { @@ -30,8 +32,8 @@ func loadFromFile(filepath string, dirs []string, root fs.FS) ([]byte, error) { ) for _, p := range dirs { - absFilepath := path.Join(p, filepath) - content, err = fs.ReadFile(root, absFilepath) + absFilepath := filepath.Join(p, filename) + content, err = io.FSReadFile(root, absFilepath) if err != nil { if os.IsNotExist(err) { continue diff --git a/internal/seclang/parser.go b/internal/seclang/parser.go index 2532d9eaf..d578e9edd 100644 --- a/internal/seclang/parser.go +++ b/internal/seclang/parser.go @@ -56,7 +56,7 @@ func (p *Parser) FromFile(profilePath string) error { p.currentFile = profilePath lastDir := p.currentDir p.currentDir = filepath.Dir(profilePath) - file, err := fs.ReadFile(p.root, profilePath) + file, err := io.FSReadFile(p.root, profilePath) if err != nil { // we don't use defer for this as tinygo does not seem to like it p.currentDir = originalDir From fba8d7752e51b042b04c0b20b0197d2d7d33d75f Mon Sep 17 00:00:00 2001 From: Johannes Drummer Date: Wed, 28 Aug 2024 10:56:28 +0200 Subject: [PATCH 2/3] fix: add tests and license to FSReadFile --- internal/io/{embedio.go => ioutil.go} | 3 + internal/io/ioutil_test.go | 72 ++++++++++++++++++++++++ internal/io/testdata/subdir/testfile.txt | 1 + 3 files changed, 76 insertions(+) rename internal/io/{embedio.go => ioutil.go} (74%) create mode 100644 internal/io/ioutil_test.go create mode 100644 internal/io/testdata/subdir/testfile.txt diff --git a/internal/io/embedio.go b/internal/io/ioutil.go similarity index 74% rename from internal/io/embedio.go rename to internal/io/ioutil.go index 2886422ca..7c3d0a33d 100644 --- a/internal/io/embedio.go +++ b/internal/io/ioutil.go @@ -1,3 +1,6 @@ +// Copyright 2022 Juan Pablo Tosso and the OWASP Coraza contributors +// SPDX-License-Identifier: Apache-2.0 + package io import ( diff --git a/internal/io/ioutil_test.go b/internal/io/ioutil_test.go new file mode 100644 index 000000000..e68b3084d --- /dev/null +++ b/internal/io/ioutil_test.go @@ -0,0 +1,72 @@ +// Copyright 2022 Juan Pablo Tosso and the OWASP Coraza contributors +// SPDX-License-Identifier: Apache-2.0 + +package io + +import ( + "embed" + "io/fs" + "os" + "path/filepath" + "runtime" + "testing" +) + +//go:embed testdata +var testdata embed.FS + +func TestFSReadFile(t *testing.T) { + testdir, err := os.MkdirTemp(t.TempDir(), "testdata") + if err != nil { + t.Fatal(err) + } + err = os.Mkdir(filepath.Join(testdir, "subdir"), os.ModePerm) + if err != nil { + t.Fatal(err) + } + err = os.WriteFile(filepath.Join(testdir, "subdir", "testfile.txt"), []byte("Hello World\n"), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + realFS, err := fs.Sub(os.DirFS(testdir), ".") + if err != nil { + t.Fatal(err) + } + + tests := []struct { + name string + path string + fail bool + fs fs.FS + }{ + {name: "embed/unix path", path: "testdata/subdir/testfile.txt", fail: false, fs: testdata}, + {name: "embed/windows path", path: "testdata\\subdir\\testfile.txt", fail: runtime.GOOS != "windows", fs: testdata}, + {name: "embed/invalid", path: "testdata/subdir/notexist", fail: true, fs: testdata}, + {name: "real/unix path", path: "testdata/subdir/testfile.txt", fail: false, fs: realFS}, + {name: "real/windows path", path: "testdata\\subdir\\testfile.txt", fail: runtime.GOOS != "windows", fs: realFS}, + {name: "real/invalid", path: "testdata/subdir/notexist", fail: true, fs: realFS}, + } + + for _, next := range tests { + test := next + t.Run(test.name, func(t *testing.T) { + data, err := FSReadFile(testdata, test.path) + if test.fail { + if err == nil { + t.Fatal("expected an error but it is nil") + } + if data != nil { + t.Fatal("expected data to be nil") + } + } else { + if err != nil { + t.Fatal(err) + } + if string(data) != "Hello World\n" { + t.Fatal("unexpected output: \"", string(data), "\"") + } + } + }) + } +} diff --git a/internal/io/testdata/subdir/testfile.txt b/internal/io/testdata/subdir/testfile.txt new file mode 100644 index 000000000..557db03de --- /dev/null +++ b/internal/io/testdata/subdir/testfile.txt @@ -0,0 +1 @@ +Hello World From 8d627d170c1834d2fb31a2e9fc4e5bad591338cc Mon Sep 17 00:00:00 2001 From: Johannes Drummer Date: Wed, 28 Aug 2024 19:53:26 +0200 Subject: [PATCH 3/3] split FSReadFile into platform tags --- internal/io/ioutil.go | 11 +++-------- internal/io/ioutil_windows.go | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 internal/io/ioutil_windows.go diff --git a/internal/io/ioutil.go b/internal/io/ioutil.go index 7c3d0a33d..4a83ccd62 100644 --- a/internal/io/ioutil.go +++ b/internal/io/ioutil.go @@ -1,18 +1,13 @@ // Copyright 2022 Juan Pablo Tosso and the OWASP Coraza contributors // SPDX-License-Identifier: Apache-2.0 +//go:build !windows + package io import ( "io/fs" - "path/filepath" - "strings" ) // FSReadFile wraps fs.ReadFile supporting embedio on windows -func FSReadFile(fsys fs.FS, name string) ([]byte, error) { - if filepath.Separator != '/' { - name = strings.ReplaceAll(name, string(filepath.Separator), "/") - } - return fs.ReadFile(fsys, name) -} +var FSReadFile = fs.ReadFile diff --git a/internal/io/ioutil_windows.go b/internal/io/ioutil_windows.go new file mode 100644 index 000000000..720cccf42 --- /dev/null +++ b/internal/io/ioutil_windows.go @@ -0,0 +1,15 @@ +// Copyright 2022 Juan Pablo Tosso and the OWASP Coraza contributors +// SPDX-License-Identifier: Apache-2.0 + +package io + +import ( + "io/fs" + "path/filepath" + "strings" +) + +// FSReadFile wraps fs.ReadFile supporting embedio on windows +func FSReadFile(fsys fs.FS, name string) ([]byte, error) { + return fs.ReadFile(fsys, strings.ReplaceAll(name, string(filepath.Separator), "/")) +}