MM-13276: expose Websocket(URL|(Secure)Port) in limited client config (#10110)
This fixes a race condition client-side that fails to connect to websockets during MFA enforcement since the necessary config data isn't fetched. There are no security concerns in exposing this data to non-authenticated users, though we'd like to revisit this to tighten it down later: https://mattermost.atlassian.net/browse/MM-13785.
Этот коммит содержится в:
коммит произвёл
Christopher Speller
родитель
c208de7c44
Коммит
8ead10effb
@@ -428,7 +428,6 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
|
|||||||
props := GenerateLimitedClientConfig(c, diagnosticId, license)
|
props := GenerateLimitedClientConfig(c, diagnosticId, license)
|
||||||
|
|
||||||
props["SiteURL"] = strings.TrimRight(*c.ServiceSettings.SiteURL, "/")
|
props["SiteURL"] = strings.TrimRight(*c.ServiceSettings.SiteURL, "/")
|
||||||
props["WebsocketURL"] = strings.TrimRight(*c.ServiceSettings.WebsocketURL, "/")
|
|
||||||
props["EnableUserDeactivation"] = strconv.FormatBool(*c.TeamSettings.EnableUserDeactivation)
|
props["EnableUserDeactivation"] = strconv.FormatBool(*c.TeamSettings.EnableUserDeactivation)
|
||||||
props["RestrictDirectMessage"] = *c.TeamSettings.RestrictDirectMessage
|
props["RestrictDirectMessage"] = *c.TeamSettings.RestrictDirectMessage
|
||||||
props["EnableXToLeaveChannelsFromLHS"] = strconv.FormatBool(*c.TeamSettings.EnableXToLeaveChannelsFromLHS)
|
props["EnableXToLeaveChannelsFromLHS"] = strconv.FormatBool(*c.TeamSettings.EnableXToLeaveChannelsFromLHS)
|
||||||
@@ -476,9 +475,6 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
|
|||||||
props["EnableFileAttachments"] = strconv.FormatBool(*c.FileSettings.EnableFileAttachments)
|
props["EnableFileAttachments"] = strconv.FormatBool(*c.FileSettings.EnableFileAttachments)
|
||||||
props["EnablePublicLink"] = strconv.FormatBool(c.FileSettings.EnablePublicLink)
|
props["EnablePublicLink"] = strconv.FormatBool(c.FileSettings.EnablePublicLink)
|
||||||
|
|
||||||
props["WebsocketPort"] = fmt.Sprintf("%v", *c.ServiceSettings.WebsocketPort)
|
|
||||||
props["WebsocketSecurePort"] = fmt.Sprintf("%v", *c.ServiceSettings.WebsocketSecurePort)
|
|
||||||
|
|
||||||
props["AvailableLocales"] = *c.LocalizationSettings.AvailableLocales
|
props["AvailableLocales"] = *c.LocalizationSettings.AvailableLocales
|
||||||
props["SQLDriverName"] = *c.SqlSettings.DriverName
|
props["SQLDriverName"] = *c.SqlSettings.DriverName
|
||||||
|
|
||||||
@@ -610,6 +606,9 @@ func GenerateLimitedClientConfig(c *model.Config, diagnosticId string, license *
|
|||||||
props["BuildEnterpriseReady"] = model.BuildEnterpriseReady
|
props["BuildEnterpriseReady"] = model.BuildEnterpriseReady
|
||||||
|
|
||||||
props["SiteName"] = c.TeamSettings.SiteName
|
props["SiteName"] = c.TeamSettings.SiteName
|
||||||
|
props["WebsocketURL"] = strings.TrimRight(*c.ServiceSettings.WebsocketURL, "/")
|
||||||
|
props["WebsocketPort"] = fmt.Sprintf("%v", *c.ServiceSettings.WebsocketPort)
|
||||||
|
props["WebsocketSecurePort"] = fmt.Sprintf("%v", *c.ServiceSettings.WebsocketSecurePort)
|
||||||
props["EnableUserCreation"] = strconv.FormatBool(*c.TeamSettings.EnableUserCreation)
|
props["EnableUserCreation"] = strconv.FormatBool(*c.TeamSettings.EnableUserCreation)
|
||||||
props["EnableOpenServer"] = strconv.FormatBool(*c.TeamSettings.EnableOpenServer)
|
props["EnableOpenServer"] = strconv.FormatBool(*c.TeamSettings.EnableOpenServer)
|
||||||
|
|
||||||
|
|||||||
@@ -483,6 +483,11 @@ func TestGetClientConfig(t *testing.T) {
|
|||||||
// Ignored, since not licensed.
|
// Ignored, since not licensed.
|
||||||
AllowCustomThemes: bToP(false),
|
AllowCustomThemes: bToP(false),
|
||||||
},
|
},
|
||||||
|
ServiceSettings: model.ServiceSettings{
|
||||||
|
WebsocketURL: sToP("ws://mattermost.example.com:8065"),
|
||||||
|
WebsocketPort: iToP(80),
|
||||||
|
WebsocketSecurePort: iToP(443),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"",
|
"",
|
||||||
nil,
|
nil,
|
||||||
@@ -491,6 +496,9 @@ func TestGetClientConfig(t *testing.T) {
|
|||||||
"EmailNotificationContentsType": "full",
|
"EmailNotificationContentsType": "full",
|
||||||
"AllowCustomThemes": "true",
|
"AllowCustomThemes": "true",
|
||||||
"EnforceMultifactorAuthentication": "false",
|
"EnforceMultifactorAuthentication": "false",
|
||||||
|
"WebsocketURL": "ws://mattermost.example.com:8065",
|
||||||
|
"WebsocketPort": "80",
|
||||||
|
"WebsocketSecurePort": "443",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -570,8 +578,67 @@ func TestGetClientConfig(t *testing.T) {
|
|||||||
configMap := GenerateClientConfig(testCase.config, testCase.diagnosticId, testCase.license)
|
configMap := GenerateClientConfig(testCase.config, testCase.diagnosticId, testCase.license)
|
||||||
for expectedField, expectedValue := range testCase.expectedFields {
|
for expectedField, expectedValue := range testCase.expectedFields {
|
||||||
actualValue, ok := configMap[expectedField]
|
actualValue, ok := configMap[expectedField]
|
||||||
assert.True(t, ok, fmt.Sprintf("config does not contain %v", expectedField))
|
if assert.True(t, ok, fmt.Sprintf("config does not contain %v", expectedField)) {
|
||||||
assert.Equal(t, expectedValue, actualValue)
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetLimitedClientConfig(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
testCases := []struct {
|
||||||
|
description string
|
||||||
|
config *model.Config
|
||||||
|
diagnosticId string
|
||||||
|
license *model.License
|
||||||
|
expectedFields map[string]string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"unlicensed",
|
||||||
|
&model.Config{
|
||||||
|
EmailSettings: model.EmailSettings{
|
||||||
|
EmailNotificationContentsType: sToP(model.EMAIL_NOTIFICATION_CONTENTS_FULL),
|
||||||
|
},
|
||||||
|
ThemeSettings: model.ThemeSettings{
|
||||||
|
// Ignored, since not licensed.
|
||||||
|
AllowCustomThemes: bToP(false),
|
||||||
|
},
|
||||||
|
ServiceSettings: model.ServiceSettings{
|
||||||
|
WebsocketURL: sToP("ws://mattermost.example.com:8065"),
|
||||||
|
WebsocketPort: iToP(80),
|
||||||
|
WebsocketSecurePort: iToP(443),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"",
|
||||||
|
nil,
|
||||||
|
map[string]string{
|
||||||
|
"DiagnosticId": "",
|
||||||
|
"EnforceMultifactorAuthentication": "false",
|
||||||
|
"WebsocketURL": "ws://mattermost.example.com:8065",
|
||||||
|
"WebsocketPort": "80",
|
||||||
|
"WebsocketSecurePort": "443",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
testCase := testCase
|
||||||
|
t.Run(testCase.description, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
testCase.config.SetDefaults()
|
||||||
|
if testCase.license != nil {
|
||||||
|
testCase.license.Features.SetDefaults()
|
||||||
|
}
|
||||||
|
|
||||||
|
configMap := GenerateLimitedClientConfig(testCase.config, testCase.diagnosticId, testCase.license)
|
||||||
|
for expectedField, expectedValue := range testCase.expectedFields {
|
||||||
|
actualValue, ok := configMap[expectedField]
|
||||||
|
if assert.True(t, ok, fmt.Sprintf("config does not contain %v", expectedField)) {
|
||||||
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -585,6 +652,10 @@ func bToP(b bool) *bool {
|
|||||||
return &b
|
return &b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func iToP(i int) *int {
|
||||||
|
return &i
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetDefaultsFromStruct(t *testing.T) {
|
func TestGetDefaultsFromStruct(t *testing.T) {
|
||||||
s := struct {
|
s := struct {
|
||||||
TestSettings struct {
|
TestSettings struct {
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user