Skip to content

Commit

Permalink
Upgrade to sdk rc10 (#807)
Browse files Browse the repository at this point in the history
closes #806
  • Loading branch information
roman-khimov authored Aug 15, 2023
2 parents 6a3ccfe + cb7d1e5 commit 5c083a9
Show file tree
Hide file tree
Showing 23 changed files with 448 additions and 579 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ This document outlines major changes between releases.

## [Unreleased]

### Added
- NoOpResolver as backward compatibility for case when rpc_endpoint/S3_GW_RPC_ENDPOINT param is empty in config.

### Changed
- Options `rpc_endpoint` in yaml config or `S3_GW_RPC_ENDPOINT` in env config is mandatory.

### Removed
- Options `resolve_order` in yaml config and `S3_GW_RESOLVE_ORDER` in env.

## [0.27.1] - 2023-06-15

### Fixed
Expand Down
26 changes: 17 additions & 9 deletions api/handler/handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ import (
"github.com/nspcc-dev/neofs-s3-gw/api"
"github.com/nspcc-dev/neofs-s3-gw/api/data"
"github.com/nspcc-dev/neofs-s3-gw/api/layer"
"github.com/nspcc-dev/neofs-s3-gw/api/resolver"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
"github.com/nspcc-dev/neofs-sdk-go/netmap"
"github.com/nspcc-dev/neofs-sdk-go/object"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
Expand All @@ -28,6 +26,14 @@ import (
"go.uber.org/zap"
)

type contResolver struct {
layer *layer.TestNeoFS
}

func (r *contResolver) Resolve(_ context.Context, name string) (cid.ID, error) {
return r.layer.ContainerID(name)
}

type handlerContext struct {
owner user.ID
t *testing.T
Expand Down Expand Up @@ -68,20 +74,22 @@ func prepareHandlerContext(t *testing.T) *handlerContext {
key, err := keys.NewPrivateKey()
require.NoError(t, err)

anonKey, err := keys.NewPrivateKey()
require.NoError(t, err)
anonSigner := user.NewAutoIDSignerRFC6979(anonKey.PrivateKey)

l := zap.NewExample()
tp := layer.NewTestNeoFS()

testResolver := &resolver.Resolver{Name: "test_resolver"}
testResolver.SetResolveFunc(func(_ context.Context, name string) (cid.ID, error) {
return tp.ContainerID(name)
})
testResolver := &contResolver{layer: tp}

var owner user.ID
require.NoError(t, user.IDFromSigner(&owner, neofsecdsa.SignerRFC6979(key.PrivateKey)))
signer := user.NewAutoIDSignerRFC6979(key.PrivateKey)
owner := signer.UserID()

layerCfg := &layer.Config{
Caches: layer.DefaultCachesConfigs(zap.NewExample()),
AnonKey: layer.AnonymousKey{Key: key},
GateKey: key,
Anonymous: anonSigner.UserID(),
Resolver: testResolver,
TreeService: layer.NewTreeService(),
}
Expand Down
6 changes: 6 additions & 0 deletions api/handler/multipart_upload.go
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,12 @@ func (h *handler) CompleteMultipartUploadHandler(w http.ResponseWriter, r *http.
h.logAndSendError(w, "could not translate acl of completed multipart upload to ast", reqInfo, err, additional...)
return
}

if sessionTokenSetEACL, err = getSessionTokenSetEACL(r.Context()); err != nil {
h.logAndSendError(w, "couldn't get eacl token", reqInfo, err)
return
}

if _, err = h.updateBucketACL(r, astObject, bktInfo, sessionTokenSetEACL); err != nil {
h.logAndSendError(w, "could not update bucket acl while completing multipart upload", reqInfo, err, additional...)
return
Expand Down
3 changes: 1 addition & 2 deletions api/handler/notifications.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
"github.com/nspcc-dev/neofs-s3-gw/api/data"
"github.com/nspcc-dev/neofs-s3-gw/api/layer"
"github.com/nspcc-dev/neofs-s3-gw/api/s3errors"
"github.com/nspcc-dev/neofs-sdk-go/bearer"
)

type (
Expand Down Expand Up @@ -163,7 +162,7 @@ func (h *handler) sendNotifications(ctx context.Context, p *SendNotificationPara

box, err := layer.GetBoxData(ctx)
if err == nil && box.Gate.BearerToken != nil {
p.User = bearer.ResolveIssuer(*box.Gate.BearerToken).EncodeToString()
p.User = box.Gate.BearerToken.ResolveIssuer().EncodeToString()
}

p.Time = layer.TimeNow(ctx)
Expand Down
47 changes: 14 additions & 33 deletions api/layer/layer.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import (
"github.com/nspcc-dev/neofs-s3-gw/api"
"github.com/nspcc-dev/neofs-s3-gw/api/data"
"github.com/nspcc-dev/neofs-s3-gw/api/layer/encryption"
"github.com/nspcc-dev/neofs-s3-gw/api/resolver"
"github.com/nspcc-dev/neofs-s3-gw/api/s3errors"
"github.com/nspcc-dev/neofs-s3-gw/creds/accessbox"
"github.com/nspcc-dev/neofs-sdk-go/bearer"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
"github.com/nspcc-dev/neofs-sdk-go/eacl"
"github.com/nspcc-dev/neofs-sdk-go/netmap"
Expand All @@ -39,15 +39,13 @@ type (

MsgHandlerFunc func(context.Context, *nats.Msg) error

BucketResolver interface {
Resolve(ctx context.Context, name string) (cid.ID, error)
}

layer struct {
neoFS NeoFS
log *zap.Logger
anonKey AnonymousKey
resolver BucketResolver
neoFS NeoFS
log *zap.Logger
// used in case of user wants to do something like anonymous.
// Typical using is a flag --no-sign-request in aws-cli.
anonymous user.ID
resolver resolver.Resolver
ncontroller EventListener
cache *Cache
treeService TreeService
Expand All @@ -56,16 +54,12 @@ type (
Config struct {
ChainAddress string
Caches *CachesConfig
AnonKey AnonymousKey
Resolver BucketResolver
GateKey *keys.PrivateKey
Anonymous user.ID
Resolver resolver.Resolver
TreeService TreeService
}

// AnonymousKey contains data for anonymous requests.
AnonymousKey struct {
Key *keys.PrivateKey
}

// GetObjectParams stores object get request parameters.
GetObjectParams struct {
Range *RangeParams
Expand Down Expand Up @@ -185,7 +179,6 @@ type (
// Client provides S3 API client interface.
Client interface {
Initialize(ctx context.Context, c EventListener) error
EphemeralKey() *keys.PublicKey

GetBucketSettings(ctx context.Context, bktInfo *data.BucketInfo) (*data.BucketSettings, error)
PutBucketSettings(ctx context.Context, p *PutSettingsParams) error
Expand Down Expand Up @@ -271,17 +264,13 @@ func NewLayer(log *zap.Logger, neoFS NeoFS, config *Config) Client {
return &layer{
neoFS: neoFS,
log: log,
anonKey: config.AnonKey,
anonymous: config.Anonymous,
resolver: config.Resolver,
cache: NewCache(config.Caches),
treeService: config.TreeService,
}
}

func (n *layer) EphemeralKey() *keys.PublicKey {
return n.anonKey.Key.PublicKey()
}

func (n *layer) Initialize(ctx context.Context, c EventListener) error {
if n.IsNotificationEnabled() {
return fmt.Errorf("already initialized")
Expand Down Expand Up @@ -317,26 +306,18 @@ func TimeNow(ctx context.Context) time.Time {
// Owner returns owner id from BearerToken (context) or from client owner.
func (n *layer) Owner(ctx context.Context) user.ID {
if bd, ok := ctx.Value(api.BoxData).(*accessbox.Box); ok && bd != nil && bd.Gate != nil && bd.Gate.BearerToken != nil {
return bearer.ResolveIssuer(*bd.Gate.BearerToken)
}

var ownerID user.ID
if err := user.IDFromKey(&ownerID, n.EphemeralKey().Bytes()); err != nil {
panic(fmt.Errorf("id from key: %w", err))
return bd.Gate.BearerToken.ResolveIssuer()
}

return ownerID
return n.anonymous
}

func (n *layer) prepareAuthParameters(ctx context.Context, prm *PrmAuth, bktOwner user.ID) {
if bd, ok := ctx.Value(api.BoxData).(*accessbox.Box); ok && bd != nil && bd.Gate != nil && bd.Gate.BearerToken != nil {
if bktOwner.Equals(bearer.ResolveIssuer(*bd.Gate.BearerToken)) {
if bktOwner.Equals(bd.Gate.BearerToken.ResolveIssuer()) {
prm.BearerToken = bd.Gate.BearerToken
return
}
}

prm.PrivateKey = &n.anonKey.Key.PrivateKey
}

// GetBucketInfo returns bucket info by name.
Expand Down
4 changes: 0 additions & 4 deletions api/layer/neofs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package layer

import (
"context"
"crypto/ecdsa"
"errors"
"io"
"time"
Expand Down Expand Up @@ -47,9 +46,6 @@ type PrmContainerCreate struct {
type PrmAuth struct {
// Bearer token to be used for the operation. Overlaps PrivateKey. Optional.
BearerToken *bearer.Token

// Private key used for the operation if BearerToken is missing (in this case non-nil).
PrivateKey *ecdsa.PrivateKey
}

// PrmObjectRead groups parameters of NeoFS.ReadObject operation.
Expand Down
3 changes: 1 addition & 2 deletions api/layer/neofs_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
objectv2 "github.com/nspcc-dev/neofs-api-go/v2/object"
"github.com/nspcc-dev/neofs-s3-gw/api"
"github.com/nspcc-dev/neofs-s3-gw/creds/accessbox"
"github.com/nspcc-dev/neofs-sdk-go/bearer"
"github.com/nspcc-dev/neofs-sdk-go/checksum"
"github.com/nspcc-dev/neofs-sdk-go/container"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
Expand Down Expand Up @@ -284,7 +283,7 @@ func (t *TestNeoFS) ContainerEACL(_ context.Context, cnrID cid.ID) (*eacl.Table,

func getOwner(ctx context.Context) user.ID {
if bd, ok := ctx.Value(api.BoxData).(*accessbox.Box); ok && bd != nil && bd.Gate != nil && bd.Gate.BearerToken != nil {
return bearer.ResolveIssuer(*bd.Gate.BearerToken)
return bd.Gate.BearerToken.ResolveIssuer()
}

return user.ID{}
Expand Down
15 changes: 10 additions & 5 deletions api/layer/versioning_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"github.com/nspcc-dev/neofs-s3-gw/api/data"
"github.com/nspcc-dev/neofs-s3-gw/creds/accessbox"
bearertest "github.com/nspcc-dev/neofs-sdk-go/bearer/test"
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
"github.com/nspcc-dev/neofs-sdk-go/object"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"github.com/nspcc-dev/neofs-sdk-go/user"
Expand Down Expand Up @@ -138,8 +137,14 @@ func prepareContext(t *testing.T, cachesConfig ...*CachesConfig) *testContext {
key, err := keys.NewPrivateKey()
require.NoError(t, err)

anonKey, err := keys.NewPrivateKey()
require.NoError(t, err)
anonSigner := user.NewAutoIDSignerRFC6979(anonKey.PrivateKey)

signer := user.NewAutoIDSignerRFC6979(key.PrivateKey)

bearerToken := bearertest.Token(t)
require.NoError(t, bearerToken.Sign(neofsecdsa.SignerRFC6979(key.PrivateKey)))
require.NoError(t, bearerToken.Sign(signer))

ctx := context.WithValue(context.Background(), api.BoxData, &accessbox.Box{
Gate: &accessbox.GateData{
Expand All @@ -160,12 +165,12 @@ func prepareContext(t *testing.T, cachesConfig ...*CachesConfig) *testContext {
config = cachesConfig[0]
}

var owner user.ID
require.NoError(t, user.IDFromSigner(&owner, neofsecdsa.SignerRFC6979(key.PrivateKey)))
owner := signer.UserID()

layerCfg := &Config{
Caches: config,
AnonKey: AnonymousKey{Key: key},
GateKey: key,
Anonymous: anonSigner.UserID(),
TreeService: NewTreeService(),
}

Expand Down
106 changes: 106 additions & 0 deletions api/resolver/init.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package resolver

import (
"context"
"fmt"
"sync"

"github.com/nspcc-dev/neo-go/pkg/rpcclient"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
"github.com/nspcc-dev/neo-go/pkg/util"
rpcNNS "github.com/nspcc-dev/neofs-contract/rpc/nns"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
)

const (
nnsContract = int32(1)
)

// Container is a wrapper for the [Resolver]. It allows to update resolvers in runtime, without service restarting.
//
// The Container should be used like regular [Resolver].
type Container struct {
mu sync.RWMutex
resolver Resolver
}

// Resolve looks up the container id by its name via NNS contract.
// The method calls inline resolver.
func (r *Container) Resolve(ctx context.Context, name string) (cid.ID, error) {
r.mu.RLock()
defer r.mu.RUnlock()

return r.resolver.Resolve(ctx, name)
}

// UpdateResolvers allows to update resolver in runtime. Resolvers will be created from scratch.
func (r *Container) UpdateResolvers(ctx context.Context, endpoint string) error {
newResolver, err := NewResolver(ctx, endpoint)
if err != nil {
return fmt.Errorf("resolver reinit: %w", err)
}

r.mu.Lock()
r.resolver = newResolver
r.mu.Unlock()

return nil
}

// NewContainer is a constructor for the [Container].
func NewContainer(ctx context.Context, endpoint string) (*Container, error) {
newResolver, err := NewResolver(ctx, endpoint)
if err != nil {
return nil, fmt.Errorf("resolver reinit: %w", err)
}

return &Container{
resolver: newResolver,
}, nil
}

// NewResolver returns resolver depending on corresponding endpoint.
//
// If endpoint is empty, [NoOpResolver] will be returned.
func NewResolver(ctx context.Context, endpoint string) (Resolver, error) {
if endpoint == "" {
return NewNoOpResolver(), nil
}

cl, err := rpcClient(ctx, endpoint)
if err != nil {
return nil, fmt.Errorf("rpcclient: %w", err)
}

nnsHash, err := systemContractHash(cl, nnsContract)
if err != nil {
return nil, fmt.Errorf("nns contract: %w", err)
}

inv := invoker.New(cl, nil)
nnsReader := rpcNNS.NewReader(inv, nnsHash)
return NewNNSResolver(nnsReader), nil
}

func systemContractHash(cl *rpcclient.Client, id int32) (util.Uint160, error) {
c, err := cl.GetContractStateByID(id)
if err != nil {
return util.Uint160{}, fmt.Errorf("GetContractStateByID [%d]: %w", id, err)
}

return c.Hash, nil
}

func rpcClient(ctx context.Context, endpoint string) (*rpcclient.Client, error) {
cl, err := rpcclient.New(ctx, endpoint, rpcclient.Options{})
if err != nil {
return nil, fmt.Errorf("new: %w", err)
}

err = cl.Init()
if err != nil {
return nil, fmt.Errorf("init: %w", err)
}

return cl, nil
}
Loading

0 comments on commit 5c083a9

Please sign in to comment.