From 6d8140337ef0f68f5177988f3c87bba5e4946399 Mon Sep 17 00:00:00 2001 From: Harrison Healey Date: Mon, 18 Jun 2018 12:39:22 -0400 Subject: 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 --- api4/system.go | 9 ++- api4/system_test.go | 108 ++++++++++++++++++++++++---- app/app.go | 7 +- app/config.go | 22 ++++++ config/default.json | 3 +- model/config.go | 5 ++ utils/config.go | 194 +++++++++++++++++++++++++++++---------------------- utils/config_test.go | 4 +- 8 files changed, 246 insertions(+), 106 deletions(-) diff --git a/api4/system.go b/api4/system.go index acb02bc3e..68f998d6d 100644 --- a/api4/system.go +++ b/api4/system.go @@ -250,7 +250,14 @@ func getClientConfig(c *Context, w http.ResponseWriter, r *http.Request) { 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) { diff --git a/api4/system_test.go b/api4/system_test.go index f46ae7436..f784a8be4 100644 --- a/api4/system_test.go +++ b/api4/system_test.go @@ -228,27 +228,105 @@ func TestGetEnvironmentConfig(t *testing.T) { func TestGetOldClientConfig(t *testing.T) { th := Setup().InitBasic().InitSystemAdmin() defer th.TearDown() - Client := th.Client - config, resp := Client.GetOldClientConfig("") - CheckNoError(t, resp) + testKey := "supersecretkey" + th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.GoogleDeveloperKey = testKey }) - if len(config["Version"]) == 0 { - t.Fatal("config not returned correctly") - } + t.Run("with session, without limited config", func(t *testing.T) { + th.App.UpdateConfig(func(cfg *model.Config) { + cfg.ServiceSettings.GoogleDeveloperKey = testKey + *cfg.ServiceSettings.ExperimentalLimitClientConfig = false + }) - Client.Logout() + Client := th.Client - _, resp = Client.GetOldClientConfig("") - CheckNoError(t, resp) + config, resp := Client.GetOldClientConfig("") + CheckNoError(t, resp) - if _, err := Client.DoApiGet("/config/client", ""); err == nil || err.StatusCode != http.StatusNotImplemented { - t.Fatal("should have errored with 501") - } + if len(config["Version"]) == 0 { + t.Fatal("config not returned correctly") + } - if _, err := Client.DoApiGet("/config/client?format=junk", ""); err == nil || err.StatusCode != http.StatusBadRequest { - t.Fatal("should have errored with 400") - } + 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 = 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) { diff --git a/app/app.go b/app/app.go index d97c6c385..3f70974cf 100644 --- a/app/app.go +++ b/app/app.go @@ -90,9 +90,10 @@ type App struct { pluginCommands []*PluginCommand pluginCommandsLock sync.RWMutex - clientConfig map[string]string - clientConfigHash string - diagnosticId string + clientConfig map[string]string + clientConfigHash string + limitedClientConfig map[string]string + diagnosticId string phase2PermissionsMigrationComplete bool } diff --git a/app/config.go b/app/config.go index b4fbfe725..21571f291 100644 --- a/app/config.go +++ b/app/config.go @@ -91,6 +91,10 @@ func (a *App) ClientConfigHash() string { return a.clientConfigHash } +func (a *App) LimitedClientConfig() map[string]string { + return a.limitedClientConfig +} + func (a *App) EnableConfigWatch() { if a.configWatcher == nil && !a.disableConfigWatch { configWatcher, err := utils.NewConfigWatcher(a.ConfigFileName(), func() { @@ -211,10 +215,14 @@ func (a *App) AsymmetricSigningKey() *ecdsa.PrivateKey { func (a *App) regenerateClientConfig() { 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 { der, _ := x509.MarshalPKIXPublicKey(&key.PublicKey) a.clientConfig["AsymmetricSigningPublicKey"] = base64.StdEncoding.EncodeToString(der) + a.limitedClientConfig["AsymmetricSigningPublicKey"] = base64.StdEncoding.EncodeToString(der) } + clientConfigJSON, _ := json.Marshal(a.clientConfig) a.clientConfigHash = fmt.Sprintf("%x", md5.Sum(clientConfigJSON)) } @@ -291,3 +299,17 @@ func (a *App) ClientConfigWithComputed() map[string]string { 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 +} diff --git a/config/default.json b/config/default.json index 30c8f282f..ac57fe5e4 100644 --- a/config/default.json +++ b/config/default.json @@ -64,7 +64,8 @@ "ImageProxyOptions": "", "ImageProxyURL": "", "EnableAPITeamDeletion": false, - "ExperimentalEnableHardenedMode": false + "ExperimentalEnableHardenedMode": false, + "ExperimentalLimitClientConfig": false }, "TeamSettings": { "SiteName": "Mattermost", diff --git a/model/config.go b/model/config.go index 47e2f68a4..2f40c22b0 100644 --- a/model/config.go +++ b/model/config.go @@ -230,6 +230,7 @@ type ServiceSettings struct { ImageProxyOptions *string EnableAPITeamDeletion *bool ExperimentalEnableHardenedMode *bool + ExperimentalLimitClientConfig *bool } func (s *ServiceSettings) SetDefaults() { @@ -466,6 +467,10 @@ func (s *ServiceSettings) SetDefaults() { if s.ExperimentalEnableHardenedMode == nil { s.ExperimentalEnableHardenedMode = NewBool(false) } + + if s.ExperimentalLimitClientConfig == nil { + s.ExperimentalLimitClientConfig = NewBool(false) + } } type ClusterSettings struct { diff --git a/utils/config.go b/utils/config.go index e42c2820b..d3cdbd3ee 100644 --- a/utils/config.go +++ b/utils/config.go @@ -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 { - 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 := GenerateLimitedClientConfig(c, diagnosticId, license) props["SiteURL"] = strings.TrimRight(*c.ServiceSettings.SiteURL, "/") 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["EnableOpenServer"] = strconv.FormatBool(*c.TeamSettings.EnableOpenServer) props["RestrictDirectMessage"] = *c.TeamSettings.RestrictDirectMessage props["RestrictTeamInvite"] = *c.TeamSettings.RestrictTeamInvite 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["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["GoogleDeveloperKey"] = c.ServiceSettings.GoogleDeveloperKey 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["EnableTesting"] = strconv.FormatBool(c.ServiceSettings.EnableTesting) props["EnableDeveloper"] = strconv.FormatBool(*c.ServiceSettings.EnableDeveloper) - props["EnableDiagnostics"] = strconv.FormatBool(*c.LogSettings.EnableDiagnostics) props["RestrictPostDelete"] = *c.ServiceSettings.RestrictPostDelete props["AllowEditPost"] = *c.ServiceSettings.AllowEditPost 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["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["EnableEmailBatching"] = strconv.FormatBool(*c.EmailSettings.EnableEmailBatching) props["EnablePreviewModeBanner"] = strconv.FormatBool(*c.EmailSettings.EnablePreviewModeBanner) 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["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["EnablePublicLink"] = strconv.FormatBool(c.FileSettings.EnablePublicLink) props["WebsocketPort"] = fmt.Sprintf("%v", *c.ServiceSettings.WebsocketPort) props["WebsocketSecurePort"] = fmt.Sprintf("%v", *c.ServiceSettings.WebsocketSecurePort) - props["DefaultClientLocale"] = *c.LocalizationSettings.DefaultClientLocale props["AvailableLocales"] = *c.LocalizationSettings.AvailableLocales props["SQLDriverName"] = *c.SqlSettings.DriverName - props["EnableCustomEmoji"] = strconv.FormatBool(*c.ServiceSettings.EnableCustomEmoji) props["EnableEmojiPicker"] = strconv.FormatBool(*c.ServiceSettings.EnableEmojiPicker) props["RestrictCustomEmojiCreation"] = *c.ServiceSettings.RestrictCustomEmojiCreation 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) @@ -606,48 +566,26 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L props["EnableUserTypingMessages"] = strconv.FormatBool(*c.ServiceSettings.EnableUserTypingMessages) props["EnableChannelViewedMessages"] = strconv.FormatBool(*c.ServiceSettings.EnableChannelViewedMessages) - props["DiagnosticId"] = diagnosticId - props["DiagnosticsEnabled"] = strconv.FormatBool(*c.LogSettings.EnableDiagnostics) - 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) // Set default values for all options that require a license. props["ExperimentalHideTownSquareinLHS"] = "false" props["ExperimentalTownSquareIsReadOnly"] = "false" props["ExperimentalEnableAuthenticationTransfer"] = "true" - props["EnableCustomBrand"] = "false" - props["CustomBrandText"] = "" - props["CustomDescriptionText"] = "" - props["EnableLdap"] = "false" - props["LdapLoginFieldName"] = "" props["LdapNicknameAttributeSet"] = "false" props["LdapFirstNameAttributeSet"] = "false" props["LdapLastNameAttributeSet"] = "false" - props["LdapLoginButtonColor"] = "" - props["LdapLoginButtonBorderColor"] = "" - props["LdapLoginButtonTextColor"] = "" - props["EnableMultifactorAuthentication"] = "false" props["EnforceMultifactorAuthentication"] = "false" props["EnableCompliance"] = "false" props["EnableMobileFileDownload"] = "true" props["EnableMobileFileUpload"] = "true" - props["EnableSaml"] = "false" - props["SamlLoginButtonText"] = "" props["SamlFirstNameAttributeSet"] = "false" props["SamlLastNameAttributeSet"] = "false" props["SamlNicknameAttributeSet"] = "false" - props["SamlLoginButtonColor"] = "" - props["SamlLoginButtonBorderColor"] = "" - props["SamlLoginButtonTextColor"] = "" props["EnableCluster"] = "false" props["EnableMetrics"] = "false" - props["EnableSignUpWithGoogle"] = "false" - props["EnableSignUpWithOffice365"] = "false" props["PasswordMinimumLength"] = "0" props["PasswordRequireLowercase"] = "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["PasswordRequireSymbol"] = strconv.FormatBool(*c.PasswordSettings.Symbol) 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 { 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) if *license.Features.LDAP { - props["EnableLdap"] = strconv.FormatBool(*c.LdapSettings.Enable) - props["LdapLoginFieldName"] = *c.LdapSettings.LoginFieldName props["LdapNicknameAttributeSet"] = strconv.FormatBool(*c.LdapSettings.NicknameAttribute != "") props["LdapFirstNameAttributeSet"] = strconv.FormatBool(*c.LdapSettings.FirstNameAttribute != "") 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 { - props["EnableMultifactorAuthentication"] = strconv.FormatBool(*c.ServiceSettings.EnableMultifactorAuthentication) 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 { - props["EnableSaml"] = strconv.FormatBool(*c.SamlSettings.Enable) - props["SamlLoginButtonText"] = *c.SamlSettings.LoginButtonText props["SamlFirstNameAttributeSet"] = strconv.FormatBool(*c.SamlSettings.FirstNameAttribute != "") props["SamlLastNameAttributeSet"] = strconv.FormatBool(*c.SamlSettings.LastNameAttribute != "") 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 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) } - 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 { props["EnableBanner"] = strconv.FormatBool(*c.AnnouncementSettings.EnableBanner) props["BannerText"] = *c.AnnouncementSettings.BannerText @@ -760,6 +676,114 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L 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 { if *cfg.LdapSettings.Enable && ldap != nil && *cfg.LdapSettings.UserFilter != "" { if err := ldap.ValidateFilter(*cfg.LdapSettings.UserFilter); err != nil { diff --git a/utils/config_test.go b/utils/config_test.go index 63b283584..278f24251 100644 --- a/utils/config_test.go +++ b/utils/config_test.go @@ -645,7 +645,9 @@ func TestGetClientConfig(t *testing.T) { configMap := GenerateClientConfig(testCase.config, testCase.diagnosticId, testCase.license) 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) } }) } -- cgit v1.2.3-1-g7c22