summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config/default.json1
-rw-r--r--i18n/en.json4
-rw-r--r--model/config.go31
-rw-r--r--model/config_test.go83
-rw-r--r--utils/config.go1
5 files changed, 120 insertions, 0 deletions
diff --git a/config/default.json b/config/default.json
index 3548339d0..9f35ad7d1 100644
--- a/config/default.json
+++ b/config/default.json
@@ -97,6 +97,7 @@
"ExperimentalPrimaryTeam": ""
},
"DisplaySettings": {
+ "CustomUrlSchemes": [],
"ExperimentalTimezone": false
},
"ClientRequirements": {
diff --git a/i18n/en.json b/i18n/en.json
index 4a9532ca3..fb6d5eeb1 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -4951,6 +4951,10 @@
"translation": "Message retention must be one day or longer."
},
{
+ "id": "model.config.is_valid.display.custom_url_schemes.app_error",
+ "translation": "The custom URL scheme {{.Scheme}} is invalid. Custom URL schemes must start with a letter and contain only letters, numbers, plus (+), period (.), and hyphen (-)."
+ },
+ {
"id": "model.config.is_valid.elastic_search.aggregate_posts_after_days.app_error",
"translation": "Elasticsearch AggregatePostsAfterDays setting must be a number greater than or equal to 1"
},
diff --git a/model/config.go b/model/config.go
index d5a8ad38e..074632a67 100644
--- a/model/config.go
+++ b/model/config.go
@@ -8,6 +8,7 @@ import (
"io"
"net/http"
"net/url"
+ "regexp"
"strings"
"time"
)
@@ -1772,10 +1773,16 @@ func (s *MessageExportSettings) SetDefaults() {
}
type DisplaySettings struct {
+ CustomUrlSchemes *[]string
ExperimentalTimezone *bool
}
func (s *DisplaySettings) SetDefaults() {
+ if s.CustomUrlSchemes == nil {
+ customUrlSchemes := []string{}
+ s.CustomUrlSchemes = &customUrlSchemes
+ }
+
if s.ExperimentalTimezone == nil {
s.ExperimentalTimezone = NewBool(false)
}
@@ -1968,6 +1975,10 @@ func (o *Config) IsValid() *AppError {
return err
}
+ if err := o.DisplaySettings.isValid(); err != nil {
+ return err
+ }
+
return nil
}
@@ -2348,6 +2359,26 @@ func (mes *MessageExportSettings) isValid(fs FileSettings) *AppError {
return nil
}
+func (ds *DisplaySettings) isValid() *AppError {
+ if len(*ds.CustomUrlSchemes) != 0 {
+ validProtocolPattern := regexp.MustCompile(`(?i)^\s*[a-z][a-z0-9+.-]*\s*$`)
+
+ for _, scheme := range *ds.CustomUrlSchemes {
+ if !validProtocolPattern.MatchString(scheme) {
+ return NewAppError(
+ "Config.IsValid",
+ "model.config.is_valid.display.custom_url_schemes.app_error",
+ map[string]interface{}{"Protocol": scheme},
+ "",
+ http.StatusBadRequest,
+ )
+ }
+ }
+ }
+
+ return nil
+}
+
func (o *Config) GetSanitizeOptions() map[string]bool {
options := map[string]bool{}
options["fullname"] = o.PrivacySettings.ShowFullName
diff --git a/model/config_test.go b/model/config_test.go
index b7533145b..5406d680d 100644
--- a/model/config_test.go
+++ b/model/config_test.go
@@ -436,3 +436,86 @@ func TestMessageExportSetDefaultsExportDisabledExportFromTimestampNonZero(t *tes
require.Equal(t, int64(0), *mes.ExportFromTimestamp)
require.Equal(t, 10000, *mes.BatchSize)
}
+
+func TestDisplaySettingsIsValidCustomUrlSchemes(t *testing.T) {
+ tests := []struct {
+ name string
+ value []string
+ valid bool
+ }{
+ {
+ name: "empty",
+ value: []string{},
+ valid: true,
+ },
+ {
+ name: "custom protocol",
+ value: []string{"steam"},
+ valid: true,
+ },
+ {
+ name: "multiple custom protocols",
+ value: []string{"bitcoin", "rss", "redis"},
+ valid: true,
+ },
+ {
+ name: "containing numbers",
+ value: []string{"ut2004", "ts3server", "h323"},
+ valid: true,
+ },
+ {
+ name: "containing period",
+ value: []string{"iris.beep"},
+ valid: true,
+ },
+ {
+ name: "containing hyphen",
+ value: []string{"ms-excel"},
+ valid: true,
+ },
+ {
+ name: "containing plus",
+ value: []string{"coap+tcp", "coap+ws"},
+ valid: true,
+ },
+ {
+ name: "starting with number",
+ value: []string{"4four"},
+ valid: false,
+ },
+ {
+ name: "starting with period",
+ value: []string{"data", ".dot"},
+ valid: false,
+ },
+ {
+ name: "starting with hyphen",
+ value: []string{"-hyphen", "dns"},
+ valid: false,
+ },
+ {
+ name: "invalid symbols",
+ value: []string{"!!fun!!"},
+ valid: false,
+ },
+ {
+ name: "invalid letters",
+ value: []string{"école"},
+ valid: false,
+ },
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ ds := &DisplaySettings{}
+ ds.SetDefaults()
+
+ ds.CustomUrlSchemes = &test.value
+
+ if err := ds.isValid(); err != nil && test.valid {
+ t.Error("Expected CustomUrlSchemes to be valid but got error:", err)
+ } else if err == nil && !test.valid {
+ t.Error("Expected CustomUrlSchemes to be invalid but got no error")
+ }
+ })
+ }
+}
diff --git a/utils/config.go b/utils/config.go
index 00fd2642a..2e6f4182f 100644
--- a/utils/config.go
+++ b/utils/config.go
@@ -609,6 +609,7 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
props["PasswordRequireUppercase"] = strconv.FormatBool(*c.PasswordSettings.Uppercase)
props["PasswordRequireNumber"] = strconv.FormatBool(*c.PasswordSettings.Number)
props["PasswordRequireSymbol"] = strconv.FormatBool(*c.PasswordSettings.Symbol)
+ props["CustomUrlSchemes"] = strings.Join(*c.DisplaySettings.CustomUrlSchemes, ",")
if license != nil {
props["ExperimentalHideTownSquareinLHS"] = strconv.FormatBool(*c.TeamSettings.ExperimentalHideTownSquareinLHS)