2020-02-19 01:56:22 -08:00
|
|
|
package host
|
|
|
|
|
|
|
|
import (
|
2020-05-15 10:24:31 -07:00
|
|
|
"regexp"
|
2020-02-19 01:56:22 -08:00
|
|
|
"strings"
|
|
|
|
|
|
|
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
|
|
|
)
|
|
|
|
|
2020-05-15 10:24:31 -07:00
|
|
|
// IsValidID defines regular expression to check if the string consist of
|
|
|
|
// characters in one of the following categories only:
|
|
|
|
// - Alphanumeric
|
|
|
|
// - `.`, `_`, `+`, `-`, `#`
|
|
|
|
// - `[`, `]`, `<`, `>`
|
|
|
|
var IsValidID = regexp.MustCompile(`^[a-zA-Z0-9\.\_\+\-\#\[\]\<\>]+$`).MatchString
|
|
|
|
|
2020-07-03 02:28:02 -07:00
|
|
|
// IsValidConnectionVersion defines the regular expression to check if the
|
|
|
|
// string is in the form of a tuple consisting of a string identifier and
|
|
|
|
// a set of features. The entire version tuple must be enclosed in parentheses.
|
|
|
|
// The version identifier must not contain any commas. The set of features
|
|
|
|
// must be enclosed in brackets and separated by commas.
|
|
|
|
//
|
|
|
|
// valid connection version = ([version_identifier], [feature_0, feature_1, etc])
|
|
|
|
var IsValidConnectionVersion = regexp.MustCompile(`^\([^,]+\,\[([^,]+(\,[^,]+)*)?\]\)$`).MatchString
|
|
|
|
|
2020-02-19 01:56:22 -08:00
|
|
|
// ICS 024 Identifier and Path Validation Implementation
|
|
|
|
//
|
|
|
|
// This file defines ValidateFn to validate identifier and path strings
|
|
|
|
// The spec for ICS 024 can be located here:
|
|
|
|
// https://github.com/cosmos/ics/tree/master/spec/ics-024-host-requirements
|
|
|
|
|
|
|
|
// ValidateFn function type to validate path and identifier bytestrings
|
|
|
|
type ValidateFn func(string) error
|
|
|
|
|
2020-05-02 12:26:59 -07:00
|
|
|
func defaultIdentifierValidator(id string, min, max int) error { //nolint:unparam
|
2020-05-15 10:24:31 -07:00
|
|
|
if strings.TrimSpace(id) == "" {
|
|
|
|
return sdkerrors.Wrap(ErrInvalidID, "identifier cannot be blank")
|
|
|
|
}
|
2020-02-19 01:56:22 -08:00
|
|
|
// valid id MUST NOT contain "/" separator
|
|
|
|
if strings.Contains(id, "/") {
|
|
|
|
return sdkerrors.Wrapf(ErrInvalidID, "identifier %s cannot contain separator '/'", id)
|
|
|
|
}
|
2020-04-27 11:04:26 -07:00
|
|
|
// valid id must be between 9 and 20 characters
|
2020-02-19 01:56:22 -08:00
|
|
|
if len(id) < min || len(id) > max {
|
|
|
|
return sdkerrors.Wrapf(ErrInvalidID, "identifier %s has invalid length: %d, must be between %d-%d characters", id, len(id), min, max)
|
|
|
|
}
|
|
|
|
// valid id must contain only lower alphabetic characters
|
2020-05-15 10:24:31 -07:00
|
|
|
if !IsValidID(id) {
|
|
|
|
return sdkerrors.Wrapf(
|
|
|
|
ErrInvalidID,
|
|
|
|
"identifier %s must contain only alphanumeric or the following characters: '.', '_', '+', '-', '#', '[', ']', '<', '>'",
|
|
|
|
id,
|
|
|
|
)
|
2020-02-19 01:56:22 -08:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-05-14 15:47:11 -07:00
|
|
|
// ClientIdentifierValidator is the default validator function for Client identifiers.
|
2020-04-27 11:04:26 -07:00
|
|
|
// A valid Identifier must be between 9-20 characters and only contain lowercase
|
2020-02-19 01:56:22 -08:00
|
|
|
// alphabetic characters,
|
2020-05-14 15:47:11 -07:00
|
|
|
func ClientIdentifierValidator(id string) error {
|
2020-04-27 11:04:26 -07:00
|
|
|
return defaultIdentifierValidator(id, 9, 20)
|
2020-02-19 01:56:22 -08:00
|
|
|
}
|
|
|
|
|
2020-05-14 15:47:11 -07:00
|
|
|
// ConnectionIdentifierValidator is the default validator function for Connection identifiers.
|
2020-02-19 01:56:22 -08:00
|
|
|
// A valid Identifier must be between 10-20 characters and only contain lowercase
|
|
|
|
// alphabetic characters,
|
2020-05-14 15:47:11 -07:00
|
|
|
func ConnectionIdentifierValidator(id string) error {
|
2020-02-19 01:56:22 -08:00
|
|
|
return defaultIdentifierValidator(id, 10, 20)
|
|
|
|
}
|
|
|
|
|
2020-05-14 15:47:11 -07:00
|
|
|
// ChannelIdentifierValidator is the default validator function for Channel identifiers.
|
2020-02-19 01:56:22 -08:00
|
|
|
// A valid Identifier must be between 10-20 characters and only contain lowercase
|
|
|
|
// alphabetic characters,
|
2020-05-14 15:47:11 -07:00
|
|
|
func ChannelIdentifierValidator(id string) error {
|
2020-02-19 01:56:22 -08:00
|
|
|
return defaultIdentifierValidator(id, 10, 20)
|
|
|
|
}
|
|
|
|
|
2020-05-14 15:47:11 -07:00
|
|
|
// PortIdentifierValidator is the default validator function for Port identifiers.
|
2020-02-19 01:56:22 -08:00
|
|
|
// A valid Identifier must be between 2-20 characters and only contain lowercase
|
|
|
|
// alphabetic characters,
|
2020-05-14 15:47:11 -07:00
|
|
|
func PortIdentifierValidator(id string) error {
|
2020-02-19 01:56:22 -08:00
|
|
|
return defaultIdentifierValidator(id, 2, 20)
|
|
|
|
}
|
|
|
|
|
2020-07-03 02:28:02 -07:00
|
|
|
// ConnectionVersionValidator is the default validator function for Connection
|
|
|
|
// versions. A valid version must be in semantic versioning form and contain
|
|
|
|
// only non-negative integers.
|
|
|
|
func ConnectionVersionValidator(version string) error {
|
|
|
|
if strings.TrimSpace(version) == "" {
|
|
|
|
return sdkerrors.Wrap(ErrInvalidVersion, "version cannot be blank")
|
|
|
|
}
|
|
|
|
|
|
|
|
if !IsValidConnectionVersion(version) {
|
|
|
|
return sdkerrors.Wrapf(
|
|
|
|
ErrInvalidVersion,
|
|
|
|
"version '%s' must be in '(version_identifier,[feature_0, feature_1])' with no extra spacing", version,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-02-19 01:56:22 -08:00
|
|
|
// NewPathValidator takes in a Identifier Validator function and returns
|
|
|
|
// a Path Validator function which requires path only has valid identifiers
|
|
|
|
// alphanumeric character strings, and "/" separators
|
|
|
|
func NewPathValidator(idValidator ValidateFn) ValidateFn {
|
|
|
|
return func(path string) error {
|
|
|
|
pathArr := strings.Split(path, "/")
|
2020-05-15 10:24:31 -07:00
|
|
|
if len(pathArr) > 0 && pathArr[0] == path {
|
|
|
|
return sdkerrors.Wrapf(ErrInvalidPath, "path %s doesn't contain any separator '/'", path)
|
|
|
|
}
|
|
|
|
|
2020-02-19 01:56:22 -08:00
|
|
|
for _, p := range pathArr {
|
2020-05-15 11:58:43 -07:00
|
|
|
// a path beginning or ending in a separator returns empty string elements.
|
2020-05-15 10:24:31 -07:00
|
|
|
if p == "" {
|
2020-05-15 11:58:43 -07:00
|
|
|
return sdkerrors.Wrapf(ErrInvalidPath, "path %s cannot begin or end with '/'", path)
|
2020-05-15 10:24:31 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if err := idValidator(p); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// Each path element must either be a valid identifier or constant number
|
|
|
|
if err := defaultIdentifierValidator(p, 1, 20); err != nil {
|
|
|
|
return sdkerrors.Wrapf(err, "path %s contains an invalid identifier: '%s'", path, p)
|
2020-02-19 01:56:22 -08:00
|
|
|
}
|
|
|
|
}
|
2020-05-15 10:24:31 -07:00
|
|
|
|
2020-02-19 01:56:22 -08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-15 10:24:31 -07:00
|
|
|
// PathValidator takes in path string and validates with default identifier rules.
|
2020-05-14 15:47:11 -07:00
|
|
|
// This is optimized by simply checking that all path elements are alphanumeric.
|
|
|
|
func PathValidator(path string) error {
|
2020-02-19 01:56:22 -08:00
|
|
|
pathArr := strings.Split(path, "/")
|
2020-05-15 10:24:31 -07:00
|
|
|
if len(pathArr) > 0 && pathArr[0] == path {
|
2020-02-19 01:56:22 -08:00
|
|
|
return sdkerrors.Wrapf(ErrInvalidPath, "path %s doesn't contain any separator '/'", path)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, p := range pathArr {
|
2020-05-15 11:58:43 -07:00
|
|
|
// a path beginning or ending in a separator returns empty string elements.
|
2020-05-15 10:24:31 -07:00
|
|
|
if p == "" {
|
2020-05-15 11:58:43 -07:00
|
|
|
return sdkerrors.Wrapf(ErrInvalidPath, "path %s cannot begin or end with '/'", path)
|
2020-05-15 10:24:31 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Each path element must be a valid identifier or constant number
|
|
|
|
if err := defaultIdentifierValidator(p, 1, 20); err != nil {
|
|
|
|
return sdkerrors.Wrapf(err, "path %s contains an invalid identifier: '%s'", path, p)
|
2020-02-19 01:56:22 -08:00
|
|
|
}
|
|
|
|
}
|
2020-05-15 10:24:31 -07:00
|
|
|
|
2020-02-19 01:56:22 -08:00
|
|
|
return nil
|
|
|
|
}
|