Skip to content

Commit

Permalink
fix: API address parameter validation (sourcenetwork#1311)
Browse files Browse the repository at this point in the history
  • Loading branch information
orpheuslummis authored Apr 12, 2023
1 parent ebb7d87 commit 8d609ad
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 20 deletions.
8 changes: 6 additions & 2 deletions api/http/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,14 @@ func WithAddress(addr string) func(*Server) {
// If the address is not localhost, we check to see if it's a valid IP address.
// If it's not a valid IP, we assume that it's a domain name to be used with TLS.
if !strings.HasPrefix(addr, "localhost:") && !strings.HasPrefix(addr, ":") {
ip := net.ParseIP(addr)
host, _, err := net.SplitHostPort(addr)
if err != nil {
host = addr
}
ip := net.ParseIP(host)
if ip == nil {
s.Addr = httpPort
s.options.domain = immutable.Some(addr)
s.options.domain = immutable.Some(host)
}
}
}
Expand Down
36 changes: 28 additions & 8 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import (
ma "github.com/multiformats/go-multiaddr"
"github.com/spf13/pflag"
"github.com/spf13/viper"
"golang.org/x/net/idna"

badgerds "github.com/sourcenetwork/defradb/datastore/badger/v3"
"github.com/sourcenetwork/defradb/logging"
Expand Down Expand Up @@ -296,18 +297,37 @@ func (apicfg *APIConfig) validate() error {
if apicfg.Address == "" {
return ErrInvalidDatabaseURL
}
ip := net.ParseIP(apicfg.Address)
if strings.HasPrefix(apicfg.Address, "localhost") || strings.HasPrefix(apicfg.Address, ":") || ip != nil {
_, err := net.ResolveTCPAddr("tcp", apicfg.Address)
if err != nil {
return NewErrInvalidDatabaseURL(err)
}
} else if ip == nil {
return ErrInvalidDatabaseURL

if apicfg.Address == "localhost" || net.ParseIP(apicfg.Address) != nil { //nolint:goconst
return ErrMissingPortNumber
}

if isValidDomainName(apicfg.Address) {
return nil
}

host, _, err := net.SplitHostPort(apicfg.Address)
if err != nil {
return NewErrInvalidDatabaseURL(err)
}
if host == "localhost" {
return nil
}
if net.ParseIP(host) == nil {
return ErrNoPortWithDomain
}

return nil
}

func isValidDomainName(domain string) bool {
asciiDomain, err := idna.Registration.ToASCII(domain)
if err != nil {
return false
}
return asciiDomain == domain
}

// AddressToURL provides the API address as URL.
func (apicfg *APIConfig) AddressToURL() string {
if apicfg.TLS {
Expand Down
38 changes: 37 additions & 1 deletion config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -478,9 +478,45 @@ func TestValidationInvalidLoggingConfig(t *testing.T) {
assert.ErrorIs(t, err, ErrInvalidLogLevel)
}

func TestValidationAddressBasic(t *testing.T) {
func TestValidationAddressBasicIncomplete(t *testing.T) {
cfg := DefaultConfig()
cfg.API.Address = "localhost"
err := cfg.validate()
assert.ErrorIs(t, err, ErrFailedToValidateConfig)
}

func TestValidationAddressLocalhostValid(t *testing.T) {
cfg := DefaultConfig()
cfg.API.Address = "localhost:9876"
err := cfg.validate()
assert.NoError(t, err)
}

func TestValidationAddress0000Incomplete(t *testing.T) {
cfg := DefaultConfig()
cfg.API.Address = "0.0.0.0"
err := cfg.validate()
assert.ErrorIs(t, err, ErrFailedToValidateConfig)
}

func TestValidationAddress0000Valid(t *testing.T) {
cfg := DefaultConfig()
cfg.API.Address = "0.0.0.0:9876"
err := cfg.validate()
assert.NoError(t, err)
}

func TestValidationAddressDomainWithSubdomainValidWithTLSCorrectPortIsInvalid(t *testing.T) {
cfg := DefaultConfig()
cfg.API.Address = "sub.example.com:443"
cfg.API.TLS = true
err := cfg.validate()
assert.ErrorIs(t, err, ErrNoPortWithDomain)
}

func TestValidationAddressDomainWithSubdomainWrongPortIsInvalid(t *testing.T) {
cfg := DefaultConfig()
cfg.API.Address = "sub.example.com:9876"
err := cfg.validate()
assert.ErrorIs(t, err, ErrNoPortWithDomain)
}
4 changes: 4 additions & 0 deletions config/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ const (
errLoadingConfig string = "failed to load config"
errUnableToParseByteSize string = "unable to parse byte size"
errInvalidDatastorePath string = "invalid datastore path"
errMissingPortNumber string = "missing port number"
errNoPortWithDomain string = "cannot provide port with domain name"
)

var (
Expand Down Expand Up @@ -82,6 +84,8 @@ var (
ErrUnableToParseByteSize = errors.New(errUnableToParseByteSize)
ErrInvalidLoggerConfig = errors.New(errInvalidLoggerConfig)
ErrorInvalidDatastorePath = errors.New(errInvalidDatastorePath)
ErrMissingPortNumber = errors.New(errMissingPortNumber)
ErrNoPortWithDomain = errors.New(errNoPortWithDomain)
)

func NewErrFailedToWriteFile(inner error, path string) error {
Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ require (
go.opentelemetry.io/otel/sdk/metric v0.36.0
go.uber.org/zap v1.24.0
golang.org/x/crypto v0.7.0
golang.org/x/net v0.9.0
google.golang.org/grpc v1.54.0
)

Expand Down Expand Up @@ -181,10 +182,9 @@ require (
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/exp v0.0.0-20230129154200-a960b3787bd2 // indirect
golang.org/x/mod v0.8.0 // indirect
golang.org/x/net v0.8.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/text v0.8.0 // indirect
golang.org/x/sys v0.7.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/tools v0.6.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect
Expand Down
12 changes: 6 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1151,8 +1151,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
Expand Down Expand Up @@ -1253,8 +1253,8 @@ golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
Expand All @@ -1266,8 +1266,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
Expand Down

0 comments on commit 8d609ad

Please sign in to comment.