diff --git a/go.mod b/go.mod index 8731939..66511ee 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,6 @@ module github.com/zalando/go-keyring go 1.18 require ( - al.essio.dev/pkg/shellescape v1.5.1 github.com/danieljoos/wincred v1.2.2 github.com/godbus/dbus/v5 v5.1.0 ) diff --git a/go.sum b/go.sum index 2743e22..6f2abf4 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,8 @@ -al.essio.dev/pkg/shellescape v1.5.1 h1:86HrALUujYS/h+GtqoB26SBEdkWfmMI6FubjXlsXyho= -al.essio.dev/pkg/shellescape v1.5.1/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890= github.com/danieljoos/wincred v1.2.2 h1:774zMFJrqaeYCK2W57BgAem/MLi6mtSE47MB6BOJ0i0= github.com/danieljoos/wincred v1.2.2/go.mod h1:w7w4Utbrz8lqeMbDAK0lkNJUv5sAOkFi7nd/ogr0Uh8= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= diff --git a/internal/shellescape/LICENSE b/internal/shellescape/LICENSE new file mode 100644 index 0000000..9f76067 --- /dev/null +++ b/internal/shellescape/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Alessio Treglia + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/internal/shellescape/shellescape.go b/internal/shellescape/shellescape.go new file mode 100644 index 0000000..13e0d1f --- /dev/null +++ b/internal/shellescape/shellescape.go @@ -0,0 +1,39 @@ +/* +Package shellescape provides the shellescape.Quote to escape arbitrary +strings for a safe use as command line arguments in the most common +POSIX shells. + +The original Python package which this work was inspired by can be found +at https://pypi.python.org/pypi/shellescape. + +Portions of this file are from al.essio.dev/pkg/shellescape, © 2016 Alessio Treglia under the MIT License. +See LICENSE for more information. +*/ +package shellescape + +/* +The functionality provided by shellescape.Quote could be helpful +in those cases where it is known that the output of a Go program will +be appended to/used in the context of shell programs' command line arguments. +*/ + +import ( + "regexp" + "strings" +) + +var pattern *regexp.Regexp = regexp.MustCompile(`[^\w@%+=:,./-]`) + +// Quote returns a shell-escaped version of the string s. The returned value +// is a string that can safely be used as one token in a shell command line. +func Quote(s string) string { + if len(s) == 0 { + return "''" + } + + if pattern.MatchString(s) { + return "'" + strings.ReplaceAll(s, "'", "'\"'\"'") + "'" + } + + return s +} diff --git a/internal/shellescape/shellescape_test.go b/internal/shellescape/shellescape_test.go new file mode 100644 index 0000000..b2ca792 --- /dev/null +++ b/internal/shellescape/shellescape_test.go @@ -0,0 +1,69 @@ +package shellescape_test + +import ( + "testing" + + "github.com/zalando/go-keyring/internal/shellescape" +) + +func assertEqual(t *testing.T, s, expected string) { + if s != expected { + t.Fatalf("%q (expected: %q)", s, expected) + } +} + +func TestEmptyString(t *testing.T) { + s := shellescape.Quote("") + expected := "''" + if s != expected { + t.Errorf("Expected escaped string %s, got: %s", expected, s) + } +} + +func TestDoubleQuotedString(t *testing.T) { + s := shellescape.Quote(`"double quoted"`) + expected := `'"double quoted"'` + if s != expected { + t.Errorf("Expected escaped string %s, got: %s", expected, s) + } +} + +func TestSingleQuotedString(t *testing.T) { + s := shellescape.Quote(`'single quoted'`) + expected := `''"'"'single quoted'"'"''` + if s != expected { + t.Errorf("Expected escaped string %s, got: %s", expected, s) + } +} + +func TestUnquotedString(t *testing.T) { + s := shellescape.Quote(`no quotes`) + expected := `'no quotes'` + if s != expected { + t.Errorf("Expected escaped string %s, got: %s", expected, s) + } +} + +func TestSingleInvalid(t *testing.T) { + s := shellescape.Quote(`;`) + expected := `';'` + if s != expected { + t.Errorf("Expected escaped string %s, got: %s", expected, s) + } +} + +func TestAllInvalid(t *testing.T) { + s := shellescape.Quote(`;${}`) + expected := `';${}'` + if s != expected { + t.Errorf("Expected escaped string %s, got: %s", expected, s) + } +} + +func TestCleanString(t *testing.T) { + s := shellescape.Quote("foo.example.com") + expected := `foo.example.com` + if s != expected { + t.Errorf("Expected escaped string %s, got: %s", expected, s) + } +} diff --git a/keyring_darwin.go b/keyring_darwin.go index 63104b0..5e3ae1b 100644 --- a/keyring_darwin.go +++ b/keyring_darwin.go @@ -22,7 +22,7 @@ import ( "os/exec" "strings" - "al.essio.dev/pkg/shellescape" + "github.com/zalando/go-keyring/internal/shellescape" ) const (