Skip to content

Commit

Permalink
Support string.host_and_port standard constraint (#95)
Browse files Browse the repository at this point in the history
  • Loading branch information
rodaine committed Feb 12, 2024
1 parent 3f1653a commit d04f363
Show file tree
Hide file tree
Showing 8 changed files with 1,326 additions and 948 deletions.
5 changes: 4 additions & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ linters:
- wrapcheck # don't _always_ need to wrap errors
- wsl # over-generous whitespace violates house style
issues:
exclude:
# we will continue to support the deprecated field until it's removed
- "IgnoreEmpty is deprecated"
exclude-rules:
# Loosen requirements on conformance executor
- path: internal/cmd/
Expand Down Expand Up @@ -81,4 +84,4 @@ issues:
- path: resolver/resolver.go
linters:
# uses deprecated fields on protoimpl.ExtensionInfo but its the only way
- staticcheck
- staticcheck
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ ARGS ?= --strict --strict_message --strict_error
# Set to use a different version of protovalidate-conformance.
# Should be kept in sync with the version referenced in proto/buf.lock and
# 'buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go' in go.mod.
CONFORMANCE_VERSION ?= v0.5.3
CONFORMANCE_VERSION ?= v0.5.6

.PHONY: help
help: ## Describe useful make targets
Expand Down
59 changes: 57 additions & 2 deletions celext/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"net/mail"
"net/netip"
"net/url"
"strconv"
"strings"

"github.com/google/cel-go/cel"
Expand Down Expand Up @@ -294,7 +295,8 @@ func (l lib) CompileOptions() []cel.EnvOption {
return types.Bool(bytes.Contains(lhs.Value().([]byte), substr))
}),
),
), cel.Function(overloads.EndsWith,
),
cel.Function(overloads.EndsWith,
cel.MemberOverload(
overloads.EndsWithString, []*cel.Type{cel.StringType, cel.StringType}, cel.BoolType,
cel.BinaryBinding(func(lhs ref.Val, rhs ref.Val) ref.Val {
Expand Down Expand Up @@ -336,6 +338,19 @@ func (l lib) CompileOptions() []cel.EnvOption {
}),
),
),
cel.Function("isHostAndPort",
cel.MemberOverload("string_bool_is_host_and_port_bool",
[]*cel.Type{cel.StringType, cel.BoolType}, cel.BoolType,
cel.BinaryBinding(func(lhs ref.Val, rhs ref.Val) ref.Val {
val, vok := lhs.Value().(string)
portReq, pok := rhs.Value().(bool)
if !vok || !pok {
return types.Bool(false)
}
return types.Bool(l.isHostAndPort(val, portReq))
}),
),
),
}
}

Expand Down Expand Up @@ -413,8 +428,10 @@ func (l lib) validateHostname(host string) bool {
}

s := strings.ToLower(strings.TrimSuffix(host, "."))
allDigits := false
// split hostname on '.' and validate each part
for _, part := range strings.Split(s, ".") {
allDigits = true
// if part is empty, longer than 63 chars, or starts/ends with '-', it is invalid
if l := len(part); l == 0 || l > 63 || part[0] == '-' || part[l-1] == '-' {
return false
Expand All @@ -425,10 +442,12 @@ func (l lib) validateHostname(host string) bool {
if (ch < 'a' || ch > 'z') && (ch < '0' || ch > '9') && ch != '-' {
return false
}
allDigits = allDigits && ch >= '0' && ch <= '9'
}
}

return true
// the last part cannot be all numbers
return !allDigits
}

func (l lib) validateIP(addr string, ver int64) bool {
Expand Down Expand Up @@ -467,3 +486,39 @@ func (l lib) validateIPPrefix(p string, ver int64, strict bool) bool {
return false
}
}

func (l lib) isHostAndPort(val string, portRequired bool) bool {
if len(val) == 0 {
return false
}

splitIdx := strings.LastIndexByte(val, ':')
if val[0] == '[' { // ipv6
end := strings.IndexByte(val, ']')
switch end + 1 {
case len(val): // no port
return !portRequired && l.validateIP(val[1:end], 6)
case splitIdx: // port
return l.validateIP(val[1:end], 6) &&
l.validatePort(val[splitIdx+1:])
default: // malformed
return false
}
}

if splitIdx < 0 {
return !portRequired &&
(l.validateHostname(val) ||
l.validateIP(val, 4))
}

host, port := val[:splitIdx], val[splitIdx+1:]
return (l.validateHostname(host) ||
l.validateIP(host, 4)) &&
l.validatePort(port)
}

func (l lib) validatePort(val string) bool {
n, err := strconv.ParseUint(val, 10, 32)
return err == nil && n <= 65535
}
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ module github.com/bufbuild/protovalidate-go
go 1.19

require (
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.32.0-20231115204500-e097f827e652.1
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.32.0-20240212200630-3014d81c3a48.1
github.com/envoyproxy/protoc-gen-validate v1.0.4
github.com/google/cel-go v0.18.2
github.com/google/cel-go v0.19.0
github.com/stretchr/testify v1.8.4
google.golang.org/protobuf v1.32.0
)
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.32.0-20231115204500-e097f827e652.1 h1:u0olL4yf2p7Tl5jfsAK5keaFi+JFJuv1CDHrbiXkxkk=
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.32.0-20231115204500-e097f827e652.1/go.mod h1:tiTMKD8j6Pd/D2WzREoweufjzaJKHZg35f/VGcZ2v3I=
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.32.0-20240212200630-3014d81c3a48.1 h1:rOe/itdO7+9cWOnKqvpn1K7VmTDwp3vI4juPz6aNQbc=
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.32.0-20240212200630-3014d81c3a48.1/go.mod h1:tiTMKD8j6Pd/D2WzREoweufjzaJKHZg35f/VGcZ2v3I=
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
Expand All @@ -11,6 +13,8 @@ github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZ
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/cel-go v0.18.2 h1:L0B6sNBSVmt0OyECi8v6VOS74KOc9W/tLiWKfZABvf4=
github.com/google/cel-go v0.18.2/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg=
github.com/google/cel-go v0.19.0 h1:vVgaZoHPBDd1lXCYGQOh5A06L4EtuIfmqQ/qnSXSKiU=
github.com/google/cel-go v0.19.0/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
Expand Down
Loading

0 comments on commit d04f363

Please sign in to comment.