diff --git a/fs/config/configfile/configfile_test.go b/fs/config/configfile/configfile_test.go index 8ec7cd518..be77bb6cc 100644 --- a/fs/config/configfile/configfile_test.go +++ b/fs/config/configfile/configfile_test.go @@ -2,6 +2,7 @@ package configfile import ( "fmt" + "io" "os" "path/filepath" "runtime" @@ -362,3 +363,39 @@ func TestConfigFileSaveSymlinkAbsolute(t *testing.T) { testSymlink(t, link, target, resolvedTarget) }) } + +type pipedInput struct { + io.Reader +} + +func (p *pipedInput) Read(b []byte) (int, error) { + return p.Reader.Read(b) +} + +func (_ *pipedInput) Seek(_ int64, _ int) (int64, error) { + return 0, fmt.Errorf("Seek not supported") +} + +func TestPipedConfig(t *testing.T) { + t.Run("DoesNotSupportSeeking", func(t *testing.T) { + r := &pipedInput{strings.NewReader("")} + _, err := r.Seek(0, io.SeekStart) + require.Error(t, err) + }) + + t.Run("IsSupported", func(t *testing.T) { + r := &pipedInput{strings.NewReader(configData)} + _, err := config.Decrypt(r) + require.NoError(t, err) + }) + + t.Run("PlainTextConfigIsNotConsumedByCryptCheck", func(t *testing.T) { + in := &pipedInput{strings.NewReader(configData)} + + r, _ := config.Decrypt(in) + got, err := io.ReadAll(r) + require.NoError(t, err) + + assert.Equal(t, configData, string(got)) + }) +} diff --git a/fs/config/crypt.go b/fs/config/crypt.go index 4b356580c..c111fbbbe 100644 --- a/fs/config/crypt.go +++ b/fs/config/crypt.go @@ -77,8 +77,9 @@ func Decrypt(b io.ReadSeeker) (io.Reader, error) { if strings.HasPrefix(l, "RCLONE_ENCRYPT_V") { return nil, errors.New("unsupported configuration encryption - update rclone for support") } + // Restore non-seekable plain-text stream to its original state if _, err := b.Seek(0, io.SeekStart); err != nil { - return nil, err + return io.MultiReader(strings.NewReader(l+"\n"), r), nil } return b, nil }