forked from TrueCloudLab/frostfs-s3-gw
[#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:
parent
5e3220a622
commit
1e86413667
3 changed files with 102 additions and 27 deletions
|
@ -142,7 +142,7 @@ func newApp(ctx context.Context, l *zap.Logger, v *viper.Viper) *App {
|
|||
}
|
||||
|
||||
treeServiceEndpoint := v.GetString(cfgTreeServiceEndpoint)
|
||||
treeService, err := neofs.NewTreeClient(treeServiceEndpoint)
|
||||
treeService, err := neofs.NewTreeClient(treeServiceEndpoint, key)
|
||||
if err != nil {
|
||||
l.Fatal("failed to create tree service", zap.Error(err))
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"strconv"
|
||||
"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/data"
|
||||
"github.com/nspcc-dev/neofs-s3-gw/api/layer"
|
||||
|
@ -20,6 +21,7 @@ import (
|
|||
|
||||
type (
|
||||
TreeClient struct {
|
||||
key *keys.PrivateKey
|
||||
conn *grpc.ClientConn
|
||||
service tree.TreeServiceClient
|
||||
}
|
||||
|
@ -56,7 +58,7 @@ const (
|
|||
)
|
||||
|
||||
// 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()))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("did not connect: %v", err)
|
||||
|
@ -65,6 +67,7 @@ func NewTreeClient(addr string) (*TreeClient, error) {
|
|||
c := tree.NewTreeServiceClient(conn)
|
||||
|
||||
return &TreeClient{
|
||||
key: key,
|
||||
conn: conn,
|
||||
service: c,
|
||||
}, 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 {
|
||||
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 {
|
||||
return c.removeVersion(ctx, cnrID, systemTree, id)
|
||||
return c.removeNode(ctx, cnrID, systemTree, id)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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) {
|
||||
keysToReturn := []string{oidKV, isUnversionedKV, isDeleteMarkerKV}
|
||||
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) {
|
||||
request := &tree.GetSubTreeRequest{
|
||||
Body: &tree.GetSubTreeRequest_Body{
|
||||
ContainerId: []byte(cnrID.EncodeToString()),
|
||||
ContainerId: cnrID[:],
|
||||
TreeId: treeID,
|
||||
RootId: id,
|
||||
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)
|
||||
if err != nil {
|
||||
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) {
|
||||
request := &tree.GetNodeByPathRequest{
|
||||
Body: &tree.GetNodeByPathRequest_Body{
|
||||
ContainerId: []byte(cnrID.EncodeToString()),
|
||||
ContainerId: cnrID[:],
|
||||
TreeId: treeID,
|
||||
Path: path,
|
||||
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)
|
||||
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
|
||||
|
@ -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) {
|
||||
request := &tree.AddRequest{
|
||||
Body: &tree.AddRequest_Body{
|
||||
ContainerId: []byte(cnrID.EncodeToString()),
|
||||
ContainerId: cnrID[:],
|
||||
TreeId: treeID,
|
||||
ParentId: parent,
|
||||
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 0, err
|
||||
}
|
||||
|
||||
resp, err := c.service.Add(ctx, request)
|
||||
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 {
|
||||
request := &tree.AddByPathRequest{
|
||||
Body: &tree.AddByPathRequest_Body{
|
||||
ContainerId: []byte(cnrID.EncodeToString()),
|
||||
ContainerId: cnrID[:],
|
||||
TreeId: treeID,
|
||||
Path: path,
|
||||
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)
|
||||
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 {
|
||||
request := &tree.MoveRequest{
|
||||
Body: &tree.MoveRequest_Body{
|
||||
ContainerId: []byte(cnrID.EncodeToString()),
|
||||
ContainerId: cnrID[:],
|
||||
TreeId: treeID,
|
||||
NodeId: nodeID,
|
||||
ParentId: parentID,
|
||||
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)
|
||||
return err
|
||||
}
|
||||
|
||||
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{
|
||||
ContainerId: []byte(cnrID.EncodeToString()),
|
||||
ContainerId: cnrID[:],
|
||||
TreeId: treeID,
|
||||
NodeId: nodeID,
|
||||
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
|
||||
}
|
||||
|
||||
|
|
32
internal/neofs/tree_signature.go
Normal file
32
internal/neofs/tree_signature.go
Normal 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)
|
||||
}
|
Loading…
Reference in a new issue