mirror of
https://github.com/portainer/portainer.git
synced 2025-07-19 05:19:39 +02:00
fix(govalidator): replace govalidator dependency [BE-11574] (#673)
This commit is contained in:
parent
3edacee59b
commit
1a3df54c04
18 changed files with 571 additions and 43 deletions
|
@ -3,9 +3,9 @@ package update
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/asaskevich/govalidator"
|
|
||||||
portainer "github.com/portainer/portainer/api"
|
portainer "github.com/portainer/portainer/api"
|
||||||
httperrors "github.com/portainer/portainer/api/http/errors"
|
httperrors "github.com/portainer/portainer/api/http/errors"
|
||||||
|
"github.com/portainer/portainer/pkg/validate"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ValidateAutoUpdateSettings(autoUpdate *portainer.AutoUpdateSettings) error {
|
func ValidateAutoUpdateSettings(autoUpdate *portainer.AutoUpdateSettings) error {
|
||||||
|
@ -17,7 +17,7 @@ func ValidateAutoUpdateSettings(autoUpdate *portainer.AutoUpdateSettings) error
|
||||||
return httperrors.NewInvalidPayloadError("Webhook or Interval must be provided")
|
return httperrors.NewInvalidPayloadError("Webhook or Interval must be provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
if autoUpdate.Webhook != "" && !govalidator.IsUUID(autoUpdate.Webhook) {
|
if autoUpdate.Webhook != "" && !validate.IsUUID(autoUpdate.Webhook) {
|
||||||
return httperrors.NewInvalidPayloadError("invalid Webhook format")
|
return httperrors.NewInvalidPayloadError("invalid Webhook format")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,17 @@
|
||||||
package git
|
package git
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/asaskevich/govalidator"
|
|
||||||
|
|
||||||
gittypes "github.com/portainer/portainer/api/git/types"
|
gittypes "github.com/portainer/portainer/api/git/types"
|
||||||
httperrors "github.com/portainer/portainer/api/http/errors"
|
httperrors "github.com/portainer/portainer/api/http/errors"
|
||||||
|
"github.com/portainer/portainer/pkg/validate"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ValidateRepoConfig(repoConfig *gittypes.RepoConfig) error {
|
func ValidateRepoConfig(repoConfig *gittypes.RepoConfig) error {
|
||||||
if len(repoConfig.URL) == 0 || !govalidator.IsURL(repoConfig.URL) {
|
if len(repoConfig.URL) == 0 || !validate.IsURL(repoConfig.URL) {
|
||||||
return httperrors.NewInvalidPayloadError("Invalid repository URL. Must correspond to a valid URL format")
|
return httperrors.NewInvalidPayloadError("Invalid repository URL. Must correspond to a valid URL format")
|
||||||
}
|
}
|
||||||
|
|
||||||
return ValidateRepoAuthentication(repoConfig.Authentication)
|
return ValidateRepoAuthentication(repoConfig.Authentication)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ValidateRepoAuthentication(auth *gittypes.GitAuthentication) error {
|
func ValidateRepoAuthentication(auth *gittypes.GitAuthentication) error {
|
||||||
|
|
|
@ -16,8 +16,8 @@ import (
|
||||||
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
||||||
"github.com/portainer/portainer/pkg/libhttp/request"
|
"github.com/portainer/portainer/pkg/libhttp/request"
|
||||||
"github.com/portainer/portainer/pkg/libhttp/response"
|
"github.com/portainer/portainer/pkg/libhttp/response"
|
||||||
|
"github.com/portainer/portainer/pkg/validate"
|
||||||
|
|
||||||
"github.com/asaskevich/govalidator"
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/segmentio/encoding/json"
|
"github.com/segmentio/encoding/json"
|
||||||
)
|
)
|
||||||
|
@ -228,7 +228,7 @@ func (payload *customTemplateFromGitRepositoryPayload) Validate(r *http.Request)
|
||||||
if len(payload.Description) == 0 {
|
if len(payload.Description) == 0 {
|
||||||
return errors.New("Invalid custom template description")
|
return errors.New("Invalid custom template description")
|
||||||
}
|
}
|
||||||
if len(payload.RepositoryURL) == 0 || !govalidator.IsURL(payload.RepositoryURL) {
|
if len(payload.RepositoryURL) == 0 || !validate.IsURL(payload.RepositoryURL) {
|
||||||
return errors.New("Invalid repository URL. Must correspond to a valid URL format")
|
return errors.New("Invalid repository URL. Must correspond to a valid URL format")
|
||||||
}
|
}
|
||||||
if payload.RepositoryAuthentication && (len(payload.RepositoryUsername) == 0 || len(payload.RepositoryPassword) == 0) {
|
if payload.RepositoryAuthentication && (len(payload.RepositoryUsername) == 0 || len(payload.RepositoryPassword) == 0) {
|
||||||
|
|
|
@ -15,8 +15,7 @@ import (
|
||||||
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
||||||
"github.com/portainer/portainer/pkg/libhttp/request"
|
"github.com/portainer/portainer/pkg/libhttp/request"
|
||||||
"github.com/portainer/portainer/pkg/libhttp/response"
|
"github.com/portainer/portainer/pkg/libhttp/response"
|
||||||
|
"github.com/portainer/portainer/pkg/validate"
|
||||||
"github.com/asaskevich/govalidator"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type customTemplateUpdatePayload struct {
|
type customTemplateUpdatePayload struct {
|
||||||
|
@ -170,7 +169,7 @@ func (handler *Handler) customTemplateUpdate(w http.ResponseWriter, r *http.Requ
|
||||||
customTemplate.EdgeTemplate = payload.EdgeTemplate
|
customTemplate.EdgeTemplate = payload.EdgeTemplate
|
||||||
|
|
||||||
if payload.RepositoryURL != "" {
|
if payload.RepositoryURL != "" {
|
||||||
if !govalidator.IsURL(payload.RepositoryURL) {
|
if !validate.IsURL(payload.RepositoryURL) {
|
||||||
return httperror.BadRequest("Invalid repository URL. Must correspond to a valid URL format", err)
|
return httperror.BadRequest("Invalid repository URL. Must correspond to a valid URL format", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,7 @@ import (
|
||||||
"github.com/portainer/portainer/api/internal/endpointutils"
|
"github.com/portainer/portainer/api/internal/endpointutils"
|
||||||
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
||||||
"github.com/portainer/portainer/pkg/libhttp/request"
|
"github.com/portainer/portainer/pkg/libhttp/request"
|
||||||
|
"github.com/portainer/portainer/pkg/validate"
|
||||||
"github.com/asaskevich/govalidator"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type edgeJobBasePayload struct {
|
type edgeJobBasePayload struct {
|
||||||
|
@ -53,7 +52,7 @@ func (payload *edgeJobCreateFromFileContentPayload) Validate(r *http.Request) er
|
||||||
return errors.New("invalid Edge job name")
|
return errors.New("invalid Edge job name")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !govalidator.Matches(payload.Name, `^[a-zA-Z0-9][a-zA-Z0-9_.-]*$`) {
|
if !validate.Matches(payload.Name, `^[a-zA-Z0-9][a-zA-Z0-9_.-]*$`) {
|
||||||
return errors.New("invalid Edge job name format. Allowed characters are: [a-zA-Z0-9_.-]")
|
return errors.New("invalid Edge job name format. Allowed characters are: [a-zA-Z0-9_.-]")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +135,7 @@ func (payload *edgeJobCreateFromFilePayload) Validate(r *http.Request) error {
|
||||||
return errors.New("invalid Edge job name")
|
return errors.New("invalid Edge job name")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !govalidator.Matches(name, `^[a-zA-Z0-9][a-zA-Z0-9_.-]+$`) {
|
if !validate.Matches(name, `^[a-zA-Z0-9][a-zA-Z0-9_.-]+$`) {
|
||||||
return errors.New("invalid Edge job name format. Allowed characters are: [a-zA-Z0-9_.-]")
|
return errors.New("invalid Edge job name format. Allowed characters are: [a-zA-Z0-9_.-]")
|
||||||
}
|
}
|
||||||
payload.Name = name
|
payload.Name = name
|
||||||
|
|
|
@ -14,8 +14,7 @@ import (
|
||||||
"github.com/portainer/portainer/api/internal/endpointutils"
|
"github.com/portainer/portainer/api/internal/endpointutils"
|
||||||
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
||||||
"github.com/portainer/portainer/pkg/libhttp/request"
|
"github.com/portainer/portainer/pkg/libhttp/request"
|
||||||
|
"github.com/portainer/portainer/pkg/validate"
|
||||||
"github.com/asaskevich/govalidator"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type edgeJobUpdatePayload struct {
|
type edgeJobUpdatePayload struct {
|
||||||
|
@ -28,7 +27,7 @@ type edgeJobUpdatePayload struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (payload *edgeJobUpdatePayload) Validate(r *http.Request) error {
|
func (payload *edgeJobUpdatePayload) Validate(r *http.Request) error {
|
||||||
if payload.Name != nil && !govalidator.Matches(*payload.Name, `^[a-zA-Z0-9][a-zA-Z0-9_.-]+$`) {
|
if payload.Name != nil && !validate.Matches(*payload.Name, `^[a-zA-Z0-9][a-zA-Z0-9_.-]+$`) {
|
||||||
return errors.New("invalid Edge job name format. Allowed characters are: [a-zA-Z0-9_.-]")
|
return errors.New("invalid Edge job name format. Allowed characters are: [a-zA-Z0-9_.-]")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,8 @@ import (
|
||||||
httperrors "github.com/portainer/portainer/api/http/errors"
|
httperrors "github.com/portainer/portainer/api/http/errors"
|
||||||
"github.com/portainer/portainer/pkg/edge"
|
"github.com/portainer/portainer/pkg/edge"
|
||||||
"github.com/portainer/portainer/pkg/libhttp/request"
|
"github.com/portainer/portainer/pkg/libhttp/request"
|
||||||
|
"github.com/portainer/portainer/pkg/validate"
|
||||||
|
|
||||||
"github.com/asaskevich/govalidator"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ func (payload *edgeStackFromGitRepositoryPayload) Validate(r *http.Request) erro
|
||||||
return httperrors.NewInvalidPayloadError("Invalid stack name. Stack name must only consist of lowercase alpha characters, numbers, hyphens, or underscores as well as start with a lowercase character or number")
|
return httperrors.NewInvalidPayloadError("Invalid stack name. Stack name must only consist of lowercase alpha characters, numbers, hyphens, or underscores as well as start with a lowercase character or number")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(payload.RepositoryURL) == 0 || !govalidator.IsURL(payload.RepositoryURL) {
|
if len(payload.RepositoryURL) == 0 || !validate.IsURL(payload.RepositoryURL) {
|
||||||
return httperrors.NewInvalidPayloadError("Invalid repository URL. Must correspond to a valid URL format")
|
return httperrors.NewInvalidPayloadError("Invalid repository URL. Must correspond to a valid URL format")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,7 @@ import (
|
||||||
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
||||||
"github.com/portainer/portainer/pkg/libhttp/request"
|
"github.com/portainer/portainer/pkg/libhttp/request"
|
||||||
"github.com/portainer/portainer/pkg/libhttp/response"
|
"github.com/portainer/portainer/pkg/libhttp/response"
|
||||||
|
"github.com/portainer/portainer/pkg/validate"
|
||||||
"github.com/asaskevich/govalidator"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type fileResponse struct {
|
type fileResponse struct {
|
||||||
|
@ -29,7 +28,7 @@ type repositoryFilePreviewPayload struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (payload *repositoryFilePreviewPayload) Validate(r *http.Request) error {
|
func (payload *repositoryFilePreviewPayload) Validate(r *http.Request) error {
|
||||||
if len(payload.Repository) == 0 || !govalidator.IsURL(payload.Repository) {
|
if len(payload.Repository) == 0 || !validate.IsURL(payload.Repository) {
|
||||||
return errors.New("invalid repository URL. Must correspond to a valid URL format")
|
return errors.New("invalid repository URL. Must correspond to a valid URL format")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,8 @@ import (
|
||||||
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
||||||
"github.com/portainer/portainer/pkg/libhttp/request"
|
"github.com/portainer/portainer/pkg/libhttp/request"
|
||||||
"github.com/portainer/portainer/pkg/libhttp/response"
|
"github.com/portainer/portainer/pkg/libhttp/response"
|
||||||
|
"github.com/portainer/portainer/pkg/validate"
|
||||||
|
|
||||||
"github.com/asaskevich/govalidator"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
)
|
)
|
||||||
|
@ -62,15 +62,15 @@ func (payload *settingsUpdatePayload) Validate(r *http.Request) error {
|
||||||
return errors.New("Invalid authentication method value. Value must be one of: 1 (internal), 2 (LDAP/AD) or 3 (OAuth)")
|
return errors.New("Invalid authentication method value. Value must be one of: 1 (internal), 2 (LDAP/AD) or 3 (OAuth)")
|
||||||
}
|
}
|
||||||
|
|
||||||
if payload.LogoURL != nil && *payload.LogoURL != "" && !govalidator.IsURL(*payload.LogoURL) {
|
if payload.LogoURL != nil && *payload.LogoURL != "" && !validate.IsURL(*payload.LogoURL) {
|
||||||
return errors.New("Invalid logo URL. Must correspond to a valid URL format")
|
return errors.New("Invalid logo URL. Must correspond to a valid URL format")
|
||||||
}
|
}
|
||||||
|
|
||||||
if payload.TemplatesURL != nil && *payload.TemplatesURL != "" && !govalidator.IsURL(*payload.TemplatesURL) {
|
if payload.TemplatesURL != nil && *payload.TemplatesURL != "" && !validate.IsURL(*payload.TemplatesURL) {
|
||||||
return errors.New("Invalid external templates URL. Must correspond to a valid URL format")
|
return errors.New("Invalid external templates URL. Must correspond to a valid URL format")
|
||||||
}
|
}
|
||||||
|
|
||||||
if payload.HelmRepositoryURL != nil && *payload.HelmRepositoryURL != "" && !govalidator.IsURL(*payload.HelmRepositoryURL) {
|
if payload.HelmRepositoryURL != nil && *payload.HelmRepositoryURL != "" && !validate.IsURL(*payload.HelmRepositoryURL) {
|
||||||
return errors.New("Invalid Helm repository URL. Must correspond to a valid URL format")
|
return errors.New("Invalid Helm repository URL. Must correspond to a valid URL format")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,8 @@ import (
|
||||||
"github.com/portainer/portainer/api/stacks/stackutils"
|
"github.com/portainer/portainer/api/stacks/stackutils"
|
||||||
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
||||||
"github.com/portainer/portainer/pkg/libhttp/request"
|
"github.com/portainer/portainer/pkg/libhttp/request"
|
||||||
|
"github.com/portainer/portainer/pkg/validate"
|
||||||
|
|
||||||
"github.com/asaskevich/govalidator"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
@ -205,7 +205,7 @@ func (payload *composeStackFromGitRepositoryPayload) Validate(r *http.Request) e
|
||||||
if len(payload.Name) == 0 {
|
if len(payload.Name) == 0 {
|
||||||
return errors.New("Invalid stack name")
|
return errors.New("Invalid stack name")
|
||||||
}
|
}
|
||||||
if len(payload.RepositoryURL) == 0 || !govalidator.IsURL(payload.RepositoryURL) {
|
if len(payload.RepositoryURL) == 0 || !validate.IsURL(payload.RepositoryURL) {
|
||||||
return errors.New("Invalid repository URL. Must correspond to a valid URL format")
|
return errors.New("Invalid repository URL. Must correspond to a valid URL format")
|
||||||
}
|
}
|
||||||
if payload.RepositoryAuthentication && len(payload.RepositoryPassword) == 0 {
|
if payload.RepositoryAuthentication && len(payload.RepositoryPassword) == 0 {
|
||||||
|
|
|
@ -15,8 +15,8 @@ import (
|
||||||
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
||||||
"github.com/portainer/portainer/pkg/libhttp/request"
|
"github.com/portainer/portainer/pkg/libhttp/request"
|
||||||
"github.com/portainer/portainer/pkg/libhttp/response"
|
"github.com/portainer/portainer/pkg/libhttp/response"
|
||||||
|
"github.com/portainer/portainer/pkg/validate"
|
||||||
|
|
||||||
"github.com/asaskevich/govalidator"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ func (payload *kubernetesStringDeploymentPayload) Validate(r *http.Request) erro
|
||||||
}
|
}
|
||||||
|
|
||||||
func (payload *kubernetesGitDeploymentPayload) Validate(r *http.Request) error {
|
func (payload *kubernetesGitDeploymentPayload) Validate(r *http.Request) error {
|
||||||
if len(payload.RepositoryURL) == 0 || !govalidator.IsURL(payload.RepositoryURL) {
|
if len(payload.RepositoryURL) == 0 || !validate.IsURL(payload.RepositoryURL) {
|
||||||
return errors.New("Invalid repository URL. Must correspond to a valid URL format")
|
return errors.New("Invalid repository URL. Must correspond to a valid URL format")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ func (payload *kubernetesGitDeploymentPayload) Validate(r *http.Request) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (payload *kubernetesManifestURLDeploymentPayload) Validate(r *http.Request) error {
|
func (payload *kubernetesManifestURLDeploymentPayload) Validate(r *http.Request) error {
|
||||||
if len(payload.ManifestURL) == 0 || !govalidator.IsURL(payload.ManifestURL) {
|
if len(payload.ManifestURL) == 0 || !validate.IsURL(payload.ManifestURL) {
|
||||||
return errors.New("Invalid manifest URL")
|
return errors.New("Invalid manifest URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,8 @@ import (
|
||||||
"github.com/portainer/portainer/api/stacks/stackutils"
|
"github.com/portainer/portainer/api/stacks/stackutils"
|
||||||
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
||||||
"github.com/portainer/portainer/pkg/libhttp/request"
|
"github.com/portainer/portainer/pkg/libhttp/request"
|
||||||
|
valid "github.com/portainer/portainer/pkg/validate"
|
||||||
|
|
||||||
"github.com/asaskevich/govalidator"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -142,7 +142,7 @@ func (payload *swarmStackFromGitRepositoryPayload) Validate(r *http.Request) err
|
||||||
if len(payload.SwarmID) == 0 {
|
if len(payload.SwarmID) == 0 {
|
||||||
return errors.New("Invalid Swarm ID")
|
return errors.New("Invalid Swarm ID")
|
||||||
}
|
}
|
||||||
if len(payload.RepositoryURL) == 0 || !govalidator.IsURL(payload.RepositoryURL) {
|
if len(payload.RepositoryURL) == 0 || !valid.IsURL(payload.RepositoryURL) {
|
||||||
return errors.New("Invalid repository URL. Must correspond to a valid URL format")
|
return errors.New("Invalid repository URL. Must correspond to a valid URL format")
|
||||||
}
|
}
|
||||||
if payload.RepositoryAuthentication && len(payload.RepositoryPassword) == 0 {
|
if payload.RepositoryAuthentication && len(payload.RepositoryPassword) == 0 {
|
||||||
|
|
|
@ -11,8 +11,7 @@ import (
|
||||||
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
||||||
"github.com/portainer/portainer/pkg/libhttp/request"
|
"github.com/portainer/portainer/pkg/libhttp/request"
|
||||||
"github.com/portainer/portainer/pkg/libhttp/response"
|
"github.com/portainer/portainer/pkg/libhttp/response"
|
||||||
|
"github.com/portainer/portainer/pkg/validate"
|
||||||
"github.com/asaskevich/govalidator"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type userAccessTokenCreatePayload struct {
|
type userAccessTokenCreatePayload struct {
|
||||||
|
@ -24,10 +23,10 @@ func (payload *userAccessTokenCreatePayload) Validate(r *http.Request) error {
|
||||||
if len(payload.Description) == 0 {
|
if len(payload.Description) == 0 {
|
||||||
return errors.New("invalid description: cannot be empty")
|
return errors.New("invalid description: cannot be empty")
|
||||||
}
|
}
|
||||||
if govalidator.HasWhitespaceOnly(payload.Description) {
|
if validate.HasWhitespaceOnly(payload.Description) {
|
||||||
return errors.New("invalid description: cannot contain only whitespaces")
|
return errors.New("invalid description: cannot contain only whitespaces")
|
||||||
}
|
}
|
||||||
if govalidator.MinStringLength(payload.Description, "128") {
|
if validate.MinStringLength(payload.Description, 128) {
|
||||||
return errors.New("invalid description: cannot be longer than 128 characters")
|
return errors.New("invalid description: cannot be longer than 128 characters")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -9,8 +9,8 @@ import (
|
||||||
"github.com/portainer/portainer/api/ws"
|
"github.com/portainer/portainer/api/ws"
|
||||||
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
||||||
"github.com/portainer/portainer/pkg/libhttp/request"
|
"github.com/portainer/portainer/pkg/libhttp/request"
|
||||||
|
"github.com/portainer/portainer/pkg/validate"
|
||||||
|
|
||||||
"github.com/asaskevich/govalidator"
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ func (handler *Handler) websocketAttach(w http.ResponseWriter, r *http.Request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return httperror.BadRequest("Invalid query parameter: id", err)
|
return httperror.BadRequest("Invalid query parameter: id", err)
|
||||||
}
|
}
|
||||||
if !govalidator.IsHexadecimal(attachID) {
|
if !validate.IsHexadecimal(attachID) {
|
||||||
return httperror.BadRequest("Invalid query parameter: id (must be hexadecimal identifier)", err)
|
return httperror.BadRequest("Invalid query parameter: id (must be hexadecimal identifier)", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@ import (
|
||||||
"github.com/portainer/portainer/api/ws"
|
"github.com/portainer/portainer/api/ws"
|
||||||
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
||||||
"github.com/portainer/portainer/pkg/libhttp/request"
|
"github.com/portainer/portainer/pkg/libhttp/request"
|
||||||
|
"github.com/portainer/portainer/pkg/validate"
|
||||||
|
|
||||||
"github.com/asaskevich/govalidator"
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/segmentio/encoding/json"
|
"github.com/segmentio/encoding/json"
|
||||||
)
|
)
|
||||||
|
@ -42,7 +42,7 @@ func (handler *Handler) websocketExec(w http.ResponseWriter, r *http.Request) *h
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return httperror.BadRequest("Invalid query parameter: id", err)
|
return httperror.BadRequest("Invalid query parameter: id", err)
|
||||||
}
|
}
|
||||||
if !govalidator.IsHexadecimal(execID) {
|
if !validate.IsHexadecimal(execID) {
|
||||||
return httperror.BadRequest("Invalid query parameter: id (must be hexadecimal identifier)", err)
|
return httperror.BadRequest("Invalid query parameter: id (must be hexadecimal identifier)", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -6,7 +6,6 @@ require (
|
||||||
github.com/Masterminds/semver v1.5.0
|
github.com/Masterminds/semver v1.5.0
|
||||||
github.com/Microsoft/go-winio v0.6.2
|
github.com/Microsoft/go-winio v0.6.2
|
||||||
github.com/VictoriaMetrics/fastcache v1.12.0
|
github.com/VictoriaMetrics/fastcache v1.12.0
|
||||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2
|
|
||||||
github.com/aws/aws-sdk-go-v2 v1.24.1
|
github.com/aws/aws-sdk-go-v2 v1.24.1
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.16.16
|
github.com/aws/aws-sdk-go-v2/credentials v1.16.16
|
||||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.24.1
|
github.com/aws/aws-sdk-go-v2/service/ecr v1.24.1
|
||||||
|
@ -85,6 +84,7 @@ require (
|
||||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
|
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
|
||||||
github.com/andrew-d/go-termutil v0.0.0-20150726205930-009166a695a2 // indirect
|
github.com/andrew-d/go-termutil v0.0.0-20150726205930-009166a695a2 // indirect
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 // indirect
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 // indirect
|
||||||
|
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.26.6 // indirect
|
github.com/aws/aws-sdk-go-v2/config v1.26.6 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 // indirect
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 // indirect
|
||||||
|
|
111
pkg/validate/validate.go
Normal file
111
pkg/validate/validate.go
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
package validate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"net/url"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
minURLRuneCount = 3
|
||||||
|
maxURLRuneCount = 2083
|
||||||
|
|
||||||
|
ipPattern = `(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))`
|
||||||
|
urlSchemaPattern = `((ftp|tcp|udp|wss?|https?):\/\/)`
|
||||||
|
urlUsernamePattern = `(\S+(:\S*)?@)`
|
||||||
|
urlPathPattern = `((\/|\?|#)[^\s]*)`
|
||||||
|
urlPortPattern = `(:(\d{1,5}))`
|
||||||
|
urlIPPattern = `([1-9]\d?|1\d\d|2[01]\d|22[0-3]|24\d|25[0-5])(\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-5]))`
|
||||||
|
urlSubdomainPattern = `((www\.)|([a-zA-Z0-9]+([-_\.]?[a-zA-Z0-9])*[a-zA-Z0-9]\.[a-zA-Z0-9]+))`
|
||||||
|
urlPattern = `^` + urlSchemaPattern + `?` + urlUsernamePattern + `?` + `((` + urlIPPattern + `|(\[` + ipPattern + `\])|(([a-zA-Z0-9]([a-zA-Z0-9-_]+)?[a-zA-Z0-9]([-\.][a-zA-Z0-9]+)*)|(` + urlSubdomainPattern + `?))?(([a-zA-Z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-zA-Z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-zA-Z\x{00a1}-\x{ffff}]{1,}))?))\.?` + urlPortPattern + `?` + urlPathPattern + `?$`
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
urlRegex = regexp.MustCompile(urlPattern)
|
||||||
|
uuidRegex = regexp.MustCompile(`^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`)
|
||||||
|
hexadecimalRegex = regexp.MustCompile(`^[0-9a-fA-F]+$`)
|
||||||
|
whitespaceRegex = regexp.MustCompile(`^[[:space:]]+$`)
|
||||||
|
dnsNameRegex = regexp.MustCompile(`^([a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62}){1}(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*[\._]?$`)
|
||||||
|
)
|
||||||
|
|
||||||
|
func IsURL(urlString string) bool {
|
||||||
|
if urlString == "" ||
|
||||||
|
utf8.RuneCountInString(urlString) >= maxURLRuneCount ||
|
||||||
|
len(urlString) <= minURLRuneCount ||
|
||||||
|
strings.HasPrefix(urlString, ".") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
strTemp := urlString
|
||||||
|
if strings.Contains(urlString, ":") && !strings.Contains(urlString, "://") {
|
||||||
|
// support no indicated urlscheme but with colon for port number
|
||||||
|
// http:// is appended so url.Parse will succeed, strTemp used so it does not impact rxURL.MatchString
|
||||||
|
strTemp = "http://" + urlString
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := url.Parse(strTemp)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(u.Host, ".") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if u.Host == "" && (u.Path != "" && !strings.Contains(u.Path, ".")) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return urlRegex.MatchString(urlString)
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsUUID(uuidString string) bool {
|
||||||
|
return uuidRegex.MatchString(uuidString)
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsHexadecimal(hexString string) bool {
|
||||||
|
return hexadecimalRegex.MatchString(hexString)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HasWhitespaceOnly(s string) bool {
|
||||||
|
return len(s) > 0 && whitespaceRegex.MatchString(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MinStringLength(s string, len int) bool {
|
||||||
|
return utf8.RuneCountInString(s) >= len
|
||||||
|
}
|
||||||
|
|
||||||
|
func Matches(s, pattern string) bool {
|
||||||
|
match, err := regexp.MatchString(pattern, s)
|
||||||
|
return err == nil && match
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsNonPositive(f float64) bool {
|
||||||
|
return f <= 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func InRange(val, left, right float64) bool {
|
||||||
|
if left > right {
|
||||||
|
left, right = right, left
|
||||||
|
}
|
||||||
|
|
||||||
|
return val >= left && val <= right
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsHost(s string) bool {
|
||||||
|
return IsIP(s) || IsDNSName(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsIP(s string) bool {
|
||||||
|
return net.ParseIP(s) != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsDNSName(s string) bool {
|
||||||
|
if s == "" || len(strings.ReplaceAll(s, ".", "")) > 255 {
|
||||||
|
// constraints already violated
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return !IsIP(s) && dnsNameRegex.MatchString(s)
|
||||||
|
}
|
424
pkg/validate/validate_test.go
Normal file
424
pkg/validate/validate_test.go
Normal file
|
@ -0,0 +1,424 @@
|
||||||
|
package validate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_IsURL(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
url string
|
||||||
|
expectedResult bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "simple url",
|
||||||
|
url: "https://google.com",
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no schema",
|
||||||
|
url: "google.com",
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "path",
|
||||||
|
url: "https://google.com/some/thing",
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "query params",
|
||||||
|
url: "https://google.com/some/thing?a=5&b=6",
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid",
|
||||||
|
url: "google",
|
||||||
|
expectedResult: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
result := IsURL(tc.url)
|
||||||
|
require.Equal(t, tc.expectedResult, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_IsUUID(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
uuid string
|
||||||
|
expectedResult bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
uuid: "",
|
||||||
|
expectedResult: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "version 3 UUID",
|
||||||
|
uuid: "060507eb-3b9a-362e-b850-d5f065eea403",
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "version 4 UUID",
|
||||||
|
uuid: "63e695ee-48a9-498a-98b3-9472ff75e09f",
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "version 5 UUID",
|
||||||
|
uuid: "5daabcd8-f17e-568c-aa6f-da9d92c7032c",
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "text",
|
||||||
|
uuid: "something like this",
|
||||||
|
expectedResult: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
result := IsUUID(tc.uuid)
|
||||||
|
require.Equal(t, tc.expectedResult, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_IsHexadecimal(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
hex string
|
||||||
|
expectedResult bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
hex: "",
|
||||||
|
expectedResult: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "hex",
|
||||||
|
hex: "48656C6C6F20736F6D657468696E67",
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "text",
|
||||||
|
hex: "something like this",
|
||||||
|
expectedResult: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
result := IsHexadecimal(tc.hex)
|
||||||
|
require.Equal(t, tc.expectedResult, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_HasWhitespaceOnly(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
s string
|
||||||
|
expectedResult bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
s: "",
|
||||||
|
expectedResult: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "space",
|
||||||
|
s: " ",
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "tab",
|
||||||
|
s: "\t",
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "text",
|
||||||
|
s: "something like this",
|
||||||
|
expectedResult: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
result := HasWhitespaceOnly(tc.s)
|
||||||
|
require.Equal(t, tc.expectedResult, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_MinStringLength(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
s string
|
||||||
|
len int
|
||||||
|
expectedResult bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty + zero len",
|
||||||
|
s: "",
|
||||||
|
len: 0,
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty + non zero len",
|
||||||
|
s: "",
|
||||||
|
len: 10,
|
||||||
|
expectedResult: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "long text + non zero len",
|
||||||
|
s: "something else",
|
||||||
|
len: 10,
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multibyte characters - enough",
|
||||||
|
s: "X生",
|
||||||
|
len: 2,
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multibyte characters - not enough",
|
||||||
|
s: "X生",
|
||||||
|
len: 3,
|
||||||
|
expectedResult: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
result := MinStringLength(tc.s, tc.len)
|
||||||
|
require.Equal(t, tc.expectedResult, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Matches(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
s string
|
||||||
|
pattern string
|
||||||
|
expectedResult bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
s: "",
|
||||||
|
pattern: "",
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "space",
|
||||||
|
s: "something else",
|
||||||
|
pattern: " ",
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
result := Matches(tc.s, tc.pattern)
|
||||||
|
require.Equal(t, tc.expectedResult, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_IsNonPositive(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
f float64
|
||||||
|
expectedResult bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "zero",
|
||||||
|
f: 0,
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "positive",
|
||||||
|
f: 1,
|
||||||
|
expectedResult: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "negative",
|
||||||
|
f: -1,
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
result := IsNonPositive(tc.f)
|
||||||
|
require.Equal(t, tc.expectedResult, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_InRange(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
f float64
|
||||||
|
left float64
|
||||||
|
right float64
|
||||||
|
expectedResult bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "zero",
|
||||||
|
f: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "equal left",
|
||||||
|
f: 1,
|
||||||
|
left: 1,
|
||||||
|
right: 2,
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "equal right",
|
||||||
|
f: 2,
|
||||||
|
left: 1,
|
||||||
|
right: 2,
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "above",
|
||||||
|
f: 3,
|
||||||
|
left: 1,
|
||||||
|
right: 2,
|
||||||
|
expectedResult: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "below",
|
||||||
|
f: 0,
|
||||||
|
left: 1,
|
||||||
|
right: 2,
|
||||||
|
expectedResult: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
result := InRange(tc.f, tc.left, tc.right)
|
||||||
|
require.Equal(t, tc.expectedResult, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_IsHost(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
s string
|
||||||
|
expectedResult bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
s: "",
|
||||||
|
expectedResult: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ip address",
|
||||||
|
s: "192.168.1.1",
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "hostname",
|
||||||
|
s: "google.com",
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "text",
|
||||||
|
s: "Something like this",
|
||||||
|
expectedResult: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
result := IsHost(tc.s)
|
||||||
|
require.Equal(t, tc.expectedResult, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_IsIP(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
s string
|
||||||
|
expectedResult bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
s: "",
|
||||||
|
expectedResult: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ip address",
|
||||||
|
s: "192.168.1.1",
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "hostname",
|
||||||
|
s: "google.com",
|
||||||
|
expectedResult: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "text",
|
||||||
|
s: "Something like this",
|
||||||
|
expectedResult: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
result := IsIP(tc.s)
|
||||||
|
require.Equal(t, tc.expectedResult, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_IsDNSName(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
s string
|
||||||
|
expectedResult bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
s: "",
|
||||||
|
expectedResult: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ip address",
|
||||||
|
s: "192.168.1.1",
|
||||||
|
expectedResult: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "hostname",
|
||||||
|
s: "google.com",
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "text",
|
||||||
|
s: "Something like this",
|
||||||
|
expectedResult: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
result := IsDNSName(tc.s)
|
||||||
|
require.Equal(t, tc.expectedResult, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue