-
Notifications
You must be signed in to change notification settings - Fork 3.5k
/
validate.go
136 lines (117 loc) · 5.07 KB
/
validate.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package host
import (
"regexp"
"strings"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// DefaultMaxCharacterLength defines the default maximum character length used
// in validation of identifiers including the client, connection, port and
// channel identifiers.
//
// NOTE: this restriction is specific to this golang implementation of IBC. If
// your use case demands a higher limit, please open an issue and we will consider
// adjusting this restriction.
const DefaultMaxCharacterLength = 64
// 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
// 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
func defaultIdentifierValidator(id string, min, max int) error { //nolint:unparam
if strings.TrimSpace(id) == "" {
return sdkerrors.Wrap(ErrInvalidID, "identifier cannot be blank")
}
// valid id MUST NOT contain "/" separator
if strings.Contains(id, "/") {
return sdkerrors.Wrapf(ErrInvalidID, "identifier %s cannot contain separator '/'", id)
}
// valid id must fit the length requirements
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
if !IsValidID(id) {
return sdkerrors.Wrapf(
ErrInvalidID,
"identifier %s must contain only alphanumeric or the following characters: '.', '_', '+', '-', '#', '[', ']', '<', '>'",
id,
)
}
return nil
}
// ClientIdentifierValidator is the default validator function for Client identifiers.
// A valid Identifier must be between 9-20 characters and only contain lowercase
// alphabetic characters,
func ClientIdentifierValidator(id string) error {
return defaultIdentifierValidator(id, 9, DefaultMaxCharacterLength)
}
// ConnectionIdentifierValidator is the default validator function for Connection identifiers.
// A valid Identifier must be between 10-20 characters and only contain lowercase
// alphabetic characters,
func ConnectionIdentifierValidator(id string) error {
return defaultIdentifierValidator(id, 10, DefaultMaxCharacterLength)
}
// ChannelIdentifierValidator is the default validator function for Channel identifiers.
// A valid Identifier must be between 10-20 characters and only contain lowercase
// alphabetic characters,
func ChannelIdentifierValidator(id string) error {
return defaultIdentifierValidator(id, 10, DefaultMaxCharacterLength)
}
// PortIdentifierValidator is the default validator function for Port identifiers.
// A valid Identifier must be between 2-20 characters and only contain lowercase
// alphabetic characters,
func PortIdentifierValidator(id string) error {
return defaultIdentifierValidator(id, 2, DefaultMaxCharacterLength)
}
// 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, "/")
if len(pathArr) > 0 && pathArr[0] == path {
return sdkerrors.Wrapf(ErrInvalidPath, "path %s doesn't contain any separator '/'", path)
}
for _, p := range pathArr {
// a path beginning or ending in a separator returns empty string elements.
if p == "" {
return sdkerrors.Wrapf(ErrInvalidPath, "path %s cannot begin or end with '/'", path)
}
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, DefaultMaxCharacterLength); err != nil {
return sdkerrors.Wrapf(err, "path %s contains an invalid identifier: '%s'", path, p)
}
}
return nil
}
}
// PathValidator takes in path string and validates with default identifier rules.
// This is optimized by simply checking that all path elements are alphanumeric.
func PathValidator(path string) error {
pathArr := strings.Split(path, "/")
if len(pathArr) > 0 && pathArr[0] == path {
return sdkerrors.Wrapf(ErrInvalidPath, "path %s doesn't contain any separator '/'", path)
}
for _, p := range pathArr {
// a path beginning or ending in a separator returns empty string elements.
if p == "" {
return sdkerrors.Wrapf(ErrInvalidPath, "path %s cannot begin or end with '/'", path)
}
// Each path element must be a valid identifier or constant number
if err := defaultIdentifierValidator(p, 1, DefaultMaxCharacterLength); err != nil {
return sdkerrors.Wrapf(err, "path %s contains an invalid identifier: '%s'", path, p)
}
}
return nil
}