Skip to content

Commit

Permalink
upgraded to aws-sdk-go-v2 and added a special middleware for GCP
Browse files Browse the repository at this point in the history
  • Loading branch information
ganigeorgiev committed Feb 5, 2024
1 parent 03a3f98 commit b902901
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 11 deletions.
44 changes: 33 additions & 11 deletions tools/filesystem/filesystem.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ import (
"strconv"
"strings"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/disintegration/imaging"
"github.com/gabriel-vasile/mimetype"
"github.com/pocketbase/pocketbase/tools/list"
Expand All @@ -26,6 +27,8 @@ import (
"gocloud.dev/blob/s3blob"
)

var gcpIgnoreHeaders = []string{"Accept-Encoding"}

type System struct {
ctx context.Context
bucket *blob.Bucket
Expand All @@ -44,19 +47,38 @@ func NewS3(
) (*System, error) {
ctx := context.Background() // default context

cred := credentials.NewStaticCredentials(accessKey, secretKey, "")
cred := credentials.NewStaticCredentialsProvider(accessKey, secretKey, "")

cfg, err := config.LoadDefaultConfig(ctx,
config.WithCredentialsProvider(cred),
config.WithRegion(region),
config.WithEndpointResolverWithOptions(aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) {
// ensure that the endpoint has url scheme for
// backward compatibility with v1 of the aws sdk
prefixedEndpoint := endpoint
if !strings.Contains(endpoint, "://") {
prefixedEndpoint = "https://" + endpoint
}

sess, err := session.NewSession(&aws.Config{
Region: aws.String(region),
Endpoint: aws.String(endpoint),
Credentials: cred,
S3ForcePathStyle: aws.Bool(s3ForcePathStyle),
})
return aws.Endpoint{URL: prefixedEndpoint, SigningRegion: region}, nil
})),
)
if err != nil {
return nil, err
}

bucket, err := s3blob.OpenBucket(ctx, sess, bucketName, nil)
client := s3.NewFromConfig(cfg, func(o *s3.Options) {
o.UsePathStyle = s3ForcePathStyle

// Google Cloud Storage alters the Accept-Encoding header,
// which breaks the v2 request signature
// (https://github.com/aws/aws-sdk-go-v2/issues/1816)
if strings.Contains(endpoint, "storage.googleapis.com") {
ignoreSigningHeaders(o, gcpIgnoreHeaders)
}
})

bucket, err := s3blob.OpenBucketV2(ctx, client, bucketName, nil)
if err != nil {
return nil, err
}
Expand Down
72 changes: 72 additions & 0 deletions tools/filesystem/ignores_signing_headers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package filesystem

import (
"context"
"fmt"

v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/smithy-go/middleware"
smithyhttp "github.com/aws/smithy-go/transport/http"
)

// ignoreSigningHeaders excludes the listed headers
// from the request signing because some providers may alter them.
//
// See https://github.com/aws/aws-sdk-go-v2/issues/1816.
func ignoreSigningHeaders(o *s3.Options, headers []string) {
o.APIOptions = append(o.APIOptions, func(stack *middleware.Stack) error {
if err := stack.Finalize.Insert(ignoreHeaders(headers), "Signing", middleware.Before); err != nil {
return err
}

if err := stack.Finalize.Insert(restoreIgnored(), "Signing", middleware.After); err != nil {
return err
}

return nil
})
}

type ignoredHeadersKey struct{}

func ignoreHeaders(headers []string) middleware.FinalizeMiddleware {
return middleware.FinalizeMiddlewareFunc(
"IgnoreHeaders",
func(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) (out middleware.FinalizeOutput, metadata middleware.Metadata, err error) {
req, ok := in.Request.(*smithyhttp.Request)
if !ok {
return out, metadata, &v4.SigningError{Err: fmt.Errorf("(ignoreHeaders) unexpected request middleware type %T", in.Request)}
}

ignored := make(map[string]string, len(headers))
for _, h := range headers {
ignored[h] = req.Header.Get(h)
req.Header.Del(h)
}

ctx = middleware.WithStackValue(ctx, ignoredHeadersKey{}, ignored)

return next.HandleFinalize(ctx, in)
},
)
}

func restoreIgnored() middleware.FinalizeMiddleware {
return middleware.FinalizeMiddlewareFunc(
"RestoreIgnored",
func(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) (out middleware.FinalizeOutput, metadata middleware.Metadata, err error) {
req, ok := in.Request.(*smithyhttp.Request)
if !ok {
return out, metadata, &v4.SigningError{Err: fmt.Errorf("(restoreIgnored) unexpected request middleware type %T", in.Request)}
}

ignored, _ := middleware.GetStackValue(ctx, ignoredHeadersKey{}).(map[string]string)
for k, v := range ignored {
req.Header.Set(k, v)
}

return next.HandleFinalize(ctx, in)
},
)
}

0 comments on commit b902901

Please sign in to comment.