forked from TrueCloudLab/frostfs-rest-gw
[#15] Check container name
Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
parent
9fba8d7f23
commit
eab43cea3b
3 changed files with 103 additions and 4 deletions
|
@ -60,7 +60,7 @@ const (
|
||||||
|
|
||||||
// tests configuration.
|
// tests configuration.
|
||||||
useWalletConnect = false
|
useWalletConnect = false
|
||||||
useLocalEnvironment = true
|
useLocalEnvironment = false
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestIntegration(t *testing.T) {
|
func TestIntegration(t *testing.T) {
|
||||||
|
@ -123,6 +123,7 @@ func runTests(ctx context.Context, t *testing.T, key *keys.PrivateKey, version s
|
||||||
t.Run("rest delete object "+version, func(t *testing.T) { restObjectDelete(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 search objects "+version, func(t *testing.T) { restObjectsSearch(ctx, t, clientPool, 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 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 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 delete container "+version, func(t *testing.T) { restContainerDelete(ctx, t, clientPool) })
|
||||||
|
@ -813,6 +814,36 @@ func signTokenWalletConnect(t *testing.T, key *keys.PrivateKey, data []byte) *ha
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func restContainerPutInvalid(ctx context.Context, t *testing.T) {
|
||||||
|
bearer := &models.Bearer{
|
||||||
|
Container: &models.Rule{
|
||||||
|
Verb: models.NewVerb(models.VerbPUT),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
httpClient := &http.Client{Timeout: 30 * time.Second}
|
||||||
|
bearerTokens := makeAuthTokenRequest(ctx, t, []*models.Bearer{bearer}, httpClient)
|
||||||
|
bearerToken := bearerTokens[0]
|
||||||
|
|
||||||
|
reqURL, err := url.Parse(testHost + "/v1/containers")
|
||||||
|
require.NoError(t, err)
|
||||||
|
query := reqURL.Query()
|
||||||
|
query.Add("name-scope-global", "true")
|
||||||
|
query.Add(walletConnectQuery, strconv.FormatBool(useWalletConnect))
|
||||||
|
reqURL.RawQuery = query.Encode()
|
||||||
|
|
||||||
|
body, err := json.Marshal(&operations.PutContainerBody{ContainerName: "nameWithCapitalLetters"})
|
||||||
|
require.NoError(t, err)
|
||||||
|
request, err := http.NewRequest(http.MethodPut, reqURL.String(), bytes.NewReader(body))
|
||||||
|
require.NoError(t, err)
|
||||||
|
prepareCommonHeaders(request.Header, bearerToken)
|
||||||
|
|
||||||
|
resp := &models.ErrorResponse{}
|
||||||
|
doRequest(t, httpClient, request, http.StatusBadRequest, resp)
|
||||||
|
require.Equal(t, int64(0), resp.Code)
|
||||||
|
require.Equal(t, models.ErrorTypeGW, *resp.Type)
|
||||||
|
}
|
||||||
|
|
||||||
func restContainerPut(ctx context.Context, t *testing.T, clientPool *pool.Pool) {
|
func restContainerPut(ctx context.Context, t *testing.T, clientPool *pool.Pool) {
|
||||||
bearer := &models.Bearer{
|
bearer := &models.Bearer{
|
||||||
Container: &models.Rule{
|
Container: &models.Rule{
|
||||||
|
|
37
handlers/container_test.go
Normal file
37
handlers/container_test.go
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCheckContainerName(t *testing.T) {
|
||||||
|
name64 := "container-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||||
|
name256 := "container-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||||
|
|
||||||
|
for _, tc := range []struct {
|
||||||
|
name string
|
||||||
|
valid bool
|
||||||
|
}{
|
||||||
|
{name: "container", valid: true},
|
||||||
|
{name: "container-name", valid: true},
|
||||||
|
{name: "container.name", valid: true},
|
||||||
|
{name: "container2", valid: true},
|
||||||
|
{name: "2container.name", valid: true},
|
||||||
|
{name: "containerName", valid: false},
|
||||||
|
{name: "-container", valid: false},
|
||||||
|
{name: "container-", valid: false},
|
||||||
|
{name: "container name", valid: false},
|
||||||
|
{name: "c", valid: false},
|
||||||
|
{name: name64 + ".name", valid: false},
|
||||||
|
{name: name256, valid: false},
|
||||||
|
} {
|
||||||
|
err := checkNNSContainerName(tc.name)
|
||||||
|
if tc.valid {
|
||||||
|
require.NoError(t, err)
|
||||||
|
} else {
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -341,8 +341,8 @@ func createContainer(ctx context.Context, p *pool.Pool, stoken *session.Token, p
|
||||||
cnr.SetSessionToken(stoken)
|
cnr.SetSessionToken(stoken)
|
||||||
|
|
||||||
if *params.NameScopeGlobal { // we don't check for nil because there is default false value
|
if *params.NameScopeGlobal { // we don't check for nil because there is default false value
|
||||||
if request.ContainerName == "" {
|
if err = checkNNSContainerName(request.ContainerName); err != nil {
|
||||||
return nil, fmt.Errorf("container name must not be empty to be registered in NNS")
|
return nil, fmt.Errorf("invalid container name: %w", err)
|
||||||
}
|
}
|
||||||
container.SetNativeName(cnr, request.ContainerName)
|
container.SetNativeName(cnr, request.ContainerName)
|
||||||
}
|
}
|
||||||
|
@ -352,12 +352,43 @@ func createContainer(ctx context.Context, p *pool.Pool, stoken *session.Token, p
|
||||||
|
|
||||||
cnrID, err := p.PutContainer(ctx, prm)
|
cnrID, err := p.PutContainer(ctx, prm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could put object to neofs: %w", err)
|
return nil, fmt.Errorf("put container: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return cnrID, nil
|
return cnrID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkNNSContainerName(name string) error {
|
||||||
|
length := len(name)
|
||||||
|
if length < 3 || 255 < length {
|
||||||
|
return fmt.Errorf("invalid length: %d", length)
|
||||||
|
}
|
||||||
|
fragments := strings.Split(name, ".")
|
||||||
|
|
||||||
|
for _, fragment := range fragments {
|
||||||
|
fLength := len(fragment)
|
||||||
|
if fLength < 1 || 63 < fLength {
|
||||||
|
return fmt.Errorf("invalid fragment length: %d", fLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isAlNum(fragment[0]) || !isAlNum(fragment[fLength-1]) {
|
||||||
|
return fmt.Errorf("invalid fragment: '%s'", fragment)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 1; i < fLength-1; i++ {
|
||||||
|
if fragment[i] != '-' && !isAlNum(fragment[i]) {
|
||||||
|
return fmt.Errorf("invalid fragment: '%s'", fragment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isAlNum(c uint8) bool {
|
||||||
|
return c >= 'a' && c <= 'z' || c >= '0' && c <= '9'
|
||||||
|
}
|
||||||
|
|
||||||
func prepareSessionToken(bt *BearerToken, isWalletConnect bool) (*session.Token, error) {
|
func prepareSessionToken(bt *BearerToken, isWalletConnect bool) (*session.Token, error) {
|
||||||
data, err := base64.StdEncoding.DecodeString(bt.Token)
|
data, err := base64.StdEncoding.DecodeString(bt.Token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Reference in a new issue