Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/Panic in SessionCreate #422

Merged
merged 2 commits into from
May 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions client/accounting.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,17 @@ func (x ResBalanceGet) Amount() accounting.Decimal {
//
// Return errors:
// - [ErrMissingAccount]
// - [ErrMissingSigner]
func (c *Client) BalanceGet(ctx context.Context, prm PrmBalanceGet) (*ResBalanceGet, error) {
switch {
case !prm.accountSet:
return nil, ErrMissingAccount
}

if c.prm.signer == nil {
return nil, ErrMissingSigner
roman-khimov marked this conversation as resolved.
Show resolved Hide resolved
}

// form request body
var accountV2 refs.OwnerID
prm.account.WriteToV2(&accountV2)
Expand Down
29 changes: 29 additions & 0 deletions client/accounting_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package client

import (
"context"
"testing"

"github.com/nspcc-dev/neofs-sdk-go/user"
"github.com/stretchr/testify/require"
)

func TestClient_BalanceGet(t *testing.T) {
c := newClient(t, nil, nil)
ctx := context.Background()

t.Run("missing", func(t *testing.T) {
t.Run("account", func(t *testing.T) {
_, err := c.BalanceGet(ctx, PrmBalanceGet{})
require.ErrorIs(t, err, ErrMissingAccount)
})

t.Run("signer", func(t *testing.T) {
var prm PrmBalanceGet
prm.SetAccount(user.ID{})

_, err := c.BalanceGet(ctx, prm)
require.ErrorIs(t, err, ErrMissingSigner)
})
})
}
16 changes: 16 additions & 0 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,22 @@ func (c *Client) setNeoFSAPIServer(server neoFSAPIServer) {
c.server = server
}

// getSigner returns a signer for requests. Provided signer fromPrm (if any) is prioritized, otherwise
// Client's default is used.
// Returns [ErrMissingSigner] if no signer is provided at all.
func (c *Client) getSigner(fromPrm neofscrypto.Signer) (neofscrypto.Signer, error) {
signer := fromPrm
if signer == nil {
signer = c.prm.signer
}

if signer == nil {
return nil, ErrMissingSigner
}

return signer, nil
}

// Close closes underlying connection to the NeoFS server. Implements io.Closer.
// MUST NOT be called before successful Dial. Can be called concurrently
// with server operations processing on running goroutines: in this case
Expand Down
78 changes: 49 additions & 29 deletions client/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,6 @@ func (x ResContainerPut) ID() cid.ID {
return x.id
}

func (c *Client) defaultSigner() neofscrypto.Signer {
return c.prm.signer
}

// ContainerPut sends request to save container in NeoFS.
//
// Any errors (local or remote, including returned status codes) are returned as Go errors,
Expand All @@ -88,25 +84,26 @@ func (c *Client) defaultSigner() neofscrypto.Signer {
//
// Return errors:
// - [ErrMissingContainer]
// - [ErrMissingSigner]
func (c *Client) ContainerPut(ctx context.Context, prm PrmContainerPut) (*ResContainerPut, error) {
// check parameters
switch {
case !prm.cnrSet:
return nil, ErrMissingContainer
}

signer, err := c.getSigner(prm.signer)
if err != nil {
return nil, err
}

// TODO: check private signer is set before forming the request
// sign container
var cnr v2container.Container
prm.cnr.WriteToV2(&cnr)

var sig neofscrypto.Signature
signer := prm.signer
if signer == nil {
signer = c.defaultSigner()
}

err := container.CalculateSignature(&sig, prm.cnr, signer)
err = container.CalculateSignature(&sig, prm.cnr, signer)
if err != nil {
return nil, fmt.Errorf("calculate container signature: %w", err)
}
Expand Down Expand Up @@ -210,12 +207,17 @@ func (x ResContainerGet) Container() container.Container {
//
// Return errors:
// - [ErrMissingContainer]
// - [ErrMissingSigner]
func (c *Client) ContainerGet(ctx context.Context, prm PrmContainerGet) (*ResContainerGet, error) {
switch {
case !prm.idSet:
return nil, ErrMissingContainer
}

if c.prm.signer == nil {
return nil, ErrMissingSigner
}

var cidV2 refs.ContainerID
prm.id.WriteToV2(&cidV2)

Expand Down Expand Up @@ -300,13 +302,18 @@ func (x ResContainerList) Containers() []cid.ID {
//
// Return errors:
// - [ErrMissingAccount]
// - [ErrMissingSigner]
func (c *Client) ContainerList(ctx context.Context, prm PrmContainerList) (*ResContainerList, error) {
// check parameters
switch {
case !prm.ownerSet:
return nil, ErrMissingAccount
}

if c.prm.signer == nil {
return nil, ErrMissingSigner
}

// form request body
var ownerV2 refs.OwnerID
prm.ownerID.WriteToV2(&ownerV2)
Expand Down Expand Up @@ -406,6 +413,7 @@ func (x *PrmContainerDelete) WithinSession(tok session.Container) {
//
// Return errors:
// - [ErrMissingContainer]
// - [ErrMissingSigner]
// - [neofscrypto.ErrIncorrectSigner]
//
// Reflects all internal errors in second return value (transport problems, response processing, etc.).
Expand All @@ -416,6 +424,15 @@ func (c *Client) ContainerDelete(ctx context.Context, prm PrmContainerDelete) er
return ErrMissingContainer
}

signer, err := c.getSigner(prm.signer)
if err != nil {
return err
}

if signer.Scheme() != neofscrypto.ECDSA_DETERMINISTIC_SHA256 {
return errNonNeoSigner
}

// sign container ID
var cidV2 refs.ContainerID
prm.id.WriteToV2(&cidV2)
Expand All @@ -425,15 +442,7 @@ func (c *Client) ContainerDelete(ctx context.Context, prm PrmContainerDelete) er
data := cidV2.GetValue()

var sig neofscrypto.Signature
signer := prm.signer
if signer == nil {
signer = c.defaultSigner()
}

if signer.Scheme() != neofscrypto.ECDSA_DETERMINISTIC_SHA256 {
return errNonNeoSigner
}
err := sig.Calculate(signer, data)
err = sig.Calculate(signer, data)
if err != nil {
return fmt.Errorf("calculate signature: %w", err)
}
Expand Down Expand Up @@ -518,13 +527,18 @@ func (x ResContainerEACL) Table() eacl.Table {
//
// Return errors:
// - [ErrMissingContainer]
// - [ErrMissingSigner]
func (c *Client) ContainerEACL(ctx context.Context, prm PrmContainerEACL) (*ResContainerEACL, error) {
// check parameters
switch {
case !prm.idSet:
return nil, ErrMissingContainer
}

if c.prm.signer == nil {
return nil, ErrMissingSigner
}

var cidV2 refs.ContainerID
prm.id.WriteToV2(&cidV2)

Expand Down Expand Up @@ -627,6 +641,7 @@ func (x *PrmContainerSetEACL) WithinSession(s session.Container) {
// - [ErrMissingEACL]
// - [ErrMissingEACLContainer]
// - [neofscrypto.ErrIncorrectSigner]
// - [ErrMissingSigner]
//
// Context is required and must not be nil. It is used for network communication.
func (c *Client) ContainerSetEACL(ctx context.Context, prm PrmContainerSetEACL) error {
Expand All @@ -636,6 +651,15 @@ func (c *Client) ContainerSetEACL(ctx context.Context, prm PrmContainerSetEACL)
return ErrMissingEACL
}

signer, err := c.getSigner(prm.signer)
if err != nil {
return err
}

if signer.Scheme() != neofscrypto.ECDSA_DETERMINISTIC_SHA256 {
return errNonNeoSigner
}

_, isCIDSet := prm.table.CID()
if !isCIDSet {
return ErrMissingEACLContainer
Expand All @@ -645,16 +669,7 @@ func (c *Client) ContainerSetEACL(ctx context.Context, prm PrmContainerSetEACL)
eaclV2 := prm.table.ToV2()

var sig neofscrypto.Signature
signer := prm.signer
if signer == nil {
signer = c.defaultSigner()
}

if signer.Scheme() != neofscrypto.ECDSA_DETERMINISTIC_SHA256 {
return errNonNeoSigner
}

err := sig.Calculate(signer, eaclV2.StableMarshal(nil))
err = sig.Calculate(signer, eaclV2.StableMarshal(nil))
if err != nil {
return fmt.Errorf("calculate signature: %w", err)
}
Expand Down Expand Up @@ -734,13 +749,18 @@ func (x *PrmAnnounceSpace) SetValues(vs []container.SizeEstimation) {
//
// Return errors:
// - [ErrMissingAnnouncements]
// - [ErrMissingSigner]
func (c *Client) ContainerAnnounceUsedSpace(ctx context.Context, prm PrmAnnounceSpace) error {
// check parameters
switch {
case len(prm.announcements) == 0:
return ErrMissingAnnouncements
}

if c.prm.signer == nil {
return ErrMissingSigner
}

// convert list of SDK announcement structures into NeoFS-API v2 list
v2announce := make([]v2container.UsedSpaceAnnouncement, len(prm.announcements))
for i := range prm.announcements {
Expand Down
74 changes: 74 additions & 0 deletions client/container_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package client

import (
"context"
"testing"

"github.com/nspcc-dev/neofs-sdk-go/container"
"github.com/stretchr/testify/require"
)

func TestClient_Container(t *testing.T) {
c := newClient(t, nil, nil)
ctx := context.Background()

t.Run("missing signer", func(t *testing.T) {
tt := []struct {
name string
methodCall func() error
}{
{
"put",
func() error {
_, err := c.ContainerPut(ctx, PrmContainerPut{cnrSet: true})
return err
},
},
{
"get",
func() error {
_, err := c.ContainerGet(ctx, PrmContainerGet{idSet: true})
return err
},
},
{
"list",
func() error {
_, err := c.ContainerList(ctx, PrmContainerList{ownerSet: true})
return err
},
},
{
"delete",
func() error {
return c.ContainerDelete(ctx, PrmContainerDelete{idSet: true})
},
},
{
"eacl",
func() error {
_, err := c.ContainerEACL(ctx, PrmContainerEACL{idSet: true})
return err
},
},
{
"set_eacl",
func() error {
return c.ContainerSetEACL(ctx, PrmContainerSetEACL{tableSet: true})
},
},
{
"announce_space",
func() error {
return c.ContainerAnnounceUsedSpace(ctx, PrmAnnounceSpace{announcements: make([]container.SizeEstimation, 1)})
},
},
}

for _, test := range tt {
t.Run(test.name, func(t *testing.T) {
require.ErrorIs(t, test.methodCall(), ErrMissingSigner)
})
}
})
}
2 changes: 2 additions & 0 deletions client/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ var (
ErrMissingObject = errors.New("missing object")
// ErrMissingAccount is returned when account/owner is not provided.
ErrMissingAccount = errors.New("missing account")
// ErrMissingSigner is returned when signer is not provided.
ErrMissingSigner = errors.New("missing signer")
roman-khimov marked this conversation as resolved.
Show resolved Hide resolved
// ErrMissingEACL is returned when eACL table is not provided.
ErrMissingEACL = errors.New("missing eACL table")
// ErrMissingEACLContainer is returned when container info is not provided in eACL table.
Expand Down
14 changes: 14 additions & 0 deletions client/netmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,14 @@ func (x ResEndpointInfo) NodeInfo() netmap.NodeInfo {
//
// Exactly one return value is non-nil. Server status return is returned in ResEndpointInfo.
// Reflects all internal errors in second return value (transport problems, response processing, etc.).
//
// Returns errors:
// - [ErrMissingSigner]
func (c *Client) EndpointInfo(ctx context.Context, prm PrmEndpointInfo) (*ResEndpointInfo, error) {
if c.prm.signer == nil {
return nil, ErrMissingSigner
}

// form request
var req v2netmap.LocalNodeInfoRequest

Expand Down Expand Up @@ -194,7 +201,14 @@ func (x ResNetMapSnapshot) NetMap() netmap.NetMap {
//
// Exactly one return value is non-nil. Server status return is returned in ResNetMapSnapshot.
// Reflects all internal errors in second return value (transport problems, response processing, etc.).
//
// Returns errors:
// - [ErrMissingSigner]
func (c *Client) NetMapSnapshot(ctx context.Context, _ PrmNetMapSnapshot) (*ResNetMapSnapshot, error) {
if c.prm.signer == nil {
return nil, ErrMissingSigner
}

// form request body
var body v2netmap.SnapshotRequestBody

Expand Down
9 changes: 9 additions & 0 deletions client/netmap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,12 @@ func TestClient_NetMapSnapshot(t *testing.T) {
require.NoError(t, err)
require.Equal(t, netMap, res.NetMap())
}

func TestClient_NetMapSnapshot_MissingSigner(t *testing.T) {
c := newClient(t, nil, nil)

t.Run("missing signer", func(t *testing.T) {
_, err := c.NetMapSnapshot(context.Background(), PrmNetMapSnapshot{})
require.ErrorIs(t, err, ErrMissingSigner)
})
}
Loading