[#413] Add signature for tree requests

Signed-off-by: Denis Kirillov <denis@nspcc.ru>
Signed-off-by: Alex Vanin <alexey@nspcc.ru>
This commit is contained in:
Denis Kirillov 2022-05-18 16:40:09 +03:00 committed by Alex Vanin
parent 5e3220a622
commit 1e86413667
3 changed files with 102 additions and 27 deletions

View file

@ -142,7 +142,7 @@ func newApp(ctx context.Context, l *zap.Logger, v *viper.Viper) *App {
} }
treeServiceEndpoint := v.GetString(cfgTreeServiceEndpoint) treeServiceEndpoint := v.GetString(cfgTreeServiceEndpoint)
treeService, err := neofs.NewTreeClient(treeServiceEndpoint) treeService, err := neofs.NewTreeClient(treeServiceEndpoint, key)
if err != nil { if err != nil {
l.Fatal("failed to create tree service", zap.Error(err)) l.Fatal("failed to create tree service", zap.Error(err))
} }

View file

@ -7,6 +7,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neofs-s3-gw/api" "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/data"
"github.com/nspcc-dev/neofs-s3-gw/api/layer" "github.com/nspcc-dev/neofs-s3-gw/api/layer"
@ -20,6 +21,7 @@ import (
type ( type (
TreeClient struct { TreeClient struct {
key *keys.PrivateKey
conn *grpc.ClientConn conn *grpc.ClientConn
service tree.TreeServiceClient service tree.TreeServiceClient
} }
@ -56,7 +58,7 @@ const (
) )
// NewTreeClient creates instance of TreeClient using provided address and create grpc connection. // NewTreeClient creates instance of TreeClient using provided address and create grpc connection.
func NewTreeClient(addr string) (*TreeClient, error) { func NewTreeClient(addr string, key *keys.PrivateKey) (*TreeClient, error) {
conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials())) conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil { if err != nil {
return nil, fmt.Errorf("did not connect: %v", err) return nil, fmt.Errorf("did not connect: %v", err)
@ -65,6 +67,7 @@ func NewTreeClient(addr string) (*TreeClient, error) {
c := tree.NewTreeServiceClient(conn) c := tree.NewTreeServiceClient(conn)
return &TreeClient{ return &TreeClient{
key: key,
conn: conn, conn: conn,
service: c, service: c,
}, nil }, nil
@ -299,11 +302,11 @@ func (c *TreeClient) AddSystemVersion(ctx context.Context, cnrID *cid.ID, filepa
} }
func (c *TreeClient) RemoveVersion(ctx context.Context, cnrID *cid.ID, id uint64) error { func (c *TreeClient) RemoveVersion(ctx context.Context, cnrID *cid.ID, id uint64) error {
return c.removeVersion(ctx, cnrID, versionTree, id) return c.removeNode(ctx, cnrID, versionTree, id)
} }
func (c *TreeClient) RemoveSystemVersion(ctx context.Context, cnrID *cid.ID, id uint64) error { func (c *TreeClient) RemoveSystemVersion(ctx context.Context, cnrID *cid.ID, id uint64) error {
return c.removeVersion(ctx, cnrID, systemTree, id) return c.removeNode(ctx, cnrID, systemTree, id)
} }
func (c *TreeClient) Close() error { func (c *TreeClient) Close() error {
@ -346,20 +349,6 @@ func (c *TreeClient) addVersion(ctx context.Context, cnrID *cid.ID, treeID, attr
return c.addNodeByPath(ctx, cnrID, treeID, path[:len(path)-1], meta) return c.addNodeByPath(ctx, cnrID, treeID, path[:len(path)-1], meta)
} }
func (c *TreeClient) removeVersion(ctx context.Context, cnrID *cid.ID, treeID string, id uint64) error {
request := &tree.RemoveRequest{
Body: &tree.RemoveRequest_Body{
ContainerId: []byte(cnrID.EncodeToString()),
TreeId: treeID,
NodeId: id,
BearerToken: getBearer(ctx),
},
}
_, err := c.service.Remove(ctx, request)
return err
}
func (c *TreeClient) getVersions(ctx context.Context, cnrID *cid.ID, treeID, filepath string, onlyUnversioned bool) ([]*layer.NodeVersion, error) { func (c *TreeClient) getVersions(ctx context.Context, cnrID *cid.ID, treeID, filepath string, onlyUnversioned bool) ([]*layer.NodeVersion, error) {
keysToReturn := []string{oidKV, isUnversionedKV, isDeleteMarkerKV} keysToReturn := []string{oidKV, isUnversionedKV, isDeleteMarkerKV}
path := strings.Split(filepath, separator) path := strings.Split(filepath, separator)
@ -391,13 +380,22 @@ func (c *TreeClient) getVersions(ctx context.Context, cnrID *cid.ID, treeID, fil
func (c *TreeClient) getParent(ctx context.Context, cnrID *cid.ID, treeID string, id uint64) (uint64, error) { func (c *TreeClient) getParent(ctx context.Context, cnrID *cid.ID, treeID string, id uint64) (uint64, error) {
request := &tree.GetSubTreeRequest{ request := &tree.GetSubTreeRequest{
Body: &tree.GetSubTreeRequest_Body{ Body: &tree.GetSubTreeRequest_Body{
ContainerId: []byte(cnrID.EncodeToString()), ContainerId: cnrID[:],
TreeId: treeID, TreeId: treeID,
RootId: id, RootId: id,
BearerToken: getBearer(ctx), BearerToken: getBearer(ctx),
}, },
} }
if err := c.signRequest(request.Body, func(key, sign []byte) {
request.Signature = &tree.Signature{
Key: key,
Sign: sign,
}
}); err != nil {
return 0, err
}
cli, err := c.service.GetSubTree(ctx, request) cli, err := c.service.GetSubTree(ctx, request)
if err != nil { if err != nil {
return 0, fmt.Errorf("failed to get sub tree client: %w", err) return 0, fmt.Errorf("failed to get sub tree client: %w", err)
@ -446,7 +444,7 @@ func (c *TreeClient) getNode(ctx context.Context, cnrID *cid.ID, treeID, pathAtt
func (c *TreeClient) getNodes(ctx context.Context, cnrID *cid.ID, treeID, pathAttr string, path, meta []string, latestOnly bool) ([]*tree.GetNodeByPathResponse_Info, error) { func (c *TreeClient) getNodes(ctx context.Context, cnrID *cid.ID, treeID, pathAttr string, path, meta []string, latestOnly bool) ([]*tree.GetNodeByPathResponse_Info, error) {
request := &tree.GetNodeByPathRequest{ request := &tree.GetNodeByPathRequest{
Body: &tree.GetNodeByPathRequest_Body{ Body: &tree.GetNodeByPathRequest_Body{
ContainerId: []byte(cnrID.EncodeToString()), ContainerId: cnrID[:],
TreeId: treeID, TreeId: treeID,
Path: path, Path: path,
Attributes: meta, Attributes: meta,
@ -456,9 +454,18 @@ func (c *TreeClient) getNodes(ctx context.Context, cnrID *cid.ID, treeID, pathAt
}, },
} }
if err := c.signRequest(request.Body, func(key, sign []byte) {
request.Signature = &tree.Signature{
Key: key,
Sign: sign,
}
}); err != nil {
return nil, err
}
resp, err := c.service.GetNodeByPath(ctx, request) resp, err := c.service.GetNodeByPath(ctx, request)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get node path: %w", err) return nil, fmt.Errorf("failed to get node path deb: %w", err)
} }
return resp.GetBody().GetNodes(), nil return resp.GetBody().GetNodes(), nil
@ -476,13 +483,21 @@ func getBearer(ctx context.Context) []byte {
func (c *TreeClient) addNode(ctx context.Context, cnrID *cid.ID, treeID string, parent uint64, meta map[string]string) (uint64, error) { func (c *TreeClient) addNode(ctx context.Context, cnrID *cid.ID, treeID string, parent uint64, meta map[string]string) (uint64, error) {
request := &tree.AddRequest{ request := &tree.AddRequest{
Body: &tree.AddRequest_Body{ Body: &tree.AddRequest_Body{
ContainerId: []byte(cnrID.EncodeToString()), ContainerId: cnrID[:],
TreeId: treeID, TreeId: treeID,
ParentId: parent, ParentId: parent,
Meta: metaToKV(meta), Meta: metaToKV(meta),
BearerToken: getBearer(ctx), BearerToken: getBearer(ctx),
}, },
} }
if err := c.signRequest(request.Body, func(key, sign []byte) {
request.Signature = &tree.Signature{
Key: key,
Sign: sign,
}
}); err != nil {
return 0, err
}
resp, err := c.service.Add(ctx, request) resp, err := c.service.Add(ctx, request)
if err != nil { if err != nil {
@ -495,7 +510,7 @@ func (c *TreeClient) addNode(ctx context.Context, cnrID *cid.ID, treeID string,
func (c *TreeClient) addNodeByPath(ctx context.Context, cnrID *cid.ID, treeID string, path []string, meta map[string]string) error { func (c *TreeClient) addNodeByPath(ctx context.Context, cnrID *cid.ID, treeID string, path []string, meta map[string]string) error {
request := &tree.AddByPathRequest{ request := &tree.AddByPathRequest{
Body: &tree.AddByPathRequest_Body{ Body: &tree.AddByPathRequest_Body{
ContainerId: []byte(cnrID.EncodeToString()), ContainerId: cnrID[:],
TreeId: treeID, TreeId: treeID,
Path: path, Path: path,
Meta: metaToKV(meta), Meta: metaToKV(meta),
@ -504,6 +519,15 @@ func (c *TreeClient) addNodeByPath(ctx context.Context, cnrID *cid.ID, treeID st
}, },
} }
if err := c.signRequest(request.Body, func(key, sign []byte) {
request.Signature = &tree.Signature{
Key: key,
Sign: sign,
}
}); err != nil {
return err
}
_, err := c.service.AddByPath(ctx, request) _, err := c.service.AddByPath(ctx, request)
return err return err
} }
@ -511,28 +535,47 @@ func (c *TreeClient) addNodeByPath(ctx context.Context, cnrID *cid.ID, treeID st
func (c *TreeClient) moveNode(ctx context.Context, cnrID *cid.ID, treeID string, nodeID, parentID uint64, meta map[string]string) error { func (c *TreeClient) moveNode(ctx context.Context, cnrID *cid.ID, treeID string, nodeID, parentID uint64, meta map[string]string) error {
request := &tree.MoveRequest{ request := &tree.MoveRequest{
Body: &tree.MoveRequest_Body{ Body: &tree.MoveRequest_Body{
ContainerId: []byte(cnrID.EncodeToString()), ContainerId: cnrID[:],
TreeId: treeID, TreeId: treeID,
NodeId: nodeID, NodeId: nodeID,
ParentId: parentID, ParentId: parentID,
Meta: metaToKV(meta), Meta: metaToKV(meta),
BearerToken: getBearer(ctx),
}, },
} }
if err := c.signRequest(request.Body, func(key, sign []byte) {
request.Signature = &tree.Signature{
Key: key,
Sign: sign,
}
}); err != nil {
return err
}
_, err := c.service.Move(ctx, request) _, err := c.service.Move(ctx, request)
return err return err
} }
func (c *TreeClient) removeNode(ctx context.Context, cnrID *cid.ID, treeID string, nodeID uint64) error { func (c *TreeClient) removeNode(ctx context.Context, cnrID *cid.ID, treeID string, nodeID uint64) error {
r := &tree.RemoveRequest{ request := &tree.RemoveRequest{
Body: &tree.RemoveRequest_Body{ Body: &tree.RemoveRequest_Body{
ContainerId: []byte(cnrID.EncodeToString()), ContainerId: cnrID[:],
TreeId: treeID, TreeId: treeID,
NodeId: nodeID, NodeId: nodeID,
BearerToken: getBearer(ctx), BearerToken: getBearer(ctx),
}, },
} }
_, err := c.service.Remove(ctx, r) if err := c.signRequest(request.Body, func(key, sign []byte) {
request.Signature = &tree.Signature{
Key: key,
Sign: sign,
}
}); err != nil {
return err
}
_, err := c.service.Remove(ctx, request)
return err return err
} }

View file

@ -0,0 +1,32 @@
/* REMOVE THIS AFTER SIGNATURE WILL BE AVAILABLE IN TREE CLIENT FROM NEOFS NODE */
package neofs
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha512"
"google.golang.org/protobuf/proto"
)
func (c *TreeClient) signData(buf []byte, f func(key, sign []byte)) error {
hash := sha512.Sum512(buf)
x, y, err := ecdsa.Sign(rand.Reader, &c.key.PrivateKey, hash[:])
if err != nil {
return err
}
sign := elliptic.Marshal(elliptic.P256(), x, y)
f(c.key.PublicKey().Bytes(), sign)
return nil
}
func (c *TreeClient) signRequest(requestBody proto.Message, f func(key, sign []byte)) error {
buf, err := proto.Marshal(requestBody)
if err != nil {
return err
}
return c.signData(buf, f)
}