Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions blob/memory/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ const (
uploadURL = "https://upload.blobs.test/"
downloadURLPrefix = "https://cdn.blobs.test/"

uploadTTL = 15 * time.Minute
uploadTTL = 15 * time.Minute
downloadTTL = 15 * time.Minute
)

// Storage is an in-memory blob.ObjectStorage for tests. It stands in for the
Expand Down Expand Up @@ -88,8 +89,11 @@ func (s *Storage) DeleteUpload(_ context.Context, key string) error {
return nil
}

func (s *Storage) SignDownloadURL(_ context.Context, key string) (string, error) {
return downloadURLPrefix + key, nil
func (s *Storage) SignDownloadURL(_ context.Context, key string) (*blobpb.DownloadUrl, error) {
return &blobpb.DownloadUrl{
Url: downloadURLPrefix + key,
ExpiresAt: timestamppb.New(time.Now().Add(downloadTTL)),
}, nil
}

// SimulateUpload stores bytes as if the client had POSTed them to the presigned
Expand Down
12 changes: 8 additions & 4 deletions blob/s3/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,13 +282,17 @@ func (s *Storage) DeleteUpload(ctx context.Context, key string) error {
return nil
}

func (s *Storage) SignDownloadURL(_ context.Context, key string) (string, error) {
func (s *Storage) SignDownloadURL(_ context.Context, key string) (*blobpb.DownloadUrl, error) {
expiresAt := time.Now().Add(s.cfg.DownloadTTL)
rawURL := strings.TrimRight(s.cfg.CDNBaseURL, "/") + "/" + key
signed, err := s.signer.Sign(rawURL, time.Now().Add(s.cfg.DownloadTTL))
signed, err := s.signer.Sign(rawURL, expiresAt)
if err != nil {
return "", fmt.Errorf("failed to sign download url: %w", err)
return nil, fmt.Errorf("failed to sign download url: %w", err)
}
return signed, nil
return &blobpb.DownloadUrl{
Url: signed,
ExpiresAt: timestamppb.New(expiresAt),
}, nil
}

// sigV4SigningKey derives the SigV4 signing key for the S3 service.
Expand Down
25 changes: 20 additions & 5 deletions blob/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,9 +207,18 @@ func (s *Server) CompleteExternalUpload(ctx context.Context, req *blobpb.Complet
return nil, status.Error(codes.Unavailable, "upload not yet finalized")
}

// todo: Support rejection metadata
var rejectionMetadata *blobpb.RejectionMetadata
if finalStatus == blobpb.BlobStatus_BLOB_STATUS_REJECTED {
rejectionMetadata = &blobpb.RejectionMetadata{
Reason: blobpb.RejectionReason_REJECTION_REASON_INTERNAL,
}
}

return &blobpb.CompleteExternalUploadResponse{
Result: blobpb.CompleteExternalUploadResponse_OK,
Status: finalStatus,
Result: blobpb.CompleteExternalUploadResponse_OK,
Status: finalStatus,
RejectionMetadata: rejectionMetadata,
}, nil
}

Expand Down Expand Up @@ -243,9 +252,10 @@ func (s *Server) GetBlobs(ctx context.Context, req *blobpb.GetBlobsRequest) (*bl
Status: blobStatus,
}

// download_url and the rest of the metadata are only meaningful, and only
// minted, for a servable (READY) blob.
if blobStatus == blobpb.BlobStatus_BLOB_STATUS_READY {
switch blobStatus {
case blobpb.BlobStatus_BLOB_STATUS_READY:
// download_url and the rest of the metadata are only meaningful, and only
// minted, for a servable (READY) blob.
metadata, err := s.buildMetadata(ctx, record)
if err != nil {
s.log.Warn("Failed to mint blob metadata",
Expand All @@ -255,6 +265,11 @@ func (s *Server) GetBlobs(ctx context.Context, req *blobpb.GetBlobsRequest) (*bl
return nil, status.Error(codes.Internal, "failed to get blobs")
}
protoBlob.Metadata = metadata
case blobpb.BlobStatus_BLOB_STATUS_REJECTED:
// todo: Support rejection metadata
protoBlob.Rejection = &blobpb.RejectionMetadata{
Reason: blobpb.RejectionReason_REJECTION_REASON_INTERNAL,
}
}

resolved = append(resolved, protoBlob)
Expand Down
7 changes: 4 additions & 3 deletions blob/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,10 @@ type ObjectStorage interface {
DeleteUpload(ctx context.Context, key string) error

// SignDownloadURL mints a fresh, short-lived CDN URL for fetching a promoted
// object's bytes from the ORIGIN store. It is authorized at mint time and
// expires on its own, so callers mint a new one rather than persisting it.
SignDownloadURL(ctx context.Context, key string) (string, error)
// object's bytes from the ORIGIN store, paired with the instant it expires. It
// is authorized at mint time and expires on its own, so callers mint a new one
// rather than persisting it.
SignDownloadURL(ctx context.Context, key string) (*blobpb.DownloadUrl, error)
}

// StorageKey derives the object key for an image blob's bytes from its id and
Expand Down
6 changes: 5 additions & 1 deletion blob/tests/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"image/color"
"image/png"
"testing"
"time"

"github.com/stretchr/testify/require"
"go.uber.org/zap/zaptest"
Expand Down Expand Up @@ -274,7 +275,10 @@ func testGetBlobs(t *testing.T, accounts account.Store, blobs blob.Store, storag
require.NotNil(t, got.Metadata)
require.Equal(t, "image/png", got.Metadata.MimeType)
require.EqualValues(t, len(imageBytes), got.Metadata.SizeBytes)
require.NotEmpty(t, got.Metadata.DownloadUrl)
require.NotNil(t, got.Metadata.DownloadUrl)
require.NotEmpty(t, got.Metadata.DownloadUrl.Url)
require.NotNil(t, got.Metadata.DownloadUrl.ExpiresAt)
require.True(t, got.Metadata.DownloadUrl.ExpiresAt.AsTime().After(time.Now()))
image := got.Metadata.GetImage()
require.NotNil(t, image)
require.EqualValues(t, 10, image.Width)
Expand Down
3 changes: 1 addition & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.42.3
github.com/aws/smithy-go v1.27.1
github.com/buckket/go-blurhash v1.1.0
github.com/code-payments/flipcash2-protobuf-api v1.14.1-0.20260629164249-229024d1e8f3
github.com/code-payments/flipcash2-protobuf-api v1.14.1-0.20260629203049-f1014792ec00
github.com/code-payments/ocp-protobuf-api v1.13.2-0.20260610171241-de46af911053
github.com/code-payments/ocp-server v1.19.0
github.com/devsisters/go-applereceipt v0.0.0-20240805020915-fa22a0160fc2
Expand Down Expand Up @@ -101,7 +101,6 @@ require (
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/steebchen/prisma-client-go v0.47.0 // indirect
github.com/tyler-smith/go-bip39 v1.1.0 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
Expand Down
6 changes: 2 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ github.com/cockroachdb/cockroach-go/v2 v2.2.0 h1:/5znzg5n373N/3ESjHF5SMLxiW4RKB0
github.com/cockroachdb/cockroach-go/v2 v2.2.0/go.mod h1:u3MiKYGupPPjkn3ozknpMUpxPaNLTFWAya419/zv6eI=
github.com/code-payments/code-vm-indexer v1.2.0 h1:rSHpBMiT9BKgmKcXg/VIoi/h0t7jNxGx07Qz59m+6Q0=
github.com/code-payments/code-vm-indexer v1.2.0/go.mod h1:vn91YN2qNqb+gGJeZe2+l+TNxVmEEiRHXXnIn2Y40h8=
github.com/code-payments/flipcash2-protobuf-api v1.14.1-0.20260629164249-229024d1e8f3 h1:UqbDRlTMBuRMr7R+k/LrwnEBYjkZhWQStwIqrFryEd4=
github.com/code-payments/flipcash2-protobuf-api v1.14.1-0.20260629164249-229024d1e8f3/go.mod h1:s/1pOsb4FTRD+LcvRKGjfmm6ygRS/m1ep34EIW0fuDs=
github.com/code-payments/flipcash2-protobuf-api v1.14.1-0.20260629203049-f1014792ec00 h1:YT5cVHI5610PW6vvPUjgHqV3FzmWdIXKcBqH6ngX9/o=
github.com/code-payments/flipcash2-protobuf-api v1.14.1-0.20260629203049-f1014792ec00/go.mod h1:s/1pOsb4FTRD+LcvRKGjfmm6ygRS/m1ep34EIW0fuDs=
github.com/code-payments/ocp-protobuf-api v1.13.2-0.20260610171241-de46af911053 h1:0B96K7/z7TpFbAJeyzP43A0eM58Ie/KRuu5U6PUrses=
github.com/code-payments/ocp-protobuf-api v1.13.2-0.20260610171241-de46af911053/go.mod h1:tw6BooY5a8l6CtSZnKOruyKII0W04n89pcM4BizrgG8=
github.com/code-payments/ocp-server v1.19.0 h1:l4cznUxOAmaclHKpJANJ2zE3LTXg+BDBbRhl+r66lFI=
Expand Down Expand Up @@ -316,8 +316,6 @@ github.com/smartystreets/assertions v1.13.1 h1:Ef7KhSmjZcK6AVf9YbJdvPYG9avaF0Zxu
github.com/smartystreets/assertions v1.13.1/go.mod h1:cXr/IwVfSo/RbCSPhoAPv73p3hlSdrBH/b3SdnW/LMY=
github.com/smartystreets/goconvey v1.8.0 h1:Oi49ha/2MURE0WexF052Z0m+BNSGirfjg5RL+JXWq3w=
github.com/smartystreets/goconvey v1.8.0/go.mod h1:EdX8jtrTIj26jmjCOVNMVSIYAtgexqXKHOXW2Dx9JLg=
github.com/steebchen/prisma-client-go v0.47.0 h1:mKelgkcGPcIardjTP5diGq6hvnueQc/DYEyQ+6uZ0/E=
github.com/steebchen/prisma-client-go v0.47.0/go.mod h1:i1B0PEaE+BUcBUiwvd9drWpyMG/zNYMRrD5MancMf2I=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
Expand Down
Loading