[#16] Update SDK to v1.0.0-rc.5
Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
parent
0df815ed27
commit
aeb68fdd7a
12 changed files with 313 additions and 559 deletions
|
@ -25,16 +25,16 @@ import (
|
|||
"github.com/nspcc-dev/neofs-rest-gw/gen/restapi/operations"
|
||||
"github.com/nspcc-dev/neofs-rest-gw/handlers"
|
||||
"github.com/nspcc-dev/neofs-rest-gw/internal/util"
|
||||
walletconnect "github.com/nspcc-dev/neofs-rest-gw/internal/wallet-connect"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/container"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/container/acl"
|
||||
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/eacl"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/object"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/owner"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/policy"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/pool"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/user"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/testcontainers/testcontainers-go"
|
||||
|
@ -59,7 +59,7 @@ const (
|
|||
XBearerOwnerID = "X-Bearer-Owner-Id"
|
||||
|
||||
// tests configuration.
|
||||
useWalletConnect = false
|
||||
useWalletConnect = true
|
||||
useLocalEnvironment = false
|
||||
)
|
||||
|
||||
|
@ -82,11 +82,7 @@ func runLocalTests(ctx context.Context, t *testing.T, key *keys.PrivateKey) {
|
|||
func runTestInContainer(rootCtx context.Context, t *testing.T, key *keys.PrivateKey) {
|
||||
aioImage := "nspccdev/neofs-aio-testcontainer:"
|
||||
versions := []string{
|
||||
//"0.24.0",
|
||||
//"0.25.1",
|
||||
//"0.26.1",
|
||||
//"0.27.5",
|
||||
"0.27.7",
|
||||
"0.29.0",
|
||||
//"latest",
|
||||
}
|
||||
|
||||
|
@ -112,25 +108,28 @@ func runTests(ctx context.Context, t *testing.T, key *keys.PrivateKey, version s
|
|||
cancel := runServer(ctx, t, node)
|
||||
defer cancel()
|
||||
|
||||
var owner user.ID
|
||||
user.IDFromKey(&owner, key.PrivateKey.PublicKey)
|
||||
|
||||
clientPool := getPool(ctx, t, key, node)
|
||||
cnrID := createContainer(ctx, t, clientPool, containerName)
|
||||
cnrID := createContainer(ctx, t, clientPool, owner, containerName)
|
||||
restrictByEACL(ctx, t, clientPool, cnrID)
|
||||
|
||||
t.Run("rest auth several tokens "+version, func(t *testing.T) { authTokens(ctx, t) })
|
||||
t.Run("rest check mix tokens up "+version, func(t *testing.T) { mixTokens(ctx, t, cnrID) })
|
||||
|
||||
t.Run("rest put object "+version, func(t *testing.T) { restObjectPut(ctx, t, clientPool, cnrID) })
|
||||
t.Run("rest get object "+version, func(t *testing.T) { restObjectGet(ctx, t, clientPool, cnrID) })
|
||||
t.Run("rest delete object "+version, func(t *testing.T) { restObjectDelete(ctx, t, clientPool, cnrID) })
|
||||
t.Run("rest search objects "+version, func(t *testing.T) { restObjectsSearch(ctx, t, clientPool, cnrID) })
|
||||
t.Run("rest get object "+version, func(t *testing.T) { restObjectGet(ctx, t, clientPool, &owner, cnrID) })
|
||||
t.Run("rest delete object "+version, func(t *testing.T) { restObjectDelete(ctx, t, clientPool, &owner, cnrID) })
|
||||
t.Run("rest search objects "+version, func(t *testing.T) { restObjectsSearch(ctx, t, clientPool, &owner, cnrID) })
|
||||
|
||||
t.Run("rest put container invalid "+version, func(t *testing.T) { restContainerPutInvalid(ctx, t) })
|
||||
t.Run("rest put container "+version, func(t *testing.T) { restContainerPut(ctx, t, clientPool) })
|
||||
t.Run("rest get container "+version, func(t *testing.T) { restContainerGet(ctx, t, clientPool, cnrID) })
|
||||
t.Run("rest delete container "+version, func(t *testing.T) { restContainerDelete(ctx, t, clientPool) })
|
||||
t.Run("rest put container eacl "+version, func(t *testing.T) { restContainerEACLPut(ctx, t, clientPool) })
|
||||
t.Run("rest get container "+version, func(t *testing.T) { restContainerGet(ctx, t, owner, cnrID) })
|
||||
t.Run("rest delete container "+version, func(t *testing.T) { restContainerDelete(ctx, t, clientPool, owner) })
|
||||
t.Run("rest put container eacl "+version, func(t *testing.T) { restContainerEACLPut(ctx, t, clientPool, owner) })
|
||||
t.Run("rest get container eacl "+version, func(t *testing.T) { restContainerEACLGet(ctx, t, clientPool, cnrID) })
|
||||
t.Run("rest list containers "+version, func(t *testing.T) { restContainerList(ctx, t, clientPool, cnrID) })
|
||||
t.Run("rest list containers "+version, func(t *testing.T) { restContainerList(ctx, t, clientPool, owner, cnrID) })
|
||||
}
|
||||
|
||||
func createDockerContainer(ctx context.Context, t *testing.T, image string) testcontainers.Container {
|
||||
|
@ -270,7 +269,7 @@ func authTokens(ctx context.Context, t *testing.T) {
|
|||
makeAuthTokenRequest(ctx, t, bearers, httpClient)
|
||||
}
|
||||
|
||||
func mixTokens(ctx context.Context, t *testing.T, cnrID *cid.ID) {
|
||||
func mixTokens(ctx context.Context, t *testing.T, cnrID cid.ID) {
|
||||
bearers := []*models.Bearer{
|
||||
{
|
||||
Name: "all-object",
|
||||
|
@ -332,8 +331,8 @@ func checkPutContainerWithError(t *testing.T, httpClient *http.Client, token *ha
|
|||
checkGWErrorResponse(t, httpClient, request)
|
||||
}
|
||||
|
||||
func checkDeleteContainerWithError(t *testing.T, httpClient *http.Client, cnrID *cid.ID, token *handlers.BearerToken) {
|
||||
reqURL, err := url.Parse(testHost + "/v1/containers/" + cnrID.String())
|
||||
func checkDeleteContainerWithError(t *testing.T, httpClient *http.Client, cnrID cid.ID, token *handlers.BearerToken) {
|
||||
reqURL, err := url.Parse(testHost + "/v1/containers/" + cnrID.EncodeToString())
|
||||
require.NoError(t, err)
|
||||
request, err := http.NewRequest(http.MethodDelete, reqURL.String(), nil)
|
||||
require.NoError(t, err)
|
||||
|
@ -342,20 +341,20 @@ func checkDeleteContainerWithError(t *testing.T, httpClient *http.Client, cnrID
|
|||
checkGWErrorResponse(t, httpClient, request)
|
||||
}
|
||||
|
||||
func checkSetEACLContainerWithError(t *testing.T, httpClient *http.Client, cnrID *cid.ID, token *handlers.BearerToken) {
|
||||
func checkSetEACLContainerWithError(t *testing.T, httpClient *http.Client, cnrID cid.ID, token *handlers.BearerToken) {
|
||||
req := models.Eacl{Records: []*models.Record{}}
|
||||
body, err := json.Marshal(&req)
|
||||
require.NoError(t, err)
|
||||
request, err := http.NewRequest(http.MethodPut, testHost+"/v1/containers/"+cnrID.String()+"/eacl", bytes.NewReader(body))
|
||||
request, err := http.NewRequest(http.MethodPut, testHost+"/v1/containers/"+cnrID.EncodeToString()+"/eacl", bytes.NewReader(body))
|
||||
require.NoError(t, err)
|
||||
prepareCommonHeaders(request.Header, token)
|
||||
|
||||
checkGWErrorResponse(t, httpClient, request)
|
||||
}
|
||||
|
||||
func checkPutObjectWithError(t *testing.T, httpClient *http.Client, cnrID *cid.ID, token *handlers.BearerToken) {
|
||||
func checkPutObjectWithError(t *testing.T, httpClient *http.Client, cnrID cid.ID, token *handlers.BearerToken) {
|
||||
req := &models.ObjectUpload{
|
||||
ContainerID: util.NewString(cnrID.String()),
|
||||
ContainerID: util.NewString(cnrID.EncodeToString()),
|
||||
FileName: util.NewString("newFile.txt"),
|
||||
Payload: base64.StdEncoding.EncodeToString([]byte("content")),
|
||||
}
|
||||
|
@ -377,7 +376,7 @@ func checkGWErrorResponse(t *testing.T, httpClient *http.Client, request *http.R
|
|||
require.Equal(t, models.ErrorTypeGW, *resp.Type)
|
||||
}
|
||||
|
||||
func restObjectPut(ctx context.Context, t *testing.T, clientPool *pool.Pool, cnrID *cid.ID) {
|
||||
func restObjectPut(ctx context.Context, t *testing.T, clientPool *pool.Pool, cnrID cid.ID) {
|
||||
bearer := &models.Bearer{
|
||||
Object: []*models.Record{{
|
||||
Operation: models.NewOperation(models.OperationPUT),
|
||||
|
@ -404,7 +403,7 @@ func restObjectPut(ctx context.Context, t *testing.T, clientPool *pool.Pool, cnr
|
|||
}
|
||||
|
||||
req := &models.ObjectUpload{
|
||||
ContainerID: util.NewString(cnrID.String()),
|
||||
ContainerID: util.NewString(cnrID.EncodeToString()),
|
||||
FileName: util.NewString("newFile.txt"),
|
||||
Payload: base64.StdEncoding.EncodeToString([]byte(content)),
|
||||
Attributes: []*models.Attribute{{
|
||||
|
@ -427,17 +426,17 @@ func restObjectPut(ctx context.Context, t *testing.T, clientPool *pool.Pool, cnr
|
|||
doRequest(t, httpClient, request, http.StatusOK, addr)
|
||||
|
||||
var CID cid.ID
|
||||
err = CID.Parse(*addr.ContainerID)
|
||||
err = CID.DecodeString(*addr.ContainerID)
|
||||
require.NoError(t, err)
|
||||
var id oid.ID
|
||||
err = id.Parse(*addr.ObjectID)
|
||||
err = id.DecodeString(*addr.ObjectID)
|
||||
require.NoError(t, err)
|
||||
objectAddress := address.NewAddress()
|
||||
objectAddress.SetContainerID(&CID)
|
||||
objectAddress.SetObjectID(&id)
|
||||
var objectAddress oid.Address
|
||||
objectAddress.SetContainer(CID)
|
||||
objectAddress.SetObject(id)
|
||||
|
||||
var prm pool.PrmObjectGet
|
||||
prm.SetAddress(*objectAddress)
|
||||
prm.SetAddress(objectAddress)
|
||||
res, err := clientPool.GetObject(ctx, prm)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
@ -451,14 +450,14 @@ func restObjectPut(ctx context.Context, t *testing.T, clientPool *pool.Pool, cnr
|
|||
}
|
||||
}
|
||||
|
||||
func restObjectGet(ctx context.Context, t *testing.T, p *pool.Pool, cnrID *cid.ID) {
|
||||
func restObjectGet(ctx context.Context, t *testing.T, p *pool.Pool, ownerID *user.ID, cnrID cid.ID) {
|
||||
content := []byte("some content")
|
||||
attributes := map[string]string{
|
||||
object.AttributeFileName: "get-obj-name",
|
||||
"user-attribute": "user value",
|
||||
}
|
||||
|
||||
objID := createObject(ctx, t, p, cnrID, attributes, content)
|
||||
objID := createObject(ctx, t, p, ownerID, cnrID, attributes, content)
|
||||
|
||||
bearer := &models.Bearer{
|
||||
Object: []*models.Record{
|
||||
|
@ -491,16 +490,16 @@ func restObjectGet(ctx context.Context, t *testing.T, p *pool.Pool, cnrID *cid.I
|
|||
query := make(url.Values)
|
||||
query.Add(walletConnectQuery, strconv.FormatBool(useWalletConnect))
|
||||
|
||||
request, err := http.NewRequest(http.MethodGet, testHost+"/v1/objects/"+cnrID.String()+"/"+objID.String()+"?"+query.Encode(), nil)
|
||||
request, err := http.NewRequest(http.MethodGet, testHost+"/v1/objects/"+cnrID.EncodeToString()+"/"+objID.EncodeToString()+"?"+query.Encode(), nil)
|
||||
require.NoError(t, err)
|
||||
prepareCommonHeaders(request.Header, bearerToken)
|
||||
|
||||
objInfo := &models.ObjectInfo{}
|
||||
doRequest(t, httpClient, request, http.StatusOK, objInfo)
|
||||
|
||||
require.Equal(t, cnrID.String(), *objInfo.ContainerID)
|
||||
require.Equal(t, objID.String(), *objInfo.ObjectID)
|
||||
require.Equal(t, p.OwnerID().String(), *objInfo.OwnerID)
|
||||
require.Equal(t, cnrID.EncodeToString(), *objInfo.ContainerID)
|
||||
require.Equal(t, objID.EncodeToString(), *objInfo.ObjectID)
|
||||
require.Equal(t, ownerID.EncodeToString(), *objInfo.OwnerID)
|
||||
require.Equal(t, len(attributes), len(objInfo.Attributes))
|
||||
require.Equal(t, int64(len(content)), *objInfo.ObjectSize)
|
||||
|
||||
|
@ -517,7 +516,7 @@ func restObjectGet(ctx context.Context, t *testing.T, p *pool.Pool, cnrID *cid.I
|
|||
query.Add(walletConnectQuery, strconv.FormatBool(useWalletConnect))
|
||||
query.Add("max-payload-size", "0")
|
||||
|
||||
request, err = http.NewRequest(http.MethodGet, testHost+"/v1/objects/"+cnrID.String()+"/"+objID.String()+"?"+query.Encode(), nil)
|
||||
request, err = http.NewRequest(http.MethodGet, testHost+"/v1/objects/"+cnrID.EncodeToString()+"/"+objID.EncodeToString()+"?"+query.Encode(), nil)
|
||||
require.NoError(t, err)
|
||||
prepareCommonHeaders(request.Header, bearerToken)
|
||||
|
||||
|
@ -533,7 +532,7 @@ func restObjectGet(ctx context.Context, t *testing.T, p *pool.Pool, cnrID *cid.I
|
|||
query.Add("range-offset", "0")
|
||||
query.Add("range-length", strconv.Itoa(rangeLength))
|
||||
|
||||
request, err = http.NewRequest(http.MethodGet, testHost+"/v1/objects/"+cnrID.String()+"/"+objID.String()+"?"+query.Encode(), nil)
|
||||
request, err = http.NewRequest(http.MethodGet, testHost+"/v1/objects/"+cnrID.EncodeToString()+"/"+objID.EncodeToString()+"?"+query.Encode(), nil)
|
||||
require.NoError(t, err)
|
||||
prepareCommonHeaders(request.Header, bearerToken)
|
||||
|
||||
|
@ -546,8 +545,8 @@ func restObjectGet(ctx context.Context, t *testing.T, p *pool.Pool, cnrID *cid.I
|
|||
require.Equal(t, content[:rangeLength], contentData)
|
||||
}
|
||||
|
||||
func restObjectDelete(ctx context.Context, t *testing.T, p *pool.Pool, cnrID *cid.ID) {
|
||||
objID := createObject(ctx, t, p, cnrID, nil, []byte("some content"))
|
||||
func restObjectDelete(ctx context.Context, t *testing.T, p *pool.Pool, owner *user.ID, cnrID cid.ID) {
|
||||
objID := createObject(ctx, t, p, owner, cnrID, nil, []byte("some content"))
|
||||
|
||||
bearer := &models.Bearer{
|
||||
Object: []*models.Record{{
|
||||
|
@ -569,7 +568,7 @@ func restObjectDelete(ctx context.Context, t *testing.T, p *pool.Pool, cnrID *ci
|
|||
query := make(url.Values)
|
||||
query.Add(walletConnectQuery, strconv.FormatBool(useWalletConnect))
|
||||
|
||||
request, err := http.NewRequest(http.MethodDelete, testHost+"/v1/objects/"+cnrID.String()+"/"+objID.String()+"?"+query.Encode(), nil)
|
||||
request, err := http.NewRequest(http.MethodDelete, testHost+"/v1/objects/"+cnrID.EncodeToString()+"/"+objID.EncodeToString()+"?"+query.Encode(), nil)
|
||||
require.NoError(t, err)
|
||||
prepareCommonHeaders(request.Header, bearerToken)
|
||||
|
||||
|
@ -577,9 +576,9 @@ func restObjectDelete(ctx context.Context, t *testing.T, p *pool.Pool, cnrID *ci
|
|||
doRequest(t, httpClient, request, http.StatusOK, resp)
|
||||
require.True(t, *resp.Success)
|
||||
|
||||
var addr address.Address
|
||||
addr.SetContainerID(cnrID)
|
||||
addr.SetObjectID(objID)
|
||||
var addr oid.Address
|
||||
addr.SetContainer(cnrID)
|
||||
addr.SetObject(objID)
|
||||
|
||||
var prm pool.PrmObjectHead
|
||||
prm.SetAddress(addr)
|
||||
|
@ -588,16 +587,16 @@ func restObjectDelete(ctx context.Context, t *testing.T, p *pool.Pool, cnrID *ci
|
|||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func restObjectsSearch(ctx context.Context, t *testing.T, p *pool.Pool, cnrID *cid.ID) {
|
||||
func restObjectsSearch(ctx context.Context, t *testing.T, p *pool.Pool, owner *user.ID, cnrID cid.ID) {
|
||||
userKey, userValue := "User-Attribute", "user-attribute-value"
|
||||
objectName := "object-name"
|
||||
headers := map[string]string{
|
||||
object.AttributeFileName: objectName,
|
||||
userKey: userValue,
|
||||
}
|
||||
objID := createObject(ctx, t, p, cnrID, headers, []byte("some content"))
|
||||
objID := createObject(ctx, t, p, owner, cnrID, headers, []byte("some content"))
|
||||
headers[userKey] = "dummy"
|
||||
_ = createObject(ctx, t, p, cnrID, headers, []byte("some content"))
|
||||
_ = createObject(ctx, t, p, owner, cnrID, headers, []byte("some content"))
|
||||
|
||||
bearer := &models.Bearer{
|
||||
Object: []*models.Record{
|
||||
|
@ -643,7 +642,7 @@ func restObjectsSearch(ctx context.Context, t *testing.T, p *pool.Pool, cnrID *c
|
|||
query := make(url.Values)
|
||||
query.Add(walletConnectQuery, strconv.FormatBool(useWalletConnect))
|
||||
|
||||
request, err := http.NewRequest(http.MethodPost, testHost+"/v1/objects/"+cnrID.String()+"/search?"+query.Encode(), bytes.NewReader(body))
|
||||
request, err := http.NewRequest(http.MethodPost, testHost+"/v1/objects/"+cnrID.EncodeToString()+"/search?"+query.Encode(), bytes.NewReader(body))
|
||||
require.NoError(t, err)
|
||||
prepareCommonHeaders(request.Header, bearerToken)
|
||||
|
||||
|
@ -654,8 +653,8 @@ func restObjectsSearch(ctx context.Context, t *testing.T, p *pool.Pool, cnrID *c
|
|||
require.Len(t, resp.Objects, 1)
|
||||
|
||||
objBaseInfo := resp.Objects[0]
|
||||
require.Equal(t, cnrID.String(), *objBaseInfo.Address.ContainerID)
|
||||
require.Equal(t, objID.String(), *objBaseInfo.Address.ObjectID)
|
||||
require.Equal(t, cnrID.EncodeToString(), *objBaseInfo.Address.ContainerID)
|
||||
require.Equal(t, objID.EncodeToString(), *objBaseInfo.Address.ObjectID)
|
||||
require.Equal(t, objectName, objBaseInfo.Name)
|
||||
}
|
||||
|
||||
|
@ -682,21 +681,21 @@ func doRequest(t *testing.T, httpClient *http.Client, request *http.Request, exp
|
|||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func restContainerGet(ctx context.Context, t *testing.T, clientPool *pool.Pool, cnrID *cid.ID) {
|
||||
func restContainerGet(ctx context.Context, t *testing.T, owner user.ID, cnrID cid.ID) {
|
||||
httpClient := &http.Client{Timeout: 5 * time.Second}
|
||||
request, err := http.NewRequest(http.MethodGet, testHost+"/v1/containers/"+cnrID.String(), nil)
|
||||
request, err := http.NewRequest(http.MethodGet, testHost+"/v1/containers/"+cnrID.EncodeToString(), nil)
|
||||
require.NoError(t, err)
|
||||
request = request.WithContext(ctx)
|
||||
|
||||
cnrInfo := &models.ContainerInfo{}
|
||||
doRequest(t, httpClient, request, http.StatusOK, cnrInfo)
|
||||
|
||||
require.Equal(t, cnrID.String(), *cnrInfo.ContainerID)
|
||||
require.Equal(t, clientPool.OwnerID().String(), *cnrInfo.OwnerID)
|
||||
require.Equal(t, cnrID.EncodeToString(), *cnrInfo.ContainerID)
|
||||
require.Equal(t, owner.EncodeToString(), *cnrInfo.OwnerID)
|
||||
}
|
||||
|
||||
func restContainerDelete(ctx context.Context, t *testing.T, clientPool *pool.Pool) {
|
||||
cnrID := createContainer(ctx, t, clientPool, "for-delete")
|
||||
func restContainerDelete(ctx context.Context, t *testing.T, clientPool *pool.Pool, owner user.ID) {
|
||||
cnrID := createContainer(ctx, t, clientPool, owner, "for-delete")
|
||||
|
||||
bearer := &models.Bearer{
|
||||
Container: &models.Rule{
|
||||
|
@ -711,7 +710,7 @@ func restContainerDelete(ctx context.Context, t *testing.T, clientPool *pool.Poo
|
|||
query := make(url.Values)
|
||||
query.Add(walletConnectQuery, strconv.FormatBool(useWalletConnect))
|
||||
|
||||
request, err := http.NewRequest(http.MethodDelete, testHost+"/v1/containers/"+cnrID.String()+"?"+query.Encode(), nil)
|
||||
request, err := http.NewRequest(http.MethodDelete, testHost+"/v1/containers/"+cnrID.EncodeToString()+"?"+query.Encode(), nil)
|
||||
require.NoError(t, err)
|
||||
request = request.WithContext(ctx)
|
||||
prepareCommonHeaders(request.Header, bearerToken)
|
||||
|
@ -721,15 +720,15 @@ func restContainerDelete(ctx context.Context, t *testing.T, clientPool *pool.Poo
|
|||
require.True(t, *resp.Success)
|
||||
|
||||
var prm pool.PrmContainerGet
|
||||
prm.SetContainerID(*cnrID)
|
||||
prm.SetContainerID(cnrID)
|
||||
|
||||
_, err = clientPool.GetContainer(ctx, prm)
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "not found")
|
||||
}
|
||||
|
||||
func restContainerEACLPut(ctx context.Context, t *testing.T, clientPool *pool.Pool) {
|
||||
cnrID := createContainer(ctx, t, clientPool, "for-eacl-put")
|
||||
func restContainerEACLPut(ctx context.Context, t *testing.T, clientPool *pool.Pool, owner user.ID) {
|
||||
cnrID := createContainer(ctx, t, clientPool, owner, "for-eacl-put")
|
||||
httpClient := &http.Client{Timeout: 60 * time.Second}
|
||||
bearer := &models.Bearer{
|
||||
Container: &models.Rule{
|
||||
|
@ -757,7 +756,7 @@ func restContainerEACLPut(ctx context.Context, t *testing.T, clientPool *pool.Po
|
|||
query := make(url.Values)
|
||||
query.Add(walletConnectQuery, strconv.FormatBool(useWalletConnect))
|
||||
|
||||
request, err := http.NewRequest(http.MethodPut, testHost+"/v1/containers/"+cnrID.String()+"/eacl?"+query.Encode(), bytes.NewReader(body))
|
||||
request, err := http.NewRequest(http.MethodPut, testHost+"/v1/containers/"+cnrID.EncodeToString()+"/eacl?"+query.Encode(), bytes.NewReader(body))
|
||||
require.NoError(t, err)
|
||||
request = request.WithContext(ctx)
|
||||
prepareCommonHeaders(request.Header, bearerToken)
|
||||
|
@ -767,7 +766,7 @@ func restContainerEACLPut(ctx context.Context, t *testing.T, clientPool *pool.Po
|
|||
require.True(t, *resp.Success)
|
||||
|
||||
var prm pool.PrmContainerEACL
|
||||
prm.SetContainerID(*cnrID)
|
||||
prm.SetContainerID(cnrID)
|
||||
|
||||
table, err := clientPool.GetEACL(ctx, prm)
|
||||
require.NoError(t, err)
|
||||
|
@ -779,22 +778,22 @@ func restContainerEACLPut(ctx context.Context, t *testing.T, clientPool *pool.Po
|
|||
require.True(t, eacl.EqualTables(*expectedTable, *table))
|
||||
}
|
||||
|
||||
func restContainerEACLGet(ctx context.Context, t *testing.T, p *pool.Pool, cnrID *cid.ID) {
|
||||
func restContainerEACLGet(ctx context.Context, t *testing.T, p *pool.Pool, cnrID cid.ID) {
|
||||
var prm pool.PrmContainerEACL
|
||||
prm.SetContainerID(*cnrID)
|
||||
prm.SetContainerID(cnrID)
|
||||
expectedTable, err := p.GetEACL(ctx, prm)
|
||||
require.NoError(t, err)
|
||||
|
||||
httpClient := &http.Client{Timeout: 60 * time.Second}
|
||||
|
||||
request, err := http.NewRequest(http.MethodGet, testHost+"/v1/containers/"+cnrID.String()+"/eacl", nil)
|
||||
request, err := http.NewRequest(http.MethodGet, testHost+"/v1/containers/"+cnrID.EncodeToString()+"/eacl", nil)
|
||||
require.NoError(t, err)
|
||||
request = request.WithContext(ctx)
|
||||
|
||||
responseTable := &models.Eacl{}
|
||||
doRequest(t, httpClient, request, http.StatusOK, responseTable)
|
||||
|
||||
require.Equal(t, cnrID.String(), responseTable.ContainerID)
|
||||
require.Equal(t, cnrID.EncodeToString(), responseTable.ContainerID)
|
||||
|
||||
actualTable, err := util.ToNativeTable(responseTable.Records)
|
||||
require.NoError(t, err)
|
||||
|
@ -803,9 +802,9 @@ func restContainerEACLGet(ctx context.Context, t *testing.T, p *pool.Pool, cnrID
|
|||
require.True(t, eacl.EqualTables(*expectedTable, *actualTable))
|
||||
}
|
||||
|
||||
func restContainerList(ctx context.Context, t *testing.T, p *pool.Pool, cnrID *cid.ID) {
|
||||
func restContainerList(ctx context.Context, t *testing.T, p *pool.Pool, owner user.ID, cnrID cid.ID) {
|
||||
var prm pool.PrmContainerList
|
||||
prm.SetOwnerID(*p.OwnerID())
|
||||
prm.SetOwnerID(owner)
|
||||
|
||||
ids, err := p.ListContainers(ctx, prm)
|
||||
require.NoError(t, err)
|
||||
|
@ -813,7 +812,7 @@ func restContainerList(ctx context.Context, t *testing.T, p *pool.Pool, cnrID *c
|
|||
httpClient := defaultHTTPClient()
|
||||
|
||||
query := make(url.Values)
|
||||
query.Add("ownerId", p.OwnerID().String())
|
||||
query.Add("ownerId", owner.EncodeToString())
|
||||
|
||||
request, err := http.NewRequest(http.MethodGet, testHost+"/v1/containers?"+query.Encode(), nil)
|
||||
require.NoError(t, err)
|
||||
|
@ -824,14 +823,14 @@ func restContainerList(ctx context.Context, t *testing.T, p *pool.Pool, cnrID *c
|
|||
|
||||
require.Equal(t, len(ids), int(*list.Size))
|
||||
|
||||
require.Truef(t, containsContainer(list.Containers, cnrID.String(), containerName), "list doesn't contain cnr '%s' with name '%s'", cnrID.String(), containerName)
|
||||
require.Truef(t, containsContainer(list.Containers, cnrID.EncodeToString(), containerName), "list doesn't contain cnr '%s' with name '%s'", cnrID.EncodeToString(), containerName)
|
||||
}
|
||||
|
||||
func containsContainer(containers []*models.ContainerInfo, cnrID, cnrName string) bool {
|
||||
for _, cnrInfo := range containers {
|
||||
if *cnrInfo.ContainerID == cnrID {
|
||||
for _, attr := range cnrInfo.Attributes {
|
||||
if *attr.Key == container.AttributeName && *attr.Value == cnrName {
|
||||
if *attr.Key == "Name" && *attr.Value == cnrName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -848,7 +847,8 @@ func makeAuthTokenRequest(ctx context.Context, t *testing.T, bearers []*models.B
|
|||
key, err := keys.NewPrivateKeyFromHex(devenvPrivateKey)
|
||||
require.NoError(t, err)
|
||||
|
||||
ownerID := owner.NewIDFromPublicKey((*ecdsa.PublicKey)(key.PublicKey()))
|
||||
var ownerID user.ID
|
||||
user.IDFromKey(&ownerID, key.PrivateKey.PublicKey)
|
||||
|
||||
data, err := json.Marshal(bearers)
|
||||
require.NoError(t, err)
|
||||
|
@ -924,14 +924,13 @@ func signToken(t *testing.T, key *keys.PrivateKey, data []byte) *handlers.Bearer
|
|||
}
|
||||
|
||||
func signTokenWalletConnect(t *testing.T, key *keys.PrivateKey, data []byte) *handlers.BearerToken {
|
||||
b64Token := make([]byte, base64.StdEncoding.EncodedLen(len(data)))
|
||||
base64.StdEncoding.Encode(b64Token, data)
|
||||
sm, err := walletconnect.SignMessage(&key.PrivateKey, b64Token[:])
|
||||
signer := neofsecdsa.SignerWalletConnect(key.PrivateKey)
|
||||
signature, err := signer.Sign(data)
|
||||
require.NoError(t, err)
|
||||
|
||||
return &handlers.BearerToken{
|
||||
Token: string(b64Token),
|
||||
Signature: hex.EncodeToString(append(sm.Data, sm.Salt...)),
|
||||
Token: base64.StdEncoding.EncodeToString(data),
|
||||
Signature: hex.EncodeToString(signature),
|
||||
Key: hex.EncodeToString(key.PublicKey().Bytes()),
|
||||
}
|
||||
}
|
||||
|
@ -1018,7 +1017,7 @@ func restContainerPut(ctx context.Context, t *testing.T, clientPool *pool.Pool)
|
|||
doRequest(t, httpClient, request, http.StatusOK, addr)
|
||||
|
||||
var CID cid.ID
|
||||
err = CID.Parse(*addr.ContainerID)
|
||||
err = CID.DecodeString(*addr.ContainerID)
|
||||
require.NoError(t, err)
|
||||
fmt.Println(CID.String())
|
||||
|
||||
|
@ -1028,10 +1027,10 @@ func restContainerPut(ctx context.Context, t *testing.T, clientPool *pool.Pool)
|
|||
cnr, err := clientPool.GetContainer(ctx, prm)
|
||||
require.NoError(t, err)
|
||||
|
||||
cnrAttr := make(map[string]string, len(cnr.Attributes()))
|
||||
for _, attribute := range cnr.Attributes() {
|
||||
cnrAttr[attribute.Key()] = attribute.Value()
|
||||
}
|
||||
cnrAttr := make(map[string]string)
|
||||
cnr.IterateAttributes(func(key, val string) {
|
||||
cnrAttr[key] = val
|
||||
})
|
||||
|
||||
for key, val := range userAttributes {
|
||||
require.Equal(t, val, cnrAttr[key])
|
||||
|
@ -1045,32 +1044,38 @@ func prepareCommonHeaders(header http.Header, bearerToken *handlers.BearerToken)
|
|||
header.Add(XBearerSignatureKey, bearerToken.Key)
|
||||
}
|
||||
|
||||
func createContainer(ctx context.Context, t *testing.T, clientPool *pool.Pool, name string) *cid.ID {
|
||||
pp, err := policy.Parse("REP 1")
|
||||
func createContainer(ctx context.Context, t *testing.T, clientPool *pool.Pool, owner user.ID, name string) cid.ID {
|
||||
var policy netmap.PlacementPolicy
|
||||
err := policy.DecodeString("REP 1")
|
||||
require.NoError(t, err)
|
||||
|
||||
cnr := container.New(
|
||||
container.WithPolicy(pp),
|
||||
container.WithCustomBasicACL(0x0FFFFFFF),
|
||||
container.WithAttribute(container.AttributeName, name),
|
||||
container.WithAttribute(container.AttributeTimestamp, strconv.FormatInt(time.Now().Unix(), 10)))
|
||||
cnr.SetOwnerID(clientPool.OwnerID())
|
||||
var cnr container.Container
|
||||
cnr.Init()
|
||||
cnr.SetOwner(owner)
|
||||
cnr.SetPlacementPolicy(policy)
|
||||
cnr.SetBasicACL(acl.PublicRWExtended)
|
||||
|
||||
container.SetName(&cnr, name)
|
||||
container.SetCreationTime(&cnr, time.Now())
|
||||
|
||||
err = pool.SyncContainerWithNetwork(ctx, &cnr, clientPool)
|
||||
require.NoError(t, err)
|
||||
|
||||
var waitPrm pool.WaitParams
|
||||
waitPrm.SetPollInterval(3 * time.Second)
|
||||
waitPrm.SetTimeout(15 * time.Second)
|
||||
|
||||
var prm pool.PrmContainerPut
|
||||
prm.SetContainer(*cnr)
|
||||
prm.SetContainer(cnr)
|
||||
prm.SetWaitParams(waitPrm)
|
||||
|
||||
CID, err := clientPool.PutContainer(ctx, prm)
|
||||
require.NoError(t, err)
|
||||
|
||||
return CID
|
||||
return *CID
|
||||
}
|
||||
|
||||
func createObject(ctx context.Context, t *testing.T, p *pool.Pool, cnrID *cid.ID, headers map[string]string, payload []byte) *oid.ID {
|
||||
func createObject(ctx context.Context, t *testing.T, p *pool.Pool, ownerID *user.ID, cnrID cid.ID, headers map[string]string, payload []byte) oid.ID {
|
||||
attributes := make([]object.Attribute, 0, len(headers))
|
||||
|
||||
for key, val := range headers {
|
||||
|
@ -1081,7 +1086,7 @@ func createObject(ctx context.Context, t *testing.T, p *pool.Pool, cnrID *cid.ID
|
|||
}
|
||||
|
||||
obj := object.New()
|
||||
obj.SetOwnerID(p.OwnerID())
|
||||
obj.SetOwnerID(ownerID)
|
||||
obj.SetContainerID(cnrID)
|
||||
obj.SetAttributes(attributes...)
|
||||
obj.SetPayload(payload)
|
||||
|
@ -1092,10 +1097,10 @@ func createObject(ctx context.Context, t *testing.T, p *pool.Pool, cnrID *cid.ID
|
|||
objID, err := p.PutObject(ctx, prm)
|
||||
require.NoError(t, err)
|
||||
|
||||
return objID
|
||||
return *objID
|
||||
}
|
||||
|
||||
func restrictByEACL(ctx context.Context, t *testing.T, clientPool *pool.Pool, cnrID *cid.ID) *eacl.Table {
|
||||
func restrictByEACL(ctx context.Context, t *testing.T, clientPool *pool.Pool, cnrID cid.ID) *eacl.Table {
|
||||
table := eacl.NewTable()
|
||||
table.SetCID(cnrID)
|
||||
|
||||
|
|
7
go.mod
7
go.mod
|
@ -12,8 +12,8 @@ require (
|
|||
github.com/go-openapi/validate v0.21.0
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/nspcc-dev/neo-go v0.98.2
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.12.1
|
||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.3.0.20220412151250-3e75660802ae
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.13.0
|
||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.5
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/testcontainers/testcontainers-go v0.13.0
|
||||
|
@ -64,8 +64,9 @@ require (
|
|||
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c // indirect
|
||||
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||
github.com/nspcc-dev/hrw v1.0.9 // indirect
|
||||
github.com/nspcc-dev/neofs-crypto v0.3.0
|
||||
github.com/nspcc-dev/neofs-crypto v0.3.0 // indirect
|
||||
github.com/nspcc-dev/rfc6979 v0.2.0 // indirect
|
||||
github.com/nspcc-dev/tzhash v1.5.2 // indirect
|
||||
github.com/oklog/ulid v1.3.1 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.2 // indirect
|
||||
|
|
12
go.sum
12
go.sum
|
@ -742,19 +742,22 @@ github.com/nspcc-dev/neo-go v0.98.2/go.mod h1:KXKqJwfTyVJzDarSCDqFaKrVbg/qz0ZBk2
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220321113211-526c423a6152/go.mod h1:QBE0I30F2kOAISNpT5oks82yF4wkkUq3SCfI3Hqgx/Y=
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.11.0-pre.0.20211201134523-3604d96f3fe1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs=
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.11.1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs=
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.12.1 h1:PVU2rLlG9S0jDe5eKyaUs4nKo/la+mN5pvz32Gib3qM=
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.12.1/go.mod h1:73j09Xa7I2zQbM3HCvAHnDHPYiiWnEHa1d6Z6RDMBLU=
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.13.0 h1:7BcBiSjmWqJx0SPFlGRYt9ZFbMjucRIz9+Mv8UBLeq8=
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.13.0/go.mod h1:73j09Xa7I2zQbM3HCvAHnDHPYiiWnEHa1d6Z6RDMBLU=
|
||||
github.com/nspcc-dev/neofs-contract v0.15.1/go.mod h1:kxO5ZTqdzFnRM5RMvM+Fhd+3GGrJo6AmG2ZyA9OCqqQ=
|
||||
github.com/nspcc-dev/neofs-crypto v0.2.0/go.mod h1:F/96fUzPM3wR+UGsPi3faVNmFlA9KAEAUQR7dMxZmNA=
|
||||
github.com/nspcc-dev/neofs-crypto v0.2.3/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw=
|
||||
github.com/nspcc-dev/neofs-crypto v0.3.0 h1:zlr3pgoxuzrmGCxc5W8dGVfA9Rro8diFvVnBg0L4ifM=
|
||||
github.com/nspcc-dev/neofs-crypto v0.3.0/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw=
|
||||
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20211201182451-a5b61c4f6477/go.mod h1:dfMtQWmBHYpl9Dez23TGtIUKiFvCIxUZq/CkSIhEpz4=
|
||||
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20220113123743-7f3162110659/go.mod h1:/jay1lr3w7NQd/VDBkEhkJmDmyPNsu4W+QV2obsUV40=
|
||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.3.0.20220412151250-3e75660802ae h1:xcoEwEwZXu784Re1PPE35vm1A4+sUCVgMuGFqQPnN1Q=
|
||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.3.0.20220412151250-3e75660802ae/go.mod h1:Hl7a1l0ntZ4b1ZABpGX6fuAuFS3c6+hyMCUNVvZv/w4=
|
||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.5 h1:PSUUUL0XloTQdAgaI0WIY54TsqQ0GpxehHC7FaTkHvI=
|
||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.5/go.mod h1:hP3HrbK8omERJZvwjsGZgvzsUDxsPDPemrHzgqfpADM=
|
||||
github.com/nspcc-dev/rfc6979 v0.1.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso=
|
||||
github.com/nspcc-dev/rfc6979 v0.2.0 h1:3e1WNxrN60/6N0DW7+UYisLeZJyfqZTNOjeV/toYvOE=
|
||||
github.com/nspcc-dev/rfc6979 v0.2.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso=
|
||||
github.com/nspcc-dev/tzhash v1.5.2 h1:GuIQPOY2xpl5ZE1pbUbz+QdKXVOTyzbbxSVv0nBfa98=
|
||||
github.com/nspcc-dev/tzhash v1.5.2/go.mod h1:gwAx6mcsbkfY+JVp+PovoP2Gvw6y57W8dj7zDHKOhzI=
|
||||
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
|
||||
|
@ -1291,6 +1294,7 @@ golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220403205710-6acee93ad0eb h1:PVGECzEo9Y3uOidtkHGdd347NjLtITfJFO9BxFpmRoo=
|
||||
golang.org/x/sys v0.0.0-20220403205710-6acee93ad0eb/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/nspcc-dev/neofs-rest-gw/gen/restapi/operations"
|
||||
"github.com/nspcc-dev/neofs-rest-gw/internal/util"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/pool"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/user"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
|
@ -22,6 +23,7 @@ type API struct {
|
|||
log *zap.Logger
|
||||
pool *pool.Pool
|
||||
key *keys.PrivateKey
|
||||
owner *user.ID
|
||||
defaultTimestamp bool
|
||||
}
|
||||
|
||||
|
@ -59,10 +61,14 @@ const (
|
|||
|
||||
// New creates a new API using specified logger, connection pool and other parameters.
|
||||
func New(prm *PrmAPI) *API {
|
||||
var owner user.ID
|
||||
user.IDFromKey(&owner, prm.Key.PrivateKey.PublicKey)
|
||||
|
||||
return &API{
|
||||
log: prm.Logger,
|
||||
pool: prm.Pool,
|
||||
key: prm.Key,
|
||||
owner: &owner,
|
||||
defaultTimestamp: prm.DefaultTimestamp,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,11 +8,15 @@ import (
|
|||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/google/uuid"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neofs-api-go/v2/acl"
|
||||
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||
sessionv2 "github.com/nspcc-dev/neofs-api-go/v2/session"
|
||||
"github.com/nspcc-dev/neofs-rest-gw/gen/models"
|
||||
"github.com/nspcc-dev/neofs-rest-gw/gen/restapi/operations"
|
||||
"github.com/nspcc-dev/neofs-rest-gw/internal/util"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/owner"
|
||||
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/pool"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/user"
|
||||
)
|
||||
|
||||
const defaultTokenExpDuration = 100 // in epoch
|
||||
|
@ -83,7 +87,7 @@ func (a *API) PostAuth(params operations.AuthParams) middleware.Responder {
|
|||
|
||||
if isObject {
|
||||
prm := newObjectParams(commonPrm, token)
|
||||
response[i], err = prepareObjectToken(ctx, prm, a.pool)
|
||||
response[i], err = prepareObjectToken(ctx, prm, a.pool, *a.owner)
|
||||
} else {
|
||||
prm := newContainerParams(commonPrm, token)
|
||||
response[i], err = prepareContainerTokens(ctx, prm, a.pool, a.key.PublicKey())
|
||||
|
@ -96,23 +100,23 @@ func (a *API) PostAuth(params operations.AuthParams) middleware.Responder {
|
|||
return operations.NewAuthOK().WithPayload(response)
|
||||
}
|
||||
|
||||
func prepareObjectToken(ctx context.Context, params objectTokenParams, pool *pool.Pool) (*models.TokenResponse, error) {
|
||||
func prepareObjectToken(ctx context.Context, params objectTokenParams, pool *pool.Pool, owner user.ID) (*models.TokenResponse, error) {
|
||||
btoken, err := util.ToNativeObjectToken(params.Records)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't transform token to native: %w", err)
|
||||
}
|
||||
btoken.SetOwner(pool.OwnerID())
|
||||
btoken.ForUser(owner)
|
||||
|
||||
iat, exp, err := getTokenLifetime(ctx, pool, params.XBearerLifetime)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't get lifetime: %w", err)
|
||||
}
|
||||
btoken.SetLifetime(exp, 0, iat)
|
||||
btoken.SetIat(iat)
|
||||
btoken.SetExp(exp)
|
||||
|
||||
binaryBearer, err := btoken.ToV2().GetBody().StableMarshal(nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't marshal bearer token: %w", err)
|
||||
}
|
||||
var v2token acl.BearerToken
|
||||
btoken.WriteToV2(&v2token)
|
||||
binaryBearer := v2token.GetBody().StableMarshal(nil)
|
||||
|
||||
return &models.TokenResponse{
|
||||
Name: params.Name,
|
||||
|
@ -127,8 +131,8 @@ func prepareContainerTokens(ctx context.Context, params containerTokenParams, po
|
|||
return nil, fmt.Errorf("couldn't get lifetime: %w", err)
|
||||
}
|
||||
|
||||
var ownerID owner.ID
|
||||
if err = ownerID.Parse(params.XBearerOwnerID); err != nil {
|
||||
var ownerID user.ID
|
||||
if err = ownerID.DecodeString(params.XBearerOwnerID); err != nil {
|
||||
return nil, fmt.Errorf("invalid bearer owner: %w", err)
|
||||
}
|
||||
|
||||
|
@ -137,22 +141,21 @@ func prepareContainerTokens(ctx context.Context, params containerTokenParams, po
|
|||
return nil, fmt.Errorf("couldn't transform rule to native session token: %w", err)
|
||||
}
|
||||
|
||||
uid, err := uuid.New().MarshalBinary()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stoken.SetID(uid)
|
||||
|
||||
stoken.SetOwnerID(&ownerID)
|
||||
|
||||
stoken.SetID(uuid.New())
|
||||
stoken.SetIat(iat)
|
||||
stoken.SetExp(exp)
|
||||
stoken.SetSessionKey(key.Bytes())
|
||||
|
||||
binaryToken, err := stoken.ToV2().GetBody().StableMarshal(nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't marshal session token: %w", err)
|
||||
}
|
||||
authKey := neofsecdsa.PublicKey(*key)
|
||||
stoken.SetAuthKey(&authKey)
|
||||
|
||||
var v2token sessionv2.Token
|
||||
stoken.WriteToV2(&v2token)
|
||||
|
||||
var issuer refs.OwnerID
|
||||
ownerID.WriteToV2(&issuer)
|
||||
v2token.GetBody().SetOwnerID(&issuer)
|
||||
|
||||
binaryToken := v2token.GetBody().StableMarshal(nil)
|
||||
|
||||
return &models.TokenResponse{
|
||||
Name: params.Name,
|
||||
|
|
|
@ -7,12 +7,14 @@ import (
|
|||
"crypto/sha512"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neofs-api-go/v2/acl"
|
||||
"github.com/nspcc-dev/neofs-rest-gw/gen/models"
|
||||
"github.com/nspcc-dev/neofs-rest-gw/internal/util"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/owner"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/user"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
@ -37,14 +39,19 @@ func TestSign(t *testing.T) {
|
|||
btoken, err := util.ToNativeObjectToken(records)
|
||||
require.NoError(t, err)
|
||||
|
||||
btoken.SetExp(math.MaxInt64)
|
||||
|
||||
ownerKey, err := keys.NewPublicKeyFromString(pubKeyHex)
|
||||
require.NoError(t, err)
|
||||
|
||||
btoken.SetOwner(owner.NewIDFromPublicKey((*ecdsa.PublicKey)(ownerKey)))
|
||||
var owner user.ID
|
||||
user.IDFromKey(&owner, *(*ecdsa.PublicKey)(ownerKey))
|
||||
btoken.ForUser(owner)
|
||||
|
||||
binaryBearer, err := btoken.ToV2().GetBody().StableMarshal(nil)
|
||||
require.NoError(t, err)
|
||||
var v2token acl.BearerToken
|
||||
btoken.WriteToV2(&v2token)
|
||||
|
||||
binaryBearer := v2token.GetBody().StableMarshal(nil)
|
||||
bearerBase64 := base64.StdEncoding.EncodeToString(binaryBearer)
|
||||
|
||||
h := sha512.Sum512(binaryBearer)
|
||||
|
|
|
@ -2,13 +2,11 @@ package handlers
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -19,20 +17,21 @@ import (
|
|||
"github.com/nspcc-dev/neofs-rest-gw/gen/models"
|
||||
"github.com/nspcc-dev/neofs-rest-gw/gen/restapi/operations"
|
||||
"github.com/nspcc-dev/neofs-rest-gw/internal/util"
|
||||
walletconnect "github.com/nspcc-dev/neofs-rest-gw/internal/wallet-connect"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/acl"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/container"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/container/acl"
|
||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/owner"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/policy"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/pool"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/session"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/user"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultPlacementPolicy = "REP 3"
|
||||
defaultBasicACL = acl.PrivateBasicName
|
||||
defaultBasicACL = acl.NamePrivate
|
||||
attributeName = "Name"
|
||||
attributeTimestamp = "Timestamp"
|
||||
)
|
||||
|
||||
// PutContainers handler that creates container in NeoFS.
|
||||
|
@ -60,7 +59,7 @@ func (a *API) PutContainers(params operations.PutContainerParams, principal *mod
|
|||
}
|
||||
|
||||
var resp operations.PutContainerOKBody
|
||||
resp.ContainerID = util.NewString(cnrID.String())
|
||||
resp.ContainerID = util.NewString(cnrID.EncodeToString())
|
||||
|
||||
return operations.NewPutContainerOK().WithPayload(&resp)
|
||||
}
|
||||
|
@ -73,7 +72,7 @@ func (a *API) GetContainer(params operations.GetContainerParams) middleware.Resp
|
|||
return operations.NewGetContainerBadRequest().WithPayload(resp)
|
||||
}
|
||||
|
||||
cnrInfo, err := getContainerInfo(params.HTTPRequest.Context(), a.pool, *cnrID)
|
||||
cnrInfo, err := getContainerInfo(params.HTTPRequest.Context(), a.pool, cnrID)
|
||||
if err != nil {
|
||||
resp := a.logAndGetErrorResponse("get container", err)
|
||||
return operations.NewGetContainerBadRequest().WithPayload(resp)
|
||||
|
@ -133,8 +132,8 @@ func (a *API) GetContainerEACL(params operations.GetContainerEACLParams) middlew
|
|||
func (a *API) ListContainer(params operations.ListContainersParams) middleware.Responder {
|
||||
ctx := params.HTTPRequest.Context()
|
||||
|
||||
var ownerID owner.ID
|
||||
if err := ownerID.Parse(params.OwnerID); err != nil {
|
||||
var ownerID user.ID
|
||||
if err := ownerID.DecodeString(params.OwnerID); err != nil {
|
||||
resp := a.logAndGetErrorResponse("invalid owner id", err)
|
||||
return operations.NewListContainersBadRequest().WithPayload(resp)
|
||||
}
|
||||
|
@ -203,8 +202,8 @@ func (a *API) DeleteContainer(params operations.DeleteContainerParams, principal
|
|||
}
|
||||
|
||||
var prm pool.PrmContainerDelete
|
||||
prm.SetContainerID(*cnrID)
|
||||
prm.SetSessionToken(*stoken)
|
||||
prm.SetContainerID(cnrID)
|
||||
prm.SetSessionToken(stoken)
|
||||
|
||||
if err = a.pool.DeleteContainer(params.HTTPRequest.Context(), prm); err != nil {
|
||||
resp := a.logAndGetErrorResponse("delete container", err, zap.String("container", params.ContainerID))
|
||||
|
@ -223,58 +222,62 @@ func getContainerInfo(ctx context.Context, p *pool.Pool, cnrID cid.ID) (*models.
|
|||
return nil, err
|
||||
}
|
||||
|
||||
attrs := make([]*models.Attribute, len(cnr.Attributes()))
|
||||
for i, attr := range cnr.Attributes() {
|
||||
attrs[i] = &models.Attribute{
|
||||
Key: util.NewString(attr.Key()),
|
||||
Value: util.NewString(attr.Value()),
|
||||
}
|
||||
var attrs []*models.Attribute
|
||||
cnr.IterateAttributes(func(key, val string) {
|
||||
attrs = append(attrs, &models.Attribute{
|
||||
Key: util.NewString(key),
|
||||
Value: util.NewString(val),
|
||||
})
|
||||
})
|
||||
|
||||
var sb strings.Builder
|
||||
if err = cnr.PlacementPolicy().WriteStringTo(&sb); err != nil {
|
||||
return nil, fmt.Errorf("writer policy to string: %w", err)
|
||||
}
|
||||
|
||||
return &models.ContainerInfo{
|
||||
ContainerID: util.NewString(cnrID.String()),
|
||||
Version: util.NewString(cnr.Version().String()),
|
||||
OwnerID: util.NewString(cnr.OwnerID().String()),
|
||||
BasicACL: util.NewString(acl.BasicACL(cnr.BasicACL()).String()),
|
||||
PlacementPolicy: util.NewString(strings.Join(policy.Encode(cnr.PlacementPolicy()), " ")),
|
||||
OwnerID: util.NewString(cnr.Owner().String()),
|
||||
BasicACL: util.NewString(cnr.BasicACL().EncodeToString()),
|
||||
PlacementPolicy: util.NewString(sb.String()),
|
||||
Attributes: attrs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func prepareUserAttributes(header http.Header) map[string]string {
|
||||
filtered := filterHeaders(header)
|
||||
delete(filtered, container.AttributeName)
|
||||
delete(filtered, container.AttributeTimestamp)
|
||||
delete(filtered, attributeName)
|
||||
delete(filtered, attributeTimestamp)
|
||||
return filtered
|
||||
}
|
||||
|
||||
func parseContainerID(containerID string) (*cid.ID, error) {
|
||||
func parseContainerID(containerID string) (cid.ID, error) {
|
||||
var cnrID cid.ID
|
||||
if err := cnrID.Parse(containerID); err != nil {
|
||||
return nil, fmt.Errorf("parse container id '%s': %w", containerID, err)
|
||||
if err := cnrID.DecodeString(containerID); err != nil {
|
||||
return cid.ID{}, fmt.Errorf("parse container id '%s': %w", containerID, err)
|
||||
}
|
||||
|
||||
return &cnrID, nil
|
||||
return cnrID, nil
|
||||
}
|
||||
|
||||
func setContainerEACL(ctx context.Context, p *pool.Pool, cnrID *cid.ID, stoken *session.Token, eaclPrm *models.Eacl) error {
|
||||
func setContainerEACL(ctx context.Context, p *pool.Pool, cnrID cid.ID, stoken session.Container, eaclPrm *models.Eacl) error {
|
||||
table, err := util.ToNativeTable(eaclPrm.Records)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
table.SetCID(cnrID)
|
||||
table.SetSessionToken(stoken)
|
||||
|
||||
var prm pool.PrmContainerSetEACL
|
||||
prm.SetTable(*table)
|
||||
prm.WithinSession(stoken)
|
||||
|
||||
return p.SetEACL(ctx, prm)
|
||||
}
|
||||
|
||||
func getContainerEACL(ctx context.Context, p *pool.Pool, cnrID *cid.ID) (*models.Eacl, error) {
|
||||
func getContainerEACL(ctx context.Context, p *pool.Pool, cnrID cid.ID) (*models.Eacl, error) {
|
||||
var prm pool.PrmContainerEACL
|
||||
prm.SetContainerID(*cnrID)
|
||||
prm.SetContainerID(cnrID)
|
||||
|
||||
table, err := p.GetEACL(ctx, prm)
|
||||
if err != nil {
|
||||
|
@ -282,7 +285,7 @@ func getContainerEACL(ctx context.Context, p *pool.Pool, cnrID *cid.ID) (*models
|
|||
}
|
||||
|
||||
tableResp := &models.Eacl{
|
||||
ContainerID: cnrID.String(),
|
||||
ContainerID: cnrID.EncodeToString(),
|
||||
Records: make([]*models.Record, len(table.Records())),
|
||||
}
|
||||
|
||||
|
@ -297,59 +300,63 @@ func getContainerEACL(ctx context.Context, p *pool.Pool, cnrID *cid.ID) (*models
|
|||
return tableResp, nil
|
||||
}
|
||||
|
||||
func createContainer(ctx context.Context, p *pool.Pool, stoken *session.Token, params *operations.PutContainerParams, userAttrs map[string]string) (*cid.ID, error) {
|
||||
func createContainer(ctx context.Context, p *pool.Pool, stoken session.Container, params *operations.PutContainerParams, userAttrs map[string]string) (cid.ID, error) {
|
||||
request := params.Container
|
||||
|
||||
if request.PlacementPolicy == "" {
|
||||
request.PlacementPolicy = defaultPlacementPolicy
|
||||
}
|
||||
pp, err := policy.Parse(request.PlacementPolicy)
|
||||
var policy netmap.PlacementPolicy
|
||||
err := policy.DecodeString(request.PlacementPolicy)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't parse placement policy: %w", err)
|
||||
return cid.ID{}, fmt.Errorf("couldn't parse placement policy: %w", err)
|
||||
}
|
||||
|
||||
if request.BasicACL == "" {
|
||||
request.BasicACL = defaultBasicACL
|
||||
}
|
||||
basicACL, err := acl.ParseBasicACL(request.BasicACL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't parse basic acl: %w", err)
|
||||
|
||||
var basicACL acl.Basic
|
||||
if err = basicACL.DecodeString(request.BasicACL); err != nil {
|
||||
return cid.ID{}, fmt.Errorf("couldn't parse basic acl: %w", err)
|
||||
}
|
||||
|
||||
cnrOptions := []container.Option{
|
||||
container.WithPolicy(pp),
|
||||
container.WithCustomBasicACL(basicACL),
|
||||
container.WithAttribute(container.AttributeTimestamp, strconv.FormatInt(time.Now().Unix(), 10)),
|
||||
}
|
||||
var cnr container.Container
|
||||
cnr.Init()
|
||||
cnr.SetPlacementPolicy(policy)
|
||||
cnr.SetBasicACL(basicACL)
|
||||
cnr.SetOwner(stoken.Issuer())
|
||||
|
||||
container.SetCreationTime(&cnr, time.Now())
|
||||
|
||||
if request.ContainerName != "" {
|
||||
container.WithAttribute(container.AttributeName, request.ContainerName)
|
||||
container.SetName(&cnr, request.ContainerName)
|
||||
}
|
||||
|
||||
for key, val := range userAttrs {
|
||||
cnrOptions = append(cnrOptions, container.WithAttribute(key, val))
|
||||
cnr.SetAttribute(key, val)
|
||||
}
|
||||
|
||||
cnr := container.New(cnrOptions...)
|
||||
cnr.SetOwnerID(stoken.OwnerID())
|
||||
cnr.SetSessionToken(stoken)
|
||||
|
||||
if *params.NameScopeGlobal { // we don't check for nil because there is default false value
|
||||
if err = checkNNSContainerName(request.ContainerName); err != nil {
|
||||
return nil, fmt.Errorf("invalid container name: %w", err)
|
||||
return cid.ID{}, fmt.Errorf("invalid container name: %w", err)
|
||||
}
|
||||
container.SetNativeName(cnr, request.ContainerName)
|
||||
|
||||
var domain container.Domain
|
||||
domain.SetName(request.ContainerName)
|
||||
container.WriteDomain(&cnr, domain)
|
||||
}
|
||||
|
||||
var prm pool.PrmContainerPut
|
||||
prm.SetContainer(*cnr)
|
||||
prm.SetContainer(cnr)
|
||||
prm.WithinSession(stoken)
|
||||
|
||||
cnrID, err := p.PutContainer(ctx, prm)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("put container: %w", err)
|
||||
return cid.ID{}, fmt.Errorf("put container: %w", err)
|
||||
}
|
||||
|
||||
return cnrID, nil
|
||||
return *cnrID, nil
|
||||
}
|
||||
|
||||
func checkNNSContainerName(name string) error {
|
||||
|
@ -383,51 +390,52 @@ func isAlNum(c uint8) bool {
|
|||
return c >= 'a' && c <= 'z' || c >= '0' && c <= '9'
|
||||
}
|
||||
|
||||
func prepareSessionToken(st *SessionToken, isWalletConnect bool) (*session.Token, error) {
|
||||
func prepareSessionToken(st *SessionToken, isWalletConnect bool) (session.Container, error) {
|
||||
data, err := base64.StdEncoding.DecodeString(st.Token)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't base64-decode session token: %w", err)
|
||||
return session.Container{}, fmt.Errorf("can't base64-decode session token: %w", err)
|
||||
}
|
||||
|
||||
signature, err := hex.DecodeString(st.Signature)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't decode signature: %w", err)
|
||||
return session.Container{}, fmt.Errorf("couldn't decode signature: %w", err)
|
||||
}
|
||||
|
||||
ownerKey, err := keys.NewPublicKeyFromString(st.Key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't fetch session token owner key: %w", err)
|
||||
return session.Container{}, fmt.Errorf("couldn't fetch session token owner key: %w", err)
|
||||
}
|
||||
|
||||
body := new(sessionv2.TokenBody)
|
||||
if err = body.Unmarshal(data); err != nil {
|
||||
return nil, fmt.Errorf("can't unmarshal session token: %w", err)
|
||||
return session.Container{}, fmt.Errorf("can't unmarshal session token: %w", err)
|
||||
}
|
||||
|
||||
if sessionContext, ok := body.GetContext().(*sessionv2.ContainerSessionContext); !ok {
|
||||
return nil, errors.New("expected container session context but got something different")
|
||||
return session.Container{}, errors.New("expected container session context but got something different")
|
||||
} else if sessionContext.Verb() != st.Verb {
|
||||
return nil, fmt.Errorf("invalid container session verb '%s', expected: '%s'", sessionContext.Verb().String(), st.Verb.String())
|
||||
return session.Container{}, fmt.Errorf("invalid container session verb '%s', expected: '%s'", sessionContext.Verb().String(), st.Verb.String())
|
||||
}
|
||||
|
||||
stoken := new(session.Token)
|
||||
stoken.ToV2().SetBody(body)
|
||||
|
||||
v2signature := new(refs.Signature)
|
||||
v2signature.SetScheme(refs.ECDSA_SHA512)
|
||||
if isWalletConnect {
|
||||
v2signature.SetScheme(2)
|
||||
v2signature.SetScheme(refs.ECDSA_RFC6979_SHA256_WALLET_CONNECT)
|
||||
}
|
||||
v2signature.SetSign(signature)
|
||||
v2signature.SetKey(ownerKey.Bytes())
|
||||
stoken.ToV2().SetSignature(v2signature)
|
||||
|
||||
if isWalletConnect {
|
||||
if !walletconnect.Verify((*ecdsa.PublicKey)(ownerKey), []byte(st.Token), signature) {
|
||||
return nil, fmt.Errorf("invalid signature")
|
||||
}
|
||||
} else if !stoken.VerifySignature() {
|
||||
return nil, fmt.Errorf("invalid signature")
|
||||
var v2token sessionv2.Token
|
||||
v2token.SetBody(body)
|
||||
v2token.SetSignature(v2signature)
|
||||
|
||||
var stoken session.Container
|
||||
if err = stoken.ReadFromV2(v2token); err != nil {
|
||||
return session.Container{}, fmt.Errorf("read from v2 token: %w", err)
|
||||
}
|
||||
|
||||
if !stoken.VerifySignature() {
|
||||
return session.Container{}, fmt.Errorf("invalid signature")
|
||||
}
|
||||
|
||||
return stoken, err
|
||||
|
|
|
@ -2,7 +2,6 @@ package handlers
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
|
@ -17,13 +16,11 @@ import (
|
|||
"github.com/nspcc-dev/neofs-rest-gw/gen/models"
|
||||
"github.com/nspcc-dev/neofs-rest-gw/gen/restapi/operations"
|
||||
"github.com/nspcc-dev/neofs-rest-gw/internal/util"
|
||||
walletconnect "github.com/nspcc-dev/neofs-rest-gw/internal/wallet-connect"
|
||||
"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/object"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/pool"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/token"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
|
@ -39,7 +36,7 @@ func (a *API) PutObjects(params operations.PutObjectParams, principal *models.Pr
|
|||
}
|
||||
|
||||
var cnrID cid.ID
|
||||
if err = cnrID.Parse(*params.Object.ContainerID); err != nil {
|
||||
if err = cnrID.DecodeString(*params.Object.ContainerID); err != nil {
|
||||
resp := a.logAndGetErrorResponse("invalid container id", err)
|
||||
return errorResponse.WithPayload(resp)
|
||||
}
|
||||
|
@ -60,9 +57,11 @@ func (a *API) PutObjects(params operations.PutObjectParams, principal *models.Pr
|
|||
return errorResponse.WithPayload(resp)
|
||||
}
|
||||
|
||||
owner := bearer.ResolveIssuer(btoken)
|
||||
|
||||
obj := object.New()
|
||||
obj.SetContainerID(&cnrID)
|
||||
obj.SetOwnerID(btoken.OwnerID())
|
||||
obj.SetContainerID(cnrID)
|
||||
obj.SetOwnerID(&owner)
|
||||
obj.SetPayload(payload)
|
||||
obj.SetAttributes(attributes...)
|
||||
|
||||
|
@ -101,7 +100,7 @@ func (a *API) GetObjectInfo(params operations.GetObjectInfoParams, principal *mo
|
|||
}
|
||||
|
||||
var prm pool.PrmObjectHead
|
||||
prm.SetAddress(*addr)
|
||||
prm.SetAddress(addr)
|
||||
prm.UseBearer(btoken)
|
||||
|
||||
objInfo, err := a.pool.HeadObject(ctx, prm)
|
||||
|
@ -126,7 +125,7 @@ func (a *API) GetObjectInfo(params operations.GetObjectInfoParams, principal *mo
|
|||
}
|
||||
|
||||
var prmRange pool.PrmObjectRange
|
||||
prmRange.SetAddress(*addr)
|
||||
prmRange.SetAddress(addr)
|
||||
prmRange.UseBearer(btoken)
|
||||
|
||||
var offset, length uint64
|
||||
|
@ -195,7 +194,7 @@ func (a *API) DeleteObject(params operations.DeleteObjectParams, principal *mode
|
|||
}
|
||||
|
||||
var prm pool.PrmObjectDelete
|
||||
prm.SetAddress(*addr)
|
||||
prm.SetAddress(addr)
|
||||
prm.UseBearer(btoken)
|
||||
|
||||
if err = a.pool.DeleteObject(ctx, prm); err != nil {
|
||||
|
@ -212,7 +211,7 @@ func (a *API) SearchObjects(params operations.SearchObjectsParams, principal *mo
|
|||
ctx := params.HTTPRequest.Context()
|
||||
|
||||
var cnrID cid.ID
|
||||
if err := cnrID.Parse(params.ContainerID); err != nil {
|
||||
if err := cnrID.DecodeString(params.ContainerID); err != nil {
|
||||
resp := a.logAndGetErrorResponse("invalid container id", err)
|
||||
return errorResponse.WithPayload(resp)
|
||||
}
|
||||
|
@ -254,7 +253,7 @@ func (a *API) SearchObjects(params operations.SearchObjectsParams, principal *mo
|
|||
return false
|
||||
}
|
||||
|
||||
if obj, iterateErr = headObjectBaseInfo(ctx, a.pool, &cnrID, &id, btoken); iterateErr != nil {
|
||||
if obj, iterateErr = headObjectBaseInfo(ctx, a.pool, cnrID, id, btoken); iterateErr != nil {
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -278,13 +277,13 @@ func (a *API) SearchObjects(params operations.SearchObjectsParams, principal *mo
|
|||
return operations.NewSearchObjectsOK().WithPayload(list)
|
||||
}
|
||||
|
||||
func headObjectBaseInfo(ctx context.Context, p *pool.Pool, cnrID *cid.ID, objID *oid.ID, btoken *token.BearerToken) (*models.ObjectBaseInfo, error) {
|
||||
addr := address.NewAddress()
|
||||
addr.SetContainerID(cnrID)
|
||||
addr.SetObjectID(objID)
|
||||
func headObjectBaseInfo(ctx context.Context, p *pool.Pool, cnrID cid.ID, objID oid.ID, btoken bearer.Token) (*models.ObjectBaseInfo, error) {
|
||||
var addr oid.Address
|
||||
addr.SetContainer(cnrID)
|
||||
addr.SetObject(objID)
|
||||
|
||||
var prm pool.PrmObjectHead
|
||||
prm.SetAddress(*addr)
|
||||
prm.SetAddress(addr)
|
||||
prm.UseBearer(btoken)
|
||||
|
||||
objInfo, err := p.HeadObject(ctx, prm)
|
||||
|
@ -309,24 +308,24 @@ func headObjectBaseInfo(ctx context.Context, p *pool.Pool, cnrID *cid.ID, objID
|
|||
return resp, nil
|
||||
}
|
||||
|
||||
func parseAddress(containerID, objectID string) (*address.Address, error) {
|
||||
func parseAddress(containerID, objectID string) (oid.Address, error) {
|
||||
var cnrID cid.ID
|
||||
if err := cnrID.Parse(containerID); err != nil {
|
||||
return nil, fmt.Errorf("invalid container id: %w", err)
|
||||
if err := cnrID.DecodeString(containerID); err != nil {
|
||||
return oid.Address{}, fmt.Errorf("invalid container id: %w", err)
|
||||
}
|
||||
var objID oid.ID
|
||||
if err := objID.Parse(objectID); err != nil {
|
||||
return nil, fmt.Errorf("invalid object id: %w", err)
|
||||
if err := objID.DecodeString(objectID); err != nil {
|
||||
return oid.Address{}, fmt.Errorf("invalid object id: %w", err)
|
||||
}
|
||||
|
||||
addr := address.NewAddress()
|
||||
addr.SetContainerID(&cnrID)
|
||||
addr.SetObjectID(&objID)
|
||||
var addr oid.Address
|
||||
addr.SetContainer(cnrID)
|
||||
addr.SetObject(objID)
|
||||
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
func getBearerToken(token *models.Principal, signature, key string, isWalletConnect bool) (*token.BearerToken, error) {
|
||||
func getBearerToken(token *models.Principal, signature, key string, isWalletConnect bool) (bearer.Token, error) {
|
||||
bt := &BearerToken{
|
||||
Token: string(*token),
|
||||
Signature: signature,
|
||||
|
@ -336,45 +335,46 @@ func getBearerToken(token *models.Principal, signature, key string, isWalletConn
|
|||
return prepareBearerToken(bt, isWalletConnect)
|
||||
}
|
||||
|
||||
func prepareBearerToken(bt *BearerToken, isWalletConnect bool) (*token.BearerToken, error) {
|
||||
func prepareBearerToken(bt *BearerToken, isWalletConnect bool) (bearer.Token, error) {
|
||||
data, err := base64.StdEncoding.DecodeString(bt.Token)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't base64-decode bearer token: %w", err)
|
||||
return bearer.Token{}, fmt.Errorf("can't base64-decode bearer token: %w", err)
|
||||
}
|
||||
|
||||
signature, err := hex.DecodeString(bt.Signature)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't decode bearer signature: %w", err)
|
||||
return bearer.Token{}, fmt.Errorf("couldn't decode bearer signature: %w", err)
|
||||
}
|
||||
|
||||
ownerKey, err := keys.NewPublicKeyFromString(bt.Key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't fetch bearer token owner key: %w", err)
|
||||
return bearer.Token{}, fmt.Errorf("couldn't fetch bearer token owner key: %w", err)
|
||||
}
|
||||
|
||||
body := new(acl.BearerTokenBody)
|
||||
if err = body.Unmarshal(data); err != nil {
|
||||
return nil, fmt.Errorf("can't unmarshal bearer token: %w", err)
|
||||
return bearer.Token{}, fmt.Errorf("can't unmarshal bearer token: %w", err)
|
||||
}
|
||||
|
||||
btoken := new(token.BearerToken)
|
||||
btoken.ToV2().SetBody(body)
|
||||
|
||||
v2signature := new(refs.Signature)
|
||||
v2signature.SetScheme(refs.ECDSA_SHA512)
|
||||
if isWalletConnect {
|
||||
v2signature.SetScheme(2)
|
||||
v2signature.SetScheme(refs.ECDSA_RFC6979_SHA256_WALLET_CONNECT)
|
||||
}
|
||||
v2signature.SetSign(signature)
|
||||
v2signature.SetKey(ownerKey.Bytes())
|
||||
btoken.ToV2().SetSignature(v2signature)
|
||||
|
||||
if isWalletConnect {
|
||||
if !walletconnect.Verify((*ecdsa.PublicKey)(ownerKey), []byte(bt.Token), signature) {
|
||||
return nil, fmt.Errorf("invalid signature")
|
||||
}
|
||||
} else if err = btoken.VerifySignature(); err != nil {
|
||||
return nil, fmt.Errorf("invalid signature")
|
||||
var v2btoken acl.BearerToken
|
||||
v2btoken.SetBody(body)
|
||||
v2btoken.SetSignature(v2signature)
|
||||
|
||||
var btoken bearer.Token
|
||||
if err = btoken.ReadFromV2(v2btoken); err != nil {
|
||||
return bearer.Token{}, fmt.Errorf("read from v2 token: %w", err)
|
||||
}
|
||||
|
||||
if !btoken.VerifySignature() {
|
||||
return bearer.Token{}, fmt.Errorf("invalid signature")
|
||||
}
|
||||
|
||||
return btoken, nil
|
||||
|
|
|
@ -2,7 +2,6 @@ package handlers
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
@ -11,7 +10,6 @@ import (
|
|||
|
||||
objectv2 "github.com/nspcc-dev/neofs-api-go/v2/object"
|
||||
"github.com/nspcc-dev/neofs-rest-gw/gen/models"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/object"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/pool"
|
||||
)
|
||||
|
@ -134,21 +132,13 @@ func getEpochDurations(ctx context.Context, p *pool.Pool) (*epochDurations, erro
|
|||
}
|
||||
|
||||
res := &epochDurations{
|
||||
currentEpoch: networkInfo.CurrentEpoch(),
|
||||
msPerBlock: networkInfo.MsPerBlock(),
|
||||
currentEpoch: networkInfo.CurrentEpoch(),
|
||||
msPerBlock: networkInfo.MsPerBlock(),
|
||||
blockPerEpoch: networkInfo.EpochDuration(),
|
||||
}
|
||||
|
||||
networkInfo.NetworkConfig().IterateParameters(func(parameter *netmap.NetworkParameter) bool {
|
||||
if string(parameter.Key()) == "EpochDuration" {
|
||||
data := make([]byte, 8)
|
||||
copy(data, parameter.Value())
|
||||
res.blockPerEpoch = binary.LittleEndian.Uint64(data)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
if res.blockPerEpoch == 0 {
|
||||
return nil, fmt.Errorf("not found param: EpochDuration")
|
||||
return nil, fmt.Errorf("EpochDuration is zero")
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
|
|
@ -5,14 +5,13 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
|
||||
sessionv2 "github.com/nspcc-dev/neofs-api-go/v2/session"
|
||||
"github.com/nspcc-dev/neofs-rest-gw/gen/models"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/bearer"
|
||||
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||
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/object"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/session"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/token"
|
||||
)
|
||||
|
||||
// ToNativeAction converts models.Action to appropriate eacl.Action.
|
||||
|
@ -184,54 +183,40 @@ func FromNativeRole(r eacl.Role) (*models.Role, error) {
|
|||
}
|
||||
|
||||
// ToNativeVerb converts models.Verb to appropriate session.ContainerSessionVerb.
|
||||
func ToNativeVerb(r *models.Verb) (sessionv2.ContainerSessionVerb, error) {
|
||||
func ToNativeVerb(r *models.Verb) (session.ContainerVerb, error) {
|
||||
if r == nil {
|
||||
return sessionv2.ContainerVerbUnknown, fmt.Errorf("unsupported empty verb type")
|
||||
return 0, fmt.Errorf("unsupported empty verb type")
|
||||
}
|
||||
|
||||
switch *r {
|
||||
case models.VerbPUT:
|
||||
return sessionv2.ContainerVerbPut, nil
|
||||
return session.VerbContainerPut, nil
|
||||
case models.VerbDELETE:
|
||||
return sessionv2.ContainerVerbDelete, nil
|
||||
return session.VerbContainerDelete, nil
|
||||
case models.VerbSETEACL:
|
||||
return sessionv2.ContainerVerbSetEACL, nil
|
||||
return session.VerbContainerSetEACL, nil
|
||||
default:
|
||||
return sessionv2.ContainerVerbUnknown, fmt.Errorf("unsupported verb type: '%s'", *r)
|
||||
return 0, fmt.Errorf("unsupported verb type: '%s'", *r)
|
||||
}
|
||||
}
|
||||
|
||||
// ToNativeRule converts models.Rule to appropriate session.ContainerContext.
|
||||
func ToNativeRule(r *models.Rule) (*session.ContainerContext, error) {
|
||||
var ctx session.ContainerContext
|
||||
|
||||
verb, err := ToNativeVerb(r.Verb)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctx.ToV2().SetVerb(verb)
|
||||
|
||||
if r.ContainerID == "" {
|
||||
ctx.ApplyTo(nil)
|
||||
} else {
|
||||
var cnrID cid.ID
|
||||
if err = cnrID.Parse(r.ContainerID); err != nil {
|
||||
return nil, fmt.Errorf("couldn't parse container id: %w", err)
|
||||
}
|
||||
ctx.ApplyTo(&cnrID)
|
||||
}
|
||||
|
||||
return &ctx, nil
|
||||
}
|
||||
|
||||
// ToNativeContainerToken converts models.Rule to appropriate session.Token.
|
||||
func ToNativeContainerToken(tokenRule *models.Rule) (*session.Token, error) {
|
||||
sctx, err := ToNativeRule(tokenRule)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't transform rule to native: %w", err)
|
||||
func ToNativeContainerToken(tokenRule *models.Rule) (session.Container, error) {
|
||||
var tok session.Container
|
||||
|
||||
if tokenRule.ContainerID != "" {
|
||||
var cnrID cid.ID
|
||||
if err := cnrID.DecodeString(tokenRule.ContainerID); err != nil {
|
||||
return session.Container{}, fmt.Errorf("couldn't parse container id: %w", err)
|
||||
}
|
||||
tok.ApplyOnlyTo(cnrID)
|
||||
}
|
||||
tok := session.NewToken()
|
||||
tok.SetContext(sctx)
|
||||
|
||||
verb, err := ToNativeVerb(tokenRule.Verb)
|
||||
if err != nil {
|
||||
return session.Container{}, err
|
||||
}
|
||||
tok.ForVerb(verb)
|
||||
|
||||
return tok, nil
|
||||
}
|
||||
|
@ -368,14 +353,14 @@ func FromNativeTarget(t eacl.Target) (*models.Target, error) {
|
|||
}
|
||||
|
||||
// ToNativeObjectToken converts []*models.Record to appropriate token.BearerToken.
|
||||
func ToNativeObjectToken(tokenRecords []*models.Record) (*token.BearerToken, error) {
|
||||
func ToNativeObjectToken(tokenRecords []*models.Record) (*bearer.Token, error) {
|
||||
table, err := ToNativeTable(tokenRecords)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var btoken token.BearerToken
|
||||
btoken.SetEACLTable(table)
|
||||
var btoken bearer.Token
|
||||
btoken.SetEACLTable(*table)
|
||||
|
||||
return &btoken, nil
|
||||
}
|
||||
|
|
|
@ -1,149 +0,0 @@
|
|||
package walletconnect
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
|
||||
crypto "github.com/nspcc-dev/neofs-crypto"
|
||||
)
|
||||
|
||||
const (
|
||||
// saltSize is the salt size added to signed message.
|
||||
saltSize = 16
|
||||
// signatureLen is the length of RFC6979 signature.
|
||||
signatureLen = 64
|
||||
)
|
||||
|
||||
// SignedMessage contains mirrors `SignedMessage` struct from the WalletConnect API.
|
||||
// https://neon.coz.io/wksdk/core/modules.html#SignedMessage
|
||||
type SignedMessage struct {
|
||||
Data []byte
|
||||
Message []byte
|
||||
PublicKey []byte
|
||||
Salt []byte
|
||||
}
|
||||
|
||||
// Sign signs message using WalletConnect API. The returned signature
|
||||
// contains RFC6979 signature and 16-byte salt.
|
||||
func Sign(p *ecdsa.PrivateKey, msg []byte) ([]byte, error) {
|
||||
sm, err := SignMessage(p, msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append(sm.Data, sm.Salt...), nil
|
||||
}
|
||||
|
||||
// Verify verifies message using WalletConnect API. The returned signature
|
||||
// contains RFC6979 signature and 16-byte salt.
|
||||
func Verify(p *ecdsa.PublicKey, data, sign []byte) bool {
|
||||
if len(sign) != signatureLen+saltSize {
|
||||
return false
|
||||
}
|
||||
|
||||
salt := sign[signatureLen:]
|
||||
return VerifyMessage(p, SignedMessage{
|
||||
Data: sign[:signatureLen],
|
||||
Message: createMessageWithSalt(data, salt),
|
||||
Salt: salt,
|
||||
})
|
||||
}
|
||||
|
||||
// SignMessage signs message with a private key and returns structure similar to
|
||||
// `signMessage` of the WalletConnect API.
|
||||
// https://github.com/CityOfZion/wallet-connect-sdk/blob/89c236b/packages/wallet-connect-sdk-core/src/index.ts#L496
|
||||
// https://github.com/CityOfZion/neon-wallet/blob/1174a9388480e6bbc4f79eb13183c2a573f67ca8/app/context/WalletConnect/helpers.js#L133
|
||||
func SignMessage(p *ecdsa.PrivateKey, msg []byte) (SignedMessage, error) {
|
||||
var salt [saltSize]byte
|
||||
_, _ = rand.Read(salt[:])
|
||||
|
||||
msg = createMessageWithSalt(msg, salt[:])
|
||||
sign, err := crypto.SignRFC6979(p, msg)
|
||||
if err != nil {
|
||||
return SignedMessage{}, err
|
||||
}
|
||||
|
||||
return SignedMessage{
|
||||
Data: sign,
|
||||
Message: msg,
|
||||
PublicKey: elliptic.MarshalCompressed(p.Curve, p.X, p.Y),
|
||||
Salt: salt[:],
|
||||
}, nil
|
||||
}
|
||||
|
||||
// VerifyMessage verifies message with a private key and returns structure similar to
|
||||
// `verifyMessage` of WalletConnect API.
|
||||
// https://github.com/CityOfZion/wallet-connect-sdk/blob/89c236b/packages/wallet-connect-sdk-core/src/index.ts#L515
|
||||
// https://github.com/CityOfZion/neon-wallet/blob/1174a9388480e6bbc4f79eb13183c2a573f67ca8/app/context/WalletConnect/helpers.js#L147
|
||||
func VerifyMessage(p *ecdsa.PublicKey, m SignedMessage) bool {
|
||||
if p == nil {
|
||||
x, y := elliptic.UnmarshalCompressed(elliptic.P256(), m.PublicKey)
|
||||
if x == nil || y == nil {
|
||||
return false
|
||||
}
|
||||
p = &ecdsa.PublicKey{
|
||||
Curve: elliptic.P256(),
|
||||
X: x,
|
||||
Y: y,
|
||||
}
|
||||
}
|
||||
return crypto.VerifyRFC6979(p, m.Message, m.Data) == nil
|
||||
}
|
||||
|
||||
func createMessageWithSalt(msg, salt []byte) []byte {
|
||||
// 4 byte prefix + length of the message with salt in bytes +
|
||||
// + salt + message + 2 byte postfix.
|
||||
saltedLen := len(salt)*2 + len(msg)
|
||||
data := make([]byte, 4+getVarIntSize(saltedLen)+saltedLen+2)
|
||||
|
||||
n := copy(data, []byte{0x01, 0x00, 0x01, 0xf0}) // fixed prefix
|
||||
n += putVarUint(data[n:], uint64(saltedLen))
|
||||
n += hex.Encode(data[n:], salt[:]) // for some reason we encode salt in hex
|
||||
n += copy(data[n:], msg)
|
||||
copy(data[n:], []byte{0x00, 0x00})
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
// Following functions are copied from github.com/nspcc-dev/neo-go/pkg/io package
|
||||
// to avoid having another dependency.
|
||||
|
||||
// getVarIntSize returns the size in number of bytes of a variable integer.
|
||||
// (reference: GetVarSize(int value), https://github.com/neo-project/neo/blob/master/neo/IO/Helper.cs)
|
||||
func getVarIntSize(value int) int {
|
||||
var size uintptr
|
||||
|
||||
if value < 0xFD {
|
||||
size = 1 // unit8
|
||||
} else if value <= 0xFFFF {
|
||||
size = 3 // byte + uint16
|
||||
} else {
|
||||
size = 5 // byte + uint32
|
||||
}
|
||||
return int(size)
|
||||
}
|
||||
|
||||
// putVarUint puts val in varint form to the pre-allocated buffer.
|
||||
func putVarUint(data []byte, val uint64) int {
|
||||
_ = data[8]
|
||||
if val < 0xfd {
|
||||
data[0] = byte(val)
|
||||
return 1
|
||||
}
|
||||
if val < 0xFFFF {
|
||||
data[0] = byte(0xfd)
|
||||
binary.LittleEndian.PutUint16(data[1:], uint16(val))
|
||||
return 3
|
||||
}
|
||||
if val < 0xFFFFFFFF {
|
||||
data[0] = byte(0xfe)
|
||||
binary.LittleEndian.PutUint32(data[1:], uint32(val))
|
||||
return 5
|
||||
}
|
||||
|
||||
data[0] = byte(0xff)
|
||||
binary.LittleEndian.PutUint64(data[1:], val)
|
||||
return 9
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
package walletconnect
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neofs-rest-gw/gen/models"
|
||||
"github.com/nspcc-dev/neofs-rest-gw/internal/util"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/owner"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const devenvPrivateKey = "1dd37fba80fec4e6a6f13fd708d8dcb3b29def768017052f6c930fa1c5d90bbb"
|
||||
|
||||
func TestSign(t *testing.T) {
|
||||
key, err := keys.NewPrivateKeyFromHex(devenvPrivateKey)
|
||||
require.NoError(t, err)
|
||||
|
||||
pubKeyHex := hex.EncodeToString(key.PublicKey().Bytes())
|
||||
|
||||
records := []*models.Record{{
|
||||
Operation: models.NewOperation(models.OperationPUT),
|
||||
Action: models.NewAction(models.ActionALLOW),
|
||||
Filters: []*models.Filter{},
|
||||
Targets: []*models.Target{{
|
||||
Role: models.NewRole(models.RoleOTHERS),
|
||||
Keys: []string{},
|
||||
}},
|
||||
}}
|
||||
|
||||
btoken, err := util.ToNativeObjectToken(records)
|
||||
require.NoError(t, err)
|
||||
|
||||
ownerKey, err := keys.NewPublicKeyFromString(pubKeyHex)
|
||||
require.NoError(t, err)
|
||||
|
||||
btoken.SetOwner(owner.NewIDFromPublicKey((*ecdsa.PublicKey)(ownerKey)))
|
||||
|
||||
binaryBearer, err := btoken.ToV2().GetBody().StableMarshal(nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
sm, err := SignMessage(&key.PrivateKey, binaryBearer)
|
||||
require.NoError(t, err)
|
||||
|
||||
verified := Verify((*ecdsa.PublicKey)(key.PublicKey()), binaryBearer, append(sm.Data, sm.Salt...))
|
||||
require.True(t, verified)
|
||||
}
|
||||
|
||||
func TestVerifyMessage(t *testing.T) {
|
||||
testCases := [...]struct {
|
||||
publicKey string
|
||||
data string
|
||||
salt string
|
||||
messageHex string
|
||||
messageOriginal string
|
||||
}{
|
||||
{ // Test values from this GIF https://github.com/CityOfZion/neon-wallet/pull/2390 .
|
||||
publicKey: "02ce6228ba2cb2fc235be93aff9cd5fc0851702eb9791552f60db062f01e3d83f6",
|
||||
data: "90ab1886ca0bece59b982d9ade8f5598065d651362fb9ce45ad66d0474b89c0b80913c8f0118a282acbdf200a429ba2d81bc52534a53ab41a2c6dfe2f0b4fb1b",
|
||||
salt: "d41e348afccc2f3ee45cd9f5128b16dc",
|
||||
messageHex: "010001f05c6434316533343861666363633266336565343563643966353132386231366463436172616c686f2c206d756c65712c206f2062616775697520656820697373756d65726d6f2074616978206c696761646f206e61206d697373e36f3f0000",
|
||||
messageOriginal: "436172616c686f2c206d756c65712c206f2062616775697520656820697373756d65726d6f2074616978206c696761646f206e61206d697373e36f3f",
|
||||
},
|
||||
{ // Test value from wallet connect integration test
|
||||
publicKey: "03bd9108c0b49f657e9eee50d1399022bd1e436118e5b7529a1b7cd606652f578f",
|
||||
data: "510caa8cb6db5dedf04d215a064208d64be7496916d890df59aee132db8f2b07532e06f7ea664c4a99e3bcb74b43a35eb9653891b5f8701d2aef9e7526703eaa",
|
||||
salt: "2c5b189569e92cce12e1c640f23e83ba",
|
||||
messageHex: "010001f02632633562313839353639653932636365313265316336343066323365383362613132333435360000",
|
||||
messageOriginal: "313233343536", // ascii string "123456"
|
||||
},
|
||||
{ // Test value from wallet connect integration test
|
||||
publicKey: "03bd9108c0b49f657e9eee50d1399022bd1e436118e5b7529a1b7cd606652f578f",
|
||||
data: "1e13f248962d8b3b60708b55ddf448d6d6a28c6b43887212a38b00bf6bab695e61261e54451c6e3d5f1f000e5534d166c7ca30f662a296d3a9aafa6d8c173c01",
|
||||
salt: "58c86b2e74215b4f36b47d731236be3b",
|
||||
messageHex: "010001f02035386338366232653734323135623466333662343764373331323336626533620000",
|
||||
messageOriginal: "", // empty string
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
pub, err := keys.NewPublicKeyFromString(testCase.publicKey)
|
||||
require.NoError(t, err)
|
||||
data, err := hex.DecodeString(testCase.data)
|
||||
require.NoError(t, err)
|
||||
salt, err := hex.DecodeString(testCase.salt)
|
||||
require.NoError(t, err)
|
||||
msg, err := hex.DecodeString(testCase.messageHex)
|
||||
require.NoError(t, err)
|
||||
orig, err := hex.DecodeString(testCase.messageOriginal)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, msg, createMessageWithSalt(orig, salt))
|
||||
|
||||
sm := SignedMessage{
|
||||
Data: data,
|
||||
Message: msg,
|
||||
PublicKey: pub.Bytes(),
|
||||
Salt: salt,
|
||||
}
|
||||
require.True(t, VerifyMessage(nil, sm))
|
||||
|
||||
require.True(t, Verify((*ecdsa.PublicKey)(pub), orig, append(data, salt...)))
|
||||
}
|
||||
}
|
Reference in a new issue