From 18abd3718215ea18d6bd6c189d018a8db5fbf583 Mon Sep 17 00:00:00 2001 From: zongz Date: Fri, 15 Mar 2024 14:46:00 +0800 Subject: [PATCH 1/5] feat: Added some methods for sanitizing path on different platforms Signed-off-by: zongz --- pkg/client/client.go | 2 +- pkg/opt/opt.go | 6 +++++ pkg/path/path_test.go | 46 ++++++++++++++++++++++++++++++++++++++ pkg/path/path_unix.go | 44 ++++++++++++++++++++++++++++++++++++ pkg/path/path_windows.go | 48 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 pkg/path/path_test.go create mode 100644 pkg/path/path_unix.go create mode 100644 pkg/path/path_windows.go diff --git a/pkg/client/client.go b/pkg/client/client.go index fe782ab5..0a185a08 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -1037,7 +1037,7 @@ func (c *KpmClient) PullFromOci(localPath, source, tag string) error { } // Untar the tar file. - storagePath := ociOpts.AddStoragePathSuffix(localPath) + storagePath := ociOpts.SanitizePathWithSuffix(localPath) err = utils.UnTarDir(matches[0], storagePath) if err != nil { return reporter.NewErrorEvent( diff --git a/pkg/opt/opt.go b/pkg/opt/opt.go index acf744ca..b8ca9d1c 100644 --- a/pkg/opt/opt.go +++ b/pkg/opt/opt.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/go-version" "kcl-lang.io/kcl-go/pkg/kcl" "kcl-lang.io/kpm/pkg/errors" + "kcl-lang.io/kpm/pkg/path" "kcl-lang.io/kpm/pkg/reporter" "oras.land/oras-go/v2" ) @@ -278,6 +279,11 @@ func (oci *OciOptions) AddStoragePathSuffix(pathPrefix string) string { return filepath.Join(filepath.Join(filepath.Join(pathPrefix, oci.Reg), oci.Repo), oci.Tag) } +// SanitizePathSuffix will take 'Registry/Repo/Tag' as a path suffix and sanitize it. +func (oci *OciOptions) SanitizePathWithSuffix(pathPrefix string) string { + return path.SanitizePath(filepath.Join(filepath.Join(filepath.Join(pathPrefix, oci.Reg), oci.Repo), oci.Tag)) +} + type OciManifestOptions struct { Annotations map[string]string } diff --git a/pkg/path/path_test.go b/pkg/path/path_test.go new file mode 100644 index 00000000..7249184a --- /dev/null +++ b/pkg/path/path_test.go @@ -0,0 +1,46 @@ +package path + +import ( + "runtime" + "testing" +) + +func TestSanitizePath(t *testing.T) { + tests := []struct { + name string + input string + expected string + }{ + { + name: "Path with null character", + input: "test\x00file", + expected: "test_file", + }, + { + name: "Path without invalid characters", + input: "/usr/local/bin/test", + expected: "/usr/local/bin/test", + }, + } + + if runtime.GOOS == "windows" { + tests = append(tests, struct { + name string + input string + expected string + }{ + name: "Windows style path", + input: "C:\\Program Files\\Test<:>*|", + expected: "C:\\Program Files\\Test______", + }) + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + output := SanitizePath(tt.input) + if output != tt.expected { + t.Errorf("expected %s, got %s", tt.expected, output) + } + }) + } +} diff --git a/pkg/path/path_unix.go b/pkg/path/path_unix.go new file mode 100644 index 00000000..0fbfd127 --- /dev/null +++ b/pkg/path/path_unix.go @@ -0,0 +1,44 @@ +//go:build !windows +// +build !windows + +package path + +import ( + "path/filepath" + "strings" +) + +var NeedToSanitize map[rune]bool + +func init() { + NeedToSanitize = map[rune]bool{ + '\x00': true, + } +} + +// sanitizePath cleans a path string by removing or replacing invalid Windows file name characters. +func sanitizePath(path string, sanitize sanitizer, toSanitize map[rune]bool) string { + // replace all slashes with backslashes + path = filepath.FromSlash(path) + + // replace all invalid characters + return strings.Map(func(r rune) rune { + if _, isInvalid := toSanitize[r]; isInvalid { + return sanitize(r, toSanitize) + } + return r + }, path) +} + +// sanitizer defined how to handle and replace invalid file name characters. +type sanitizer func(rune, map[rune]bool) rune + +// SanitizePath replaces invalid characters in a Windows path with a placeholder. +func SanitizePath(path string) string { + return sanitizePath(path, func(r rune, invalidChars map[rune]bool) rune { + if _, ok := invalidChars[r]; ok { + return '_' + } + return r + }, NeedToSanitize) +} diff --git a/pkg/path/path_windows.go b/pkg/path/path_windows.go new file mode 100644 index 00000000..3a2f79d3 --- /dev/null +++ b/pkg/path/path_windows.go @@ -0,0 +1,48 @@ +//go:build windows +// +build windows + +package path + +import ( + "path/filepath" + "strings" +) + +var NeedToSanitize map[rune]bool + +func init() { + NeedToSanitize = map[rune]bool{ + '<': true, '>': true, ':': true, '"': true, + '/': true, '\\': true, '|': true, '?': true, '*': true, + } +} + +// sanitizePath cleans a path string by removing or replacing invalid Windows file name characters. +func sanitizePath(path string, sanitize sanitizer, toSanitize map[rune]bool) string { + // replace all slashes with backslashes + path = filepath.FromSlash(path) + + // replace all invalid characters + return strings.Map(func(r rune) rune { + if _, isInvalid := toSanitize[r]; isInvalid { + return sanitize(r, toSanitize) + } + return r + }, path) +} + +// sanitizer defined how to handle and replace invalid file name characters. +type sanitizer func(rune, map[rune]bool) rune + +// SanitizePath replaces invalid characters in a Windows path with a placeholder. +func SanitizePath(path string) string { + volumeName := filepath.VolumeName(path) + // Only sanitize the part of the path after the volume name + sanitized := sanitizePath(path[len(volumeName):], func(r rune, invalidChars map[rune]bool) rune { + if _, ok := invalidChars[r]; ok { + return '_' + } + return r + }, NeedToSanitize) + return volumeName + sanitized +} From 22335e0cdaac71d8d0f3d621e407490bc8c21688 Mon Sep 17 00:00:00 2001 From: zongz Date: Fri, 15 Mar 2024 15:01:54 +0800 Subject: [PATCH 2/5] fix: fix test cases Signed-off-by: zongz --- pkg/path/path_windows.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/path/path_windows.go b/pkg/path/path_windows.go index 3a2f79d3..bf87c456 100644 --- a/pkg/path/path_windows.go +++ b/pkg/path/path_windows.go @@ -12,8 +12,7 @@ var NeedToSanitize map[rune]bool func init() { NeedToSanitize = map[rune]bool{ - '<': true, '>': true, ':': true, '"': true, - '/': true, '\\': true, '|': true, '?': true, '*': true, + '<': true, '>': true, ':': true, '"': true, '|': true, '?': true, '*': true, } } @@ -44,5 +43,6 @@ func SanitizePath(path string) string { } return r }, NeedToSanitize) + return volumeName + sanitized } From db421f47dcd67a86c72c4c63c6dd06cfb1032afe Mon Sep 17 00:00:00 2001 From: zongz Date: Fri, 15 Mar 2024 15:17:57 +0800 Subject: [PATCH 3/5] fix: fix windows cases Signed-off-by: zongz --- pkg/path/path_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/path/path_test.go b/pkg/path/path_test.go index 7249184a..6b8f73ea 100644 --- a/pkg/path/path_test.go +++ b/pkg/path/path_test.go @@ -31,7 +31,7 @@ func TestSanitizePath(t *testing.T) { }{ name: "Windows style path", input: "C:\\Program Files\\Test<:>*|", - expected: "C:\\Program Files\\Test______", + expected: "C:\\Program Files\\Test_____", }) } From 9a291e754683eab23ad27a8cedd6785e07856fac Mon Sep 17 00:00:00 2001 From: zongz Date: Fri, 15 Mar 2024 15:29:33 +0800 Subject: [PATCH 4/5] fix: fix test case Signed-off-by: zongz --- pkg/path/path_test.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/pkg/path/path_test.go b/pkg/path/path_test.go index 6b8f73ea..27dd3e61 100644 --- a/pkg/path/path_test.go +++ b/pkg/path/path_test.go @@ -16,11 +16,6 @@ func TestSanitizePath(t *testing.T) { input: "test\x00file", expected: "test_file", }, - { - name: "Path without invalid characters", - input: "/usr/local/bin/test", - expected: "/usr/local/bin/test", - }, } if runtime.GOOS == "windows" { @@ -32,6 +27,17 @@ func TestSanitizePath(t *testing.T) { name: "Windows style path", input: "C:\\Program Files\\Test<:>*|", expected: "C:\\Program Files\\Test_____", + }, + ) + } else { + tests = append(tests, struct { + name string + input string + expected string + }{ + name: "Path without invalid characters", + input: "/usr/local/bin/test", + expected: "/usr/local/bin/test", }) } From d2512d6c30add204bf6bba3c4f03525373ddf6a7 Mon Sep 17 00:00:00 2001 From: zongz Date: Fri, 15 Mar 2024 15:37:50 +0800 Subject: [PATCH 5/5] fix: fix test case Signed-off-by: zongz --- pkg/path/path_windows.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/path/path_windows.go b/pkg/path/path_windows.go index bf87c456..3c51295b 100644 --- a/pkg/path/path_windows.go +++ b/pkg/path/path_windows.go @@ -12,7 +12,7 @@ var NeedToSanitize map[rune]bool func init() { NeedToSanitize = map[rune]bool{ - '<': true, '>': true, ':': true, '"': true, '|': true, '?': true, '*': true, + '<': true, '>': true, ':': true, '"': true, '|': true, '?': true, '*': true, '\x00': true, } }