From 73b880d8fe016568e7b18b9f5bf46fdef6619f5f Mon Sep 17 00:00:00 2001 From: Dominik Schulz Date: Sat, 18 Nov 2023 08:48:32 +0100 Subject: [PATCH] [bugfix] Remove leading and trailing slashes from mounts (#2698) * [bugfix] Remove leading and trailing slashes from mounts Fixes #2669 Signed-off-by: Dominik Schulz * Add tests for leading slashes Signed-off-by: Dominik Schulz * Reorder mount alias checks Signed-off-by: Dominik Schulz --------- Signed-off-by: Dominik Schulz --- internal/store/root/init.go | 1 + internal/store/root/mount.go | 30 +++++++- internal/store/root/mount_test.go | 117 ++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+), 3 deletions(-) diff --git a/internal/store/root/init.go b/internal/store/root/init.go index b3df7cd9b0..69acfaf7ae 100644 --- a/internal/store/root/init.go +++ b/internal/store/root/init.go @@ -29,6 +29,7 @@ func (r *Store) IsInitialized(ctx context.Context) (bool, error) { // Init tries to initialize a new password store location matching the object. func (r *Store) Init(ctx context.Context, alias, path string, ids ...string) error { + alias = CleanMountAlias(alias) debug.Log("Instantiating new sub store %s at %s for %+v", alias, path, ids) if !backend.HasCryptoBackend(ctx) { diff --git a/internal/store/root/mount.go b/internal/store/root/mount.go index 4c8edaa969..5d19963d3b 100644 --- a/internal/store/root/mount.go +++ b/internal/store/root/mount.go @@ -25,9 +25,6 @@ func (r *Store) AddMount(ctx context.Context, alias, path string, keys ...string } func (r *Store) addMount(ctx context.Context, alias, path string, keys ...string) error { - if alias == "" { - return fmt.Errorf("alias must not be empty") - } // disallow filepath separators in alias and always disallow regular slashes // even on Windows, since these are used internally to separate folders. if strings.HasSuffix(alias, "/") { @@ -37,6 +34,11 @@ func (r *Store) addMount(ctx context.Context, alias, path string, keys ...string return fmt.Errorf("alias must not end with '%s'", string(filepath.Separator)) } + alias = CleanMountAlias(alias) + if alias == "" { + return fmt.Errorf("alias must not be empty") + } + if r.mounts == nil { r.mounts = make(map[string]*leaf.Store, 1) } @@ -65,6 +67,7 @@ func (r *Store) addMount(ctx context.Context, alias, path string, keys ...string } func (r *Store) initSub(ctx context.Context, alias, path string, keys []string) (*leaf.Store, error) { + alias = CleanMountAlias(alias) // init regular sub store s, err := leaf.New(ctx, alias, path) if err != nil { @@ -206,3 +209,24 @@ func (r *Store) checkMounts() error { return nil } + +// CleanMountAlias removes all leading and trailing slashes from a mount alias. +// Note: Slashes inside the alias are valid and will be kept. +func CleanMountAlias(alias string) string { + for { + if !strings.HasPrefix(alias, "/") && !strings.HasPrefix(alias, "\\") { + break + } + alias = strings.TrimPrefix(strings.TrimSuffix(alias, "/"), "/") + alias = strings.TrimPrefix(strings.TrimSuffix(alias, "\\"), "\\") + } + for { + if !strings.HasSuffix(alias, "/") && !strings.HasSuffix(alias, "\\") { + break + } + alias = strings.TrimSuffix(strings.TrimPrefix(alias, "/"), "/") + alias = strings.TrimSuffix(strings.TrimPrefix(alias, "\\"), "\\") + } + + return alias +} diff --git a/internal/store/root/mount_test.go b/internal/store/root/mount_test.go index 5b2cbe519a..4151326a26 100644 --- a/internal/store/root/mount_test.go +++ b/internal/store/root/mount_test.go @@ -73,3 +73,120 @@ func TestMountPointIllegal(t *testing.T) { } require.Error(t, rs.AddMount(ctx, "sub2/", u.StoreDir("sub2"))) } + +func TestCleanMountAlias(t *testing.T) { + for _, tc := range []struct { + name string + in, want string + }{ + { + name: "simple", + in: "foo", + want: "foo", + }, + { + name: "simple", + in: "foo/bar", + want: "foo/bar", + }, + { + name: "simple", + in: "foo/bar/", + want: "foo/bar", + }, + { + name: "simple", + in: "foo/bar//", + want: "foo/bar", + }, + { + name: "simple", + in: "foo/bar////", + want: "foo/bar", + }, + { + name: "simple", + in: "foo/bar/////", + want: "foo/bar", + }, + { + name: "simple", + in: "foo/bar//////", + want: "foo/bar", + }, + { + name: "simple", + in: "foo/bar///////", + want: "foo/bar", + }, + { + name: "simple", + in: "foo/bar////////", + want: "foo/bar", + }, + { + name: "simple", + in: "foo/bar/////////", + want: "foo/bar", + }, + { + name: "simple", + in: "foo/bar//////////", + want: "foo/bar", + }, + { + name: "simple", + in: "foo/bar///////////", + want: "foo/bar", + }, + { + name: "simple", + in: "foo/bar////////////", + want: "foo/bar", + }, + { + name: "simple", + in: "foo/bar/////////////", + want: "foo/bar", + }, + { + name: "simple", + in: "foo/bar//////////////", + want: "foo/bar", + }, + { + name: "simple", + in: "foo/bar///////////////", + want: "foo/bar", + }, + { + name: "simple", + in: "foo/bar////////////////", + want: "foo/bar", + }, + { + name: "mixed", + in: "foo/bar/\\///\\////", + want: "foo/bar", + }, + { + name: "simple", + in: "/foo/bar", + want: "foo/bar", + }, + { + name: "simple", + in: "//foo/bar", + want: "foo/bar", + }, + { + name: "simple", + in: "////foo/bar", + want: "foo/bar", + }, + } { + t.Run(tc.name, func(t *testing.T) { + assert.Equal(t, tc.want, CleanMountAlias(tc.in)) + }) + } +}