satellite/metainfo: respect MaxObjectTTL in BeginObject

If MaxObjectTTL is set in the API key, BeginObject will use it for the
object expiration time, unless an explicit ExpireAt is available in the
request.

Context: https://github.com/storj/storj/issues/6249

Change-Id: I2adf57d979a9c68eec3a787f3739d2f1dbec1f7e
This commit is contained in:
Kaloyan Raev 2023-09-07 14:34:51 +03:00 committed by Storj Robot
parent 8d1a765fd6
commit 4e499fb9bf
8 changed files with 191 additions and 42 deletions

6
go.mod
View File

@ -61,11 +61,11 @@ require (
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e
gopkg.in/segmentio/analytics-go.v3 v3.1.0
gopkg.in/yaml.v3 v3.0.1
storj.io/common v0.0.0-20230906110953-ed8a53d568d8
storj.io/common v0.0.0-20230907123639-5fd0608fd947
storj.io/drpc v0.0.33
storj.io/monkit-jaeger v0.0.0-20220915074555-d100d7589f41
storj.io/private v0.0.0-20230824104110-1eac532af65a
storj.io/uplink v1.11.1-0.20230905131215-412de374f05c
storj.io/uplink v1.11.1-0.20230907104623-a2e90d4e0c18
)
require (
@ -140,5 +140,5 @@ require (
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
storj.io/picobuf v0.0.1 // indirect
storj.io/picobuf v0.0.2-0.20230906122608-c4ba17033c6c // indirect
)

12
go.sum
View File

@ -1012,16 +1012,16 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
storj.io/common v0.0.0-20220719163320-cd2ef8e1b9b0/go.mod h1:mCYV6Ud5+cdbuaxdPD5Zht/HYaIn0sffnnws9ErkrMQ=
storj.io/common v0.0.0-20230906110953-ed8a53d568d8 h1:DdgIPSCTZ2/b4hBfkTgsVKw0xI6yc1qzeBSdZZeRA1M=
storj.io/common v0.0.0-20230906110953-ed8a53d568d8/go.mod h1:9evX8PZey+J3bcflXmR666E8GW4uRy5EDiVvg8iER7s=
storj.io/common v0.0.0-20230907123639-5fd0608fd947 h1:X75A5hX1nFjQH8GIvei4T1LNQTLa++bsDKMxXxfPHE8=
storj.io/common v0.0.0-20230907123639-5fd0608fd947/go.mod h1:FMVOxf2+SgsmfjxwFCM1MZCKwXis4U7l22M/6nIhIas=
storj.io/drpc v0.0.32/go.mod h1:6rcOyR/QQkSTX/9L5ZGtlZaE2PtXTTZl8d+ulSeeYEg=
storj.io/drpc v0.0.33 h1:yCGZ26r66ZdMP0IcTYsj7WDAUIIjzXk6DJhbhvt9FHI=
storj.io/drpc v0.0.33/go.mod h1:vR804UNzhBa49NOJ6HeLjd2H3MakC1j5Gv8bsOQT6N4=
storj.io/monkit-jaeger v0.0.0-20220915074555-d100d7589f41 h1:SVuEocEhZfFc13J1AmlVLitdGXTVrvmbzN4Z9C9Ms40=
storj.io/monkit-jaeger v0.0.0-20220915074555-d100d7589f41/go.mod h1:iK+dmHZZXQlW7ahKdNSOo+raMk5BDL2wbD62FIeXLWs=
storj.io/picobuf v0.0.1 h1:ekEvxSQCbEjTVIi/qxj2za13SJyfRE37yE30IBkZeT0=
storj.io/picobuf v0.0.1/go.mod h1:7ZTAMs6VesgTHbbhFU79oQ9hDaJ+MD4uoFQZ1P4SEz0=
storj.io/picobuf v0.0.2-0.20230906122608-c4ba17033c6c h1:or/DtG5uaZpzimL61ahlgAA+MTYn/U3txz4fe+XBFUg=
storj.io/picobuf v0.0.2-0.20230906122608-c4ba17033c6c/go.mod h1:JCuc3C0gzCJHQ4J6SOx/Yjg+QTpX0D+Fvs5H46FETCk=
storj.io/private v0.0.0-20230824104110-1eac532af65a h1:x0OnU7z801JmR0XwFrFxmEBqcq+FDDuSn5jMbFoyfBo=
storj.io/private v0.0.0-20230824104110-1eac532af65a/go.mod h1:6+MGr4KUXEBIOsOstFz1efPkA+8wVVfzsO8RpuAhhB4=
storj.io/uplink v1.11.1-0.20230905131215-412de374f05c h1:UBrHiML8mRU+8qBPTMuw2WHVwwmUjfenJ17QpO1Erp8=
storj.io/uplink v1.11.1-0.20230905131215-412de374f05c/go.mod h1:JOUmWW3FrzCkDK4wgrTonKrKTWafK7jRQA8zBb8mkxs=
storj.io/uplink v1.11.1-0.20230907104623-a2e90d4e0c18 h1:xAC4VhvSQpMbUesyvQGBEORTQ64ZBK3+RfJWWa9zVbY=
storj.io/uplink v1.11.1-0.20230907104623-a2e90d4e0c18/go.mod h1:JOUmWW3FrzCkDK4wgrTonKrKTWafK7jRQA8zBb8mkxs=

View File

@ -63,8 +63,26 @@ func (endpoint *Endpoint) BeginObject(ctx context.Context, req *pb.ObjectBeginRe
}
endpoint.usageTracking(keyInfo, req.Header, fmt.Sprintf("%T", req))
if !req.ExpiresAt.IsZero() && !req.ExpiresAt.After(time.Now()) {
return nil, rpcstatus.Error(rpcstatus.InvalidArgument, "Invalid expiration time")
maxObjectTTL, err := endpoint.getMaxObjectTTL(ctx, req.Header)
if err != nil {
return nil, err
}
if !req.ExpiresAt.IsZero() {
if req.ExpiresAt.Before(now) {
return nil, rpcstatus.Error(rpcstatus.InvalidArgument, "invalid expiration time, cannot be in the past")
}
if maxObjectTTL != nil && req.ExpiresAt.After(now.Add(*maxObjectTTL)) {
return nil, rpcstatus.Errorf(rpcstatus.InvalidArgument, "invalid expiration time, cannot be longer than %v", maxObjectTTL)
}
}
var expiresAt time.Time
if !req.ExpiresAt.IsZero() {
expiresAt = req.ExpiresAt
} else if maxObjectTTL != nil {
ttl := now.Add(*maxObjectTTL)
expiresAt = ttl
}
// we can do just basic name validation because later we are checking bucket in DB
@ -75,7 +93,7 @@ func (endpoint *Endpoint) BeginObject(ctx context.Context, req *pb.ObjectBeginRe
objectKeyLength := len(req.EncryptedObjectKey)
if objectKeyLength > endpoint.config.MaxEncryptedObjectKeyLength {
return nil, rpcstatus.Error(rpcstatus.InvalidArgument, fmt.Sprintf("key length is too big, got %v, maximum allowed is %v", objectKeyLength, endpoint.config.MaxEncryptedObjectKeyLength))
return nil, rpcstatus.Errorf(rpcstatus.InvalidArgument, "key length is too big, got %v, maximum allowed is %v", objectKeyLength, endpoint.config.MaxEncryptedObjectKeyLength)
}
err = endpoint.checkUploadLimits(ctx, keyInfo.ProjectID)
@ -114,20 +132,14 @@ func (endpoint *Endpoint) BeginObject(ctx context.Context, req *pb.ObjectBeginRe
BlockSize: int32(req.EncryptionParameters.BlockSize), // TODO check conversion
}
var expiresAt *time.Time
if req.ExpiresAt.IsZero() {
expiresAt = nil
} else {
expiresAt = &req.ExpiresAt
}
var nonce []byte
if !req.EncryptedMetadataNonce.IsZero() {
nonce = req.EncryptedMetadataNonce[:]
}
usePendingObjectsTable := endpoint.config.UsePendingObjectsTableByProject(keyInfo.ProjectID)
object, err := endpoint.metabase.BeginObjectNextVersion(ctx, metabase.BeginObjectNextVersion{
opts := metabase.BeginObjectNextVersion{
ObjectStream: metabase.ObjectStream{
ProjectID: keyInfo.ProjectID,
BucketName: string(req.Bucket),
@ -135,7 +147,6 @@ func (endpoint *Endpoint) BeginObject(ctx context.Context, req *pb.ObjectBeginRe
StreamID: streamID,
Version: metabase.NextVersion,
},
ExpiresAt: expiresAt,
Encryption: encryptionParameters,
EncryptedMetadata: req.EncryptedMetadata,
@ -143,7 +154,12 @@ func (endpoint *Endpoint) BeginObject(ctx context.Context, req *pb.ObjectBeginRe
EncryptedMetadataNonce: nonce,
UsePendingObjectsTable: usePendingObjectsTable,
})
}
if !expiresAt.IsZero() {
opts.ExpiresAt = &expiresAt
}
object, err := endpoint.metabase.BeginObjectNextVersion(ctx, opts)
if err != nil {
return nil, endpoint.convertMetabaseErr(err)
}
@ -153,7 +169,7 @@ func (endpoint *Endpoint) BeginObject(ctx context.Context, req *pb.ObjectBeginRe
EncryptedObjectKey: []byte(object.ObjectKey),
Version: int64(object.Version),
CreationDate: object.CreatedAt,
ExpirationDate: req.ExpiresAt, // TODO make ExpirationDate nullable
ExpirationDate: expiresAt, // TODO make ExpirationDate nullable
StreamId: object.StreamID[:],
MultipartObject: object.FixedSegmentSize <= 0,
EncryptionParameters: req.EncryptionParameters,
@ -178,6 +194,25 @@ func (endpoint *Endpoint) BeginObject(ctx context.Context, req *pb.ObjectBeginRe
}, nil
}
func (endpoint *Endpoint) getMaxObjectTTL(ctx context.Context, header *pb.RequestHeader) (_ *time.Duration, err error) {
key, err := getAPIKey(ctx, header)
if err != nil {
return nil, rpcstatus.Errorf(rpcstatus.InvalidArgument, "Invalid API credentials: %v", err)
}
ttl, err := key.GetMaxObjectTTL(ctx)
if err != nil {
endpoint.log.Error("unable to get max object TTL", zap.Error(err))
return nil, rpcstatus.Error(rpcstatus.Internal, "unable to get max object TTL")
}
if ttl != nil && *ttl <= 0 {
return nil, rpcstatus.Errorf(rpcstatus.InvalidArgument, "invalid MaxObjectTTL in API key: %v", ttl)
}
return ttl, nil
}
// CommitObject commits an object when all its segments have already been committed.
func (endpoint *Endpoint) CommitObject(ctx context.Context, req *pb.ObjectCommitRequest) (resp *pb.ObjectCommitResponse, err error) {
defer mon.Task()(&ctx)(&err)

View File

@ -24,6 +24,7 @@ import (
"storj.io/common/errs2"
"storj.io/common/identity"
"storj.io/common/identity/testidentity"
"storj.io/common/macaroon"
"storj.io/common/memory"
"storj.io/common/nodetag"
"storj.io/common/pb"
@ -606,7 +607,7 @@ func TestEndpoint_Object_No_StorageNodes(t *testing.T) {
_, err = metainfoClient.BeginObject(ctx, params)
require.Error(t, err)
require.Contains(t, err.Error(), "Invalid expiration time")
require.Contains(t, err.Error(), "invalid expiration time")
require.True(t, errs2.IsRPC(err, rpcstatus.InvalidArgument))
})
@ -982,6 +983,119 @@ func TestEndpoint_Object_UploadLimit(t *testing.T) {
})
}
func TestEndpoint_BeginObject_MaxObjectTTL(t *testing.T) {
testplanet.Run(t, testplanet.Config{
SatelliteCount: 1, UplinkCount: 1,
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
apiKey := planet.Uplinks[0].APIKey[planet.Satellites[0].ID()]
endpoint := planet.Satellites[0].Metainfo.Endpoint
bucketName := "testbucket"
err := planet.Uplinks[0].CreateBucket(ctx, planet.Satellites[0], bucketName)
require.NoError(t, err)
t.Run("object upload with max object ttl", func(t *testing.T) {
now := time.Now()
zero := 0 * time.Hour
oneHour := time.Hour
minusOneHour := -oneHour
type TestCases struct {
maxObjectTTL *time.Duration
expiresAt time.Time
expectedExpiration time.Time
expectedErr bool
}
for _, tc := range []TestCases{
{
maxObjectTTL: nil,
expiresAt: time.Time{},
expectedExpiration: time.Time{},
expectedErr: false,
},
{
maxObjectTTL: &oneHour,
expiresAt: time.Time{},
expectedExpiration: now.Add(time.Hour),
expectedErr: false,
},
{
maxObjectTTL: &oneHour,
expiresAt: now.Add(30 * time.Minute),
expectedExpiration: now.Add(30 * time.Minute),
expectedErr: false,
},
{
maxObjectTTL: &oneHour,
expiresAt: now.Add(2 * time.Hour),
expectedExpiration: time.Time{},
expectedErr: true,
},
{
maxObjectTTL: &zero,
expiresAt: time.Time{},
expectedExpiration: time.Time{},
expectedErr: true,
},
{
maxObjectTTL: &minusOneHour,
expiresAt: time.Time{},
expectedExpiration: time.Time{},
expectedErr: true,
},
} {
t.Run("", func(t *testing.T) {
restrictedAPIKey := apiKey
if tc.maxObjectTTL != nil {
restrictedAPIKey, err = restrictedAPIKey.Restrict(macaroon.Caveat{
MaxObjectTtl: tc.maxObjectTTL,
})
}
require.NoError(t, err)
objectKey := testrand.Bytes(10)
beginResp, err := endpoint.BeginObject(ctx, &pb.BeginObjectRequest{
Header: &pb.RequestHeader{
ApiKey: restrictedAPIKey.SerializeRaw(),
},
Bucket: []byte(bucketName),
EncryptedObjectKey: objectKey,
ExpiresAt: tc.expiresAt,
EncryptionParameters: &pb.EncryptionParameters{
CipherSuite: pb.CipherSuite_ENC_AESGCM,
},
})
if tc.expectedErr {
require.Error(t, err)
return
}
require.NoError(t, err)
satStreamID := &internalpb.StreamID{}
err = pb.Unmarshal(beginResp.StreamId, satStreamID)
require.NoError(t, err)
require.WithinDuration(t, tc.expectedExpiration, satStreamID.ExpirationDate, time.Minute)
listResp, err := endpoint.ListPendingObjectStreams(ctx, &pb.ListPendingObjectStreamsRequest{
Header: &pb.RequestHeader{
ApiKey: restrictedAPIKey.SerializeRaw(),
},
Bucket: []byte(bucketName),
EncryptedObjectKey: objectKey,
})
require.NoError(t, err)
require.Len(t, listResp.Items, 1)
require.WithinDuration(t, tc.expectedExpiration, listResp.Items[0].ExpiresAt, time.Minute)
})
}
})
})
}
// TODO remove when listing query tests feature flag is removed.
func TestEndpoint_Object_No_StorageNodes_TestListingQuery(t *testing.T) {
testplanet.Run(t, testplanet.Config{

View File

@ -9,11 +9,11 @@ require (
github.com/zeebo/errs v1.3.0
go.uber.org/zap v1.21.0
golang.org/x/sync v0.3.0
storj.io/common v0.0.0-20230906110953-ed8a53d568d8
storj.io/common v0.0.0-20230907123639-5fd0608fd947
storj.io/private v0.0.0-20230824104110-1eac532af65a
storj.io/storj v1.63.1
storj.io/storjscan v0.0.0-20220926140643-1623c3b391b0
storj.io/uplink v1.11.1-0.20230905131215-412de374f05c
storj.io/uplink v1.11.1-0.20230907104623-a2e90d4e0c18
)
require (
@ -159,5 +159,5 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect
storj.io/drpc v0.0.33 // indirect
storj.io/monkit-jaeger v0.0.0-20220915074555-d100d7589f41 // indirect
storj.io/picobuf v0.0.1 // indirect
storj.io/picobuf v0.0.2-0.20230906122608-c4ba17033c6c // indirect
)

View File

@ -1254,18 +1254,18 @@ rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
storj.io/common v0.0.0-20220719163320-cd2ef8e1b9b0/go.mod h1:mCYV6Ud5+cdbuaxdPD5Zht/HYaIn0sffnnws9ErkrMQ=
storj.io/common v0.0.0-20230906110953-ed8a53d568d8 h1:DdgIPSCTZ2/b4hBfkTgsVKw0xI6yc1qzeBSdZZeRA1M=
storj.io/common v0.0.0-20230906110953-ed8a53d568d8/go.mod h1:9evX8PZey+J3bcflXmR666E8GW4uRy5EDiVvg8iER7s=
storj.io/common v0.0.0-20230907123639-5fd0608fd947 h1:X75A5hX1nFjQH8GIvei4T1LNQTLa++bsDKMxXxfPHE8=
storj.io/common v0.0.0-20230907123639-5fd0608fd947/go.mod h1:FMVOxf2+SgsmfjxwFCM1MZCKwXis4U7l22M/6nIhIas=
storj.io/drpc v0.0.32/go.mod h1:6rcOyR/QQkSTX/9L5ZGtlZaE2PtXTTZl8d+ulSeeYEg=
storj.io/drpc v0.0.33 h1:yCGZ26r66ZdMP0IcTYsj7WDAUIIjzXk6DJhbhvt9FHI=
storj.io/drpc v0.0.33/go.mod h1:vR804UNzhBa49NOJ6HeLjd2H3MakC1j5Gv8bsOQT6N4=
storj.io/monkit-jaeger v0.0.0-20220915074555-d100d7589f41 h1:SVuEocEhZfFc13J1AmlVLitdGXTVrvmbzN4Z9C9Ms40=
storj.io/monkit-jaeger v0.0.0-20220915074555-d100d7589f41/go.mod h1:iK+dmHZZXQlW7ahKdNSOo+raMk5BDL2wbD62FIeXLWs=
storj.io/picobuf v0.0.1 h1:ekEvxSQCbEjTVIi/qxj2za13SJyfRE37yE30IBkZeT0=
storj.io/picobuf v0.0.1/go.mod h1:7ZTAMs6VesgTHbbhFU79oQ9hDaJ+MD4uoFQZ1P4SEz0=
storj.io/picobuf v0.0.2-0.20230906122608-c4ba17033c6c h1:or/DtG5uaZpzimL61ahlgAA+MTYn/U3txz4fe+XBFUg=
storj.io/picobuf v0.0.2-0.20230906122608-c4ba17033c6c/go.mod h1:JCuc3C0gzCJHQ4J6SOx/Yjg+QTpX0D+Fvs5H46FETCk=
storj.io/private v0.0.0-20230824104110-1eac532af65a h1:x0OnU7z801JmR0XwFrFxmEBqcq+FDDuSn5jMbFoyfBo=
storj.io/private v0.0.0-20230824104110-1eac532af65a/go.mod h1:6+MGr4KUXEBIOsOstFz1efPkA+8wVVfzsO8RpuAhhB4=
storj.io/storjscan v0.0.0-20220926140643-1623c3b391b0 h1:pSfGf9E9OlUd17W7LSpL4tTONIyFji6dz8I2iTDd8BY=
storj.io/storjscan v0.0.0-20220926140643-1623c3b391b0/go.mod h1:5nLgAOl1KTDVyqORAhvrp+167PtShEuS1L3pJgXPjwo=
storj.io/uplink v1.11.1-0.20230905131215-412de374f05c h1:UBrHiML8mRU+8qBPTMuw2WHVwwmUjfenJ17QpO1Erp8=
storj.io/uplink v1.11.1-0.20230905131215-412de374f05c/go.mod h1:JOUmWW3FrzCkDK4wgrTonKrKTWafK7jRQA8zBb8mkxs=
storj.io/uplink v1.11.1-0.20230907104623-a2e90d4e0c18 h1:xAC4VhvSQpMbUesyvQGBEORTQ64ZBK3+RfJWWa9zVbY=
storj.io/uplink v1.11.1-0.20230907104623-a2e90d4e0c18/go.mod h1:JOUmWW3FrzCkDK4wgrTonKrKTWafK7jRQA8zBb8mkxs=

View File

@ -10,7 +10,7 @@ require (
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.8.4
go.uber.org/zap v1.23.0
storj.io/common v0.0.0-20230906110953-ed8a53d568d8
storj.io/common v0.0.0-20230907123639-5fd0608fd947
storj.io/gateway-mt v1.51.1-0.20230417204402-7d9bb25bc297
storj.io/private v0.0.0-20230824104110-1eac532af65a
storj.io/storj v0.12.1-0.20221125175451-ef4b564b82f7
@ -232,6 +232,6 @@ require (
storj.io/gateway v1.8.4-0.20230411184137-387420cf640f // indirect
storj.io/minio v0.0.0-20230118205046-c025fcc9eef3 // indirect
storj.io/monkit-jaeger v0.0.0-20220915074555-d100d7589f41 // indirect
storj.io/picobuf v0.0.1 // indirect
storj.io/uplink v1.11.1-0.20230905131215-412de374f05c // indirect
storj.io/picobuf v0.0.2-0.20230906122608-c4ba17033c6c // indirect
storj.io/uplink v1.11.1-0.20230907104623-a2e90d4e0c18 // indirect
)

View File

@ -1969,8 +1969,8 @@ sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
storj.io/common v0.0.0-20220719163320-cd2ef8e1b9b0/go.mod h1:mCYV6Ud5+cdbuaxdPD5Zht/HYaIn0sffnnws9ErkrMQ=
storj.io/common v0.0.0-20230906110953-ed8a53d568d8 h1:DdgIPSCTZ2/b4hBfkTgsVKw0xI6yc1qzeBSdZZeRA1M=
storj.io/common v0.0.0-20230906110953-ed8a53d568d8/go.mod h1:9evX8PZey+J3bcflXmR666E8GW4uRy5EDiVvg8iER7s=
storj.io/common v0.0.0-20230907123639-5fd0608fd947 h1:X75A5hX1nFjQH8GIvei4T1LNQTLa++bsDKMxXxfPHE8=
storj.io/common v0.0.0-20230907123639-5fd0608fd947/go.mod h1:FMVOxf2+SgsmfjxwFCM1MZCKwXis4U7l22M/6nIhIas=
storj.io/dotworld v0.0.0-20210324183515-0d11aeccd840 h1:oqMwoF6vaOrCe92SKRyr8cc2WSjLYAd8fjpAHA7rNqY=
storj.io/drpc v0.0.32/go.mod h1:6rcOyR/QQkSTX/9L5ZGtlZaE2PtXTTZl8d+ulSeeYEg=
storj.io/drpc v0.0.33 h1:yCGZ26r66ZdMP0IcTYsj7WDAUIIjzXk6DJhbhvt9FHI=
@ -1983,10 +1983,10 @@ storj.io/minio v0.0.0-20230118205046-c025fcc9eef3 h1:FT3ChvMha2DIwCQE49Pbkj+k+oQ
storj.io/minio v0.0.0-20230118205046-c025fcc9eef3/go.mod h1:3knaZE6oHV2TQA/H2hQ00llsP3cJixUALYznzkP3enY=
storj.io/monkit-jaeger v0.0.0-20220915074555-d100d7589f41 h1:SVuEocEhZfFc13J1AmlVLitdGXTVrvmbzN4Z9C9Ms40=
storj.io/monkit-jaeger v0.0.0-20220915074555-d100d7589f41/go.mod h1:iK+dmHZZXQlW7ahKdNSOo+raMk5BDL2wbD62FIeXLWs=
storj.io/picobuf v0.0.1 h1:ekEvxSQCbEjTVIi/qxj2za13SJyfRE37yE30IBkZeT0=
storj.io/picobuf v0.0.1/go.mod h1:7ZTAMs6VesgTHbbhFU79oQ9hDaJ+MD4uoFQZ1P4SEz0=
storj.io/picobuf v0.0.2-0.20230906122608-c4ba17033c6c h1:or/DtG5uaZpzimL61ahlgAA+MTYn/U3txz4fe+XBFUg=
storj.io/picobuf v0.0.2-0.20230906122608-c4ba17033c6c/go.mod h1:JCuc3C0gzCJHQ4J6SOx/Yjg+QTpX0D+Fvs5H46FETCk=
storj.io/private v0.0.0-20230824104110-1eac532af65a h1:x0OnU7z801JmR0XwFrFxmEBqcq+FDDuSn5jMbFoyfBo=
storj.io/private v0.0.0-20230824104110-1eac532af65a/go.mod h1:6+MGr4KUXEBIOsOstFz1efPkA+8wVVfzsO8RpuAhhB4=
storj.io/uplink v1.11.1-0.20230905131215-412de374f05c h1:UBrHiML8mRU+8qBPTMuw2WHVwwmUjfenJ17QpO1Erp8=
storj.io/uplink v1.11.1-0.20230905131215-412de374f05c/go.mod h1:JOUmWW3FrzCkDK4wgrTonKrKTWafK7jRQA8zBb8mkxs=
storj.io/uplink v1.11.1-0.20230907104623-a2e90d4e0c18 h1:xAC4VhvSQpMbUesyvQGBEORTQ64ZBK3+RfJWWa9zVbY=
storj.io/uplink v1.11.1-0.20230907104623-a2e90d4e0c18/go.mod h1:JOUmWW3FrzCkDK4wgrTonKrKTWafK7jRQA8zBb8mkxs=
storj.io/zipper v0.0.0-20220124122551-2ac2d53a46f6 h1:vJQmb+uAiYn8hVfkhMl6OqjnUyMWSCPnkzW8IsjF8vE=