blob: 8a0400654ca2fb88fff3639a85cb6d4ecdd6f11f [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package validity
import (
"context"
"errors"
"fmt"
"regexp"
"strings"
)
import (
"github.com/apache/dubbo-kubernetes/pkg/bufman/bufpkg/bufconfig"
"github.com/apache/dubbo-kubernetes/pkg/bufman/bufpkg/buflock"
"github.com/apache/dubbo-kubernetes/pkg/bufman/bufpkg/bufmanifest"
"github.com/apache/dubbo-kubernetes/pkg/bufman/bufpkg/bufmodule"
"github.com/apache/dubbo-kubernetes/pkg/bufman/constant"
"github.com/apache/dubbo-kubernetes/pkg/bufman/e"
modulev1alpha1 "github.com/apache/dubbo-kubernetes/pkg/bufman/gen/proto/go/module/v1alpha1"
manifest2 "github.com/apache/dubbo-kubernetes/pkg/bufman/pkg/manifest"
)
type Validator interface {
CheckUserName(username string) e.ResponseError // 检查用户名合法性
CheckPassword(password string) e.ResponseError // 检查密码合法性
CheckRepositoryName(repositoryName string) e.ResponseError // 检查repo name合法性
CheckTagName(tagName string) e.ResponseError // 检查tag name合法性
CheckDraftName(draftName string) e.ResponseError // 检查draft name合法性
CheckPageSize(pageSize uint32) e.ResponseError // 检查page size合法性
CheckQuery(query string) e.ResponseError
SplitFullName(fullName string) (userName, repositoryName string, respErr e.ResponseError) // 分割full name
// CheckManifestAndBlobs 检查上传的文件是否合法
CheckManifestAndBlobs(ctx context.Context, protoManifest *modulev1alpha1.Blob, protoBlobs []*modulev1alpha1.Blob) (*manifest2.Manifest, *manifest2.BlobSet, e.ResponseError)
}
func NewValidator() Validator {
return &ValidatorImpl{}
}
type ValidatorImpl struct{}
func (validator *ValidatorImpl) CheckUserName(username string) e.ResponseError {
err := validator.doCheckByLengthAndPattern(username, constant.MinUserNameLength, constant.MaxUserNameLength, constant.UserNamePattern)
if err != nil {
return e.NewInvalidArgumentError(err)
}
return nil
}
func (validator *ValidatorImpl) CheckPassword(password string) e.ResponseError {
err := validator.doCheckByLengthAndPattern(password, constant.MinPasswordLength, constant.MaxPasswordLength, constant.PasswordPattern)
if err != nil {
return e.NewInvalidArgumentError(err)
}
return nil
}
func (validator *ValidatorImpl) CheckRepositoryName(repositoryName string) e.ResponseError {
err := validator.doCheckByLengthAndPattern(repositoryName, constant.MinRepositoryNameLength, constant.MaxRepositoryNameLength, constant.RepositoryNamePattern)
if err != nil {
return e.NewInvalidArgumentError(err)
}
return nil
}
func (validator *ValidatorImpl) CheckTagName(tagName string) e.ResponseError {
err := validator.doCheckByLengthAndPattern(tagName, constant.MinTagLength, constant.MaxTagLength, constant.TagPattern)
if err != nil {
return e.NewInvalidArgumentError(err)
}
return nil
}
func (validator *ValidatorImpl) CheckDraftName(draftName string) e.ResponseError {
if draftName == constant.DefaultBranch { // draft name不能为 main
return e.NewInvalidArgumentError(fmt.Errorf("draft (can not be '%v')", constant.DefaultBranch))
}
err := validator.doCheckByLengthAndPattern(draftName, constant.MinDraftLength, constant.MaxDraftLength, constant.DraftPattern)
if err != nil {
return e.NewInvalidArgumentError(err)
}
return nil
}
func (validator *ValidatorImpl) CheckPageSize(pageSize uint32) e.ResponseError {
if pageSize < constant.MinPageSize || pageSize > constant.MaxPageSize {
return e.NewInvalidArgumentError(fmt.Errorf("page size: length is limited between %v and %v", constant.MinPageSize, constant.MaxPageSize))
}
return nil
}
func (validator *ValidatorImpl) CheckQuery(query string) e.ResponseError {
err := validator.doCheckByLengthAndPattern(query, constant.MinQueryLength, constant.MaxQueryLength, constant.QueryPattern)
if err != nil {
return e.NewInvalidArgumentError(err)
}
return nil
}
func (validator *ValidatorImpl) SplitFullName(fullName string) (userName, repositoryName string, respErr e.ResponseError) {
split := strings.SplitN(fullName, "/", 2)
if len(split) != 2 {
respErr = e.NewInvalidArgumentError(errors.New("full name"))
return
}
ok := split[0] != "" && split[1] != ""
if !ok {
respErr = e.NewInvalidArgumentError(errors.New("full name"))
return
}
userName, repositoryName = split[0], split[1]
return userName, repositoryName, nil
}
func (validator *ValidatorImpl) doCheckByLengthAndPattern(str string, minLength, maxLength int, pattern string) error {
// 长度检查
if len(str) < minLength || len(str) > maxLength {
return fmt.Errorf("length is limited between %v and %v", minLength, maxLength)
}
// 正则匹配
match, _ := regexp.MatchString(pattern, str)
if !match {
return fmt.Errorf("pattern dont math %s", pattern)
}
return nil
}
func (validator *ValidatorImpl) CheckManifestAndBlobs(ctx context.Context, protoManifest *modulev1alpha1.Blob, protoBlobs []*modulev1alpha1.Blob) (*manifest2.Manifest, *manifest2.BlobSet, e.ResponseError) {
// 读取文件清单
fileManifest, err := bufmanifest.NewManifestFromProto(ctx, protoManifest)
if err != nil {
return nil, nil, e.NewInvalidArgumentError(err)
}
if fileManifest.Empty() {
// 不允许上次空的commit
return nil, nil, e.NewInvalidArgumentError(errors.New("no files"))
}
// 读取文件列表
blobSet, err := bufmanifest.NewBlobSetFromProto(ctx, protoBlobs)
if err != nil {
return nil, nil, e.NewInvalidArgumentError(err)
}
// 检查文件清单和blobs
externalPaths := []string{
buflock.ExternalConfigFilePath,
bufmodule.LicenseFilePath,
}
externalPaths = append(externalPaths, bufmodule.AllDocumentationPaths...)
externalPaths = append(externalPaths, bufconfig.AllConfigFilePaths...)
err = fileManifest.Range(func(path string, digest manifest2.Digest) error {
_, ok := blobSet.BlobFor(digest.String())
if !ok {
// 文件清单中有的文件,在file blobs中没有
return errors.New("check manifest and file blobs failed")
}
// 仅仅允许上传.proto、readme、license、配置文件
if !strings.HasSuffix(path, ".proto") {
unexpected := true
for _, externalPath := range externalPaths {
if path == externalPath {
unexpected = false
break
}
}
if unexpected {
return errors.New("only allow update .proto、readme、license、bufman config file")
}
}
return nil
})
if err != nil {
return nil, nil, e.NewInvalidArgumentError(err)
}
return fileManifest, blobSet, nil
}