From 4cc112e708bcb7ed0625dc5502dfd75afba0e545 Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Sat, 9 May 2020 20:02:41 +0200 Subject: [PATCH 01/14] MS Windows fixes * Handle Windows path arguments like `c:/path/to/beehive.conf` when using --config. * Handle crypto URLs correctly * Test fixes, making sure we always use forward slashes in paths under Windows. For some extra context, Go URL parsing in Windows can be a bit surprising. Parsing file:///c:/beehive.conf, the URI format documented [here][1], will set the URL path to "/c:/beehive.conf". This behaviour is captured in https://github.com/golang/go/issues/6027. If we use a URL like file://c:/beehive.conf, the drive name will be parsed as the host and the path will miss the drive name. ```go package main import ( "fmt" "net/url" ) func main() { u, _ := url.Parse(`file://c:/beehive.conf`) fmt.Println(u.Host) fmt.Println(u.Path) } ``` This prints: ``` c: /beehive.conf ``` We workaround it patching the URL path and host so URLs like `crypt://sercret@c:/beehive.conf` behave as expected. [1]: https://docs.microsoft.com/en-us/archive/blogs/ie/file-uris-in-windows --- cfg/aesbackend.go | 3 +++ cfg/aesbackend_test.go | 24 ++++++++++--------- cfg/config.go | 48 ++++++++++++++++++++++++++++++-------- cfg/config_test.go | 11 +++------ cfg/config_windows_test.go | 13 +++++++++++ cfg/filebackend.go | 2 ++ cfg/filebackend_test.go | 7 +++--- cfg/helpers_test.go | 16 +++++++++++++ 8 files changed, 92 insertions(+), 32 deletions(-) create mode 100644 cfg/config_windows_test.go create mode 100644 cfg/helpers_test.go diff --git a/cfg/aesbackend.go b/cfg/aesbackend.go index b07ced8d..b3759c25 100644 --- a/cfg/aesbackend.go +++ b/cfg/aesbackend.go @@ -63,6 +63,7 @@ func NewAESBackend(u *url.URL) (*AESBackend, error) { // If the error returned is not nil, an error was returned while opening or // reading the file. func IsEncrypted(u *url.URL) (bool, error) { + fixWinURL(u) f, err := os.Open(u.Path) if err != nil { return false, err @@ -84,6 +85,7 @@ func IsEncrypted(u *url.URL) (bool, error) { // Load configuration file from the given URL and decrypt it func (b *AESBackend) Load(u *url.URL) (*Config, error) { + fixWinURL(u) config := &Config{url: u} if !exist(u.Path) { @@ -124,6 +126,7 @@ func (b *AESBackend) Load(u *url.URL) (*Config, error) { // Save encrypts then saves the configuration func (b *AESBackend) Save(config *Config) error { u := config.URL() + fixWinURL(u) cfgDir := filepath.Dir(u.Path) if !exist(cfgDir) { err := os.MkdirAll(cfgDir, 0755) diff --git a/cfg/aesbackend_test.go b/cfg/aesbackend_test.go index 49eeef2f..71c8dbe2 100644 --- a/cfg/aesbackend_test.go +++ b/cfg/aesbackend_test.go @@ -44,11 +44,11 @@ func TestAESBackendLoad(t *testing.T) { // try to load the config from an absolute path using a URI cwd, _ := os.Getwd() - u, err = url.Parse("crypto://" + testPassword + "@" + filepath.Join(cwd, "testdata", "beehive-crypto.conf")) + p := fixWindowsPath(filepath.Join(cwd, "testdata", "beehive-crypto.conf")) + u, err = url.Parse("crypto://" + testPassword + "@" + p) if err != nil { t.Fatalf("Can't parse crypto URL: %v", err) } - backend, err = NewAESBackend(u) if err != nil { t.Fatalf("Can't create AES backend: %v", err) @@ -63,11 +63,11 @@ func TestAESBackendLoad(t *testing.T) { // try to load the config using the password from the environment os.Setenv(PasswordEnvVar, testPassword) - u, err = url.Parse("crypto://" + filepath.Join(cwd, "testdata", "beehive-crypto.conf")) + p = fixWindowsPath(filepath.Join(cwd, "testdata", "beehive-crypto.conf")) + u, err = url.Parse("crypto://" + p) if err != nil { t.Fatalf("Can't parse crypto URL: %v", err) } - backend, err = NewAESBackend(u) if err != nil { t.Fatalf("Can't create AES backend: %v", err) @@ -79,11 +79,11 @@ func TestAESBackendLoad(t *testing.T) { // try to load the config with an invalid password os.Setenv(PasswordEnvVar, "") - u, err = url.Parse("crypto://bar@" + filepath.Join(cwd, "testdata", "beehive-crypto.conf")) + p = fixWindowsPath(filepath.Join(cwd, "testdata", "beehive-crypto.conf")) + u, err = url.Parse("crypto://bar@" + p) if err != nil { t.Fatalf("Can't parse crypto URL: %v", err) } - backend, err = NewAESBackend(u) if err != nil { t.Fatalf("Can't create AES backend: %v", err) @@ -95,7 +95,8 @@ func TestAESBackendLoad(t *testing.T) { // environment password takes prececence os.Setenv(PasswordEnvVar, testPassword) - u, err = url.Parse("crypto://bar@" + filepath.Join(cwd, "testdata", "beehive-crypto.conf")) + p = fixWindowsPath(filepath.Join(cwd, "testdata", "beehive-crypto.conf")) + u, err = url.Parse("crypto://bar@" + p) if err != nil { t.Fatalf("Can't parse crypto URL: %v", err) } @@ -109,11 +110,12 @@ func TestAESBackendLoad(t *testing.T) { t.Errorf("the password defined in %s should take precedence. %v", PasswordEnvVar, err) } - u, err = url.Parse("crypto://" + testPassword + "@" + filepath.Join(cwd, "testdata", "beehive.conf")) + p = fixWindowsPath(filepath.Join(cwd, "testdata", "beehive.conf")) + u, err = url.Parse("crypto://" + testPassword + "@" + p) if err != nil { t.Fatalf("Can't parse crypto URL: %v", err) } - _, err = backend.Load(u) + conf, err = backend.Load(u) if err == nil || err.Error() != "encrypted configuration header not valid" { t.Errorf("the password defined in %s should take precedence. %v", PasswordEnvVar, err) } @@ -137,7 +139,7 @@ func TestAESBackendSave(t *testing.T) { } // Save the config file to a new absolute path using a URL - p := filepath.Join(tmpdir, "beehive-crypto.conf") + p := fixWindowsPath(filepath.Join(tmpdir, "testdata", "beehive-crypto.conf")) u, err = url.Parse("crypto://" + testPassword + "@" + p) if err != nil { t.Error("cannot parse config url") @@ -149,7 +151,7 @@ func TestAESBackendSave(t *testing.T) { backend, _ = NewAESBackend(u) err = backend.Save(c) if err != nil { - t.Errorf("cailed to save the config to %s", u) + t.Errorf("failed to save the config to %s", u) } if !exist(p) { t.Errorf("configuration file wasn't saved to %s", p) diff --git a/cfg/config.go b/cfg/config.go index fedf32cb..5707e8c9 100644 --- a/cfg/config.go +++ b/cfg/config.go @@ -5,6 +5,8 @@ import ( "net/url" "os" "path/filepath" + "regexp" + "runtime" "github.com/muesli/beehive/bees" gap "github.com/muesli/go-app-paths" @@ -97,22 +99,20 @@ func New(url string) (*Config, error) { return nil, fmt.Errorf("Empty URL provided but not supported") } - err := config.SetURL(url) + winURL := regexp.MustCompile(`^[a-zA-Z]:`) + var err error + if runtime.GOOS == "windows" && winURL.MatchString(url) { + err = config.SetURL("file://" + url) + } else { + err = config.SetURL(url) + } if err != nil { return nil, err } switch config.url.Scheme { case "", "file": - if ok, _ := IsEncrypted(config.url); ok { - log.Debugf("Loading encrypted configuration file") - backend, err = NewAESBackend(config.url) - if err != nil { - log.Fatalf("error loading the AES configuration backend. err: %v", err) - } - } else { - backend = NewFileBackend() - } + backend = loadLocalFileBackend(config) case "mem": backend = NewMemBackend() case "crypto": @@ -129,6 +129,23 @@ func New(url string) (*Config, error) { return config, nil } +func loadLocalFileBackend(config *Config) ConfigBackend { + var backend ConfigBackend + var err error + + if ok, _ := IsEncrypted(config.url); ok { + log.Debugf("Loading encrypted configuration file") + backend, err = NewAESBackend(config.url) + if err != nil { + log.Fatalf("error loading the AES configuration backend. err: %v", err) + } + } else { + backend = NewFileBackend() + } + + return backend +} + // DefaultPath returns Beehive's default config path. // // The path returned is OS dependant. If there's an error @@ -185,3 +202,14 @@ func exist(file string) bool { _, err := os.Stat(file) return err == nil } + +// Workaround Go URL parsing in Windows, where URL.Host contains the drive +// info for a URL like file://c:/path/to/beehive.config +// +// no-op in non-Windows OSes +func fixWinURL(u *url.URL) { + if runtime.GOOS == "windows" { + u.Path = filepath.Join(u.Host, u.Path) + u.Host = "" + } +} diff --git a/cfg/config_test.go b/cfg/config_test.go index 1843f2e2..1d555011 100644 --- a/cfg/config_test.go +++ b/cfg/config_test.go @@ -9,7 +9,7 @@ import ( func TestNew(t *testing.T) { conf, err := New("/foobar") if err != nil { - t.Fatal("cannot create config from path") + t.Fatalf("Error in New. %v", err) } if _, ok := conf.Backend().(*FileBackend); !ok { t.Error("Backend for '/foobar' should be a FileBackend") @@ -24,10 +24,10 @@ func TestNew(t *testing.T) { } cwd, _ := os.Getwd() - p := filepath.Join(cwd, "testdata/beehive-crypto.conf") + p := fixWindowsPath(filepath.Join(cwd, "testdata", "beehive-crypto.conf")) conf, err = New(p) if err != nil { - t.Fatal(err) + t.Fatalf("Error in New: %v", err) } if _, ok := conf.Backend().(*AESBackend); !ok { t.Errorf("Backend for '%s' should be an AESBackend", p) @@ -41,11 +41,6 @@ func TestNew(t *testing.T) { t.Error("Backend for 'mem:' should be a MemoryBackend") } - _, err = New("c:\\foobar") - if err == nil { - t.Error("Not a valid URL, should return an error") - } - _, err = New("") if err == nil { t.Error("Not a valid URL, should return an error") diff --git a/cfg/config_windows_test.go b/cfg/config_windows_test.go new file mode 100644 index 00000000..435bbdb6 --- /dev/null +++ b/cfg/config_windows_test.go @@ -0,0 +1,13 @@ +package cfg + +import "testing" + +func TestWindowsStylePaths(t *testing.T) { + conf, err := New("c:/foo/bar/beehive.conf") + if err != nil { + t.Fatalf("Error in New. %v", err) + } + if _, ok := conf.Backend().(*FileBackend); !ok { + t.Errorf("Backend for %s should be a FileBackend", conf.URL().String()) + } +} diff --git a/cfg/filebackend.go b/cfg/filebackend.go index 4f83a9b0..2d85eb54 100644 --- a/cfg/filebackend.go +++ b/cfg/filebackend.go @@ -32,6 +32,7 @@ func NewFileBackend() *FileBackend { // Load loads chains from config func (fs *FileBackend) Load(u *url.URL) (*Config, error) { var config Config + fixWinURL(u) // detect file format by extension if strings.HasSuffix(u.Path, ".yaml") { @@ -67,6 +68,7 @@ func (fs *FileBackend) Load(u *url.URL) (*Config, error) { // Save saves chains to config func (fs *FileBackend) Save(config *Config) error { + fixWinURL(config.URL()) cfgDir := filepath.Dir(config.URL().Path) if !exist(cfgDir) { err := os.MkdirAll(cfgDir, 0755) diff --git a/cfg/filebackend_test.go b/cfg/filebackend_test.go index ed186460..aaf071ce 100644 --- a/cfg/filebackend_test.go +++ b/cfg/filebackend_test.go @@ -33,9 +33,10 @@ func TestFileLoad(t *testing.T) { // try to load the config from an absolute path using a URI cwd, _ := os.Getwd() - u, err = url.Parse(filepath.Join("file://", cwd, "testdata", "beehive.conf")) + p := fixWindowsPath(filepath.Join(cwd, "testdata", "beehive.conf")) + u, err = url.Parse("file://" + p) if err != nil { - t.Error("cannot parse config path") + t.Fatalf("Error parsing URL. %v", err) } backend = NewFileBackend() conf, err = backend.Load(u) @@ -64,7 +65,7 @@ func TestFileSave(t *testing.T) { } // Save the config file to a new absolute path using a URL - p := filepath.Join(tmpdir, "beehive.conf") + p := fixWindowsPath(filepath.Join(tmpdir, "beehive.conf")) u, err = url.Parse("file://" + p) if err != nil { t.Error("cannot parse config path") diff --git a/cfg/helpers_test.go b/cfg/helpers_test.go new file mode 100644 index 00000000..fc13219a --- /dev/null +++ b/cfg/helpers_test.go @@ -0,0 +1,16 @@ +package cfg + +import ( + "runtime" + "strings" +) + +// Replace backward slashes in Windows paths with /, to make them suitable +// for Go URL parsing. +func fixWindowsPath(path string) string { + if runtime.GOOS == "windows" { + return strings.Replace(path, `\`, "/", -1) + } + + return path +} From bbd1c2262d0b4be24d969e986be7edf90dbd8f93 Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Sat, 9 May 2020 21:14:18 +0200 Subject: [PATCH 02/14] DRY things up a bit --- cfg/aesbackend_test.go | 28 +++++++++------------------- cfg/helpers_test.go | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/cfg/aesbackend_test.go b/cfg/aesbackend_test.go index 71c8dbe2..04b6f1ea 100644 --- a/cfg/aesbackend_test.go +++ b/cfg/aesbackend_test.go @@ -21,7 +21,7 @@ package cfg import ( - "io/ioutil" + "fmt" "net/url" "os" "path/filepath" @@ -43,15 +43,14 @@ func TestAESBackendLoad(t *testing.T) { } // try to load the config from an absolute path using a URI - cwd, _ := os.Getwd() - p := fixWindowsPath(filepath.Join(cwd, "testdata", "beehive-crypto.conf")) - u, err = url.Parse("crypto://" + testPassword + "@" + p) + u, err = url.Parse("crypto://" + testPassword + "@" + encryptedConfPath()) + fmt.Println(u.Path) if err != nil { t.Fatalf("Can't parse crypto URL: %v", err) } backend, err = NewAESBackend(u) if err != nil { - t.Fatalf("Can't create AES backend: %v", err) + t.Errorf("Error loading AES backend. %v", err) } conf, err := backend.Load(u) if err != nil { @@ -63,8 +62,7 @@ func TestAESBackendLoad(t *testing.T) { // try to load the config using the password from the environment os.Setenv(PasswordEnvVar, testPassword) - p = fixWindowsPath(filepath.Join(cwd, "testdata", "beehive-crypto.conf")) - u, err = url.Parse("crypto://" + p) + u, err = url.Parse("crypto://" + encryptedConfPath()) if err != nil { t.Fatalf("Can't parse crypto URL: %v", err) } @@ -79,8 +77,7 @@ func TestAESBackendLoad(t *testing.T) { // try to load the config with an invalid password os.Setenv(PasswordEnvVar, "") - p = fixWindowsPath(filepath.Join(cwd, "testdata", "beehive-crypto.conf")) - u, err = url.Parse("crypto://bar@" + p) + u, err = url.Parse("crypto://bar@" + encryptedConfPath()) if err != nil { t.Fatalf("Can't parse crypto URL: %v", err) } @@ -95,8 +92,7 @@ func TestAESBackendLoad(t *testing.T) { // environment password takes prececence os.Setenv(PasswordEnvVar, testPassword) - p = fixWindowsPath(filepath.Join(cwd, "testdata", "beehive-crypto.conf")) - u, err = url.Parse("crypto://bar@" + p) + u, err = url.Parse("crypto://bar@" + encryptedConfPath()) if err != nil { t.Fatalf("Can't parse crypto URL: %v", err) } @@ -110,8 +106,7 @@ func TestAESBackendLoad(t *testing.T) { t.Errorf("the password defined in %s should take precedence. %v", PasswordEnvVar, err) } - p = fixWindowsPath(filepath.Join(cwd, "testdata", "beehive.conf")) - u, err = url.Parse("crypto://" + testPassword + "@" + p) + u, err = url.Parse("crypto://" + testPassword + "@" + confPath()) if err != nil { t.Fatalf("Can't parse crypto URL: %v", err) } @@ -122,11 +117,6 @@ func TestAESBackendLoad(t *testing.T) { } func TestAESBackendSave(t *testing.T) { - tmpdir, err := ioutil.TempDir("", "beehivetest") - if err != nil { - t.Error("Could not create temp directory") - } - cwd, _ := os.Getwd() u, err := url.Parse(filepath.Join("crypto://"+testPassword+"@", cwd, "testdata", "beehive-crypto.conf")) if err != nil { @@ -139,7 +129,7 @@ func TestAESBackendSave(t *testing.T) { } // Save the config file to a new absolute path using a URL - p := fixWindowsPath(filepath.Join(tmpdir, "testdata", "beehive-crypto.conf")) + p := encryptedTempConf() u, err = url.Parse("crypto://" + testPassword + "@" + p) if err != nil { t.Error("cannot parse config url") diff --git a/cfg/helpers_test.go b/cfg/helpers_test.go index fc13219a..52bb16f5 100644 --- a/cfg/helpers_test.go +++ b/cfg/helpers_test.go @@ -1,6 +1,9 @@ package cfg import ( + "io/ioutil" + "os" + "path/filepath" "runtime" "strings" ) @@ -14,3 +17,21 @@ func fixWindowsPath(path string) string { return path } + +func encryptedConfPath() string { + cwd, _ := os.Getwd() + return fixWindowsPath(filepath.Join(cwd, "testdata", "beehive-crypto.conf")) +} + +func confPath() string { + cwd, _ := os.Getwd() + return fixWindowsPath(filepath.Join(cwd, "testdata", "beehive.conf")) +} + +func encryptedTempConf() string { + tmpdir, err := ioutil.TempDir("", "beehivetest") + if err != nil { + panic("Could not create temp directory") + } + return fixWindowsPath(filepath.Join(tmpdir, "testdata", "beehive-crypto.conf")) +} From 4835a4a8d844073cf090cf1aabe1e709f675eca4 Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Sat, 9 May 2020 21:15:13 +0200 Subject: [PATCH 03/14] Remove debugging --- cfg/aesbackend_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/cfg/aesbackend_test.go b/cfg/aesbackend_test.go index 04b6f1ea..bc43ec9e 100644 --- a/cfg/aesbackend_test.go +++ b/cfg/aesbackend_test.go @@ -21,7 +21,6 @@ package cfg import ( - "fmt" "net/url" "os" "path/filepath" @@ -44,7 +43,6 @@ func TestAESBackendLoad(t *testing.T) { // try to load the config from an absolute path using a URI u, err = url.Parse("crypto://" + testPassword + "@" + encryptedConfPath()) - fmt.Println(u.Path) if err != nil { t.Fatalf("Can't parse crypto URL: %v", err) } From 6285f0c163ee9033f8626b77fc524391d5c4a6d8 Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Sat, 9 May 2020 21:17:41 +0200 Subject: [PATCH 04/14] Fix test error message --- cfg/aesbackend_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cfg/aesbackend_test.go b/cfg/aesbackend_test.go index bc43ec9e..87e93282 100644 --- a/cfg/aesbackend_test.go +++ b/cfg/aesbackend_test.go @@ -110,7 +110,7 @@ func TestAESBackendLoad(t *testing.T) { } conf, err = backend.Load(u) if err == nil || err.Error() != "encrypted configuration header not valid" { - t.Errorf("the password defined in %s should take precedence. %v", PasswordEnvVar, err) + t.Errorf("Loading a non-encrypted config should error") } } From 22c4512661c9466d9c04742b189a88f36c52619e Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Sun, 10 May 2020 14:24:38 +0200 Subject: [PATCH 05/14] Specialized URL struct Wraps platform-specific workarounds. --- cfg/aesbackend.go | 12 ++++------ cfg/aesbackend_test.go | 21 ++++++++--------- cfg/config.go | 20 ++++------------ cfg/filebackend.go | 4 +--- cfg/filebackend_test.go | 20 +++++++--------- cfg/membackend.go | 4 +--- cfg/membackend_test.go | 5 ++-- cfg/url.go | 52 +++++++++++++++++++++++++++++++++++++++++ 8 files changed, 82 insertions(+), 56 deletions(-) create mode 100644 cfg/url.go diff --git a/cfg/aesbackend.go b/cfg/aesbackend.go index b3759c25..b12ae5cf 100644 --- a/cfg/aesbackend.go +++ b/cfg/aesbackend.go @@ -27,7 +27,6 @@ import ( "encoding/json" "errors" "io/ioutil" - "net/url" "os" "path/filepath" @@ -50,7 +49,7 @@ type AESBackend struct{} // Given the password is required to encrypt/decrypt the configuration, if the // URL passed doesn't have a password or PasswordEnvVar is not defined, // it'll return an error. -func NewAESBackend(u *url.URL) (*AESBackend, error) { +func NewAESBackend(u *URL) (*AESBackend, error) { if _, err := getPassword(u); err != nil { return nil, err } @@ -62,8 +61,7 @@ func NewAESBackend(u *url.URL) (*AESBackend, error) { // // If the error returned is not nil, an error was returned while opening or // reading the file. -func IsEncrypted(u *url.URL) (bool, error) { - fixWinURL(u) +func IsEncrypted(u *URL) (bool, error) { f, err := os.Open(u.Path) if err != nil { return false, err @@ -84,8 +82,7 @@ func IsEncrypted(u *url.URL) (bool, error) { } // Load configuration file from the given URL and decrypt it -func (b *AESBackend) Load(u *url.URL) (*Config, error) { - fixWinURL(u) +func (b *AESBackend) Load(u *URL) (*Config, error) { config := &Config{url: u} if !exist(u.Path) { @@ -126,7 +123,6 @@ func (b *AESBackend) Load(u *url.URL) (*Config, error) { // Save encrypts then saves the configuration func (b *AESBackend) Save(config *Config) error { u := config.URL() - fixWinURL(u) cfgDir := filepath.Dir(u.Path) if !exist(cfgDir) { err := os.MkdirAll(cfgDir, 0755) @@ -225,7 +221,7 @@ func deriveKey(password, salt []byte) ([]byte, []byte, error) { return key, salt, nil } -func getPassword(u *url.URL) (string, error) { +func getPassword(u *URL) (string, error) { p := os.Getenv(PasswordEnvVar) if p != "" { return p, nil diff --git a/cfg/aesbackend_test.go b/cfg/aesbackend_test.go index 87e93282..c65ae7bb 100644 --- a/cfg/aesbackend_test.go +++ b/cfg/aesbackend_test.go @@ -21,7 +21,6 @@ package cfg import ( - "net/url" "os" "path/filepath" "testing" @@ -30,7 +29,7 @@ import ( const testPassword = "foo" func TestAESBackendLoad(t *testing.T) { - u, _ := url.Parse("crypt://foo@foobar") + u, _ := ParseURL("crypt://foo@foobar") backend, err := NewAESBackend(u) if err != nil { t.Error("The backend should return an error if no password was specified") @@ -42,7 +41,7 @@ func TestAESBackendLoad(t *testing.T) { } // try to load the config from an absolute path using a URI - u, err = url.Parse("crypto://" + testPassword + "@" + encryptedConfPath()) + u, err = ParseURL("crypto://" + testPassword + "@" + encryptedConfPath()) if err != nil { t.Fatalf("Can't parse crypto URL: %v", err) } @@ -60,7 +59,7 @@ func TestAESBackendLoad(t *testing.T) { // try to load the config using the password from the environment os.Setenv(PasswordEnvVar, testPassword) - u, err = url.Parse("crypto://" + encryptedConfPath()) + u, err = ParseURL("crypto://" + encryptedConfPath()) if err != nil { t.Fatalf("Can't parse crypto URL: %v", err) } @@ -75,7 +74,7 @@ func TestAESBackendLoad(t *testing.T) { // try to load the config with an invalid password os.Setenv(PasswordEnvVar, "") - u, err = url.Parse("crypto://bar@" + encryptedConfPath()) + u, err = ParseURL("crypto://bar@" + encryptedConfPath()) if err != nil { t.Fatalf("Can't parse crypto URL: %v", err) } @@ -90,7 +89,7 @@ func TestAESBackendLoad(t *testing.T) { // environment password takes prececence os.Setenv(PasswordEnvVar, testPassword) - u, err = url.Parse("crypto://bar@" + encryptedConfPath()) + u, err = ParseURL("crypto://bar@" + encryptedConfPath()) if err != nil { t.Fatalf("Can't parse crypto URL: %v", err) } @@ -104,7 +103,7 @@ func TestAESBackendLoad(t *testing.T) { t.Errorf("the password defined in %s should take precedence. %v", PasswordEnvVar, err) } - u, err = url.Parse("crypto://" + testPassword + "@" + confPath()) + u, err = ParseURL("crypto://" + testPassword + "@" + confPath()) if err != nil { t.Fatalf("Can't parse crypto URL: %v", err) } @@ -116,7 +115,7 @@ func TestAESBackendLoad(t *testing.T) { func TestAESBackendSave(t *testing.T) { cwd, _ := os.Getwd() - u, err := url.Parse(filepath.Join("crypto://"+testPassword+"@", cwd, "testdata", "beehive-crypto.conf")) + u, err := ParseURL(filepath.Join("crypto://"+testPassword+"@", cwd, "testdata", "beehive-crypto.conf")) if err != nil { t.Error("cannot parse config url") } @@ -128,13 +127,13 @@ func TestAESBackendSave(t *testing.T) { // Save the config file to a new absolute path using a URL p := encryptedTempConf() - u, err = url.Parse("crypto://" + testPassword + "@" + p) + u, err = ParseURL("crypto://" + testPassword + "@" + p) if err != nil { t.Error("cannot parse config url") } - err = c.SetURL(u.String()) + c.SetURL(u.String()) if err != nil { - t.Error("cannot set url") + t.Error("cannont set config url") } backend, _ = NewAESBackend(u) err = backend.Save(c) diff --git a/cfg/config.go b/cfg/config.go index 5707e8c9..ccf9b33b 100644 --- a/cfg/config.go +++ b/cfg/config.go @@ -2,7 +2,6 @@ package cfg import ( "fmt" - "net/url" "os" "path/filepath" "regexp" @@ -23,7 +22,7 @@ type Config struct { Actions []bees.Action Chains []bees.Chain backend ConfigBackend - url *url.URL + url *URL } // ConfigBackend is the interface implemented by the configuration backends. @@ -31,7 +30,7 @@ type Config struct { // Backends are responsible for loading and saving the Config struct to // memory, the local filesystem, the network, etc. type ConfigBackend interface { - Load(*url.URL) (*Config, error) + Load(*URL) (*Config, error) Save(*Config) error } @@ -68,7 +67,7 @@ func (c *Config) Backend() ConfigBackend { // Next time the config is loaded or saved // the new URL will be used. func (c *Config) SetURL(u string) error { - url, err := url.Parse(u) + url, err := ParseURL(u) if err != nil { return err } @@ -79,7 +78,7 @@ func (c *Config) SetURL(u string) error { } // URL currently being used. -func (c *Config) URL() *url.URL { +func (c *Config) URL() *URL { return c.url } @@ -202,14 +201,3 @@ func exist(file string) bool { _, err := os.Stat(file) return err == nil } - -// Workaround Go URL parsing in Windows, where URL.Host contains the drive -// info for a URL like file://c:/path/to/beehive.config -// -// no-op in non-Windows OSes -func fixWinURL(u *url.URL) { - if runtime.GOOS == "windows" { - u.Path = filepath.Join(u.Host, u.Path) - u.Host = "" - } -} diff --git a/cfg/filebackend.go b/cfg/filebackend.go index 2d85eb54..db91ceb7 100644 --- a/cfg/filebackend.go +++ b/cfg/filebackend.go @@ -3,7 +3,6 @@ package cfg import ( "encoding/json" "io/ioutil" - "net/url" "os" "path/filepath" "strings" @@ -30,7 +29,7 @@ func NewFileBackend() *FileBackend { } // Load loads chains from config -func (fs *FileBackend) Load(u *url.URL) (*Config, error) { +func (fs *FileBackend) Load(u *URL) (*Config, error) { var config Config fixWinURL(u) @@ -68,7 +67,6 @@ func (fs *FileBackend) Load(u *url.URL) (*Config, error) { // Save saves chains to config func (fs *FileBackend) Save(config *Config) error { - fixWinURL(config.URL()) cfgDir := filepath.Dir(config.URL().Path) if !exist(cfgDir) { err := os.MkdirAll(cfgDir, 0755) diff --git a/cfg/filebackend_test.go b/cfg/filebackend_test.go index aaf071ce..eb326d10 100644 --- a/cfg/filebackend_test.go +++ b/cfg/filebackend_test.go @@ -9,7 +9,7 @@ import ( ) func TestFileLoad(t *testing.T) { - u, _ := url.Parse("file://foobar") + u, _ := ParseURL("file://foobar") backend := NewFileBackend() _, err := backend.Load(u) @@ -18,7 +18,7 @@ func TestFileLoad(t *testing.T) { } // try to load the config from a relative path - u, err = url.Parse(filepath.Join("testdata", "beehive.conf")) + u, err = ParseURL(filepath.Join("testdata", "beehive.conf")) if err != nil { t.Error("cannot parse config path") } @@ -34,7 +34,7 @@ func TestFileLoad(t *testing.T) { // try to load the config from an absolute path using a URI cwd, _ := os.Getwd() p := fixWindowsPath(filepath.Join(cwd, "testdata", "beehive.conf")) - u, err = url.Parse("file://" + p) + u, err = ParseURL("file://" + p) if err != nil { t.Fatalf("Error parsing URL. %v", err) } @@ -54,7 +54,7 @@ func TestFileSave(t *testing.T) { t.Error("Could not create temp directory") } - u, err := url.Parse(filepath.Join("testdata", "beehive.conf")) + u, err := ParseURL(filepath.Join("testdata", "beehive.conf")) if err != nil { t.Error("cannot parse config path") } @@ -66,11 +66,11 @@ func TestFileSave(t *testing.T) { // Save the config file to a new absolute path using a URL p := fixWindowsPath(filepath.Join(tmpdir, "beehive.conf")) - u, err = url.Parse("file://" + p) + u, err = ParseURL("file://" + p) if err != nil { t.Error("cannot parse config path") } - err = c.SetURL(u.String()) + c.SetURL(u.String()) if err != nil { t.Error("cannot set url") } @@ -89,13 +89,9 @@ func TestFileSave(t *testing.T) { // Save the config file to a new absolute path using a regular path p = filepath.Join(tmpdir, "beehive.conf") - u, err = url.Parse(p) - if err != nil { - t.Error("cannot parse config path") - } - err = c.SetURL(u.String()) + u, err = ParseURL(p) if err != nil { - t.Error("cannot set url") + t.Error("cannot parse url") } err = backend.Save(c) if err != nil { diff --git a/cfg/membackend.go b/cfg/membackend.go index c6c7ecf0..d8965c6d 100644 --- a/cfg/membackend.go +++ b/cfg/membackend.go @@ -1,7 +1,5 @@ package cfg -import "net/url" - // MemBackend implements a dummy memory backend for the configuration type MemBackend struct { conf *Config @@ -16,7 +14,7 @@ func NewMemBackend() *MemBackend { // Load the config from memory // // No need to do anything here, already loaded -func (m *MemBackend) Load(u *url.URL) (*Config, error) { +func (m *MemBackend) Load(u *URL) (*Config, error) { return m.conf, nil } diff --git a/cfg/membackend_test.go b/cfg/membackend_test.go index d1aab8e7..88153313 100644 --- a/cfg/membackend_test.go +++ b/cfg/membackend_test.go @@ -1,13 +1,12 @@ package cfg import ( - "net/url" "path/filepath" "testing" ) func TestMemLoad(t *testing.T) { - u, _ := url.Parse("mem://") + u, _ := ParseURL("mem://") backend := NewMemBackend() _, err := backend.Load(u) if err != nil { @@ -17,7 +16,7 @@ func TestMemLoad(t *testing.T) { func TestMemSave(t *testing.T) { path := filepath.Join("testdata", "foobar") - u, _ := url.Parse(filepath.Join("testdata", "foobar")) + u, _ := ParseURL(filepath.Join("testdata", "foobar")) backend := NewMemBackend() conf := &Config{url: u} err := backend.Save(conf) diff --git a/cfg/url.go b/cfg/url.go new file mode 100644 index 00000000..ef9d24de --- /dev/null +++ b/cfg/url.go @@ -0,0 +1,52 @@ +package cfg + +import ( + "net/url" + "path/filepath" + "runtime" +) + +// URL wraps net/url.URL to deal with some platform specific issues when +// parsing configuration urls. +type URL struct { + nurl *url.URL + Path string + Host string + Scheme string + User *url.Userinfo +} + +func ParseURL(rawurl string) (*URL, error) { + u, err := url.Parse(rawurl) + if err != nil { + return nil, err + } + fixWinURL(u) + curl := URL{} + curl.nurl = u + curl.User = u.User + curl.Path = u.Path + curl.Host = u.Host + curl.Scheme = u.Scheme + + return &curl, nil +} + +func (u *URL) String() string { + return u.nurl.String() +} + +func (u *URL) NetURL() *url.URL { + return u.nurl +} + +// Workaround Go URL parsing in Windows, where URL.Host contains the drive +// info for a URL like file://c:/path/to/beehive.config +// +// no-op in non-Windows OSes +func fixWinURL(u *url.URL) { + if runtime.GOOS == "windows" { + u.Path = filepath.Join(u.Host, u.Path) + u.Host = "" + } +} From daf7fe1780c339dc3af522eac1abb35a21cfabc3 Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Sun, 10 May 2020 15:07:59 +0200 Subject: [PATCH 06/14] Test fixes --- cfg/aesbackend_test.go | 11 +++++------ cfg/filebackend_test.go | 6 +++++- cfg/testdata/beehive-crypto.conf | Bin 235 -> 235 bytes 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/cfg/aesbackend_test.go b/cfg/aesbackend_test.go index c65ae7bb..4890dca6 100644 --- a/cfg/aesbackend_test.go +++ b/cfg/aesbackend_test.go @@ -22,7 +22,6 @@ package cfg import ( "os" - "path/filepath" "testing" ) @@ -114,12 +113,12 @@ func TestAESBackendLoad(t *testing.T) { } func TestAESBackendSave(t *testing.T) { - cwd, _ := os.Getwd() - u, err := ParseURL(filepath.Join("crypto://"+testPassword+"@", cwd, "testdata", "beehive-crypto.conf")) + p := encryptedConfPath() + u, err := ParseURL("crypto://" + testPassword + "@" + p) + backend, _ := NewAESBackend(u) if err != nil { - t.Error("cannot parse config url") + t.Fatalf("Can't parse crypto URL: %v", err) } - backend, _ := NewAESBackend(u) c, err := backend.Load(u) if err != nil { t.Errorf("Failed to load config fixture from relative path %s: %v", u, err) @@ -138,7 +137,7 @@ func TestAESBackendSave(t *testing.T) { backend, _ = NewAESBackend(u) err = backend.Save(c) if err != nil { - t.Errorf("failed to save the config to %s", u) + t.Errorf("failed to save the config to %s. %v", u, err) } if !exist(p) { t.Errorf("configuration file wasn't saved to %s", p) diff --git a/cfg/filebackend_test.go b/cfg/filebackend_test.go index eb326d10..ef3c0900 100644 --- a/cfg/filebackend_test.go +++ b/cfg/filebackend_test.go @@ -20,7 +20,11 @@ func TestFileLoad(t *testing.T) { // try to load the config from a relative path u, err = ParseURL(filepath.Join("testdata", "beehive.conf")) if err != nil { +<<<<<<< HEAD t.Error("cannot parse config path") +======= + t.Fatalf("Can't parse URL. %v", err) +>>>>>>> Test fixes } backend = NewFileBackend() conf, err := backend.Load(u) @@ -56,7 +60,7 @@ func TestFileSave(t *testing.T) { u, err := ParseURL(filepath.Join("testdata", "beehive.conf")) if err != nil { - t.Error("cannot parse config path") + t.Fatalf("Can't parse URL. %v", err) } backend := NewFileBackend() c, err := backend.Load(u) diff --git a/cfg/testdata/beehive-crypto.conf b/cfg/testdata/beehive-crypto.conf index 42fae2eefed72eee698ca3970a46d6dc803b0761..94d994934e74c34312b2ec444e9bab2ae5cb21ff 100644 GIT binary patch literal 235 zcmVNkS|83>TVlhvqg^Xf=IqGF?EUMH;T4|#*M lC2Me%8{i7msV9{34b91K(MrVrZHgGTkwCE%pU#EkmE_9$b-e%p literal 235 zcmV Date: Sun, 10 May 2020 15:24:19 +0200 Subject: [PATCH 07/14] Adapt main to api changes --- beehive.go | 5 ++--- cfg/aesbackend_test.go | 8 ++++---- cfg/config_windows_test.go | 2 +- cfg/filebackend_test.go | 10 +++++----- cfg/url.go | 7 +++---- 5 files changed, 15 insertions(+), 17 deletions(-) diff --git a/beehive.go b/beehive.go index 140fc7f3..42d0a004 100644 --- a/beehive.go +++ b/beehive.go @@ -26,7 +26,6 @@ package main import ( "encoding/json" "fmt" - "net/url" "os" "os/signal" "syscall" @@ -106,7 +105,7 @@ func main() { log.Fatalf("Error creating the configuration %s", err) } - if config.URL().String() != cfg.DefaultPath() { // the user specified a custom config path or URI + if config.URL().Raw != cfg.DefaultPath() { // the user specified a custom config path or URI err = config.Load() if err != nil { log.Fatalf("Error loading configuration file from %s. err: %v", config.URL(), err) @@ -180,7 +179,7 @@ func main() { func decryptConfig(u string) { b := cfg.AESBackend{} - pu, err := url.Parse(u) + pu, err := cfg.ParseURL(u) if err != nil { log.Fatal("Invalid configuration URL. err: ", err) } diff --git a/cfg/aesbackend_test.go b/cfg/aesbackend_test.go index 4890dca6..99db6cc6 100644 --- a/cfg/aesbackend_test.go +++ b/cfg/aesbackend_test.go @@ -42,7 +42,7 @@ func TestAESBackendLoad(t *testing.T) { // try to load the config from an absolute path using a URI u, err = ParseURL("crypto://" + testPassword + "@" + encryptedConfPath()) if err != nil { - t.Fatalf("Can't parse crypto URL: %v", err) + t.Errorf("Can't parse crypto URL: %v", err) } backend, err = NewAESBackend(u) if err != nil { @@ -50,7 +50,7 @@ func TestAESBackendLoad(t *testing.T) { } conf, err := backend.Load(u) if err != nil { - t.Errorf("Error loading config file fixture from absolute path %s. %v", u, err) + t.Errorf("Error loading config file fixture from absolute path. %v", err) } if conf.Bees[0].Name != "echo" { t.Error("The first bee should be an exec bee named echo") @@ -121,7 +121,7 @@ func TestAESBackendSave(t *testing.T) { } c, err := backend.Load(u) if err != nil { - t.Errorf("Failed to load config fixture from relative path %s: %v", u, err) + t.Errorf("Failed to load config fixture from relative path %s. %v", p, err) } // Save the config file to a new absolute path using a URL @@ -137,7 +137,7 @@ func TestAESBackendSave(t *testing.T) { backend, _ = NewAESBackend(u) err = backend.Save(c) if err != nil { - t.Errorf("failed to save the config to %s. %v", u, err) + t.Errorf("failed to save the config to %s. %v", newURL, err) } if !exist(p) { t.Errorf("configuration file wasn't saved to %s", p) diff --git a/cfg/config_windows_test.go b/cfg/config_windows_test.go index 435bbdb6..2c2b412e 100644 --- a/cfg/config_windows_test.go +++ b/cfg/config_windows_test.go @@ -8,6 +8,6 @@ func TestWindowsStylePaths(t *testing.T) { t.Fatalf("Error in New. %v", err) } if _, ok := conf.Backend().(*FileBackend); !ok { - t.Errorf("Backend for %s should be a FileBackend", conf.URL().String()) + t.Errorf("Backend for %s should be a FileBackend", conf.URL().Raw) } } diff --git a/cfg/filebackend_test.go b/cfg/filebackend_test.go index ef3c0900..f0d41880 100644 --- a/cfg/filebackend_test.go +++ b/cfg/filebackend_test.go @@ -29,7 +29,7 @@ func TestFileLoad(t *testing.T) { backend = NewFileBackend() conf, err := backend.Load(u) if err != nil { - t.Errorf("Error loading config file fixture from relative path %s. %v", u, err) + t.Errorf("Error loading config file fixture from relative path %s. %v", u.Raw, err) } if conf.Bees[0].Name != "echo" { t.Error("The first bee should be an exec bee named echo") @@ -45,7 +45,7 @@ func TestFileLoad(t *testing.T) { backend = NewFileBackend() conf, err = backend.Load(u) if err != nil { - t.Errorf("Error loading config file fixture from absolute path %s. %v", u, err) + t.Errorf("Error loading config file fixture from absolute path %s. %v", u.Raw, err) } if conf.Bees[0].Name != "echo" { t.Error("The first bee should be an exec bee named echo") @@ -65,7 +65,7 @@ func TestFileSave(t *testing.T) { backend := NewFileBackend() c, err := backend.Load(u) if err != nil { - t.Errorf("Failed to load config fixture from relative path %s: %v", u, err) + t.Errorf("Failed to load config fixture from relative path %s: %v", u.Raw, err) } // Save the config file to a new absolute path using a URL @@ -81,14 +81,14 @@ func TestFileSave(t *testing.T) { backend = NewFileBackend() err = backend.Save(c) if err != nil { - t.Errorf("Failed to save the config to %s", u) + t.Errorf("Failed to save the config to %s", u.Raw) } if !exist(p) { t.Errorf("Configuration file wasn't saved to %s", p) } c, err = backend.Load(u) if err != nil { - t.Errorf("Failed to load config fixture from absolute path %s: %v", u, err) + t.Errorf("Failed to load config fixture from absolute path %s: %v", u.Raw, err) } // Save the config file to a new absolute path using a regular path diff --git a/cfg/url.go b/cfg/url.go index ef9d24de..cb14fcd0 100644 --- a/cfg/url.go +++ b/cfg/url.go @@ -14,8 +14,10 @@ type URL struct { Host string Scheme string User *url.Userinfo + Raw string } +// ParseURL mimicks net/url URL.Parse func ParseURL(rawurl string) (*URL, error) { u, err := url.Parse(rawurl) if err != nil { @@ -28,14 +30,11 @@ func ParseURL(rawurl string) (*URL, error) { curl.Path = u.Path curl.Host = u.Host curl.Scheme = u.Scheme + curl.Raw = rawurl return &curl, nil } -func (u *URL) String() string { - return u.nurl.String() -} - func (u *URL) NetURL() *url.URL { return u.nurl } From 94fc48cf8395fc9bd8c6114090e1cd2f4985e177 Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Sun, 10 May 2020 15:36:04 +0200 Subject: [PATCH 08/14] :lipstick: --- cfg/aesbackend_test.go | 2 +- cfg/filebackend_test.go | 11 +++++------ cfg/helpers_test.go | 8 ++++++++ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/cfg/aesbackend_test.go b/cfg/aesbackend_test.go index 99db6cc6..b4616cdd 100644 --- a/cfg/aesbackend_test.go +++ b/cfg/aesbackend_test.go @@ -50,7 +50,7 @@ func TestAESBackendLoad(t *testing.T) { } conf, err := backend.Load(u) if err != nil { - t.Errorf("Error loading config file fixture from absolute path. %v", err) + t.Errorf("Error loading config file fixture from absolute path %s. %v", u.Raw, err) } if conf.Bees[0].Name != "echo" { t.Error("The first bee should be an exec bee named echo") diff --git a/cfg/filebackend_test.go b/cfg/filebackend_test.go index f0d41880..18959966 100644 --- a/cfg/filebackend_test.go +++ b/cfg/filebackend_test.go @@ -1,8 +1,11 @@ package cfg import ( +<<<<<<< HEAD "io/ioutil" "net/url" +======= +>>>>>>> :lipstick: "os" "path/filepath" "testing" @@ -53,11 +56,6 @@ func TestFileLoad(t *testing.T) { } func TestFileSave(t *testing.T) { - tmpdir, err := ioutil.TempDir("", "beehivetest") - if err != nil { - t.Error("Could not create temp directory") - } - u, err := ParseURL(filepath.Join("testdata", "beehive.conf")) if err != nil { t.Fatalf("Can't parse URL. %v", err) @@ -92,7 +90,8 @@ func TestFileSave(t *testing.T) { } // Save the config file to a new absolute path using a regular path - p = filepath.Join(tmpdir, "beehive.conf") + p = tmpConfPath() + c.SetURL(p) u, err = ParseURL(p) if err != nil { t.Error("cannot parse url") diff --git a/cfg/helpers_test.go b/cfg/helpers_test.go index 52bb16f5..0e8c7f09 100644 --- a/cfg/helpers_test.go +++ b/cfg/helpers_test.go @@ -28,6 +28,14 @@ func confPath() string { return fixWindowsPath(filepath.Join(cwd, "testdata", "beehive.conf")) } +func tmpConfPath() string { + tmpdir, err := ioutil.TempDir("", "beehivetest") + if err != nil { + panic("Could not create temp directory") + } + return fixWindowsPath(filepath.Join(tmpdir, "testdata", "beehive.conf")) +} + func encryptedTempConf() string { tmpdir, err := ioutil.TempDir("", "beehivetest") if err != nil { From 8725b96f5cbe58f503ca2ffd2d9f6aac04e213d4 Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Sun, 10 May 2020 15:43:44 +0200 Subject: [PATCH 09/14] moar test fixes --- cfg/filebackend_test.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cfg/filebackend_test.go b/cfg/filebackend_test.go index 18959966..e43ce26a 100644 --- a/cfg/filebackend_test.go +++ b/cfg/filebackend_test.go @@ -91,10 +91,17 @@ func TestFileSave(t *testing.T) { // Save the config file to a new absolute path using a regular path p = tmpConfPath() +<<<<<<< HEAD c.SetURL(p) u, err = ParseURL(p) if err != nil { t.Error("cannot parse url") +======= + c, err = New(p) + if err != nil { + t.Errorf("Error creating config file") + +>>>>>>> moar test fixes } err = backend.Save(c) if err != nil { From 4ea480a3253dc2b3ad430ec5bb40257d8ceff118 Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Sun, 10 May 2020 15:49:37 +0200 Subject: [PATCH 10/14] One more test --- cfg/config_windows_test.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cfg/config_windows_test.go b/cfg/config_windows_test.go index 2c2b412e..73429571 100644 --- a/cfg/config_windows_test.go +++ b/cfg/config_windows_test.go @@ -11,3 +11,10 @@ func TestWindowsStylePaths(t *testing.T) { t.Errorf("Backend for %s should be a FileBackend", conf.URL().Raw) } } + +func TestUnsupportedWindowsPath(t *testing.T) { + _, err := New(`file://c:\foo\bar\beehive.conf`) + if err == nil { + t.Errorf("Invalid Windows file URL Should raise an error") + } +} From f4d111be19a266b0541871399a472963b293b0da Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Sun, 10 May 2020 16:11:42 +0200 Subject: [PATCH 11/14] Missed URL.String() --- cfg/url.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cfg/url.go b/cfg/url.go index cb14fcd0..376b54ab 100644 --- a/cfg/url.go +++ b/cfg/url.go @@ -35,6 +35,10 @@ func ParseURL(rawurl string) (*URL, error) { return &curl, nil } +func (u *URL) String() string { + return u.nurl.String() +} + func (u *URL) NetURL() *url.URL { return u.nurl } From d9b3d517fa4ee2ac19853faab5ed7cd361c5776d Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Sun, 10 May 2020 16:20:59 +0200 Subject: [PATCH 12/14] Fix default path loading under windows --- beehive.go | 2 +- cfg/config.go | 13 ++++++++++++- cfg/helpers_test.go | 12 ------------ 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/beehive.go b/beehive.go index 42d0a004..aeedaf84 100644 --- a/beehive.go +++ b/beehive.go @@ -110,7 +110,7 @@ func main() { if err != nil { log.Fatalf("Error loading configuration file from %s. err: %v", config.URL(), err) } - log.Infof("Loading configuration from %s", config.URL()) + log.Infof("Loading configuration from %s", config.URL().Raw) } else { // try to load default config from user paths path := cfg.Lookup() if path == "" { diff --git a/cfg/config.go b/cfg/config.go index ccf9b33b..e99c6bc7 100644 --- a/cfg/config.go +++ b/cfg/config.go @@ -6,6 +6,7 @@ import ( "path/filepath" "regexp" "runtime" + "strings" "github.com/muesli/beehive/bees" gap "github.com/muesli/go-app-paths" @@ -157,7 +158,7 @@ func DefaultPath() string { return cfgFileName } - return path + return fixWindowsPath(path) } // Lookup tries to find the config file. @@ -201,3 +202,13 @@ func exist(file string) bool { _, err := os.Stat(file) return err == nil } + +// Replace backward slashes in Windows paths with /, to make them suitable +// for Go URL parsing. +func fixWindowsPath(path string) string { + if runtime.GOOS == "windows" { + return strings.Replace(path, `\`, "/", -1) + } + + return path +} diff --git a/cfg/helpers_test.go b/cfg/helpers_test.go index 0e8c7f09..0fb870db 100644 --- a/cfg/helpers_test.go +++ b/cfg/helpers_test.go @@ -4,20 +4,8 @@ import ( "io/ioutil" "os" "path/filepath" - "runtime" - "strings" ) -// Replace backward slashes in Windows paths with /, to make them suitable -// for Go URL parsing. -func fixWindowsPath(path string) string { - if runtime.GOOS == "windows" { - return strings.Replace(path, `\`, "/", -1) - } - - return path -} - func encryptedConfPath() string { cwd, _ := os.Getwd() return fixWindowsPath(filepath.Join(cwd, "testdata", "beehive-crypto.conf")) From d097b0fcec10c4f12db845771e97fdade69affeb Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Sun, 25 Oct 2020 13:41:25 +0100 Subject: [PATCH 13/14] merge fixes --- cfg/aesbackend_test.go | 6 +++--- cfg/filebackend.go | 1 - cfg/filebackend_test.go | 20 +++----------------- 3 files changed, 6 insertions(+), 21 deletions(-) diff --git a/cfg/aesbackend_test.go b/cfg/aesbackend_test.go index b4616cdd..2c8b8470 100644 --- a/cfg/aesbackend_test.go +++ b/cfg/aesbackend_test.go @@ -106,7 +106,7 @@ func TestAESBackendLoad(t *testing.T) { if err != nil { t.Fatalf("Can't parse crypto URL: %v", err) } - conf, err = backend.Load(u) + _, err = backend.Load(u) if err == nil || err.Error() != "encrypted configuration header not valid" { t.Errorf("Loading a non-encrypted config should error") } @@ -125,7 +125,7 @@ func TestAESBackendSave(t *testing.T) { } // Save the config file to a new absolute path using a URL - p := encryptedTempConf() + p = encryptedTempConf() u, err = ParseURL("crypto://" + testPassword + "@" + p) if err != nil { t.Error("cannot parse config url") @@ -137,7 +137,7 @@ func TestAESBackendSave(t *testing.T) { backend, _ = NewAESBackend(u) err = backend.Save(c) if err != nil { - t.Errorf("failed to save the config to %s. %v", newURL, err) + t.Errorf("failed to save the config to %s. %v", u, err) } if !exist(p) { t.Errorf("configuration file wasn't saved to %s", p) diff --git a/cfg/filebackend.go b/cfg/filebackend.go index db91ceb7..6d12d580 100644 --- a/cfg/filebackend.go +++ b/cfg/filebackend.go @@ -31,7 +31,6 @@ func NewFileBackend() *FileBackend { // Load loads chains from config func (fs *FileBackend) Load(u *URL) (*Config, error) { var config Config - fixWinURL(u) // detect file format by extension if strings.HasSuffix(u.Path, ".yaml") { diff --git a/cfg/filebackend_test.go b/cfg/filebackend_test.go index e43ce26a..848bfe3a 100644 --- a/cfg/filebackend_test.go +++ b/cfg/filebackend_test.go @@ -1,11 +1,7 @@ package cfg import ( -<<<<<<< HEAD "io/ioutil" - "net/url" -======= ->>>>>>> :lipstick: "os" "path/filepath" "testing" @@ -23,11 +19,7 @@ func TestFileLoad(t *testing.T) { // try to load the config from a relative path u, err = ParseURL(filepath.Join("testdata", "beehive.conf")) if err != nil { -<<<<<<< HEAD - t.Error("cannot parse config path") -======= t.Fatalf("Can't parse URL. %v", err) ->>>>>>> Test fixes } backend = NewFileBackend() conf, err := backend.Load(u) @@ -56,6 +48,7 @@ func TestFileLoad(t *testing.T) { } func TestFileSave(t *testing.T) { + tmpdir, err := ioutil.TempDir("", "beehivetest") u, err := ParseURL(filepath.Join("testdata", "beehive.conf")) if err != nil { t.Fatalf("Can't parse URL. %v", err) @@ -91,17 +84,10 @@ func TestFileSave(t *testing.T) { // Save the config file to a new absolute path using a regular path p = tmpConfPath() -<<<<<<< HEAD c.SetURL(p) u, err = ParseURL(p) if err != nil { t.Error("cannot parse url") -======= - c, err = New(p) - if err != nil { - t.Errorf("Error creating config file") - ->>>>>>> moar test fixes } err = backend.Save(c) if err != nil { @@ -114,7 +100,7 @@ func TestFileSave(t *testing.T) { func Test_FileLoad_FileSave_YAML(t *testing.T) { // load - u, err := url.Parse(filepath.Join("testdata", "beehive.yaml")) + u, err := ParseURL(filepath.Join("testdata", "beehive.yaml")) if err != nil { t.Error("cannot parse config path") } @@ -132,7 +118,7 @@ func Test_FileLoad_FileSave_YAML(t *testing.T) { t.Error("Could not create temp directory") } p := filepath.Join(tmpdir, "beehive.yaml") - u, err = url.Parse("file://" + p) + u, err = ParseURL("file://" + p) if err != nil { t.Error("cannot parse config path") } From 0fdbdd396b852f954c0834843daf91b08bd6ae91 Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Sun, 25 Oct 2020 13:47:01 +0100 Subject: [PATCH 14/14] Add windows-latest to the test matrix --- .github/workflows/go.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 12b25fc7..3dc6b68c 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -5,7 +5,7 @@ jobs: strategy: matrix: go-version: [1.13.x, 1.14.x, 1.15.x] - os: [ubuntu-latest, macos-latest] + os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} env: GO111MODULE: "on"