diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ffa3e94ff..88f4e39fb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,14 @@ This monorepo contains a number of sdk's: Official project releases may be found here: https://github.com/stellar/go-stellar-sdk/releases ## Pending +## [0.3.0] + +### Security Fixes +* historyarchive: Added size bound to `GetPathHAS` to prevent resource exhaustion ([#5918](https://github.com/stellar/go-stellar-sdk/pull/5918)) + +### New Features +* xdr: Added `SafeUnmarshalBase64WithOptions` and regenerated with output size tracking ([#5916](https://github.com/stellar/go-stellar-sdk/pull/5916)) + ## [0.2.0] ### Breaking Changes diff --git a/support/datastore/gcs.go b/support/datastore/gcs.go index 1c3393acdc..0e69376151 100644 --- a/support/datastore/gcs.go +++ b/support/datastore/gcs.go @@ -209,16 +209,11 @@ func (b GCSDataStore) putFile(ctx context.Context, filePath string, in io.Writer func (b GCSDataStore) ListFilePaths(ctx context.Context, options ListFileOptions) ([]string, error) { var fullPrefix string - // When 'prefix' is empty, ensure the base prefix ends with a slash (e.g., "a/b/") - // so the query returns only objects within that directory, not similarly named paths like "a/b-1". - if options.Prefix == "" { - fullPrefix = b.prefix - if !strings.HasSuffix(fullPrefix, "/") { - fullPrefix += "/" - } - } else { - // Join the caller-provided prefix with the datastore prefix - fullPrefix = path.Join(b.prefix, options.Prefix) + // Ensure the prefix ends with a slash so the query returns only objects + // within that directory, not similarly named paths like "a/b-1". + fullPrefix = path.Join(b.prefix, options.Prefix) + if fullPrefix != "" { + fullPrefix += "/" } var StartAfter string diff --git a/support/datastore/gcs_test.go b/support/datastore/gcs_test.go index 516d61583d..2f56eeffb3 100644 --- a/support/datastore/gcs_test.go +++ b/support/datastore/gcs_test.go @@ -437,6 +437,40 @@ func TestGCSListFilePaths(t *testing.T) { require.Equal(t, []string{"a", "b"}, paths) } +func TestGCSListFilePaths_NoPrefix(t *testing.T) { + server := fakestorage.NewServer([]fakestorage.Object{ + { + ObjectAttrs: fakestorage.ObjectAttrs{BucketName: "test-bucket", Name: "a"}, + Content: []byte("1"), + }, + { + ObjectAttrs: fakestorage.ObjectAttrs{BucketName: "test-bucket", Name: "b"}, + Content: []byte("1"), + }, + { + ObjectAttrs: fakestorage.ObjectAttrs{BucketName: "test-bucket", Name: "c"}, + Content: []byte("1"), + }, + }) + defer server.Stop() + + store, err := FromGCSClient(context.Background(), server.Client(), "test-bucket") + require.NoError(t, err) + t.Cleanup(func() { _ = store.Close() }) + + paths, err := store.ListFilePaths(context.Background(), ListFileOptions{}) + require.NoError(t, err) + require.Equal(t, []string{"a", "b", "c"}, paths) + + paths, err = store.ListFilePaths(context.Background(), ListFileOptions{Limit: 2}) + require.NoError(t, err) + require.Equal(t, []string{"a", "b"}, paths) + + paths, err = store.ListFilePaths(context.Background(), ListFileOptions{StartAfter: "a"}) + require.NoError(t, err) + require.Equal(t, []string{"b", "c"}, paths) +} + func TestGCSListFilePaths_WithPrefix(t *testing.T) { server := fakestorage.NewServer([]fakestorage.Object{ { diff --git a/support/datastore/s3.go b/support/datastore/s3.go index 62b2901b70..81817963ce 100644 --- a/support/datastore/s3.go +++ b/support/datastore/s3.go @@ -288,16 +288,11 @@ func (b S3DataStore) putFile(ctx context.Context, filePath string, in io.WriterT func (b S3DataStore) ListFilePaths(ctx context.Context, options ListFileOptions) ([]string, error) { var fullPrefix string - // When 'prefix' is empty, ensure the base prefix ends with a slash (e.g., "a/b/") - // so the query returns only objects within that directory, not similarly named paths like "a/b-1". - if options.Prefix == "" { - fullPrefix = b.prefix - if !strings.HasSuffix(fullPrefix, "/") { - fullPrefix += "/" - } - } else { - // Join the caller-provided prefix with the datastore prefix - fullPrefix = path.Join(b.prefix, options.Prefix) + // Ensure the prefix ends with a slash so the query returns only objects + // within that directory, not similarly named paths like "a/b-1". + fullPrefix = path.Join(b.prefix, options.Prefix) + if fullPrefix != "" { + fullPrefix += "/" } var StartAfter string diff --git a/support/datastore/s3_test.go b/support/datastore/s3_test.go index c89546085a..33830e715f 100644 --- a/support/datastore/s3_test.go +++ b/support/datastore/s3_test.go @@ -256,6 +256,28 @@ func TestS3ListFilePaths(t *testing.T) { require.Equal(t, []string{"a", "b"}, paths) } +func TestS3ListFilePaths_NoPrefix(t *testing.T) { + ctx := context.Background() + store, teardown := setupTestS3DataStore(t, ctx, "test-bucket", map[string]mockS3Object{ + "a": {body: []byte("1")}, + "b": {body: []byte("1")}, + "c": {body: []byte("1")}, + }) + defer teardown() + + paths, err := store.ListFilePaths(context.Background(), ListFileOptions{}) + require.NoError(t, err) + require.Equal(t, []string{"a", "b", "c"}, paths) + + paths, err = store.ListFilePaths(context.Background(), ListFileOptions{Limit: 2}) + require.NoError(t, err) + require.Equal(t, []string{"a", "b"}, paths) + + paths, err = store.ListFilePaths(context.Background(), ListFileOptions{StartAfter: "a"}) + require.NoError(t, err) + require.Equal(t, []string{"b", "c"}, paths) +} + func TestS3ListFilePaths_WithPrefix(t *testing.T) { ctx := context.Background() store, teardown := setupTestS3DataStore(t, ctx, "test-bucket/objects/testnet", map[string]mockS3Object{