Skip to content

Commit

Permalink
fix: upload to s3 in ovh differ than s3 specs (#451)
Browse files Browse the repository at this point in the history
**Describe the pull request**
This pull request addresses an issue where the upload process to S3 in
OVH differs from the standard S3 specifications. The fix involves
aligning the upload process with the standard S3 protocol, ensuring
compatibility and smooth operation. This fix allow user to upload and
access in public-read aby cover uploaded

**Checklist**

- [x] I have made the modifications or added tests related to my PR
- [x] I have run the tests and linters locally and they pass
- [x] I have added/updated the documentation for my RP
  • Loading branch information
42atomys committed May 27, 2023
1 parent 1a2fee3 commit dcf8812
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 30 deletions.
5 changes: 5 additions & 0 deletions config/stud42.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ api:
bucket: s42-users
region: europe-west1
endpoint: http://localhost:9000
# forcePathStyle is used to force the usage of the path style
# in the endpoint. This is used to use minio as a S3 compatible
# storage in local development, or in production with a provider
# that does not support the virtual host style.
forcePathStyle: true

# Interface relatives configurations
interface: {}
Expand Down
1 change: 1 addition & 0 deletions deploy/stacks/apps/configs/stud42/stud42.yaml.tftpl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ api:
bucket: s42-users
region: gra
endpoint: https://s3.gra.io.cloud.ovh.net
forcePathStyle: false


# Interface relatives configurations
Expand Down
44 changes: 15 additions & 29 deletions internal/api/api.resolvers.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

88 changes: 88 additions & 0 deletions internal/pkg/s3/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package s3

import (
"fmt"
"regexp"
"time"

"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/service/s3"
"github.com/spf13/viper"
)

type S3Client struct {
cfg *viper.Viper
*s3.S3
}

// BucketConfigKey is a type for bucket config keys
// that are used to get bucket config from viper
// config file. This is not the bucket name itself.
type BucketConfigKey string

const (
// UsersBucketConfigKey is a bucket config key for users bucket
// This is not the bucket name itself.
UsersBucketConfigKey BucketConfigKey = "users"
)

// NewS3Client creates a new S3 client with the given bucket config key.
func NewS3Client(bucketConfigKey BucketConfigKey) (*S3Client, error) {
cfg := viper.Sub("api.s3." + string(UsersBucketConfigKey))
s, err := session.NewSession(aws.NewConfig().
WithEndpoint(cfg.GetString("endpoint")).
WithRegion(cfg.GetString("region")).
WithCredentials(credentials.NewCredentials(&credentials.EnvProvider{})),
)
if err != nil {
return nil, err
}

return &S3Client{
cfg: cfg,
S3: s3.New(
s,
aws.NewConfig().
WithS3ForcePathStyle(cfg.GetBool("forcePathStyle")),
),
}, nil
}

// PresignedUploadURL returns a presigned upload URL for the given key.
// The URL will expire after the given expiration duration. The URL will
// be valid for the given content type and content length and will be
// uploaded with the given ACL.
func (c *S3Client) PresignedUploadURL(key, contentType string, contentLength int64, acl string, expiration time.Duration) (string, error) {
request, _ := c.PutObjectRequest(&s3.PutObjectInput{
Bucket: aws.String(c.cfg.GetString("bucket")),
Key: aws.String(key),
ContentType: aws.String(contentType),
ContentLength: aws.Int64(contentLength),
ACL: aws.String(acl),
})

return request.Presign(expiration)
}

// GetBucket returns the bucket name from the config.
func (c *S3Client) GetBucket() string {
return c.cfg.GetString("bucket")
}

// GetBaseURL returns the base URL for the bucket. This is used to
// construct the full URL of the bucket based if the bucket is not
// configured to use path style URLs. If the bucket is configured to
// use path style URLs, the base URL will be the same as the endpoint.
func (c *S3Client) GetBaseURL() string {
s3Endpoint := c.cfg.GetString("endpoint")
if !c.cfg.GetBool("forcePathStyle") {
s3Endpoint = regexp.MustCompile(`://`).ReplaceAllString(
s3Endpoint,
fmt.Sprintf("://%s.", c.cfg.GetString("bucket")),
)
}

return s3Endpoint
}
6 changes: 5 additions & 1 deletion web/ui/src/pages/settings/profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,11 @@ const ProfileSettingPage: NextPage<PageProps> = () => {
fetch(presignedURL, {
method: 'PUT',
body: coverFile,
headers: { 'Content-Type': coverFile.type },
headers: {
'Content-Type': coverFile.type,
'Content-Length': coverFile.size.toString(),
'x-amz-acl': 'public-read',
},
}).then(async (d) => {
if (!d.ok) {
return addNotification({
Expand Down

0 comments on commit dcf8812

Please sign in to comment.