MM-8701 Limit the number of client config fields sent before user logs in (#8954)

* MM-8701 Limit the number of client config fields sent before user logs in

* Fixed missing client config field

* Reduced duplication between limited and regular client config
Этот коммит содержится в:
Harrison Healey
2018-06-18 12:39:22 -04:00
коммит произвёл GitHub
родитель f48d31c7a4
Коммит 6d8140337e
8 изменённых файлов: 246 добавлений и 106 удалений

Просмотреть файл

@@ -250,7 +250,14 @@ func getClientConfig(c *Context, w http.ResponseWriter, r *http.Request) {
return return
} }
w.Write([]byte(model.MapToJson(c.App.ClientConfigWithComputed()))) var config map[string]string
if *c.App.Config().ServiceSettings.ExperimentalLimitClientConfig && len(c.Session.UserId) == 0 {
config = c.App.LimitedClientConfigWithComputed()
} else {
config = c.App.ClientConfigWithComputed()
}
w.Write([]byte(model.MapToJson(config)))
} }
func getEnvironmentConfig(c *Context, w http.ResponseWriter, r *http.Request) { func getEnvironmentConfig(c *Context, w http.ResponseWriter, r *http.Request) {

Просмотреть файл

@@ -228,27 +228,105 @@ func TestGetEnvironmentConfig(t *testing.T) {
func TestGetOldClientConfig(t *testing.T) { func TestGetOldClientConfig(t *testing.T) {
th := Setup().InitBasic().InitSystemAdmin() th := Setup().InitBasic().InitSystemAdmin()
defer th.TearDown() defer th.TearDown()
Client := th.Client
config, resp := Client.GetOldClientConfig("") testKey := "supersecretkey"
CheckNoError(t, resp) th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.GoogleDeveloperKey = testKey })
if len(config["Version"]) == 0 { t.Run("with session, without limited config", func(t *testing.T) {
t.Fatal("config not returned correctly") th.App.UpdateConfig(func(cfg *model.Config) {
} cfg.ServiceSettings.GoogleDeveloperKey = testKey
*cfg.ServiceSettings.ExperimentalLimitClientConfig = false
})
Client.Logout() Client := th.Client
_, resp = Client.GetOldClientConfig("") config, resp := Client.GetOldClientConfig("")
CheckNoError(t, resp) CheckNoError(t, resp)
if _, err := Client.DoApiGet("/config/client", ""); err == nil || err.StatusCode != http.StatusNotImplemented { if len(config["Version"]) == 0 {
t.Fatal("should have errored with 501") t.Fatal("config not returned correctly")
} }
if _, err := Client.DoApiGet("/config/client?format=junk", ""); err == nil || err.StatusCode != http.StatusBadRequest { if config["GoogleDeveloperKey"] != testKey {
t.Fatal("should have errored with 400") t.Fatal("config missing developer key")
} }
})
t.Run("without session, without limited config", func(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
cfg.ServiceSettings.GoogleDeveloperKey = testKey
*cfg.ServiceSettings.ExperimentalLimitClientConfig = false
})
Client := th.CreateClient()
config, resp := Client.GetOldClientConfig("")
CheckNoError(t, resp)
if len(config["Version"]) == 0 {
t.Fatal("config not returned correctly")
}
if config["GoogleDeveloperKey"] != testKey {
t.Fatal("config missing developer key")
}
})
t.Run("with session, with limited config", func(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
cfg.ServiceSettings.GoogleDeveloperKey = testKey
*cfg.ServiceSettings.ExperimentalLimitClientConfig = true
})
Client := th.Client
config, resp := Client.GetOldClientConfig("")
CheckNoError(t, resp)
if len(config["Version"]) == 0 {
t.Fatal("config not returned correctly")
}
if config["GoogleDeveloperKey"] != testKey {
t.Fatal("config missing developer key")
}
})
t.Run("without session, without limited config", func(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
cfg.ServiceSettings.GoogleDeveloperKey = testKey
*cfg.ServiceSettings.ExperimentalLimitClientConfig = true
})
Client := th.CreateClient()
config, resp := Client.GetOldClientConfig("")
CheckNoError(t, resp)
if len(config["Version"]) == 0 {
t.Fatal("config not returned correctly")
}
if _, ok := config["GoogleDeveloperKey"]; ok {
t.Fatal("config should be missing developer key")
}
})
t.Run("missing format", func(t *testing.T) {
Client := th.Client
if _, err := Client.DoApiGet("/config/client", ""); err == nil || err.StatusCode != http.StatusNotImplemented {
t.Fatal("should have errored with 501")
}
})
t.Run("invalid format", func(t *testing.T) {
Client := th.Client
if _, err := Client.DoApiGet("/config/client?format=junk", ""); err == nil || err.StatusCode != http.StatusBadRequest {
t.Fatal("should have errored with 400")
}
})
} }
func TestGetOldClientLicense(t *testing.T) { func TestGetOldClientLicense(t *testing.T) {

Просмотреть файл

@@ -90,9 +90,10 @@ type App struct {
pluginCommands []*PluginCommand pluginCommands []*PluginCommand
pluginCommandsLock sync.RWMutex pluginCommandsLock sync.RWMutex
clientConfig map[string]string clientConfig map[string]string
clientConfigHash string clientConfigHash string
diagnosticId string limitedClientConfig map[string]string
diagnosticId string
phase2PermissionsMigrationComplete bool phase2PermissionsMigrationComplete bool
} }

Просмотреть файл

@@ -91,6 +91,10 @@ func (a *App) ClientConfigHash() string {
return a.clientConfigHash return a.clientConfigHash
} }
func (a *App) LimitedClientConfig() map[string]string {
return a.limitedClientConfig
}
func (a *App) EnableConfigWatch() { func (a *App) EnableConfigWatch() {
if a.configWatcher == nil && !a.disableConfigWatch { if a.configWatcher == nil && !a.disableConfigWatch {
configWatcher, err := utils.NewConfigWatcher(a.ConfigFileName(), func() { configWatcher, err := utils.NewConfigWatcher(a.ConfigFileName(), func() {
@@ -211,10 +215,14 @@ func (a *App) AsymmetricSigningKey() *ecdsa.PrivateKey {
func (a *App) regenerateClientConfig() { func (a *App) regenerateClientConfig() {
a.clientConfig = utils.GenerateClientConfig(a.Config(), a.DiagnosticId(), a.License()) a.clientConfig = utils.GenerateClientConfig(a.Config(), a.DiagnosticId(), a.License())
a.limitedClientConfig = utils.GenerateLimitedClientConfig(a.Config(), a.DiagnosticId(), a.License())
if key := a.AsymmetricSigningKey(); key != nil { if key := a.AsymmetricSigningKey(); key != nil {
der, _ := x509.MarshalPKIXPublicKey(&key.PublicKey) der, _ := x509.MarshalPKIXPublicKey(&key.PublicKey)
a.clientConfig["AsymmetricSigningPublicKey"] = base64.StdEncoding.EncodeToString(der) a.clientConfig["AsymmetricSigningPublicKey"] = base64.StdEncoding.EncodeToString(der)
a.limitedClientConfig["AsymmetricSigningPublicKey"] = base64.StdEncoding.EncodeToString(der)
} }
clientConfigJSON, _ := json.Marshal(a.clientConfig) clientConfigJSON, _ := json.Marshal(a.clientConfig)
a.clientConfigHash = fmt.Sprintf("%x", md5.Sum(clientConfigJSON)) a.clientConfigHash = fmt.Sprintf("%x", md5.Sum(clientConfigJSON))
} }
@@ -291,3 +299,17 @@ func (a *App) ClientConfigWithComputed() map[string]string {
return respCfg return respCfg
} }
// LimitedClientConfigWithComputed gets the configuration in a format suitable for sending to the client.
func (a *App) LimitedClientConfigWithComputed() map[string]string {
respCfg := map[string]string{}
for k, v := range a.LimitedClientConfig() {
respCfg[k] = v
}
// These properties are not configurable, but nevertheless represent configuration expected
// by the client.
respCfg["NoAccounts"] = strconv.FormatBool(a.IsFirstUserAccount())
return respCfg
}

Просмотреть файл

@@ -64,7 +64,8 @@
"ImageProxyOptions": "", "ImageProxyOptions": "",
"ImageProxyURL": "", "ImageProxyURL": "",
"EnableAPITeamDeletion": false, "EnableAPITeamDeletion": false,
"ExperimentalEnableHardenedMode": false "ExperimentalEnableHardenedMode": false,
"ExperimentalLimitClientConfig": false
}, },
"TeamSettings": { "TeamSettings": {
"SiteName": "Mattermost", "SiteName": "Mattermost",

Просмотреть файл

@@ -230,6 +230,7 @@ type ServiceSettings struct {
ImageProxyOptions *string ImageProxyOptions *string
EnableAPITeamDeletion *bool EnableAPITeamDeletion *bool
ExperimentalEnableHardenedMode *bool ExperimentalEnableHardenedMode *bool
ExperimentalLimitClientConfig *bool
} }
func (s *ServiceSettings) SetDefaults() { func (s *ServiceSettings) SetDefaults() {
@@ -466,6 +467,10 @@ func (s *ServiceSettings) SetDefaults() {
if s.ExperimentalEnableHardenedMode == nil { if s.ExperimentalEnableHardenedMode == nil {
s.ExperimentalEnableHardenedMode = NewBool(false) s.ExperimentalEnableHardenedMode = NewBool(false)
} }
if s.ExperimentalLimitClientConfig == nil {
s.ExperimentalLimitClientConfig = NewBool(false)
}
} }
type ClusterSettings struct { type ClusterSettings struct {

Просмотреть файл

@@ -495,22 +495,11 @@ func LoadConfig(fileName string) (*model.Config, string, map[string]interface{},
} }
func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.License) map[string]string { func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.License) map[string]string {
props := make(map[string]string) props := GenerateLimitedClientConfig(c, diagnosticId, license)
props["Version"] = model.CurrentVersion
props["BuildNumber"] = model.BuildNumber
props["BuildDate"] = model.BuildDate
props["BuildHash"] = model.BuildHash
props["BuildHashEnterprise"] = model.BuildHashEnterprise
props["BuildEnterpriseReady"] = model.BuildEnterpriseReady
props["SiteURL"] = strings.TrimRight(*c.ServiceSettings.SiteURL, "/") props["SiteURL"] = strings.TrimRight(*c.ServiceSettings.SiteURL, "/")
props["WebsocketURL"] = strings.TrimRight(*c.ServiceSettings.WebsocketURL, "/") props["WebsocketURL"] = strings.TrimRight(*c.ServiceSettings.WebsocketURL, "/")
props["SiteName"] = c.TeamSettings.SiteName
props["EnableTeamCreation"] = strconv.FormatBool(*c.TeamSettings.EnableTeamCreation)
props["EnableUserCreation"] = strconv.FormatBool(*c.TeamSettings.EnableUserCreation)
props["EnableUserDeactivation"] = strconv.FormatBool(*c.TeamSettings.EnableUserDeactivation) props["EnableUserDeactivation"] = strconv.FormatBool(*c.TeamSettings.EnableUserDeactivation)
props["EnableOpenServer"] = strconv.FormatBool(*c.TeamSettings.EnableOpenServer)
props["RestrictDirectMessage"] = *c.TeamSettings.RestrictDirectMessage props["RestrictDirectMessage"] = *c.TeamSettings.RestrictDirectMessage
props["RestrictTeamInvite"] = *c.TeamSettings.RestrictTeamInvite props["RestrictTeamInvite"] = *c.TeamSettings.RestrictTeamInvite
props["RestrictPublicChannelCreation"] = *c.TeamSettings.RestrictPublicChannelCreation props["RestrictPublicChannelCreation"] = *c.TeamSettings.RestrictPublicChannelCreation
@@ -524,13 +513,6 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
props["TeammateNameDisplay"] = *c.TeamSettings.TeammateNameDisplay props["TeammateNameDisplay"] = *c.TeamSettings.TeammateNameDisplay
props["ExperimentalPrimaryTeam"] = *c.TeamSettings.ExperimentalPrimaryTeam props["ExperimentalPrimaryTeam"] = *c.TeamSettings.ExperimentalPrimaryTeam
props["AndroidLatestVersion"] = c.ClientRequirements.AndroidLatestVersion
props["AndroidMinVersion"] = c.ClientRequirements.AndroidMinVersion
props["DesktopLatestVersion"] = c.ClientRequirements.DesktopLatestVersion
props["DesktopMinVersion"] = c.ClientRequirements.DesktopMinVersion
props["IosLatestVersion"] = c.ClientRequirements.IosLatestVersion
props["IosMinVersion"] = c.ClientRequirements.IosMinVersion
props["EnableOAuthServiceProvider"] = strconv.FormatBool(c.ServiceSettings.EnableOAuthServiceProvider) props["EnableOAuthServiceProvider"] = strconv.FormatBool(c.ServiceSettings.EnableOAuthServiceProvider)
props["GoogleDeveloperKey"] = c.ServiceSettings.GoogleDeveloperKey props["GoogleDeveloperKey"] = c.ServiceSettings.GoogleDeveloperKey
props["EnableIncomingWebhooks"] = strconv.FormatBool(c.ServiceSettings.EnableIncomingWebhooks) props["EnableIncomingWebhooks"] = strconv.FormatBool(c.ServiceSettings.EnableIncomingWebhooks)
@@ -543,7 +525,6 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
props["EnableLinkPreviews"] = strconv.FormatBool(*c.ServiceSettings.EnableLinkPreviews) props["EnableLinkPreviews"] = strconv.FormatBool(*c.ServiceSettings.EnableLinkPreviews)
props["EnableTesting"] = strconv.FormatBool(c.ServiceSettings.EnableTesting) props["EnableTesting"] = strconv.FormatBool(c.ServiceSettings.EnableTesting)
props["EnableDeveloper"] = strconv.FormatBool(*c.ServiceSettings.EnableDeveloper) props["EnableDeveloper"] = strconv.FormatBool(*c.ServiceSettings.EnableDeveloper)
props["EnableDiagnostics"] = strconv.FormatBool(*c.LogSettings.EnableDiagnostics)
props["RestrictPostDelete"] = *c.ServiceSettings.RestrictPostDelete props["RestrictPostDelete"] = *c.ServiceSettings.RestrictPostDelete
props["AllowEditPost"] = *c.ServiceSettings.AllowEditPost props["AllowEditPost"] = *c.ServiceSettings.AllowEditPost
props["PostEditTimeLimit"] = fmt.Sprintf("%v", *c.ServiceSettings.PostEditTimeLimit) props["PostEditTimeLimit"] = fmt.Sprintf("%v", *c.ServiceSettings.PostEditTimeLimit)
@@ -557,46 +538,25 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
props["SendEmailNotifications"] = strconv.FormatBool(c.EmailSettings.SendEmailNotifications) props["SendEmailNotifications"] = strconv.FormatBool(c.EmailSettings.SendEmailNotifications)
props["SendPushNotifications"] = strconv.FormatBool(*c.EmailSettings.SendPushNotifications) props["SendPushNotifications"] = strconv.FormatBool(*c.EmailSettings.SendPushNotifications)
props["EnableSignUpWithEmail"] = strconv.FormatBool(c.EmailSettings.EnableSignUpWithEmail)
props["EnableSignInWithEmail"] = strconv.FormatBool(*c.EmailSettings.EnableSignInWithEmail)
props["EnableSignInWithUsername"] = strconv.FormatBool(*c.EmailSettings.EnableSignInWithUsername)
props["RequireEmailVerification"] = strconv.FormatBool(c.EmailSettings.RequireEmailVerification) props["RequireEmailVerification"] = strconv.FormatBool(c.EmailSettings.RequireEmailVerification)
props["EnableEmailBatching"] = strconv.FormatBool(*c.EmailSettings.EnableEmailBatching) props["EnableEmailBatching"] = strconv.FormatBool(*c.EmailSettings.EnableEmailBatching)
props["EnablePreviewModeBanner"] = strconv.FormatBool(*c.EmailSettings.EnablePreviewModeBanner) props["EnablePreviewModeBanner"] = strconv.FormatBool(*c.EmailSettings.EnablePreviewModeBanner)
props["EmailNotificationContentsType"] = *c.EmailSettings.EmailNotificationContentsType props["EmailNotificationContentsType"] = *c.EmailSettings.EmailNotificationContentsType
props["EmailLoginButtonColor"] = *c.EmailSettings.LoginButtonColor
props["EmailLoginButtonBorderColor"] = *c.EmailSettings.LoginButtonBorderColor
props["EmailLoginButtonTextColor"] = *c.EmailSettings.LoginButtonTextColor
props["EnableSignUpWithGitLab"] = strconv.FormatBool(c.GitLabSettings.Enable)
props["ShowEmailAddress"] = strconv.FormatBool(c.PrivacySettings.ShowEmailAddress) props["ShowEmailAddress"] = strconv.FormatBool(c.PrivacySettings.ShowEmailAddress)
props["TermsOfServiceLink"] = *c.SupportSettings.TermsOfServiceLink
props["PrivacyPolicyLink"] = *c.SupportSettings.PrivacyPolicyLink
props["AboutLink"] = *c.SupportSettings.AboutLink
props["HelpLink"] = *c.SupportSettings.HelpLink
props["ReportAProblemLink"] = *c.SupportSettings.ReportAProblemLink
props["SupportEmail"] = *c.SupportSettings.SupportEmail
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["WebsocketPort"] = fmt.Sprintf("%v", *c.ServiceSettings.WebsocketPort)
props["WebsocketSecurePort"] = fmt.Sprintf("%v", *c.ServiceSettings.WebsocketSecurePort) props["WebsocketSecurePort"] = fmt.Sprintf("%v", *c.ServiceSettings.WebsocketSecurePort)
props["DefaultClientLocale"] = *c.LocalizationSettings.DefaultClientLocale
props["AvailableLocales"] = *c.LocalizationSettings.AvailableLocales props["AvailableLocales"] = *c.LocalizationSettings.AvailableLocales
props["SQLDriverName"] = *c.SqlSettings.DriverName props["SQLDriverName"] = *c.SqlSettings.DriverName
props["EnableCustomEmoji"] = strconv.FormatBool(*c.ServiceSettings.EnableCustomEmoji)
props["EnableEmojiPicker"] = strconv.FormatBool(*c.ServiceSettings.EnableEmojiPicker) props["EnableEmojiPicker"] = strconv.FormatBool(*c.ServiceSettings.EnableEmojiPicker)
props["RestrictCustomEmojiCreation"] = *c.ServiceSettings.RestrictCustomEmojiCreation props["RestrictCustomEmojiCreation"] = *c.ServiceSettings.RestrictCustomEmojiCreation
props["MaxFileSize"] = strconv.FormatInt(*c.FileSettings.MaxFileSize, 10) props["MaxFileSize"] = strconv.FormatInt(*c.FileSettings.MaxFileSize, 10)
props["AppDownloadLink"] = *c.NativeAppSettings.AppDownloadLink
props["AndroidAppDownloadLink"] = *c.NativeAppSettings.AndroidAppDownloadLink
props["IosAppDownloadLink"] = *c.NativeAppSettings.IosAppDownloadLink
props["EnableWebrtc"] = strconv.FormatBool(*c.WebrtcSettings.Enable) props["EnableWebrtc"] = strconv.FormatBool(*c.WebrtcSettings.Enable)
@@ -606,48 +566,26 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
props["EnableUserTypingMessages"] = strconv.FormatBool(*c.ServiceSettings.EnableUserTypingMessages) props["EnableUserTypingMessages"] = strconv.FormatBool(*c.ServiceSettings.EnableUserTypingMessages)
props["EnableChannelViewedMessages"] = strconv.FormatBool(*c.ServiceSettings.EnableChannelViewedMessages) props["EnableChannelViewedMessages"] = strconv.FormatBool(*c.ServiceSettings.EnableChannelViewedMessages)
props["DiagnosticId"] = diagnosticId
props["DiagnosticsEnabled"] = strconv.FormatBool(*c.LogSettings.EnableDiagnostics)
props["PluginsEnabled"] = strconv.FormatBool(*c.PluginSettings.Enable) props["PluginsEnabled"] = strconv.FormatBool(*c.PluginSettings.Enable)
hasImageProxy := c.ServiceSettings.ImageProxyType != nil && *c.ServiceSettings.ImageProxyType != "" && c.ServiceSettings.ImageProxyURL != nil && *c.ServiceSettings.ImageProxyURL != ""
props["HasImageProxy"] = strconv.FormatBool(hasImageProxy)
props["RunJobs"] = strconv.FormatBool(*c.JobSettings.RunJobs) props["RunJobs"] = strconv.FormatBool(*c.JobSettings.RunJobs)
// Set default values for all options that require a license. // Set default values for all options that require a license.
props["ExperimentalHideTownSquareinLHS"] = "false" props["ExperimentalHideTownSquareinLHS"] = "false"
props["ExperimentalTownSquareIsReadOnly"] = "false" props["ExperimentalTownSquareIsReadOnly"] = "false"
props["ExperimentalEnableAuthenticationTransfer"] = "true" props["ExperimentalEnableAuthenticationTransfer"] = "true"
props["EnableCustomBrand"] = "false"
props["CustomBrandText"] = ""
props["CustomDescriptionText"] = ""
props["EnableLdap"] = "false"
props["LdapLoginFieldName"] = ""
props["LdapNicknameAttributeSet"] = "false" props["LdapNicknameAttributeSet"] = "false"
props["LdapFirstNameAttributeSet"] = "false" props["LdapFirstNameAttributeSet"] = "false"
props["LdapLastNameAttributeSet"] = "false" props["LdapLastNameAttributeSet"] = "false"
props["LdapLoginButtonColor"] = ""
props["LdapLoginButtonBorderColor"] = ""
props["LdapLoginButtonTextColor"] = ""
props["EnableMultifactorAuthentication"] = "false"
props["EnforceMultifactorAuthentication"] = "false" props["EnforceMultifactorAuthentication"] = "false"
props["EnableCompliance"] = "false" props["EnableCompliance"] = "false"
props["EnableMobileFileDownload"] = "true" props["EnableMobileFileDownload"] = "true"
props["EnableMobileFileUpload"] = "true" props["EnableMobileFileUpload"] = "true"
props["EnableSaml"] = "false"
props["SamlLoginButtonText"] = ""
props["SamlFirstNameAttributeSet"] = "false" props["SamlFirstNameAttributeSet"] = "false"
props["SamlLastNameAttributeSet"] = "false" props["SamlLastNameAttributeSet"] = "false"
props["SamlNicknameAttributeSet"] = "false" props["SamlNicknameAttributeSet"] = "false"
props["SamlLoginButtonColor"] = ""
props["SamlLoginButtonBorderColor"] = ""
props["SamlLoginButtonTextColor"] = ""
props["EnableCluster"] = "false" props["EnableCluster"] = "false"
props["EnableMetrics"] = "false" props["EnableMetrics"] = "false"
props["EnableSignUpWithGoogle"] = "false"
props["EnableSignUpWithOffice365"] = "false"
props["PasswordMinimumLength"] = "0" props["PasswordMinimumLength"] = "0"
props["PasswordRequireLowercase"] = "false" props["PasswordRequireLowercase"] = "false"
props["PasswordRequireUppercase"] = "false" props["PasswordRequireUppercase"] = "false"
@@ -672,9 +610,6 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
props["PasswordRequireNumber"] = strconv.FormatBool(*c.PasswordSettings.Number) props["PasswordRequireNumber"] = strconv.FormatBool(*c.PasswordSettings.Number)
props["PasswordRequireSymbol"] = strconv.FormatBool(*c.PasswordSettings.Symbol) props["PasswordRequireSymbol"] = strconv.FormatBool(*c.PasswordSettings.Symbol)
props["CustomUrlSchemes"] = strings.Join(*c.DisplaySettings.CustomUrlSchemes, ",") props["CustomUrlSchemes"] = strings.Join(*c.DisplaySettings.CustomUrlSchemes, ",")
props["EnableCustomBrand"] = strconv.FormatBool(*c.TeamSettings.EnableCustomBrand)
props["CustomBrandText"] = *c.TeamSettings.CustomBrandText
props["CustomDescriptionText"] = *c.TeamSettings.CustomDescriptionText
if license != nil { if license != nil {
props["ExperimentalHideTownSquareinLHS"] = strconv.FormatBool(*c.TeamSettings.ExperimentalHideTownSquareinLHS) props["ExperimentalHideTownSquareinLHS"] = strconv.FormatBool(*c.TeamSettings.ExperimentalHideTownSquareinLHS)
@@ -682,18 +617,12 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
props["ExperimentalEnableAuthenticationTransfer"] = strconv.FormatBool(*c.ServiceSettings.ExperimentalEnableAuthenticationTransfer) props["ExperimentalEnableAuthenticationTransfer"] = strconv.FormatBool(*c.ServiceSettings.ExperimentalEnableAuthenticationTransfer)
if *license.Features.LDAP { if *license.Features.LDAP {
props["EnableLdap"] = strconv.FormatBool(*c.LdapSettings.Enable)
props["LdapLoginFieldName"] = *c.LdapSettings.LoginFieldName
props["LdapNicknameAttributeSet"] = strconv.FormatBool(*c.LdapSettings.NicknameAttribute != "") props["LdapNicknameAttributeSet"] = strconv.FormatBool(*c.LdapSettings.NicknameAttribute != "")
props["LdapFirstNameAttributeSet"] = strconv.FormatBool(*c.LdapSettings.FirstNameAttribute != "") props["LdapFirstNameAttributeSet"] = strconv.FormatBool(*c.LdapSettings.FirstNameAttribute != "")
props["LdapLastNameAttributeSet"] = strconv.FormatBool(*c.LdapSettings.LastNameAttribute != "") props["LdapLastNameAttributeSet"] = strconv.FormatBool(*c.LdapSettings.LastNameAttribute != "")
props["LdapLoginButtonColor"] = *c.LdapSettings.LoginButtonColor
props["LdapLoginButtonBorderColor"] = *c.LdapSettings.LoginButtonBorderColor
props["LdapLoginButtonTextColor"] = *c.LdapSettings.LoginButtonTextColor
} }
if *license.Features.MFA { if *license.Features.MFA {
props["EnableMultifactorAuthentication"] = strconv.FormatBool(*c.ServiceSettings.EnableMultifactorAuthentication)
props["EnforceMultifactorAuthentication"] = strconv.FormatBool(*c.ServiceSettings.EnforceMultifactorAuthentication) props["EnforceMultifactorAuthentication"] = strconv.FormatBool(*c.ServiceSettings.EnforceMultifactorAuthentication)
} }
@@ -704,14 +633,9 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
} }
if *license.Features.SAML { if *license.Features.SAML {
props["EnableSaml"] = strconv.FormatBool(*c.SamlSettings.Enable)
props["SamlLoginButtonText"] = *c.SamlSettings.LoginButtonText
props["SamlFirstNameAttributeSet"] = strconv.FormatBool(*c.SamlSettings.FirstNameAttribute != "") props["SamlFirstNameAttributeSet"] = strconv.FormatBool(*c.SamlSettings.FirstNameAttribute != "")
props["SamlLastNameAttributeSet"] = strconv.FormatBool(*c.SamlSettings.LastNameAttribute != "") props["SamlLastNameAttributeSet"] = strconv.FormatBool(*c.SamlSettings.LastNameAttribute != "")
props["SamlNicknameAttributeSet"] = strconv.FormatBool(*c.SamlSettings.NicknameAttribute != "") props["SamlNicknameAttributeSet"] = strconv.FormatBool(*c.SamlSettings.NicknameAttribute != "")
props["SamlLoginButtonColor"] = *c.SamlSettings.LoginButtonColor
props["SamlLoginButtonBorderColor"] = *c.SamlSettings.LoginButtonBorderColor
props["SamlLoginButtonTextColor"] = *c.SamlSettings.LoginButtonTextColor
// do this under the correct licensed feature // do this under the correct licensed feature
props["ExperimentalClientSideCertEnable"] = strconv.FormatBool(*c.ExperimentalSettings.ClientSideCertEnable) props["ExperimentalClientSideCertEnable"] = strconv.FormatBool(*c.ExperimentalSettings.ClientSideCertEnable)
@@ -726,14 +650,6 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
props["EnableMetrics"] = strconv.FormatBool(*c.MetricsSettings.Enable) props["EnableMetrics"] = strconv.FormatBool(*c.MetricsSettings.Enable)
} }
if *license.Features.GoogleOAuth {
props["EnableSignUpWithGoogle"] = strconv.FormatBool(c.GoogleSettings.Enable)
}
if *license.Features.Office365OAuth {
props["EnableSignUpWithOffice365"] = strconv.FormatBool(c.Office365Settings.Enable)
}
if *license.Features.Announcement { if *license.Features.Announcement {
props["EnableBanner"] = strconv.FormatBool(*c.AnnouncementSettings.EnableBanner) props["EnableBanner"] = strconv.FormatBool(*c.AnnouncementSettings.EnableBanner)
props["BannerText"] = *c.AnnouncementSettings.BannerText props["BannerText"] = *c.AnnouncementSettings.BannerText
@@ -760,6 +676,114 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
return props return props
} }
func GenerateLimitedClientConfig(c *model.Config, diagnosticId string, license *model.License) map[string]string {
props := make(map[string]string)
props["Version"] = model.CurrentVersion
props["BuildNumber"] = model.BuildNumber
props["BuildDate"] = model.BuildDate
props["BuildHash"] = model.BuildHash
props["BuildHashEnterprise"] = model.BuildHashEnterprise
props["BuildEnterpriseReady"] = model.BuildEnterpriseReady
props["SiteName"] = c.TeamSettings.SiteName
props["EnableTeamCreation"] = strconv.FormatBool(*c.TeamSettings.EnableTeamCreation)
props["EnableUserCreation"] = strconv.FormatBool(*c.TeamSettings.EnableUserCreation)
props["EnableOpenServer"] = strconv.FormatBool(*c.TeamSettings.EnableOpenServer)
props["AndroidLatestVersion"] = c.ClientRequirements.AndroidLatestVersion
props["AndroidMinVersion"] = c.ClientRequirements.AndroidMinVersion
props["DesktopLatestVersion"] = c.ClientRequirements.DesktopLatestVersion
props["DesktopMinVersion"] = c.ClientRequirements.DesktopMinVersion
props["IosLatestVersion"] = c.ClientRequirements.IosLatestVersion
props["IosMinVersion"] = c.ClientRequirements.IosMinVersion
props["EnableDiagnostics"] = strconv.FormatBool(*c.LogSettings.EnableDiagnostics)
props["EnableSignUpWithEmail"] = strconv.FormatBool(c.EmailSettings.EnableSignUpWithEmail)
props["EnableSignInWithEmail"] = strconv.FormatBool(*c.EmailSettings.EnableSignInWithEmail)
props["EnableSignInWithUsername"] = strconv.FormatBool(*c.EmailSettings.EnableSignInWithUsername)
props["EmailLoginButtonColor"] = *c.EmailSettings.LoginButtonColor
props["EmailLoginButtonBorderColor"] = *c.EmailSettings.LoginButtonBorderColor
props["EmailLoginButtonTextColor"] = *c.EmailSettings.LoginButtonTextColor
props["EnableSignUpWithGitLab"] = strconv.FormatBool(c.GitLabSettings.Enable)
props["TermsOfServiceLink"] = *c.SupportSettings.TermsOfServiceLink
props["PrivacyPolicyLink"] = *c.SupportSettings.PrivacyPolicyLink
props["AboutLink"] = *c.SupportSettings.AboutLink
props["HelpLink"] = *c.SupportSettings.HelpLink
props["ReportAProblemLink"] = *c.SupportSettings.ReportAProblemLink
props["SupportEmail"] = *c.SupportSettings.SupportEmail
props["DefaultClientLocale"] = *c.LocalizationSettings.DefaultClientLocale
props["EnableCustomEmoji"] = strconv.FormatBool(*c.ServiceSettings.EnableCustomEmoji)
props["AppDownloadLink"] = *c.NativeAppSettings.AppDownloadLink
props["AndroidAppDownloadLink"] = *c.NativeAppSettings.AndroidAppDownloadLink
props["IosAppDownloadLink"] = *c.NativeAppSettings.IosAppDownloadLink
props["DiagnosticId"] = diagnosticId
props["DiagnosticsEnabled"] = strconv.FormatBool(*c.LogSettings.EnableDiagnostics)
hasImageProxy := c.ServiceSettings.ImageProxyType != nil && *c.ServiceSettings.ImageProxyType != "" && c.ServiceSettings.ImageProxyURL != nil && *c.ServiceSettings.ImageProxyURL != ""
props["HasImageProxy"] = strconv.FormatBool(hasImageProxy)
// Set default values for all options that require a license.
props["EnableCustomBrand"] = "false"
props["CustomBrandText"] = ""
props["CustomDescriptionText"] = ""
props["EnableLdap"] = "false"
props["LdapLoginFieldName"] = ""
props["LdapLoginButtonColor"] = ""
props["LdapLoginButtonBorderColor"] = ""
props["LdapLoginButtonTextColor"] = ""
props["EnableMultifactorAuthentication"] = "false"
props["EnableSaml"] = "false"
props["SamlLoginButtonText"] = ""
props["SamlLoginButtonColor"] = ""
props["SamlLoginButtonBorderColor"] = ""
props["SamlLoginButtonTextColor"] = ""
props["EnableSignUpWithGoogle"] = "false"
props["EnableSignUpWithOffice365"] = "false"
props["EnableCustomBrand"] = strconv.FormatBool(*c.TeamSettings.EnableCustomBrand)
props["CustomBrandText"] = *c.TeamSettings.CustomBrandText
props["CustomDescriptionText"] = *c.TeamSettings.CustomDescriptionText
if license != nil {
if *license.Features.LDAP {
props["EnableLdap"] = strconv.FormatBool(*c.LdapSettings.Enable)
props["LdapLoginFieldName"] = *c.LdapSettings.LoginFieldName
props["LdapLoginButtonColor"] = *c.LdapSettings.LoginButtonColor
props["LdapLoginButtonBorderColor"] = *c.LdapSettings.LoginButtonBorderColor
props["LdapLoginButtonTextColor"] = *c.LdapSettings.LoginButtonTextColor
}
if *license.Features.MFA {
props["EnableMultifactorAuthentication"] = strconv.FormatBool(*c.ServiceSettings.EnableMultifactorAuthentication)
}
if *license.Features.SAML {
props["EnableSaml"] = strconv.FormatBool(*c.SamlSettings.Enable)
props["SamlLoginButtonText"] = *c.SamlSettings.LoginButtonText
props["SamlLoginButtonColor"] = *c.SamlSettings.LoginButtonColor
props["SamlLoginButtonBorderColor"] = *c.SamlSettings.LoginButtonBorderColor
props["SamlLoginButtonTextColor"] = *c.SamlSettings.LoginButtonTextColor
}
if *license.Features.GoogleOAuth {
props["EnableSignUpWithGoogle"] = strconv.FormatBool(c.GoogleSettings.Enable)
}
if *license.Features.Office365OAuth {
props["EnableSignUpWithOffice365"] = strconv.FormatBool(c.Office365Settings.Enable)
}
}
return props
}
func ValidateLdapFilter(cfg *model.Config, ldap einterfaces.LdapInterface) *model.AppError { func ValidateLdapFilter(cfg *model.Config, ldap einterfaces.LdapInterface) *model.AppError {
if *cfg.LdapSettings.Enable && ldap != nil && *cfg.LdapSettings.UserFilter != "" { if *cfg.LdapSettings.Enable && ldap != nil && *cfg.LdapSettings.UserFilter != "" {
if err := ldap.ValidateFilter(*cfg.LdapSettings.UserFilter); err != nil { if err := ldap.ValidateFilter(*cfg.LdapSettings.UserFilter); err != nil {

Просмотреть файл

@@ -645,7 +645,9 @@ 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 {
assert.Equal(t, expectedValue, configMap[expectedField]) actualValue, ok := configMap[expectedField]
assert.True(t, ok, fmt.Sprintf("config does not contain %v", expectedField))
assert.Equal(t, expectedValue, actualValue)
} }
}) })
} }