[#604] Add support of MFADelete argument and x-amz-mfa header
All checks were successful
/ DCO (pull_request) Successful in 27s
/ Vulncheck (pull_request) Successful in 1m13s
/ Builds (pull_request) Successful in 1m47s
/ OCI image (pull_request) Successful in 2m13s
/ Lint (pull_request) Successful in 2m42s
/ Tests (pull_request) Successful in 1m23s
All checks were successful
/ DCO (pull_request) Successful in 27s
/ Vulncheck (pull_request) Successful in 1m13s
/ Builds (pull_request) Successful in 1m47s
/ OCI image (pull_request) Successful in 2m13s
/ Lint (pull_request) Successful in 2m42s
/ Tests (pull_request) Successful in 1m23s
Signed-off-by: Pavel Pogodaev <p.pogodaev@yadro.com>
This commit is contained in:
parent
e184b333e4
commit
bd3620dabc
26 changed files with 814 additions and 88 deletions
5
api/cache/cache_test.go
vendored
5
api/cache/cache_test.go
vendored
|
@ -173,7 +173,10 @@ func TestSettingsCacheType(t *testing.T) {
|
||||||
cache := NewSystemCache(DefaultSystemConfig(logger))
|
cache := NewSystemCache(DefaultSystemConfig(logger))
|
||||||
|
|
||||||
key := "key"
|
key := "key"
|
||||||
settings := &data.BucketSettings{Versioning: data.VersioningEnabled}
|
settings := &data.BucketSettings{Versioning: data.Versioning{
|
||||||
|
VersioningStatus: data.VersioningEnabled,
|
||||||
|
MFADeleteStatus: data.MFADeleteEnabled,
|
||||||
|
}}
|
||||||
|
|
||||||
err := cache.PutSettings(key, settings)
|
err := cache.PutSettings(key, settings)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
|
@ -20,6 +20,9 @@ const (
|
||||||
VersioningUnversioned = "Unversioned"
|
VersioningUnversioned = "Unversioned"
|
||||||
VersioningEnabled = "Enabled"
|
VersioningEnabled = "Enabled"
|
||||||
VersioningSuspended = "Suspended"
|
VersioningSuspended = "Suspended"
|
||||||
|
|
||||||
|
MFADeleteDisabled = "Disabled"
|
||||||
|
MFADeleteEnabled = "Enabled"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
@ -55,12 +58,19 @@ type (
|
||||||
|
|
||||||
// BucketSettings stores settings such as versioning.
|
// BucketSettings stores settings such as versioning.
|
||||||
BucketSettings struct {
|
BucketSettings struct {
|
||||||
Versioning string
|
Versioning Versioning
|
||||||
LockConfiguration *ObjectLockConfiguration
|
LockConfiguration *ObjectLockConfiguration
|
||||||
CannedACL string
|
CannedACL string
|
||||||
OwnerKey *keys.PublicKey
|
OwnerKey *keys.PublicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Versioning stores bucket versioning settings.
|
||||||
|
Versioning struct {
|
||||||
|
VersioningStatus string
|
||||||
|
MFADeleteStatus string
|
||||||
|
MFASerialNumber string
|
||||||
|
}
|
||||||
|
|
||||||
// CORSConfiguration stores CORS configuration of a request.
|
// CORSConfiguration stores CORS configuration of a request.
|
||||||
CORSConfiguration struct {
|
CORSConfiguration struct {
|
||||||
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ CORSConfiguration" json:"-"`
|
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ CORSConfiguration" json:"-"`
|
||||||
|
@ -130,15 +140,19 @@ func (o *ObjectInfo) ETag(md5Enabled bool) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b BucketSettings) Unversioned() bool {
|
func (b BucketSettings) Unversioned() bool {
|
||||||
return b.Versioning == VersioningUnversioned
|
return b.Versioning.VersioningStatus == VersioningUnversioned
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b BucketSettings) VersioningEnabled() bool {
|
func (b BucketSettings) VersioningEnabled() bool {
|
||||||
return b.Versioning == VersioningEnabled
|
return b.Versioning.VersioningStatus == VersioningEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b BucketSettings) VersioningSuspended() bool {
|
func (b BucketSettings) VersioningSuspended() bool {
|
||||||
return b.Versioning == VersioningSuspended
|
return b.Versioning.VersioningStatus == VersioningSuspended
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b BucketSettings) MFADeleteEnabled() bool {
|
||||||
|
return b.Versioning.MFADeleteStatus == MFADeleteEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
func Quote(val string) string {
|
func Quote(val string) string {
|
||||||
|
|
|
@ -142,6 +142,7 @@ const (
|
||||||
ErrInvalidTagDirective
|
ErrInvalidTagDirective
|
||||||
// Add new error codes here.
|
// Add new error codes here.
|
||||||
ErrNotSupported
|
ErrNotSupported
|
||||||
|
ErrMFAAuthNeeded
|
||||||
|
|
||||||
// SSE-S3 related API errors.
|
// SSE-S3 related API errors.
|
||||||
ErrInvalidEncryptionMethod
|
ErrInvalidEncryptionMethod
|
||||||
|
@ -286,7 +287,7 @@ const (
|
||||||
|
|
||||||
ErrPostPolicyConditionInvalidFormat
|
ErrPostPolicyConditionInvalidFormat
|
||||||
|
|
||||||
//CORS configuration errors.
|
// CORS configuration errors.
|
||||||
ErrCORSUnsupportedMethod
|
ErrCORSUnsupportedMethod
|
||||||
ErrCORSWildcardExposeHeaders
|
ErrCORSWildcardExposeHeaders
|
||||||
|
|
||||||
|
@ -387,6 +388,12 @@ var errorCodes = errorCodeMap{
|
||||||
Description: "Access Denied.",
|
Description: "Access Denied.",
|
||||||
HTTPStatusCode: http.StatusForbidden,
|
HTTPStatusCode: http.StatusForbidden,
|
||||||
},
|
},
|
||||||
|
ErrMFAAuthNeeded: {
|
||||||
|
ErrCode: ErrMFAAuthNeeded,
|
||||||
|
Code: "AccessDenied",
|
||||||
|
Description: "Mfa Authentication must be used for this request",
|
||||||
|
HTTPStatusCode: http.StatusForbidden,
|
||||||
|
},
|
||||||
ErrAccessControlListNotSupported: {
|
ErrAccessControlListNotSupported: {
|
||||||
ErrCode: ErrAccessControlListNotSupported,
|
ErrCode: ErrAccessControlListNotSupported,
|
||||||
Code: "AccessControlListNotSupported",
|
Code: "AccessControlListNotSupported",
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
|
"git.frostfs.info/pogpp/mfa"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -24,6 +25,7 @@ type (
|
||||||
cfg Config
|
cfg Config
|
||||||
ape APE
|
ape APE
|
||||||
frostfsid FrostFSID
|
frostfsid FrostFSID
|
||||||
|
mfa *mfa.Manager
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config contains data which handler needs to keep.
|
// Config contains data which handler needs to keep.
|
||||||
|
@ -68,7 +70,7 @@ const (
|
||||||
var _ api.Handler = (*handler)(nil)
|
var _ api.Handler = (*handler)(nil)
|
||||||
|
|
||||||
// New creates new api.Handler using given logger and client.
|
// New creates new api.Handler using given logger and client.
|
||||||
func New(log *zap.Logger, obj *layer.Layer, cfg Config, storage APE, ffsid FrostFSID) (api.Handler, error) {
|
func New(log *zap.Logger, obj *layer.Layer, cfg Config, storage APE, ffsid FrostFSID, mfaMgr *mfa.Manager) (api.Handler, error) {
|
||||||
switch {
|
switch {
|
||||||
case obj == nil:
|
case obj == nil:
|
||||||
return nil, errors.New("empty FrostFS Object Layer")
|
return nil, errors.New("empty FrostFS Object Layer")
|
||||||
|
@ -86,6 +88,7 @@ func New(log *zap.Logger, obj *layer.Layer, cfg Config, storage APE, ffsid Frost
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
ape: storage,
|
ape: storage,
|
||||||
frostfsid: ffsid,
|
frostfsid: ffsid,
|
||||||
|
mfa: mfaMgr,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
|
"github.com/pquerna/otp/totp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// limitation of AWS https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjects.html
|
// limitation of AWS https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjects.html
|
||||||
|
@ -81,6 +82,26 @@ func (h *handler) DeleteObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(versionID) > 0 && bktSettings.MFADeleteEnabled() {
|
||||||
|
serialNumber, token, err := h.getMFAHeader(r)
|
||||||
|
if err != nil {
|
||||||
|
h.logAndSendError(ctx, w, "could not get mfa header", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
device, err := h.mfa.GetMFADevice(ctx, reqInfo.Namespace, nameFromArn(serialNumber))
|
||||||
|
if err != nil {
|
||||||
|
h.logAndSendError(ctx, w, "could not get mfa device", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
validate := totp.Validate(token, device.Key.Secret())
|
||||||
|
if !validate {
|
||||||
|
h.logAndSendError(ctx, w, "could not validate token", reqInfo, fmt.Errorf("mfa Authentication must be used for this request"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
networkInfo, err := h.obj.GetNetworkInfo(ctx)
|
networkInfo, err := h.obj.GetNetworkInfo(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(ctx, w, "could not get network info", reqInfo, err)
|
h.logAndSendError(ctx, w, "could not get network info", reqInfo, err)
|
||||||
|
@ -181,6 +202,26 @@ func (h *handler) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *http.Re
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if haveVersionedObjects(requested.Objects) && bktSettings.MFADeleteEnabled() {
|
||||||
|
serialNumber, token, err := h.getMFAHeader(r)
|
||||||
|
if err != nil {
|
||||||
|
h.logAndSendError(ctx, w, "could not get mfa header", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
device, err := h.mfa.GetMFADevice(ctx, reqInfo.Namespace, nameFromArn(serialNumber))
|
||||||
|
if err != nil {
|
||||||
|
h.logAndSendError(ctx, w, "could not get mfa device", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
validate := totp.Validate(token, device.Key.Secret())
|
||||||
|
if !validate {
|
||||||
|
h.logAndSendError(ctx, w, "could not validate token", reqInfo, fmt.Errorf("mfa Authentication must be used for this request"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
networkInfo, err := h.obj.GetNetworkInfo(ctx)
|
networkInfo, err := h.obj.GetNetworkInfo(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(ctx, w, "could not get network info", reqInfo, err)
|
h.logAndSendError(ctx, w, "could not get network info", reqInfo, err)
|
||||||
|
@ -280,3 +321,12 @@ func (h *handler) DeleteBucketHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
w.WriteHeader(http.StatusNoContent)
|
w.WriteHeader(http.StatusNoContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func haveVersionedObjects(objects []ObjectIdentifier) bool {
|
||||||
|
for _, o := range objects {
|
||||||
|
if len(o.VersionID) > 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
@ -437,7 +437,10 @@ func createTestBucketWithLock(hc *handlerContext, bktName string, conf *data.Obj
|
||||||
sp := &layer.PutSettingsParams{
|
sp := &layer.PutSettingsParams{
|
||||||
BktInfo: bktInfo,
|
BktInfo: bktInfo,
|
||||||
Settings: &data.BucketSettings{
|
Settings: &data.BucketSettings{
|
||||||
Versioning: data.VersioningEnabled,
|
Versioning: data.Versioning{
|
||||||
|
VersioningStatus: data.VersioningEnabled,
|
||||||
|
MFADeleteStatus: data.MFADeleteDisabled,
|
||||||
|
},
|
||||||
LockConfiguration: conf,
|
LockConfiguration: conf,
|
||||||
OwnerKey: key.PublicKey(),
|
OwnerKey: key.PublicKey(),
|
||||||
},
|
},
|
||||||
|
|
|
@ -842,12 +842,15 @@ func (h *handler) createBucketHandlerPolicy(w http.ResponseWriter, r *http.Reque
|
||||||
Settings: &data.BucketSettings{
|
Settings: &data.BucketSettings{
|
||||||
CannedACL: cannedACL,
|
CannedACL: cannedACL,
|
||||||
OwnerKey: key,
|
OwnerKey: key,
|
||||||
Versioning: data.VersioningUnversioned,
|
Versioning: data.Versioning{
|
||||||
|
VersioningStatus: data.VersioningUnversioned,
|
||||||
|
MFADeleteStatus: data.MFADeleteDisabled,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.ObjectLockEnabled {
|
if p.ObjectLockEnabled {
|
||||||
sp.Settings.Versioning = data.VersioningEnabled
|
sp.Settings.Versioning.VersioningStatus = data.VersioningEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
err = retryer.MakeWithRetry(ctx, func() error {
|
err = retryer.MakeWithRetry(ctx, func() error {
|
||||||
|
|
|
@ -138,3 +138,17 @@ func parseRange(s string) (*layer.RangeParams, error) {
|
||||||
End: values[1],
|
End: values[1],
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func nameFromArn(arn string) string {
|
||||||
|
pts := strings.Split(arn, "/")
|
||||||
|
return pts[len(pts)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *handler) getMFAHeader(r *http.Request) (string, string, error) {
|
||||||
|
parts := strings.Split(r.Header.Get(api.AmzMFA), " ")
|
||||||
|
if len(parts) != 2 {
|
||||||
|
return "", "", fmt.Errorf("%w: invalid mfa header", apierr.GetAPIError(apierr.ErrMFAAuthNeeded))
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts[0], parts[1], nil
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
|
"github.com/pquerna/otp/totp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *handler) PutBucketVersioningHandler(w http.ResponseWriter, r *http.Request) {
|
func (h *handler) PutBucketVersioningHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -31,14 +32,47 @@ func (h *handler) PutBucketVersioningHandler(w http.ResponseWriter, r *http.Requ
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// settings pointer is stored in the cache, so modify a copy of the settings
|
||||||
|
newSettings := *settings
|
||||||
|
|
||||||
|
if len(configuration.MfaDelete) > 0 {
|
||||||
|
serialNumber, token, err := h.getMFAHeader(r)
|
||||||
|
if err != nil {
|
||||||
|
h.logAndSendError(ctx, w, "invalid x-amz-mfa header", reqInfo, errors.GetAPIError(errors.ErrBadRequest))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
name := nameFromArn(serialNumber)
|
||||||
|
device, err := h.mfa.GetMFADevice(ctx, reqInfo.Namespace, name)
|
||||||
|
if err != nil {
|
||||||
|
h.logAndSendError(ctx, w, "get mfa device", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ok := totp.Validate(token, device.Key.Secret())
|
||||||
|
if !ok {
|
||||||
|
h.logAndSendError(ctx, w, "validation error", reqInfo, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch configuration.MfaDelete {
|
||||||
|
case data.MFADeleteEnabled:
|
||||||
|
newSettings.Versioning.MFADeleteStatus = data.MFADeleteEnabled
|
||||||
|
newSettings.Versioning.MFASerialNumber = serialNumber
|
||||||
|
case data.MFADeleteDisabled:
|
||||||
|
newSettings.Versioning.MFADeleteStatus = data.MFADeleteDisabled
|
||||||
|
default:
|
||||||
|
h.logAndSendError(ctx, w, "failed to get mfa configuration", reqInfo, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if configuration.Status != data.VersioningEnabled && configuration.Status != data.VersioningSuspended {
|
if configuration.Status != data.VersioningEnabled && configuration.Status != data.VersioningSuspended {
|
||||||
h.logAndSendError(ctx, w, "invalid versioning configuration", reqInfo, errors.GetAPIError(errors.ErrMalformedXML))
|
h.logAndSendError(ctx, w, "invalid versioning configuration", reqInfo, errors.GetAPIError(errors.ErrMalformedXML))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// settings pointer is stored in the cache, so modify a copy of the settings
|
newSettings.Versioning.VersioningStatus = configuration.Status
|
||||||
newSettings := *settings
|
|
||||||
newSettings.Versioning = configuration.Status
|
|
||||||
|
|
||||||
p := &layer.PutSettingsParams{
|
p := &layer.PutSettingsParams{
|
||||||
BktInfo: bktInfo,
|
BktInfo: bktInfo,
|
||||||
|
@ -80,7 +114,10 @@ func (h *handler) GetBucketVersioningHandler(w http.ResponseWriter, r *http.Requ
|
||||||
func formVersioningConfiguration(settings *data.BucketSettings) *VersioningConfiguration {
|
func formVersioningConfiguration(settings *data.BucketSettings) *VersioningConfiguration {
|
||||||
res := &VersioningConfiguration{}
|
res := &VersioningConfiguration{}
|
||||||
if !settings.Unversioned() {
|
if !settings.Unversioned() {
|
||||||
res.Status = settings.Versioning
|
res.Status = settings.Versioning.VersioningStatus
|
||||||
|
}
|
||||||
|
if settings.MFADeleteEnabled() {
|
||||||
|
res.MfaDelete = "Enabled"
|
||||||
}
|
}
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
|
@ -15,6 +15,7 @@ const (
|
||||||
AmzCopySource = "X-Amz-Copy-Source"
|
AmzCopySource = "X-Amz-Copy-Source"
|
||||||
AmzCopySourceRange = "X-Amz-Copy-Source-Range"
|
AmzCopySourceRange = "X-Amz-Copy-Source-Range"
|
||||||
AmzDate = "X-Amz-Date"
|
AmzDate = "X-Amz-Date"
|
||||||
|
AmzMFA = "X-Amz-Mfa"
|
||||||
|
|
||||||
LastModified = "Last-Modified"
|
LastModified = "Last-Modified"
|
||||||
Date = "Date"
|
Date = "Date"
|
||||||
|
|
|
@ -13,7 +13,10 @@ func TestObjectLockAttributes(t *testing.T) {
|
||||||
tc := prepareContext(t)
|
tc := prepareContext(t)
|
||||||
err := tc.layer.PutBucketSettings(tc.ctx, &PutSettingsParams{
|
err := tc.layer.PutBucketSettings(tc.ctx, &PutSettingsParams{
|
||||||
BktInfo: tc.bktInfo,
|
BktInfo: tc.bktInfo,
|
||||||
Settings: &data.BucketSettings{Versioning: data.VersioningEnabled},
|
Settings: &data.BucketSettings{Versioning: data.Versioning{
|
||||||
|
VersioningStatus: data.VersioningEnabled,
|
||||||
|
MFADeleteStatus: data.MFADeleteDisabled,
|
||||||
|
}},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
|
|
@ -216,7 +216,10 @@ func (n *Layer) GetBucketSettings(ctx context.Context, bktInfo *data.BucketInfo)
|
||||||
if !errors.Is(err, tree.ErrNodeNotFound) {
|
if !errors.Is(err, tree.ErrNodeNotFound) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
settings = &data.BucketSettings{Versioning: data.VersioningUnversioned}
|
settings = &data.BucketSettings{Versioning: data.Versioning{
|
||||||
|
VersioningStatus: data.VersioningUnversioned,
|
||||||
|
MFADeleteStatus: data.MFADeleteDisabled,
|
||||||
|
}}
|
||||||
n.reqLogger(ctx).Debug(logs.BucketSettingsNotFoundUseDefaults, logs.TagField(logs.TagDatapath))
|
n.reqLogger(ctx).Debug(logs.BucketSettingsNotFoundUseDefaults, logs.TagField(logs.TagDatapath))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -197,7 +197,10 @@ func TestSimpleVersioning(t *testing.T) {
|
||||||
tc := prepareContext(t)
|
tc := prepareContext(t)
|
||||||
err := tc.layer.PutBucketSettings(tc.ctx, &PutSettingsParams{
|
err := tc.layer.PutBucketSettings(tc.ctx, &PutSettingsParams{
|
||||||
BktInfo: tc.bktInfo,
|
BktInfo: tc.bktInfo,
|
||||||
Settings: &data.BucketSettings{Versioning: data.VersioningEnabled},
|
Settings: &data.BucketSettings{Versioning: data.Versioning{
|
||||||
|
VersioningStatus: data.VersioningEnabled,
|
||||||
|
MFADeleteStatus: data.MFADeleteDisabled,
|
||||||
|
}},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
@ -234,7 +237,10 @@ func TestSimpleNoVersioning(t *testing.T) {
|
||||||
|
|
||||||
func TestVersioningDeleteObject(t *testing.T) {
|
func TestVersioningDeleteObject(t *testing.T) {
|
||||||
tc := prepareContext(t)
|
tc := prepareContext(t)
|
||||||
settings := &data.BucketSettings{Versioning: data.VersioningEnabled}
|
settings := &data.BucketSettings{Versioning: data.Versioning{
|
||||||
|
VersioningStatus: data.VersioningEnabled,
|
||||||
|
MFADeleteStatus: data.MFADeleteDisabled,
|
||||||
|
}}
|
||||||
err := tc.layer.PutBucketSettings(tc.ctx, &PutSettingsParams{
|
err := tc.layer.PutBucketSettings(tc.ctx, &PutSettingsParams{
|
||||||
BktInfo: tc.bktInfo,
|
BktInfo: tc.bktInfo,
|
||||||
Settings: settings,
|
Settings: settings,
|
||||||
|
@ -256,7 +262,10 @@ func TestGetUnversioned(t *testing.T) {
|
||||||
objContent := []byte("content obj1 v1")
|
objContent := []byte("content obj1 v1")
|
||||||
objInfo := tc.putObject(objContent)
|
objInfo := tc.putObject(objContent)
|
||||||
|
|
||||||
settings := &data.BucketSettings{Versioning: data.VersioningUnversioned}
|
settings := &data.BucketSettings{Versioning: data.Versioning{
|
||||||
|
VersioningStatus: data.VersioningUnversioned,
|
||||||
|
MFADeleteStatus: data.MFADeleteDisabled,
|
||||||
|
}}
|
||||||
err := tc.layer.PutBucketSettings(tc.ctx, &PutSettingsParams{
|
err := tc.layer.PutBucketSettings(tc.ctx, &PutSettingsParams{
|
||||||
BktInfo: tc.bktInfo,
|
BktInfo: tc.bktInfo,
|
||||||
Settings: settings,
|
Settings: settings,
|
||||||
|
@ -270,7 +279,10 @@ func TestGetUnversioned(t *testing.T) {
|
||||||
|
|
||||||
func TestVersioningDeleteSpecificObjectVersion(t *testing.T) {
|
func TestVersioningDeleteSpecificObjectVersion(t *testing.T) {
|
||||||
tc := prepareContext(t)
|
tc := prepareContext(t)
|
||||||
settings := &data.BucketSettings{Versioning: data.VersioningEnabled}
|
settings := &data.BucketSettings{Versioning: data.Versioning{
|
||||||
|
VersioningStatus: data.VersioningEnabled,
|
||||||
|
MFADeleteStatus: data.MFADeleteDisabled,
|
||||||
|
}}
|
||||||
err := tc.layer.PutBucketSettings(tc.ctx, &PutSettingsParams{
|
err := tc.layer.PutBucketSettings(tc.ctx, &PutSettingsParams{
|
||||||
BktInfo: tc.bktInfo,
|
BktInfo: tc.bktInfo,
|
||||||
Settings: settings,
|
Settings: settings,
|
||||||
|
|
|
@ -37,6 +37,7 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/services"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/services"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
internalnet "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/net"
|
internalnet "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/net"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/unlocker"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/version"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/version"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/wallet"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/wallet"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/metrics"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/metrics"
|
||||||
|
@ -48,6 +49,7 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool"
|
||||||
treepool "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool/tree"
|
treepool "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool/tree"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||||
|
"git.frostfs.info/pogpp/mfa"
|
||||||
"github.com/go-chi/chi/v5/middleware"
|
"github.com/go-chi/chi/v5/middleware"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/panjf2000/ants/v2"
|
"github.com/panjf2000/ants/v2"
|
||||||
|
@ -645,7 +647,7 @@ func (s *appSettings) TombstoneLifetime() uint64 {
|
||||||
|
|
||||||
func (a *App) initAPI(ctx context.Context) {
|
func (a *App) initAPI(ctx context.Context) {
|
||||||
a.initLayer(ctx)
|
a.initLayer(ctx)
|
||||||
a.initHandler()
|
a.initHandler(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) initMetrics() {
|
func (a *App) initMetrics() {
|
||||||
|
@ -1188,15 +1190,51 @@ func getFrostfsIDCacheConfig(v *viper.Viper, l *zap.Logger) *cache.Config {
|
||||||
return cacheCfg
|
return cacheCfg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) initHandler() {
|
func (a *App) initHandler(ctx context.Context) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
a.api, err = handler.New(a.log, a.obj, a.settings, a.policyStorage, a.frostfsid)
|
var mfaCnrInfo *data.BucketInfo
|
||||||
|
if a.config().IsSet(cfgContainersMFA) {
|
||||||
|
mfaCnrInfo, err = a.fetchContainerInfo(ctx, cfgContainersMFA)
|
||||||
|
if err != nil {
|
||||||
|
a.log.Fatal(logs.CouldNotFetchMFAContainerInfo, zap.Error(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mfaConfig, err := a.fetchMFAConfig(mfaCnrInfo.CID)
|
||||||
|
if err != nil {
|
||||||
|
a.log.Fatal(logs.CouldNotInitMFAClient, zap.Error(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
manager, err := mfa.NewManager(mfaConfig)
|
||||||
|
if err != nil {
|
||||||
|
a.log.Fatal(logs.CouldNotInitMFAClient, zap.Error(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
a.api, err = handler.New(a.log, a.obj, a.settings, a.policyStorage, a.frostfsid, manager)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.log.Fatal(logs.CouldNotInitializeAPIHandler, zap.Error(err), logs.TagField(logs.TagApp))
|
a.log.Fatal(logs.CouldNotInitializeAPIHandler, zap.Error(err), logs.TagField(logs.TagApp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) fetchMFAConfig(id cid.ID) (mfa.Config, error) {
|
||||||
|
mfaFrostFS := frostfs.NewMFAFrostFS(frostfs.MFAFrostFSConfig{
|
||||||
|
Pool: a.pool,
|
||||||
|
TreePool: a.treePool,
|
||||||
|
Key: a.key,
|
||||||
|
Logger: a.log,
|
||||||
|
})
|
||||||
|
|
||||||
|
config := mfa.Config{
|
||||||
|
Storage: mfaFrostFS,
|
||||||
|
Unlocker: unlocker.NewUnlocker(a.key, fetchIAMServices(a.config())),
|
||||||
|
Container: id,
|
||||||
|
Logger: a.log,
|
||||||
|
}
|
||||||
|
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) getServer(address string) Server {
|
func (a *App) getServer(address string) Server {
|
||||||
for i := range a.servers {
|
for i := range a.servers {
|
||||||
if a.servers[i].Address() == address {
|
if a.servers[i].Address() == address {
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/version"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/version"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
@ -222,6 +223,10 @@ const (
|
||||||
cfgContainersCORS = "containers.cors"
|
cfgContainersCORS = "containers.cors"
|
||||||
cfgContainersLifecycle = "containers.lifecycle"
|
cfgContainersLifecycle = "containers.lifecycle"
|
||||||
cfgContainersAccessBox = "containers.accessbox"
|
cfgContainersAccessBox = "containers.accessbox"
|
||||||
|
cfgContainersMFA = "containers.mfa"
|
||||||
|
|
||||||
|
// IAM.
|
||||||
|
cfgIAMKeys = "iam_services"
|
||||||
|
|
||||||
// Multinet.
|
// Multinet.
|
||||||
cfgMultinetEnabled = "multinet.enabled"
|
cfgMultinetEnabled = "multinet.enabled"
|
||||||
|
@ -902,6 +907,22 @@ func fetchMultinetConfig(v *viper.Viper, logger *zap.Logger) (cfg internalnet.Co
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fetchIAMServices(v *viper.Viper) []*keys.PublicKey {
|
||||||
|
var res []*keys.PublicKey
|
||||||
|
for i := 0; ; i++ {
|
||||||
|
key := cfgIAMKeys + "." + strconv.Itoa(i)
|
||||||
|
value := v.GetString(key)
|
||||||
|
|
||||||
|
fromString, err := keys.NewPublicKeyFromString(value)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
res = append(res, fromString)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
func fetchTracingAttributes(v *viper.Viper) (map[string]string, error) {
|
func fetchTracingAttributes(v *viper.Viper) (map[string]string, error) {
|
||||||
attributes := make(map[string]string)
|
attributes := make(map[string]string)
|
||||||
for i := 0; ; i++ {
|
for i := 0; ; i++ {
|
||||||
|
|
|
@ -269,6 +269,7 @@ S3_GW_RETRY_STRATEGY=exponential
|
||||||
# Containers properties
|
# Containers properties
|
||||||
S3_GW_CONTAINERS_CORS=AZjLTXfK4vs4ovxMic2xEJKSymMNLqdwq9JT64ASFCRj
|
S3_GW_CONTAINERS_CORS=AZjLTXfK4vs4ovxMic2xEJKSymMNLqdwq9JT64ASFCRj
|
||||||
S3_GW_CONTAINERS_LIFECYCLE=AZjLTXfK4vs4ovxMic2xEJKSymMNLqdwq9JT64ASFCRj
|
S3_GW_CONTAINERS_LIFECYCLE=AZjLTXfK4vs4ovxMic2xEJKSymMNLqdwq9JT64ASFCRj
|
||||||
|
S3_GW_CONTAINERS_MFA=HV9h4zbp7Dti2VXef2oFSsBSRyJUR6NfMeswuv12fjZu
|
||||||
|
|
||||||
# Multinet properties
|
# Multinet properties
|
||||||
# Enable multinet support
|
# Enable multinet support
|
||||||
|
|
|
@ -318,6 +318,13 @@ retry:
|
||||||
containers:
|
containers:
|
||||||
cors: AZjLTXfK4vs4ovxMic2xEJKSymMNLqdwq9JT64ASFCRj
|
cors: AZjLTXfK4vs4ovxMic2xEJKSymMNLqdwq9JT64ASFCRj
|
||||||
lifecycle: AZjLTXfK4vs4ovxMic2xEJKSymMNLqdwq9JT64ASFCRj
|
lifecycle: AZjLTXfK4vs4ovxMic2xEJKSymMNLqdwq9JT64ASFCRj
|
||||||
|
mfa: HV9h4zbp7Dti2VXef2oFSsBSRyJUR6NfMeswuv12fjZu
|
||||||
|
|
||||||
|
# Public keys of known IAM services
|
||||||
|
iam_services:
|
||||||
|
- 02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2
|
||||||
|
- 0313b1ac3a8076e155a7e797b24f0b650cccad5941ea59d7cfd51a024a8b2a06bf
|
||||||
|
- 031a6c6fbbdf02ca351745fa86b9ba5a9452d785ac4f7fc2b7548ca2a46c4fcf4a
|
||||||
|
|
||||||
# Multinet properties
|
# Multinet properties
|
||||||
multinet:
|
multinet:
|
||||||
|
|
|
@ -330,7 +330,7 @@ func file_creds_accessbox_accessbox_proto_rawDescGZIP() []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_creds_accessbox_accessbox_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
var file_creds_accessbox_accessbox_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
||||||
var file_creds_accessbox_accessbox_proto_goTypes = []any{
|
var file_creds_accessbox_accessbox_proto_goTypes = []interface{}{
|
||||||
(*AccessBox)(nil), // 0: accessbox.AccessBox
|
(*AccessBox)(nil), // 0: accessbox.AccessBox
|
||||||
(*Tokens)(nil), // 1: accessbox.Tokens
|
(*Tokens)(nil), // 1: accessbox.Tokens
|
||||||
(*AccessBox_Gate)(nil), // 2: accessbox.AccessBox.Gate
|
(*AccessBox_Gate)(nil), // 2: accessbox.AccessBox.Gate
|
||||||
|
@ -352,7 +352,7 @@ func file_creds_accessbox_accessbox_proto_init() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !protoimpl.UnsafeEnabled {
|
if !protoimpl.UnsafeEnabled {
|
||||||
file_creds_accessbox_accessbox_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
file_creds_accessbox_accessbox_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*AccessBox); i {
|
switch v := v.(*AccessBox); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
|
@ -364,7 +364,7 @@ func file_creds_accessbox_accessbox_proto_init() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_creds_accessbox_accessbox_proto_msgTypes[1].Exporter = func(v any, i int) any {
|
file_creds_accessbox_accessbox_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*Tokens); i {
|
switch v := v.(*Tokens); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
|
@ -376,7 +376,7 @@ func file_creds_accessbox_accessbox_proto_init() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_creds_accessbox_accessbox_proto_msgTypes[2].Exporter = func(v any, i int) any {
|
file_creds_accessbox_accessbox_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*AccessBox_Gate); i {
|
switch v := v.(*AccessBox_Gate); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
|
@ -388,7 +388,7 @@ func file_creds_accessbox_accessbox_proto_init() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_creds_accessbox_accessbox_proto_msgTypes[3].Exporter = func(v any, i int) any {
|
file_creds_accessbox_accessbox_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*AccessBox_ContainerPolicy); i {
|
switch v := v.(*AccessBox_ContainerPolicy); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
|
|
|
@ -230,6 +230,11 @@ allowed_access_key_id_prefixes:
|
||||||
reconnect_interval: 1m
|
reconnect_interval: 1m
|
||||||
|
|
||||||
source_ip_header: "Source-Ip"
|
source_ip_header: "Source-Ip"
|
||||||
|
|
||||||
|
iam_services:
|
||||||
|
- 02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2
|
||||||
|
- 0313b1ac3a8076e155a7e797b24f0b650cccad5941ea59d7cfd51a024a8b2a06bf
|
||||||
|
- 031a6c6fbbdf02ca351745fa86b9ba5a9452d785ac4f7fc2b7548ca2a46c4fcf4a
|
||||||
```
|
```
|
||||||
|
|
||||||
| Parameter | Type | SIGHUP reload | Default value | Description |
|
| Parameter | Type | SIGHUP reload | Default value | Description |
|
||||||
|
@ -248,6 +253,7 @@ source_ip_header: "Source-Ip"
|
||||||
| `allowed_access_key_id_prefixes` | `[]string` | no | | List of allowed `AccessKeyID` prefixes which S3 GW serve. If the parameter is omitted, all `AccessKeyID` will be accepted. |
|
| `allowed_access_key_id_prefixes` | `[]string` | no | | List of allowed `AccessKeyID` prefixes which S3 GW serve. If the parameter is omitted, all `AccessKeyID` will be accepted. |
|
||||||
| `reconnect_interval` | `duration` | no | `1m` | Listeners reconnection interval. |
|
| `reconnect_interval` | `duration` | no | `1m` | Listeners reconnection interval. |
|
||||||
| `source_ip_header` | `string` | yes | | Custom header to retrieve Source IP. |
|
| `source_ip_header` | `string` | yes | | Custom header to retrieve Source IP. |
|
||||||
|
| `iam_services` | `[]string` | no | | List of public keys of know IAM services. |
|
||||||
|
|
||||||
### `wallet` section
|
### `wallet` section
|
||||||
|
|
||||||
|
@ -857,6 +863,7 @@ containers:
|
||||||
cors: AZjLTXfK4vs4ovxMic2xEJKSymMNLqdwq9JT64ASFCRj
|
cors: AZjLTXfK4vs4ovxMic2xEJKSymMNLqdwq9JT64ASFCRj
|
||||||
lifecycle: AZjLTXfK4vs4ovxMic2xEJKSymMNLqdwq9JT64ASFCRj
|
lifecycle: AZjLTXfK4vs4ovxMic2xEJKSymMNLqdwq9JT64ASFCRj
|
||||||
accessbox: ExnA1gSY3kzgomi2wJxNyWo1ytWv9VAKXRE55fNXEPL2
|
accessbox: ExnA1gSY3kzgomi2wJxNyWo1ytWv9VAKXRE55fNXEPL2
|
||||||
|
mfa: HV9h4zbp7Dti2VXef2oFSsBSRyJUR6NfMeswuv12fjZu
|
||||||
```
|
```
|
||||||
|
|
||||||
| Parameter | Type | SIGHUP reload | Default value | Description |
|
| Parameter | Type | SIGHUP reload | Default value | Description |
|
||||||
|
@ -864,6 +871,7 @@ containers:
|
||||||
| `cors` | `string` | no | | Container name for CORS configurations. If not set, container of the bucket is used. |
|
| `cors` | `string` | no | | Container name for CORS configurations. If not set, container of the bucket is used. |
|
||||||
| `lifecycle` | `string` | no | | Container name for lifecycle configurations. If not set, container of the bucket is used. |
|
| `lifecycle` | `string` | no | | Container name for lifecycle configurations. If not set, container of the bucket is used. |
|
||||||
| `accessbox` | `string` | no | | Container name to lookup accessbox if custom aws credentials is used. If not set, custom credentials are not supported. |
|
| `accessbox` | `string` | no | | Container name to lookup accessbox if custom aws credentials is used. If not set, custom credentials are not supported. |
|
||||||
|
| `mfa` | `string` | no | | Container name for virtual MFA devices. If not set, MFADeleteBucket are not supported. |
|
||||||
|
|
||||||
# `vhs` section
|
# `vhs` section
|
||||||
|
|
||||||
|
|
37
go.mod
37
go.mod
|
@ -4,11 +4,12 @@ go 1.22
|
||||||
|
|
||||||
require (
|
require (
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.20.1-0.20241022094040-5f956751d48b
|
git.frostfs.info/TrueCloudLab/frostfs-contract v0.20.1-0.20241022094040-5f956751d48b
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20241112082307-f17779933e88
|
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20241210155057-ec6f88033795
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20250130095343-593dd77d841a
|
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20250130095343-593dd77d841a
|
||||||
git.frostfs.info/TrueCloudLab/multinet v0.0.0-20241015075604-6cb0d80e0972
|
git.frostfs.info/TrueCloudLab/multinet v0.0.0-20241015075604-6cb0d80e0972
|
||||||
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240822104152-a3bc3099bd5b
|
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240822104152-a3bc3099bd5b
|
||||||
git.frostfs.info/TrueCloudLab/zapjournald v0.0.0-20240124114243-cb2e66427d02
|
git.frostfs.info/TrueCloudLab/zapjournald v0.0.0-20240124114243-cb2e66427d02
|
||||||
|
git.frostfs.info/pogpp/mfa v0.0.0-20250218131940-8276d0a0f422
|
||||||
github.com/aws/aws-sdk-go-v2 v1.34.0
|
github.com/aws/aws-sdk-go-v2 v1.34.0
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.27.32
|
github.com/aws/aws-sdk-go-v2/config v1.27.32
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.31
|
github.com/aws/aws-sdk-go-v2/credentials v1.17.31
|
||||||
|
@ -21,25 +22,26 @@ require (
|
||||||
github.com/mr-tron/base58 v1.2.0
|
github.com/mr-tron/base58 v1.2.0
|
||||||
github.com/nspcc-dev/neo-go v0.106.3
|
github.com/nspcc-dev/neo-go v0.106.3
|
||||||
github.com/panjf2000/ants/v2 v2.5.0
|
github.com/panjf2000/ants/v2 v2.5.0
|
||||||
github.com/prometheus/client_golang v1.19.0
|
github.com/pquerna/otp v1.4.0
|
||||||
github.com/prometheus/client_model v0.5.0
|
github.com/prometheus/client_golang v1.20.2
|
||||||
|
github.com/prometheus/client_model v0.6.1
|
||||||
github.com/spf13/cobra v1.8.1
|
github.com/spf13/cobra v1.8.1
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/spf13/viper v1.15.0
|
github.com/spf13/viper v1.15.0
|
||||||
github.com/ssgreg/journald v1.0.0
|
github.com/ssgreg/journald v1.0.0
|
||||||
github.com/stretchr/testify v1.9.0
|
github.com/stretchr/testify v1.9.0
|
||||||
github.com/trailofbits/go-fuzz-utils v0.0.0-20230413173806-58c38daa3cb4
|
github.com/trailofbits/go-fuzz-utils v0.0.0-20230413173806-58c38daa3cb4
|
||||||
github.com/urfave/cli/v2 v2.27.2
|
github.com/urfave/cli/v2 v2.27.4
|
||||||
go.opentelemetry.io/otel v1.31.0
|
go.opentelemetry.io/otel v1.31.0
|
||||||
go.opentelemetry.io/otel/trace v1.31.0
|
go.opentelemetry.io/otel/trace v1.31.0
|
||||||
go.uber.org/zap v1.27.0
|
go.uber.org/zap v1.27.0
|
||||||
golang.org/x/crypto v0.31.0
|
golang.org/x/crypto v0.31.0
|
||||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
|
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948
|
||||||
golang.org/x/net v0.30.0
|
golang.org/x/net v0.30.0
|
||||||
golang.org/x/sys v0.28.0
|
golang.org/x/sys v0.28.0
|
||||||
golang.org/x/text v0.21.0
|
golang.org/x/text v0.21.0
|
||||||
google.golang.org/grpc v1.69.2
|
google.golang.org/grpc v1.69.2
|
||||||
google.golang.org/protobuf v1.36.1
|
google.golang.org/protobuf v1.36.4
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -64,23 +66,25 @@ require (
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.6 // indirect
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.6 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.30.6 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sts v1.30.6 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||||
github.com/go-logr/logr v1.4.2 // indirect
|
github.com/go-logr/logr v1.4.2 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/golang/snappy v0.0.1 // indirect
|
github.com/golang/snappy v0.0.1 // indirect
|
||||||
github.com/gorilla/websocket v1.5.1 // indirect
|
github.com/gorilla/websocket v1.5.3 // indirect
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
github.com/holiman/uint256 v1.2.4 // indirect
|
github.com/holiman/uint256 v1.3.1 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/ipfs/go-cid v0.0.7 // indirect
|
github.com/ipfs/go-cid v0.0.7 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
|
github.com/klauspost/compress v1.17.9 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
||||||
github.com/magiconair/properties v1.8.7 // indirect
|
github.com/magiconair/properties v1.8.7 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
|
@ -92,14 +96,15 @@ require (
|
||||||
github.com/multiformats/go-multibase v0.2.0 // indirect
|
github.com/multiformats/go-multibase v0.2.0 // indirect
|
||||||
github.com/multiformats/go-multihash v0.2.3 // indirect
|
github.com/multiformats/go-multihash v0.2.3 // indirect
|
||||||
github.com/multiformats/go-varint v0.0.7 // indirect
|
github.com/multiformats/go-varint v0.0.7 // indirect
|
||||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec // indirect
|
github.com/nspcc-dev/go-ordered-json v0.0.0-20240830112754-291b000d1f3b // indirect
|
||||||
github.com/nspcc-dev/rfc6979 v0.2.1 // indirect
|
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6 // indirect
|
||||||
|
github.com/nspcc-dev/rfc6979 v0.2.3 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
|
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
|
||||||
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
|
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/prometheus/common v0.48.0 // indirect
|
github.com/prometheus/common v0.55.0 // indirect
|
||||||
github.com/prometheus/procfs v0.12.0 // indirect
|
github.com/prometheus/procfs v0.15.1 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||||
github.com/spf13/afero v1.9.3 // indirect
|
github.com/spf13/afero v1.9.3 // indirect
|
||||||
|
@ -108,8 +113,8 @@ require (
|
||||||
github.com/subosito/gotenv v1.4.2 // indirect
|
github.com/subosito/gotenv v1.4.2 // indirect
|
||||||
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 // indirect
|
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 // indirect
|
||||||
github.com/twmb/murmur3 v1.1.8 // indirect
|
github.com/twmb/murmur3 v1.1.8 // indirect
|
||||||
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect
|
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
|
||||||
go.etcd.io/bbolt v1.3.9 // indirect
|
go.etcd.io/bbolt v1.3.11 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.28.0 // indirect
|
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.28.0 // indirect
|
||||||
|
|
85
go.sum
85
go.sum
|
@ -40,8 +40,8 @@ git.frostfs.info/TrueCloudLab/frostfs-contract v0.20.1-0.20241022094040-5f956751
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.20.1-0.20241022094040-5f956751d48b/go.mod h1:5fSm/l5xSjGWqsPUffSdboiGFUHa7y/1S0fvxzQowN8=
|
git.frostfs.info/TrueCloudLab/frostfs-contract v0.20.1-0.20241022094040-5f956751d48b/go.mod h1:5fSm/l5xSjGWqsPUffSdboiGFUHa7y/1S0fvxzQowN8=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 h1:FxqFDhQYYgpe41qsIHVOcdzSVCB8JNSfPG7Uk4r2oSk=
|
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 h1:FxqFDhQYYgpe41qsIHVOcdzSVCB8JNSfPG7Uk4r2oSk=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0/go.mod h1:RUIKZATQLJ+TaYQa60X2fTDwfuhMfm8Ar60bQ5fr+vU=
|
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0/go.mod h1:RUIKZATQLJ+TaYQa60X2fTDwfuhMfm8Ar60bQ5fr+vU=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20241112082307-f17779933e88 h1:9bvBDLApbbO5sXBKdODpE9tzy3HV99nXxkDWNn22rdI=
|
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20241210155057-ec6f88033795 h1:pYKLvVL9N7/613LnVaAU4cKnyVpjVX3dNyMIjN7fHCA=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20241112082307-f17779933e88/go.mod h1:kbwB4v2o6RyOfCo9kEFeUDZIX3LKhmS0yXPrtvzkQ1g=
|
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20241210155057-ec6f88033795/go.mod h1:kbwB4v2o6RyOfCo9kEFeUDZIX3LKhmS0yXPrtvzkQ1g=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20250130095343-593dd77d841a h1:Ud+3zz4WP9HPxEQxDPJZPpiPdm30nDNSKucsWP9L54M=
|
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20250130095343-593dd77d841a h1:Ud+3zz4WP9HPxEQxDPJZPpiPdm30nDNSKucsWP9L54M=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20250130095343-593dd77d841a/go.mod h1:aQpPWfG8oyfJ2X+FenPTJpSRWZjwcP5/RAtkW+/VEX8=
|
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20250130095343-593dd77d841a/go.mod h1:aQpPWfG8oyfJ2X+FenPTJpSRWZjwcP5/RAtkW+/VEX8=
|
||||||
git.frostfs.info/TrueCloudLab/hrw v1.2.1 h1:ccBRK21rFvY5R1WotI6LNoPlizk7qSvdfD8lNIRudVc=
|
git.frostfs.info/TrueCloudLab/hrw v1.2.1 h1:ccBRK21rFvY5R1WotI6LNoPlizk7qSvdfD8lNIRudVc=
|
||||||
|
@ -56,6 +56,8 @@ git.frostfs.info/TrueCloudLab/tzhash v1.8.0 h1:UFMnUIk0Zh17m8rjGHJMqku2hCgaXDqjq
|
||||||
git.frostfs.info/TrueCloudLab/tzhash v1.8.0/go.mod h1:dhY+oy274hV8wGvGL4MwwMpdL3GYvaX1a8GQZQHvlF8=
|
git.frostfs.info/TrueCloudLab/tzhash v1.8.0/go.mod h1:dhY+oy274hV8wGvGL4MwwMpdL3GYvaX1a8GQZQHvlF8=
|
||||||
git.frostfs.info/TrueCloudLab/zapjournald v0.0.0-20240124114243-cb2e66427d02 h1:HeY8n27VyPRQe49l/fzyVMkWEB2fsLJYKp64pwA7tz4=
|
git.frostfs.info/TrueCloudLab/zapjournald v0.0.0-20240124114243-cb2e66427d02 h1:HeY8n27VyPRQe49l/fzyVMkWEB2fsLJYKp64pwA7tz4=
|
||||||
git.frostfs.info/TrueCloudLab/zapjournald v0.0.0-20240124114243-cb2e66427d02/go.mod h1:rQFJJdEOV7KbbMtQYR2lNfiZk+ONRDJSbMCTWxKt8Fw=
|
git.frostfs.info/TrueCloudLab/zapjournald v0.0.0-20240124114243-cb2e66427d02/go.mod h1:rQFJJdEOV7KbbMtQYR2lNfiZk+ONRDJSbMCTWxKt8Fw=
|
||||||
|
git.frostfs.info/pogpp/mfa v0.0.0-20250218131940-8276d0a0f422 h1:hlosvbK58mGvqZQaOiczizrp2Mc02ZslbZ6zcBsjGTQ=
|
||||||
|
git.frostfs.info/pogpp/mfa v0.0.0-20250218131940-8276d0a0f422/go.mod h1:Sgy1rVN/AkpZI2xfzQLjkTWjR1qVoCIxxAvxv8svKdg=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
github.com/VictoriaMetrics/easyproto v0.1.4 h1:r8cNvo8o6sR4QShBXQd1bKw/VVLSQma/V2KhTBPf+Sc=
|
github.com/VictoriaMetrics/easyproto v0.1.4 h1:r8cNvo8o6sR4QShBXQd1bKw/VVLSQma/V2KhTBPf+Sc=
|
||||||
|
@ -104,6 +106,8 @@ github.com/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5M
|
||||||
github.com/bits-and-blooms/bitset v1.8.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
github.com/bits-and-blooms/bitset v1.8.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||||
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
|
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
|
||||||
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
|
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
|
||||||
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
|
||||||
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
@ -125,8 +129,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg=
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
|
@ -211,8 +215,8 @@ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
||||||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||||
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
@ -221,8 +225,8 @@ github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU=
|
github.com/holiman/uint256 v1.3.1 h1:JfTzmih28bittyHM8z360dCjIA9dbPIBlcTI6lmctQs=
|
||||||
github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
|
github.com/holiman/uint256 v1.3.1/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
|
@ -235,6 +239,8 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
|
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||||
|
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
|
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||||
|
@ -245,6 +251,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||||
|
@ -280,16 +288,18 @@ github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsC
|
||||||
github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
|
github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
|
||||||
github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8=
|
github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8=
|
||||||
github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU=
|
github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/nspcc-dev/dbft v0.2.0 h1:sDwsQES600OSIMncV176t2SX5OvB14lzeOAyKFOkbMI=
|
github.com/nspcc-dev/dbft v0.2.0 h1:sDwsQES600OSIMncV176t2SX5OvB14lzeOAyKFOkbMI=
|
||||||
github.com/nspcc-dev/dbft v0.2.0/go.mod h1:oFE6paSC/yfFh9mcNU6MheMGOYXK9+sPiRk3YMoz49o=
|
github.com/nspcc-dev/dbft v0.2.0/go.mod h1:oFE6paSC/yfFh9mcNU6MheMGOYXK9+sPiRk3YMoz49o=
|
||||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2 h1:mD9hU3v+zJcnHAVmHnZKt3I++tvn30gBj2rP2PocZMk=
|
github.com/nspcc-dev/go-ordered-json v0.0.0-20240830112754-291b000d1f3b h1:DRG4cRqIOmI/nUPggMgR92Jxt63Lxsuz40m5QpdvYXI=
|
||||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2/go.mod h1:U5VfmPNM88P4RORFb6KSUVBdJBDhlqggJZYGXGPxOcc=
|
github.com/nspcc-dev/go-ordered-json v0.0.0-20240830112754-291b000d1f3b/go.mod h1:d3cUseu4Asxfo9/QA/w4TtGjM0AbC9ynyab+PfH+Bso=
|
||||||
github.com/nspcc-dev/neo-go v0.106.3 h1:HEyhgkjQY+HfBzotMJ12xx2VuOUphkngZ4kEkjvXDtE=
|
github.com/nspcc-dev/neo-go v0.106.3 h1:HEyhgkjQY+HfBzotMJ12xx2VuOUphkngZ4kEkjvXDtE=
|
||||||
github.com/nspcc-dev/neo-go v0.106.3/go.mod h1:3vEwJ2ld12N7HRGCaH/l/7EwopplC/+8XdIdPDNmD/M=
|
github.com/nspcc-dev/neo-go v0.106.3/go.mod h1:3vEwJ2ld12N7HRGCaH/l/7EwopplC/+8XdIdPDNmD/M=
|
||||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec h1:vDrbVXF2+2uP0RlkZmem3QYATcXCu9BzzGGCNsNcK7Q=
|
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6 h1:rTnsU+Y/bP1bLN/SNWmOKEexmSeniMQe5bOJxXNbXgg=
|
||||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||||
github.com/nspcc-dev/rfc6979 v0.2.1 h1:8wWxkamHWFmO790GsewSoKUSJjVnL1fmdRpokU/RgRM=
|
github.com/nspcc-dev/rfc6979 v0.2.3 h1:QNVykGZ3XjFwM/88rGfV3oj4rKNBy+nYI6jM7q19hDI=
|
||||||
github.com/nspcc-dev/rfc6979 v0.2.1/go.mod h1:Tk7h5kyUWkhjyO3zUgFFhy1v2vQv3BvQEntakdtqrWc=
|
github.com/nspcc-dev/rfc6979 v0.2.3/go.mod h1:q3sCL1Ed7homjqYK8KmFSzEmm+7Ngyo7PePbZanhaDE=
|
||||||
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
@ -309,15 +319,17 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
||||||
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
|
github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg=
|
||||||
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
|
github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||||
|
github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg=
|
||||||
|
github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
|
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||||
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||||
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
|
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
|
||||||
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
|
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
|
||||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||||
|
@ -345,6 +357,7 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE
|
||||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
@ -361,16 +374,16 @@ github.com/trailofbits/go-fuzz-utils v0.0.0-20230413173806-58c38daa3cb4 h1:GpfJ7
|
||||||
github.com/trailofbits/go-fuzz-utils v0.0.0-20230413173806-58c38daa3cb4/go.mod h1:f3jBhpWvuZmue0HZK52GzRHJOYHYSILs/c8+K2S/J+o=
|
github.com/trailofbits/go-fuzz-utils v0.0.0-20230413173806-58c38daa3cb4/go.mod h1:f3jBhpWvuZmue0HZK52GzRHJOYHYSILs/c8+K2S/J+o=
|
||||||
github.com/twmb/murmur3 v1.1.8 h1:8Yt9taO/WN3l08xErzjeschgZU2QSrwm1kclYq+0aRg=
|
github.com/twmb/murmur3 v1.1.8 h1:8Yt9taO/WN3l08xErzjeschgZU2QSrwm1kclYq+0aRg=
|
||||||
github.com/twmb/murmur3 v1.1.8/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
|
github.com/twmb/murmur3 v1.1.8/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
|
||||||
github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI=
|
github.com/urfave/cli/v2 v2.27.4 h1:o1owoI+02Eb+K107p27wEX9Bb8eqIoZCfLXloLUSWJ8=
|
||||||
github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM=
|
github.com/urfave/cli/v2 v2.27.4/go.mod h1:m4QzxcD2qpra4z7WhzEGn74WZLViBnMpb1ToCAKdGRQ=
|
||||||
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw=
|
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
|
||||||
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk=
|
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
|
||||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
|
go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
|
||||||
go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
|
go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
|
@ -422,8 +435,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
|
||||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
|
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA=
|
||||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
|
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
@ -447,8 +460,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
|
||||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
@ -612,8 +625,8 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f
|
||||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
|
||||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
@ -714,8 +727,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
|
||||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||||
google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
|
google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
|
||||||
google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
|
429
internal/frostfs/mfa.go
Normal file
429
internal/frostfs/mfa.go
Normal file
|
@ -0,0 +1,429 @@
|
||||||
|
package frostfs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
|
apitree "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/tree"
|
||||||
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
|
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool"
|
||||||
|
treepool "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool/tree"
|
||||||
|
"git.frostfs.info/pogpp/mfa"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MFAFrostFS is a mediator which implements mfa.Storage through pool.Pool and treepool.Pool.
|
||||||
|
type MFAFrostFS struct {
|
||||||
|
frostFS *FrostFS
|
||||||
|
treePool *treepool.Pool
|
||||||
|
log *zap.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MFAFrostFS) CreateObject(ctx context.Context, create mfa.PrmObjectCreate) (oid.ID, error) {
|
||||||
|
object, err := m.frostFS.CreateObject(ctx, frostfs.PrmObjectCreate{
|
||||||
|
Container: create.Container,
|
||||||
|
Payload: bytes.NewReader(create.Payload),
|
||||||
|
Filepath: create.FilePath,
|
||||||
|
PayloadSize: uint64(len(create.Payload)),
|
||||||
|
WithoutHomomorphicHash: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return [32]byte{}, err
|
||||||
|
}
|
||||||
|
return object.ObjectID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MFAFrostFS) DeleteObject(ctx context.Context, address oid.Address) error {
|
||||||
|
prm := frostfs.PrmObjectDelete{
|
||||||
|
Container: address.Container(),
|
||||||
|
Object: address.Object(),
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.frostFS.DeleteObject(ctx, prm)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MFAFrostFS) SetTreeNode(ctx context.Context, cnrID cid.ID, name string, meta map[string]string) (*mfa.TreeMultiNode, error) {
|
||||||
|
if len(name) == 0 {
|
||||||
|
return nil, errors.New("tree node name must not be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
path := pathFromName(name)
|
||||||
|
meta[fileNameKey] = path[len(path)-1]
|
||||||
|
|
||||||
|
multiNode, err := m.getTreeNode(ctx, cnrID, path)
|
||||||
|
isErrNotFound := errors.Is(err, mfa.ErrTreeNodeNotFound)
|
||||||
|
if err != nil && !isErrNotFound {
|
||||||
|
return nil, fmt.Errorf("couldn't get node to check: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if isErrNotFound {
|
||||||
|
prmAdd := treepool.AddNodeByPathParams{
|
||||||
|
CID: cnrID,
|
||||||
|
TreeID: mfaTreeName,
|
||||||
|
Path: path[:len(path)-1],
|
||||||
|
Meta: meta,
|
||||||
|
PathAttribute: fileNameKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = m.treePool.AddNodeByPath(ctx, prmAdd); err != nil {
|
||||||
|
return nil, fmt.Errorf("add node by path: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &mfa.TreeMultiNode{Current: mfa.TreeNode{Meta: meta}}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
node := multiNode.Latest()
|
||||||
|
prmMove := treepool.MoveNodeParams{
|
||||||
|
CID: cnrID,
|
||||||
|
TreeID: mfaTreeName,
|
||||||
|
NodeID: node.ID,
|
||||||
|
ParentID: node.ParentID,
|
||||||
|
Meta: meta,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = m.treePool.MoveNode(ctx, prmMove); err != nil {
|
||||||
|
return nil, fmt.Errorf("move node: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mfaMultiNode := &mfa.TreeMultiNode{Current: mfa.TreeNode{Meta: meta}}
|
||||||
|
for _, old := range m.cleanOldNodes(ctx, multiNode.Old(), cnrID) {
|
||||||
|
mfaMultiNode.Old = append(mfaMultiNode.Old, &mfa.TreeNode{Meta: old.Meta})
|
||||||
|
}
|
||||||
|
|
||||||
|
return mfaMultiNode, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MFAFrostFS) GetTreeNode(ctx context.Context, cnrID cid.ID, name string) (*mfa.TreeMultiNode, error) {
|
||||||
|
multiNode, err := m.getTreeNode(ctx, cnrID, pathFromName(name))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("couldn't get node: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return multiNode.ToMFAMultiNode(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MFAFrostFS) DeleteTreeNode(ctx context.Context, cnrID cid.ID, name string) ([]*mfa.TreeNode, error) {
|
||||||
|
multiNode, err := m.getTreeNode(ctx, cnrID, pathFromName(name))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("couldn't get node: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res := make([]*mfa.TreeNode, 0, len(multiNode.nodes))
|
||||||
|
for _, node := range m.cleanOldNodes(ctx, multiNode.nodes, cnrID) {
|
||||||
|
res = append(res, &mfa.TreeNode{Meta: node.Meta})
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(res) != len(multiNode.nodes) {
|
||||||
|
return res, fmt.Errorf("couldn't remove all mfa multi nodes '%s'", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MFAFrostFS) GetTreeNodes(ctx context.Context, cnrID cid.ID, prefix string) ([]*mfa.TreeNode, error) {
|
||||||
|
rootID := []uint64{0}
|
||||||
|
if len(prefix) != 0 {
|
||||||
|
var err error
|
||||||
|
rootID, err = m.getPrefixNodeID(ctx, cnrID, pathFromName(prefix))
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, mfa.ErrTreeNodeNotFound) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prm := treepool.GetSubTreeParams{
|
||||||
|
CID: cnrID,
|
||||||
|
TreeID: mfaTreeName,
|
||||||
|
RootID: rootID,
|
||||||
|
}
|
||||||
|
|
||||||
|
subTreeCli, err := m.treePool.GetSubTree(ctx, prm) // todo use streaming https://git.frostfs.info/TrueCloudLab/frostfs-s3-gw/issues/561
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
allNodes, err := subTreeCli.ReadAll()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
unique := filterUnique(allNodes)
|
||||||
|
res := make([]*mfa.TreeNode, 0, len(unique))
|
||||||
|
for _, v := range unique {
|
||||||
|
if isIntermediate(v.GetMeta()) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
meta := make(map[string]string, len(v.GetMeta()))
|
||||||
|
for _, kv := range v.GetMeta() {
|
||||||
|
meta[kv.GetKey()] = string(kv.GetValue())
|
||||||
|
}
|
||||||
|
res = append(res, &mfa.TreeNode{Meta: meta})
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func filterUnique(allNodes []*apitree.GetSubTreeResponseBody) map[string]*apitree.GetSubTreeResponseBody {
|
||||||
|
res := make(map[string]*apitree.GetSubTreeResponseBody, len(allNodes))
|
||||||
|
for _, node := range allNodes {
|
||||||
|
var name string
|
||||||
|
for _, kv := range node.GetMeta() {
|
||||||
|
if kv.GetKey() == fileNameKey {
|
||||||
|
name = string(kv.GetValue())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data, ok := res[name]
|
||||||
|
if !ok || getMaxTimestamp(data.GetTimestamp()) < getMaxTimestamp(node.GetTimestamp()) {
|
||||||
|
res[name] = node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMaxTimestamp(timestamps []uint64) uint64 {
|
||||||
|
var maxTimestamp uint64
|
||||||
|
|
||||||
|
for _, timestamp := range timestamps {
|
||||||
|
if timestamp > maxTimestamp {
|
||||||
|
maxTimestamp = timestamp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxTimestamp
|
||||||
|
}
|
||||||
|
|
||||||
|
type MFAFrostFSConfig struct {
|
||||||
|
Pool *pool.Pool
|
||||||
|
TreePool *treepool.Pool
|
||||||
|
Key *keys.PrivateKey
|
||||||
|
Logger *zap.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
type treeNode struct {
|
||||||
|
ID uint64
|
||||||
|
ParentID uint64
|
||||||
|
TimeStamp uint64
|
||||||
|
Meta map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
type multiSystemNode struct {
|
||||||
|
// the first element is latest
|
||||||
|
nodes []*treeNode
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
fileNameKey = "FileName"
|
||||||
|
mfaTreeName = "mfa"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewMFAFrostFS creates new MFAFrostFS using provided pool.Pool.
|
||||||
|
func NewMFAFrostFS(cfg MFAFrostFSConfig) *MFAFrostFS {
|
||||||
|
return &MFAFrostFS{
|
||||||
|
frostFS: NewFrostFS(cfg.Pool, cfg.Key),
|
||||||
|
treePool: cfg.TreePool,
|
||||||
|
log: cfg.Logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MFAFrostFS) GetObject(ctx context.Context, addr oid.Address) ([]byte, error) {
|
||||||
|
res, err := m.frostFS.GetObject(ctx, frostfs.PrmObjectGet{
|
||||||
|
Container: addr.Container(),
|
||||||
|
Object: addr.Object(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if closeErr := res.Payload.Close(); closeErr != nil {
|
||||||
|
middleware.GetReqLog(ctx).Warn(logs.CloseMFAObjectPayload, zap.Error(closeErr))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return io.ReadAll(res.Payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MFAFrostFS) getTreeNode(ctx context.Context, cnrID cid.ID, path []string) (*multiSystemNode, error) {
|
||||||
|
prmGetNodes := treepool.GetNodesParams{
|
||||||
|
CID: cnrID,
|
||||||
|
TreeID: mfaTreeName,
|
||||||
|
Path: path,
|
||||||
|
PathAttribute: fileNameKey,
|
||||||
|
LatestOnly: true,
|
||||||
|
AllAttrs: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
nodes, err := m.treePool.GetNodes(ctx, prmGetNodes)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, treepool.ErrNodeNotFound) {
|
||||||
|
return nil, fmt.Errorf("%s: %s", "mfa.ErrTreeNodeNotFound", err.Error())
|
||||||
|
// return nil, fmt.Errorf("%w: %s", mfa.ErrTreeNodeNotFound, err.Error())
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("get nodes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(nodes) == 0 {
|
||||||
|
return nil, mfa.ErrTreeNodeNotFound
|
||||||
|
}
|
||||||
|
if len(nodes) != 1 {
|
||||||
|
m.log.Warn(logs.FoundMultiNode, zap.Strings("path", path))
|
||||||
|
}
|
||||||
|
|
||||||
|
return newMultiNode(nodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MFAFrostFS) cleanOldNodes(ctx context.Context, nodes []*treeNode, cnrID cid.ID) []*treeNode {
|
||||||
|
res := make([]*treeNode, 0, len(nodes))
|
||||||
|
|
||||||
|
for _, node := range nodes {
|
||||||
|
if err := m.removeTreeNode(ctx, cnrID, node.ID); err != nil {
|
||||||
|
m.log.Warn(logs.FailedToRemoveOldTreeMultiNodes, zap.String("FileName", node.Meta[fileNameKey]), zap.Uint64("id", node.ID))
|
||||||
|
} else {
|
||||||
|
res = append(res, node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MFAFrostFS) removeTreeNode(ctx context.Context, cnrID cid.ID, nodeID uint64) error {
|
||||||
|
prmRemoveNode := treepool.RemoveNodeParams{
|
||||||
|
CID: cnrID,
|
||||||
|
TreeID: mfaTreeName,
|
||||||
|
NodeID: nodeID,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := m.treePool.RemoveNode(ctx, prmRemoveNode)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, treepool.ErrNodeNotFound) {
|
||||||
|
return fmt.Errorf("%w: %s", mfa.ErrTreeNodeNotFound, err.Error())
|
||||||
|
}
|
||||||
|
return fmt.Errorf("remove node: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MFAFrostFS) getPrefixNodeID(ctx context.Context, cnrID cid.ID, prefixPath []string) ([]uint64, error) {
|
||||||
|
p := treepool.GetNodesParams{
|
||||||
|
CID: cnrID,
|
||||||
|
TreeID: mfaTreeName,
|
||||||
|
Path: prefixPath,
|
||||||
|
LatestOnly: false,
|
||||||
|
AllAttrs: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
nodes, err := m.treePool.GetNodes(ctx, p)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, treepool.ErrNodeNotFound) {
|
||||||
|
return nil, fmt.Errorf("%w: %s", mfa.ErrTreeNodeNotFound, err.Error())
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var intermediateNodes []uint64
|
||||||
|
for _, node := range nodes {
|
||||||
|
if isIntermediate(node.GetMeta()) {
|
||||||
|
intermediateNodes = append(intermediateNodes, node.GetNodeID())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(intermediateNodes) == 0 {
|
||||||
|
return nil, treepool.ErrNodeNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
return intermediateNodes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isIntermediate(meta []*apitree.KeyValue) bool {
|
||||||
|
if len(meta) != 1 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return meta[0].GetKey() == fileNameKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMultiNode(nodes []*apitree.GetNodeByPathResponseInfo) (*multiSystemNode, error) {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
index int
|
||||||
|
maxTimestamp uint64
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(nodes) == 0 {
|
||||||
|
return nil, errors.New("multi node must have at least one node")
|
||||||
|
}
|
||||||
|
|
||||||
|
treeNodes := make([]*treeNode, len(nodes))
|
||||||
|
|
||||||
|
for i, node := range nodes {
|
||||||
|
if treeNodes[i] = newTreeNode(node); err != nil {
|
||||||
|
return nil, fmt.Errorf("parse tree node response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if maxTimestamp < node.GetTimestamp() {
|
||||||
|
index = i
|
||||||
|
maxTimestamp = node.GetTimestamp()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
treeNodes[0], treeNodes[index] = treeNodes[index], treeNodes[0]
|
||||||
|
|
||||||
|
return &multiSystemNode{
|
||||||
|
nodes: treeNodes,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *multiSystemNode) ToMFAMultiNode() *mfa.TreeMultiNode {
|
||||||
|
res := &mfa.TreeMultiNode{
|
||||||
|
Current: mfa.TreeNode{Meta: m.nodes[0].Meta},
|
||||||
|
Old: make([]*mfa.TreeNode, len(m.nodes[1:])),
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, node := range m.nodes[1:] {
|
||||||
|
res.Old[i] = &mfa.TreeNode{Meta: node.Meta}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTreeNode(nodeInfo *apitree.GetNodeByPathResponseInfo) *treeNode {
|
||||||
|
tNode := &treeNode{
|
||||||
|
ID: nodeInfo.GetNodeID(),
|
||||||
|
ParentID: nodeInfo.GetParentID(),
|
||||||
|
TimeStamp: nodeInfo.GetTimestamp(),
|
||||||
|
Meta: make(map[string]string, len(nodeInfo.GetMeta())),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, kv := range nodeInfo.GetMeta() {
|
||||||
|
tNode.Meta[kv.GetKey()] = string(kv.GetValue())
|
||||||
|
}
|
||||||
|
|
||||||
|
return tNode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *multiSystemNode) Old() []*treeNode {
|
||||||
|
return m.nodes[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *multiSystemNode) Latest() *treeNode {
|
||||||
|
return m.nodes[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// pathFromName splits name by '/'.
|
||||||
|
func pathFromName(name string) []string {
|
||||||
|
return strings.Split(name, "/")
|
||||||
|
}
|
|
@ -125,6 +125,8 @@ const (
|
||||||
FailedToParseAddressInTreeNode = "failed to parse object addr in tree node"
|
FailedToParseAddressInTreeNode = "failed to parse object addr in tree node"
|
||||||
UnexpectedMultiNodeIDsInSubTreeMultiParts = "unexpected multi node ids in sub tree multi parts"
|
UnexpectedMultiNodeIDsInSubTreeMultiParts = "unexpected multi node ids in sub tree multi parts"
|
||||||
FoundSeveralSystemNodes = "found several system nodes"
|
FoundSeveralSystemNodes = "found several system nodes"
|
||||||
|
CouldNotFetchMFAContainerInfo = "couldn't fetch mfa container info"
|
||||||
|
CouldNotInitMFAClient = "couldn't init MFA client"
|
||||||
BucketLifecycleNodeHasMultipleIDs = "bucket lifecycle node has multiple ids"
|
BucketLifecycleNodeHasMultipleIDs = "bucket lifecycle node has multiple ids"
|
||||||
UploadPart = "upload part"
|
UploadPart = "upload part"
|
||||||
FailedToSubmitTaskToPool = "failed to submit task to pool"
|
FailedToSubmitTaskToPool = "failed to submit task to pool"
|
||||||
|
@ -228,3 +230,10 @@ const (
|
||||||
FailedToReadHTTPBody = "failed to read http body"
|
FailedToReadHTTPBody = "failed to read http body"
|
||||||
FailedToProcessHTTPBody = "failed to process http body"
|
FailedToProcessHTTPBody = "failed to process http body"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// IAM Logs.
|
||||||
|
const (
|
||||||
|
FoundMultiNode = "found multi node"
|
||||||
|
CloseMFAObjectPayload = "close MFA object payload"
|
||||||
|
FailedToRemoveOldTreeMultiNodes = "failed to remove old tree multi nodes"
|
||||||
|
)
|
||||||
|
|
25
internal/unlocker/unlocker.go
Normal file
25
internal/unlocker/unlocker.go
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package unlocker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Unlocker struct {
|
||||||
|
appKey *keys.PrivateKey
|
||||||
|
iamKeys []*keys.PublicKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUnlocker(key *keys.PrivateKey, pubKeys []*keys.PublicKey) Unlocker {
|
||||||
|
return Unlocker{
|
||||||
|
appKey: key,
|
||||||
|
iamKeys: pubKeys,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u Unlocker) PrivateKey() *keys.PrivateKey {
|
||||||
|
return u.appKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u Unlocker) PublicKeys() []*keys.PublicKey {
|
||||||
|
return u.iamKeys
|
||||||
|
}
|
|
@ -89,6 +89,8 @@ var (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
versioningKV = "Versioning"
|
versioningKV = "Versioning"
|
||||||
|
mfaDeleteEnabledKV = "MFADelete"
|
||||||
|
mfaSerialNumberKV = "SerialNumber"
|
||||||
cannedACLKV = "cannedACL"
|
cannedACLKV = "cannedACL"
|
||||||
ownerKeyKV = "ownerKey"
|
ownerKeyKV = "ownerKey"
|
||||||
lockConfigurationKV = "LockConfiguration"
|
lockConfigurationKV = "LockConfiguration"
|
||||||
|
@ -500,9 +502,20 @@ func (c *Tree) GetSettingsNode(ctx context.Context, bktInfo *data.BucketInfo) (*
|
||||||
|
|
||||||
node := multiNode.Latest()
|
node := multiNode.Latest()
|
||||||
|
|
||||||
settings := &data.BucketSettings{Versioning: data.VersioningUnversioned}
|
settings := &data.BucketSettings{Versioning: data.Versioning{
|
||||||
|
VersioningStatus: data.VersioningUnversioned,
|
||||||
|
MFADeleteStatus: data.MFADeleteDisabled,
|
||||||
|
}}
|
||||||
if versioningValue, ok := node.Get(versioningKV); ok {
|
if versioningValue, ok := node.Get(versioningKV); ok {
|
||||||
settings.Versioning = versioningValue
|
settings.Versioning.VersioningStatus = versioningValue
|
||||||
|
}
|
||||||
|
if mfaDeleteValue, ok := node.Get(mfaDeleteEnabledKV); ok {
|
||||||
|
settings.Versioning.MFADeleteStatus = mfaDeleteValue
|
||||||
|
if settings.MFADeleteEnabled() {
|
||||||
|
if mfaSerialNumberValue, ok := node.Get(mfaSerialNumberKV); ok {
|
||||||
|
settings.Versioning.MFASerialNumber = mfaSerialNumberValue
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if lockConfigurationValue, ok := node.Get(lockConfigurationKV); ok {
|
if lockConfigurationValue, ok := node.Get(lockConfigurationKV); ok {
|
||||||
|
@ -1795,7 +1808,8 @@ func metaFromSettings(settings *data.BucketSettings) map[string]string {
|
||||||
results := make(map[string]string, 3)
|
results := make(map[string]string, 3)
|
||||||
|
|
||||||
results[FileNameKey] = settingsFileName
|
results[FileNameKey] = settingsFileName
|
||||||
results[versioningKV] = settings.Versioning
|
results[versioningKV] = settings.Versioning.VersioningStatus
|
||||||
|
results[mfaDeleteEnabledKV] = settings.Versioning.MFADeleteStatus
|
||||||
results[lockConfigurationKV] = encodeLockConfiguration(settings.LockConfiguration)
|
results[lockConfigurationKV] = encodeLockConfiguration(settings.LockConfiguration)
|
||||||
results[cannedACLKV] = settings.CannedACL
|
results[cannedACLKV] = settings.CannedACL
|
||||||
if settings.OwnerKey != nil {
|
if settings.OwnerKey != nil {
|
||||||
|
|
|
@ -119,7 +119,10 @@ func TestTreeServiceSettings(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
settings := &data.BucketSettings{
|
settings := &data.BucketSettings{
|
||||||
Versioning: "Versioning",
|
Versioning: data.Versioning{
|
||||||
|
VersioningStatus: data.VersioningEnabled,
|
||||||
|
MFADeleteStatus: data.MFADeleteDisabled,
|
||||||
|
},
|
||||||
LockConfiguration: &data.ObjectLockConfiguration{
|
LockConfiguration: &data.ObjectLockConfiguration{
|
||||||
ObjectLockEnabled: "Enabled",
|
ObjectLockEnabled: "Enabled",
|
||||||
Rule: &data.ObjectLockRule{
|
Rule: &data.ObjectLockRule{
|
||||||
|
|
Loading…
Add table
Reference in a new issue