summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--model/config.go13
-rw-r--r--model/config_test.go42
-rw-r--r--model/utils.go54
3 files changed, 108 insertions, 1 deletions
diff --git a/model/config.go b/model/config.go
index 1d0f40901..aa7900279 100644
--- a/model/config.go
+++ b/model/config.go
@@ -6,9 +6,12 @@ package model
import (
"encoding/json"
"io"
+ "math"
+ "net"
"net/http"
"net/url"
"regexp"
+ "strconv"
"strings"
"time"
)
@@ -2352,7 +2355,15 @@ func (ss *ServiceSettings) isValid() *AppError {
}
}
- if len(*ss.ListenAddress) == 0 {
+ host, port, err := net.SplitHostPort(*ss.ListenAddress)
+ var isValidHost bool
+ if host == "" {
+ isValidHost = true
+ } else {
+ isValidHost = (net.ParseIP(host) != nil) || IsDomainName(host)
+ }
+ portInt, err := strconv.Atoi(port)
+ if err != nil || !isValidHost || portInt < 0 || portInt > math.MaxUint16 {
return NewAppError("Config.IsValid", "model.config.is_valid.listen_address.app_error", nil, "", http.StatusBadRequest)
}
diff --git a/model/config_test.go b/model/config_test.go
index 848f4327e..179bab8e2 100644
--- a/model/config_test.go
+++ b/model/config_test.go
@@ -519,3 +519,45 @@ func TestDisplaySettingsIsValidCustomUrlSchemes(t *testing.T) {
})
}
}
+
+func TestListenAddressIsValidated(t *testing.T) {
+
+ testValues := map[string]bool{
+ ":8065": true,
+ ":9917": true,
+ "0.0.0.0:9917": true,
+ "[2001:db8::68]:9918": true,
+ "[::1]:8065": true,
+ "localhost:8065": true,
+ "test.com:8065": true,
+ ":0": true,
+ ":33147": true,
+ "123:8065": false,
+ "[::1]:99999": false,
+ "[::1]:-1": false,
+ "[::1]:8065a": false,
+ "0.0.0:9917": false,
+ "0.0.0.0:9917/": false,
+ "0..0.0:9917/": false,
+ "0.0.0222.0:9917/": false,
+ "http://0.0.0.0:9917/": false,
+ "http://0.0.0.0:9917": false,
+ "8065": false,
+ "[2001:db8::68]": false,
+ }
+
+ for key, expected := range testValues {
+ ss := &ServiceSettings{
+ ListenAddress: NewString(key),
+ }
+ ss.SetDefaults()
+ if expected {
+ require.Nil(t, ss.isValid(), fmt.Sprintf("Got an error from '%v'.", key))
+ } else {
+ err := ss.isValid()
+ require.NotNil(t, err, fmt.Sprintf("Expected '%v' to throw an error.", key))
+ require.Equal(t, "model.config.is_valid.listen_address.app_error", err.Message)
+ }
+ }
+
+}
diff --git a/model/utils.go b/model/utils.go
index 9f8ef90e1..892f8c278 100644
--- a/model/utils.go
+++ b/model/utils.go
@@ -536,3 +536,57 @@ func checkNowhereNil(t *testing.T, name string, value interface{}) bool {
return true
}
}
+
+// Copied from https://golang.org/src/net/dnsclient.go#L119
+func IsDomainName(s string) bool {
+ // See RFC 1035, RFC 3696.
+ // Presentation format has dots before every label except the first, and the
+ // terminal empty label is optional here because we assume fully-qualified
+ // (absolute) input. We must therefore reserve space for the first and last
+ // labels' length octets in wire format, where they are necessary and the
+ // maximum total length is 255.
+ // So our _effective_ maximum is 253, but 254 is not rejected if the last
+ // character is a dot.
+ l := len(s)
+ if l == 0 || l > 254 || l == 254 && s[l-1] != '.' {
+ return false
+ }
+
+ last := byte('.')
+ ok := false // Ok once we've seen a letter.
+ partlen := 0
+ for i := 0; i < len(s); i++ {
+ c := s[i]
+ switch {
+ default:
+ return false
+ case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_':
+ ok = true
+ partlen++
+ case '0' <= c && c <= '9':
+ // fine
+ partlen++
+ case c == '-':
+ // Byte before dash cannot be dot.
+ if last == '.' {
+ return false
+ }
+ partlen++
+ case c == '.':
+ // Byte before dot cannot be dot, dash.
+ if last == '.' || last == '-' {
+ return false
+ }
+ if partlen > 63 || partlen == 0 {
+ return false
+ }
+ partlen = 0
+ }
+ last = c
+ }
+ if last == '-' || partlen > 63 {
+ return false
+ }
+
+ return ok
+}