github.com/adacta-ru/mattermost-server/v6@v6.0.0/api4/config_test.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package api4
     5  
     6  import (
     7  	"net/http"
     8  	"os"
     9  	"strings"
    10  	"testing"
    11  
    12  	"github.com/adacta-ru/mattermost-server/v6/config"
    13  	"github.com/adacta-ru/mattermost-server/v6/model"
    14  	"github.com/stretchr/testify/assert"
    15  	"github.com/stretchr/testify/require"
    16  )
    17  
    18  func TestGetConfig(t *testing.T) {
    19  	th := Setup(t)
    20  	defer th.TearDown()
    21  	Client := th.Client
    22  
    23  	_, resp := Client.GetConfig()
    24  	CheckForbiddenStatus(t, resp)
    25  
    26  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
    27  		cfg, resp := client.GetConfig()
    28  		CheckNoError(t, resp)
    29  
    30  		require.NotEqual(t, "", cfg.TeamSettings.SiteName)
    31  
    32  		if *cfg.LdapSettings.BindPassword != model.FAKE_SETTING && *cfg.LdapSettings.BindPassword != "" {
    33  			require.FailNow(t, "did not sanitize properly")
    34  		}
    35  		require.Equal(t, model.FAKE_SETTING, *cfg.FileSettings.PublicLinkSalt, "did not sanitize properly")
    36  
    37  		if *cfg.FileSettings.AmazonS3SecretAccessKey != model.FAKE_SETTING && *cfg.FileSettings.AmazonS3SecretAccessKey != "" {
    38  			require.FailNow(t, "did not sanitize properly")
    39  		}
    40  		if *cfg.EmailSettings.SMTPPassword != model.FAKE_SETTING && *cfg.EmailSettings.SMTPPassword != "" {
    41  			require.FailNow(t, "did not sanitize properly")
    42  		}
    43  		if *cfg.GitLabSettings.Secret != model.FAKE_SETTING && *cfg.GitLabSettings.Secret != "" {
    44  			require.FailNow(t, "did not sanitize properly")
    45  		}
    46  		require.Equal(t, model.FAKE_SETTING, *cfg.SqlSettings.DataSource, "did not sanitize properly")
    47  		require.Equal(t, model.FAKE_SETTING, *cfg.SqlSettings.AtRestEncryptKey, "did not sanitize properly")
    48  		if !strings.Contains(strings.Join(cfg.SqlSettings.DataSourceReplicas, " "), model.FAKE_SETTING) && len(cfg.SqlSettings.DataSourceReplicas) != 0 {
    49  			require.FailNow(t, "did not sanitize properly")
    50  		}
    51  		if !strings.Contains(strings.Join(cfg.SqlSettings.DataSourceSearchReplicas, " "), model.FAKE_SETTING) && len(cfg.SqlSettings.DataSourceSearchReplicas) != 0 {
    52  			require.FailNow(t, "did not sanitize properly")
    53  		}
    54  	})
    55  }
    56  
    57  func TestGetConfigWithAccessTag(t *testing.T) {
    58  	th := Setup(t)
    59  	defer th.TearDown()
    60  
    61  	varyByHeader := *&th.App.Config().RateLimitSettings.VaryByHeader // environment perm.
    62  	supportEmail := *&th.App.Config().SupportSettings.SupportEmail   // site perm.
    63  	defer th.App.UpdateConfig(func(cfg *model.Config) {
    64  		cfg.RateLimitSettings.VaryByHeader = varyByHeader
    65  		cfg.SupportSettings.SupportEmail = supportEmail
    66  	})
    67  
    68  	// set some values so that we know they're not blank
    69  	mockVaryByHeader := model.NewId()
    70  	mockSupportEmail := model.NewId() + "@mattermost.com"
    71  	th.App.UpdateConfig(func(cfg *model.Config) {
    72  		cfg.RateLimitSettings.VaryByHeader = mockVaryByHeader
    73  		cfg.SupportSettings.SupportEmail = &mockSupportEmail
    74  	})
    75  
    76  	th.Client.Login(th.BasicUser.Username, th.BasicUser.Password)
    77  
    78  	// add read sysconsole environment config
    79  	th.AddPermissionToRole(model.PERMISSION_SYSCONSOLE_READ_ENVIRONMENT.Id, model.SYSTEM_USER_ROLE_ID)
    80  	defer th.RemovePermissionFromRole(model.PERMISSION_SYSCONSOLE_READ_ENVIRONMENT.Id, model.SYSTEM_USER_ROLE_ID)
    81  
    82  	cfg, resp := th.Client.GetConfig()
    83  	CheckNoError(t, resp)
    84  
    85  	t.Run("Cannot read value without permission", func(t *testing.T) {
    86  		assert.Nil(t, cfg.SupportSettings.SupportEmail)
    87  	})
    88  
    89  	t.Run("Can read value with permission", func(t *testing.T) {
    90  		assert.Equal(t, mockVaryByHeader, cfg.RateLimitSettings.VaryByHeader)
    91  	})
    92  }
    93  
    94  func TestReloadConfig(t *testing.T) {
    95  	th := Setup(t)
    96  	defer th.TearDown()
    97  	Client := th.Client
    98  
    99  	t.Run("as system user", func(t *testing.T) {
   100  		ok, resp := Client.ReloadConfig()
   101  		CheckForbiddenStatus(t, resp)
   102  		require.False(t, ok, "should not Reload the config due no permission.")
   103  	})
   104  
   105  	t.Run("as system admin", func(t *testing.T) {
   106  		ok, resp := th.SystemAdminClient.ReloadConfig()
   107  		CheckNoError(t, resp)
   108  		require.True(t, ok, "should Reload the config")
   109  	})
   110  
   111  	t.Run("as restricted system admin", func(t *testing.T) {
   112  		th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ExperimentalSettings.RestrictSystemAdmin = true })
   113  
   114  		ok, resp := Client.ReloadConfig()
   115  		CheckForbiddenStatus(t, resp)
   116  		require.False(t, ok, "should not Reload the config due no permission.")
   117  	})
   118  }
   119  
   120  func TestUpdateConfig(t *testing.T) {
   121  	th := Setup(t)
   122  	defer th.TearDown()
   123  	Client := th.Client
   124  
   125  	cfg, resp := th.SystemAdminClient.GetConfig()
   126  	CheckNoError(t, resp)
   127  
   128  	_, resp = Client.UpdateConfig(cfg)
   129  	CheckForbiddenStatus(t, resp)
   130  
   131  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
   132  		SiteName := th.App.Config().TeamSettings.SiteName
   133  
   134  		*cfg.TeamSettings.SiteName = "MyFancyName"
   135  		cfg, resp = client.UpdateConfig(cfg)
   136  		CheckNoError(t, resp)
   137  
   138  		require.Equal(t, "MyFancyName", *cfg.TeamSettings.SiteName, "It should update the SiteName")
   139  
   140  		//Revert the change
   141  		cfg.TeamSettings.SiteName = SiteName
   142  		cfg, resp = client.UpdateConfig(cfg)
   143  		CheckNoError(t, resp)
   144  
   145  		require.Equal(t, SiteName, cfg.TeamSettings.SiteName, "It should update the SiteName")
   146  
   147  		t.Run("Should set defaults for missing fields", func(t *testing.T) {
   148  			_, appErr := th.SystemAdminClient.DoApiPut(th.SystemAdminClient.GetConfigRoute(), "{}")
   149  			require.Nil(t, appErr)
   150  		})
   151  
   152  		t.Run("Should fail with validation error if invalid config setting is passed", func(t *testing.T) {
   153  			//Revert the change
   154  			badcfg := cfg.Clone()
   155  			badcfg.PasswordSettings.MinimumLength = model.NewInt(4)
   156  			badcfg.PasswordSettings.MinimumLength = model.NewInt(4)
   157  			_, resp = client.UpdateConfig(badcfg)
   158  			CheckBadRequestStatus(t, resp)
   159  			CheckErrorMessage(t, resp, "model.config.is_valid.password_length.app_error")
   160  		})
   161  
   162  		t.Run("Should not be able to modify PluginSettings.EnableUploads", func(t *testing.T) {
   163  			oldEnableUploads := *th.App.Config().PluginSettings.EnableUploads
   164  			*cfg.PluginSettings.EnableUploads = !oldEnableUploads
   165  
   166  			cfg, resp = client.UpdateConfig(cfg)
   167  			CheckNoError(t, resp)
   168  			assert.Equal(t, oldEnableUploads, *cfg.PluginSettings.EnableUploads)
   169  			assert.Equal(t, oldEnableUploads, *th.App.Config().PluginSettings.EnableUploads)
   170  
   171  			cfg.PluginSettings.EnableUploads = nil
   172  			cfg, resp = client.UpdateConfig(cfg)
   173  			CheckNoError(t, resp)
   174  			assert.Equal(t, oldEnableUploads, *cfg.PluginSettings.EnableUploads)
   175  			assert.Equal(t, oldEnableUploads, *th.App.Config().PluginSettings.EnableUploads)
   176  		})
   177  
   178  		t.Run("Should not be able to modify PluginSettings.SignaturePublicKeyFiles", func(t *testing.T) {
   179  			oldPublicKeys := th.App.Config().PluginSettings.SignaturePublicKeyFiles
   180  			cfg.PluginSettings.SignaturePublicKeyFiles = append(cfg.PluginSettings.SignaturePublicKeyFiles, "new_signature")
   181  
   182  			cfg, resp = client.UpdateConfig(cfg)
   183  			CheckNoError(t, resp)
   184  			assert.Equal(t, oldPublicKeys, cfg.PluginSettings.SignaturePublicKeyFiles)
   185  			assert.Equal(t, oldPublicKeys, th.App.Config().PluginSettings.SignaturePublicKeyFiles)
   186  
   187  			cfg.PluginSettings.SignaturePublicKeyFiles = nil
   188  			cfg, resp = client.UpdateConfig(cfg)
   189  			CheckNoError(t, resp)
   190  			assert.Equal(t, oldPublicKeys, cfg.PluginSettings.SignaturePublicKeyFiles)
   191  			assert.Equal(t, oldPublicKeys, th.App.Config().PluginSettings.SignaturePublicKeyFiles)
   192  		})
   193  	})
   194  
   195  	t.Run("System Admin should not be able to clear Site URL", func(t *testing.T) {
   196  		siteURL := cfg.ServiceSettings.SiteURL
   197  		defer th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.SiteURL = siteURL })
   198  
   199  		nonEmptyURL := "http://localhost"
   200  		cfg.ServiceSettings.SiteURL = &nonEmptyURL
   201  
   202  		// Set the SiteURL
   203  		cfg, resp = th.SystemAdminClient.UpdateConfig(cfg)
   204  		CheckNoError(t, resp)
   205  		require.Equal(t, nonEmptyURL, *cfg.ServiceSettings.SiteURL)
   206  
   207  		// Check that the Site URL can't be cleared
   208  		cfg.ServiceSettings.SiteURL = sToP("")
   209  		cfg, resp = th.SystemAdminClient.UpdateConfig(cfg)
   210  		CheckBadRequestStatus(t, resp)
   211  		CheckErrorMessage(t, resp, "api.config.update_config.clear_siteurl.app_error")
   212  		// Check that the Site URL wasn't cleared
   213  		cfg, resp = th.SystemAdminClient.GetConfig()
   214  		CheckNoError(t, resp)
   215  		require.Equal(t, nonEmptyURL, *cfg.ServiceSettings.SiteURL)
   216  	})
   217  }
   218  
   219  func TestGetConfigWithoutManageSystemPermission(t *testing.T) {
   220  	th := Setup(t)
   221  	defer th.TearDown()
   222  	th.Client.Login(th.BasicUser.Username, th.BasicUser.Password)
   223  
   224  	t.Run("any sysconsole read permission provides config read access", func(t *testing.T) {
   225  		// forbidden by default
   226  		_, resp := th.Client.GetConfig()
   227  		CheckForbiddenStatus(t, resp)
   228  
   229  		// add any sysconsole read permission
   230  		th.AddPermissionToRole(model.SysconsoleReadPermissions[0].Id, model.SYSTEM_USER_ROLE_ID)
   231  		_, resp = th.Client.GetConfig()
   232  
   233  		// should be readable now
   234  		CheckNoError(t, resp)
   235  	})
   236  }
   237  
   238  func TestUpdateConfigWithoutManageSystemPermission(t *testing.T) {
   239  	th := Setup(t)
   240  	defer th.TearDown()
   241  	th.Client.Login(th.BasicUser.Username, th.BasicUser.Password)
   242  
   243  	// add read sysconsole integrations config
   244  	th.AddPermissionToRole(model.PERMISSION_SYSCONSOLE_READ_INTEGRATIONS.Id, model.SYSTEM_USER_ROLE_ID)
   245  	defer th.RemovePermissionFromRole(model.PERMISSION_SYSCONSOLE_READ_INTEGRATIONS.Id, model.SYSTEM_USER_ROLE_ID)
   246  
   247  	t.Run("sysconsole read permission does not provides config write access", func(t *testing.T) {
   248  		// should be readable because has a sysconsole read permission
   249  		cfg, resp := th.Client.GetConfig()
   250  		CheckNoError(t, resp)
   251  
   252  		_, resp = th.Client.UpdateConfig(cfg)
   253  
   254  		CheckForbiddenStatus(t, resp)
   255  	})
   256  
   257  	t.Run("the wrong write permission does not grant access", func(t *testing.T) {
   258  		// should be readable because has a sysconsole read permission
   259  		cfg, resp := th.SystemAdminClient.GetConfig()
   260  		CheckNoError(t, resp)
   261  
   262  		originalValue := *cfg.ServiceSettings.AllowCorsFrom
   263  
   264  		// add the wrong write permission
   265  		th.AddPermissionToRole(model.PERMISSION_SYSCONSOLE_WRITE_ABOUT.Id, model.SYSTEM_USER_ROLE_ID)
   266  		defer th.RemovePermissionFromRole(model.PERMISSION_SYSCONSOLE_WRITE_ABOUT.Id, model.SYSTEM_USER_ROLE_ID)
   267  
   268  		// try update a config value allowed by sysconsole WRITE integrations
   269  		mockVal := model.NewId()
   270  		cfg.ServiceSettings.AllowCorsFrom = &mockVal
   271  		_, resp = th.Client.UpdateConfig(cfg)
   272  		CheckNoError(t, resp)
   273  
   274  		// ensure the config setting was not updated
   275  		cfg, resp = th.Client.GetConfig()
   276  		CheckNoError(t, resp)
   277  		assert.Equal(t, *cfg.ServiceSettings.AllowCorsFrom, originalValue)
   278  	})
   279  
   280  	t.Run("config value is writeable by specific system console permission", func(t *testing.T) {
   281  		// should be readable because has a sysconsole read permission
   282  		cfg, resp := th.SystemAdminClient.GetConfig()
   283  		CheckNoError(t, resp)
   284  
   285  		th.AddPermissionToRole(model.PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS.Id, model.SYSTEM_USER_ROLE_ID)
   286  		defer th.RemovePermissionFromRole(model.PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS.Id, model.SYSTEM_USER_ROLE_ID)
   287  
   288  		// try update a config value allowed by sysconsole WRITE integrations
   289  		mockVal := model.NewId()
   290  		cfg.ServiceSettings.AllowCorsFrom = &mockVal
   291  		_, resp = th.Client.UpdateConfig(cfg)
   292  		CheckNoError(t, resp)
   293  
   294  		// ensure the config setting was updated
   295  		cfg, resp = th.Client.GetConfig()
   296  		CheckNoError(t, resp)
   297  		assert.Equal(t, *cfg.ServiceSettings.AllowCorsFrom, mockVal)
   298  	})
   299  }
   300  
   301  func TestUpdateConfigMessageExportSpecialHandling(t *testing.T) {
   302  	th := Setup(t)
   303  	defer th.TearDown()
   304  
   305  	messageExportEnabled := *th.App.Config().MessageExportSettings.EnableExport
   306  	messageExportTimestamp := *th.App.Config().MessageExportSettings.ExportFromTimestamp
   307  
   308  	defer th.App.UpdateConfig(func(cfg *model.Config) {
   309  		*cfg.MessageExportSettings.EnableExport = messageExportEnabled
   310  		*cfg.MessageExportSettings.ExportFromTimestamp = messageExportTimestamp
   311  	})
   312  
   313  	th.App.UpdateConfig(func(cfg *model.Config) {
   314  		*cfg.MessageExportSettings.EnableExport = false
   315  		*cfg.MessageExportSettings.ExportFromTimestamp = int64(0)
   316  	})
   317  
   318  	// Turn it on, timestamp should be updated.
   319  	cfg, resp := th.SystemAdminClient.GetConfig()
   320  	CheckNoError(t, resp)
   321  
   322  	*cfg.MessageExportSettings.EnableExport = true
   323  	cfg, resp = th.SystemAdminClient.UpdateConfig(cfg)
   324  	CheckNoError(t, resp)
   325  
   326  	assert.True(t, *th.App.Config().MessageExportSettings.EnableExport)
   327  	assert.NotEqual(t, int64(0), *th.App.Config().MessageExportSettings.ExportFromTimestamp)
   328  
   329  	// Turn it off, timestamp should be cleared.
   330  	cfg, resp = th.SystemAdminClient.GetConfig()
   331  	CheckNoError(t, resp)
   332  
   333  	*cfg.MessageExportSettings.EnableExport = false
   334  	cfg, resp = th.SystemAdminClient.UpdateConfig(cfg)
   335  	CheckNoError(t, resp)
   336  
   337  	assert.False(t, *th.App.Config().MessageExportSettings.EnableExport)
   338  	assert.Equal(t, int64(0), *th.App.Config().MessageExportSettings.ExportFromTimestamp)
   339  
   340  	// Set a value from the config file.
   341  	th.App.UpdateConfig(func(cfg *model.Config) {
   342  		*cfg.MessageExportSettings.EnableExport = false
   343  		*cfg.MessageExportSettings.ExportFromTimestamp = int64(12345)
   344  	})
   345  
   346  	// Turn it on, timestamp should *not* be updated.
   347  	cfg, resp = th.SystemAdminClient.GetConfig()
   348  	CheckNoError(t, resp)
   349  
   350  	*cfg.MessageExportSettings.EnableExport = true
   351  	cfg, resp = th.SystemAdminClient.UpdateConfig(cfg)
   352  	CheckNoError(t, resp)
   353  
   354  	assert.True(t, *th.App.Config().MessageExportSettings.EnableExport)
   355  	assert.Equal(t, int64(12345), *th.App.Config().MessageExportSettings.ExportFromTimestamp)
   356  
   357  	// Turn it off, timestamp should be cleared.
   358  	cfg, resp = th.SystemAdminClient.GetConfig()
   359  	CheckNoError(t, resp)
   360  
   361  	*cfg.MessageExportSettings.EnableExport = false
   362  	cfg, resp = th.SystemAdminClient.UpdateConfig(cfg)
   363  	CheckNoError(t, resp)
   364  
   365  	assert.False(t, *th.App.Config().MessageExportSettings.EnableExport)
   366  	assert.Equal(t, int64(0), *th.App.Config().MessageExportSettings.ExportFromTimestamp)
   367  }
   368  
   369  func TestUpdateConfigRestrictSystemAdmin(t *testing.T) {
   370  	th := Setup(t)
   371  	defer th.TearDown()
   372  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ExperimentalSettings.RestrictSystemAdmin = true })
   373  
   374  	t.Run("Restrict flag should be honored for sysadmin", func(t *testing.T) {
   375  		originalCfg, resp := th.SystemAdminClient.GetConfig()
   376  		CheckNoError(t, resp)
   377  
   378  		cfg := originalCfg.Clone()
   379  		*cfg.TeamSettings.SiteName = "MyFancyName"          // Allowed
   380  		*cfg.ServiceSettings.SiteURL = "http://example.com" // Ignored
   381  
   382  		returnedCfg, resp := th.SystemAdminClient.UpdateConfig(cfg)
   383  		CheckNoError(t, resp)
   384  
   385  		require.Equal(t, "MyFancyName", *returnedCfg.TeamSettings.SiteName)
   386  		require.Equal(t, *originalCfg.ServiceSettings.SiteURL, *returnedCfg.ServiceSettings.SiteURL)
   387  
   388  		actualCfg, resp := th.SystemAdminClient.GetConfig()
   389  		CheckNoError(t, resp)
   390  
   391  		require.Equal(t, returnedCfg, actualCfg)
   392  	})
   393  
   394  	t.Run("Restrict flag should be ignored by local mode", func(t *testing.T) {
   395  		originalCfg, resp := th.LocalClient.GetConfig()
   396  		CheckNoError(t, resp)
   397  
   398  		cfg := originalCfg.Clone()
   399  		*cfg.TeamSettings.SiteName = "MyFancyName"          // Allowed
   400  		*cfg.ServiceSettings.SiteURL = "http://example.com" // Ignored
   401  
   402  		returnedCfg, resp := th.LocalClient.UpdateConfig(cfg)
   403  		CheckNoError(t, resp)
   404  
   405  		require.Equal(t, "MyFancyName", *returnedCfg.TeamSettings.SiteName)
   406  		require.Equal(t, "http://example.com", *returnedCfg.ServiceSettings.SiteURL)
   407  	})
   408  }
   409  
   410  func TestGetEnvironmentConfig(t *testing.T) {
   411  	os.Setenv("MM_SERVICESETTINGS_SITEURL", "http://example.mattermost.com")
   412  	os.Setenv("MM_SERVICESETTINGS_ENABLECUSTOMEMOJI", "true")
   413  	defer os.Unsetenv("MM_SERVICESETTINGS_SITEURL")
   414  	defer os.Unsetenv("MM_SERVICESETTINGS_ENABLECUSTOMEMOJI")
   415  
   416  	th := Setup(t)
   417  	defer th.TearDown()
   418  
   419  	t.Run("as system admin", func(t *testing.T) {
   420  		SystemAdminClient := th.SystemAdminClient
   421  
   422  		envConfig, resp := SystemAdminClient.GetEnvironmentConfig()
   423  		CheckNoError(t, resp)
   424  
   425  		serviceSettings, ok := envConfig["ServiceSettings"]
   426  		require.True(t, ok, "should've returned ServiceSettings")
   427  
   428  		serviceSettingsAsMap, ok := serviceSettings.(map[string]interface{})
   429  		require.True(t, ok, "should've returned ServiceSettings as a map")
   430  
   431  		siteURL, ok := serviceSettingsAsMap["SiteURL"]
   432  		require.True(t, ok, "should've returned ServiceSettings.SiteURL")
   433  
   434  		siteURLAsBool, ok := siteURL.(bool)
   435  		require.True(t, ok, "should've returned ServiceSettings.SiteURL as a boolean")
   436  		require.True(t, siteURLAsBool, "should've returned ServiceSettings.SiteURL as true")
   437  
   438  		enableCustomEmoji, ok := serviceSettingsAsMap["EnableCustomEmoji"]
   439  		require.True(t, ok, "should've returned ServiceSettings.EnableCustomEmoji")
   440  
   441  		enableCustomEmojiAsBool, ok := enableCustomEmoji.(bool)
   442  		require.True(t, ok, "should've returned ServiceSettings.EnableCustomEmoji as a boolean")
   443  		require.True(t, enableCustomEmojiAsBool, "should've returned ServiceSettings.EnableCustomEmoji as true")
   444  
   445  		_, ok = envConfig["TeamSettings"]
   446  		require.False(t, ok, "should not have returned TeamSettings")
   447  	})
   448  
   449  	t.Run("as team admin", func(t *testing.T) {
   450  		TeamAdminClient := th.CreateClient()
   451  		th.LoginTeamAdminWithClient(TeamAdminClient)
   452  
   453  		_, resp := TeamAdminClient.GetEnvironmentConfig()
   454  		CheckForbiddenStatus(t, resp)
   455  	})
   456  
   457  	t.Run("as regular user", func(t *testing.T) {
   458  		Client := th.Client
   459  
   460  		_, resp := Client.GetEnvironmentConfig()
   461  		CheckForbiddenStatus(t, resp)
   462  	})
   463  
   464  	t.Run("as not-regular user", func(t *testing.T) {
   465  		Client := th.CreateClient()
   466  
   467  		_, resp := Client.GetEnvironmentConfig()
   468  		CheckUnauthorizedStatus(t, resp)
   469  	})
   470  }
   471  
   472  func TestGetOldClientConfig(t *testing.T) {
   473  	th := Setup(t)
   474  	defer th.TearDown()
   475  
   476  	testKey := "supersecretkey"
   477  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.GoogleDeveloperKey = testKey })
   478  
   479  	t.Run("with session", func(t *testing.T) {
   480  		th.App.UpdateConfig(func(cfg *model.Config) {
   481  			*cfg.ServiceSettings.GoogleDeveloperKey = testKey
   482  		})
   483  
   484  		Client := th.Client
   485  
   486  		config, resp := Client.GetOldClientConfig("")
   487  		CheckNoError(t, resp)
   488  
   489  		require.NotEmpty(t, config["Version"], "config not returned correctly")
   490  		require.Equal(t, testKey, config["GoogleDeveloperKey"])
   491  	})
   492  
   493  	t.Run("without session", func(t *testing.T) {
   494  		th.App.UpdateConfig(func(cfg *model.Config) {
   495  			*cfg.ServiceSettings.GoogleDeveloperKey = testKey
   496  		})
   497  
   498  		Client := th.CreateClient()
   499  
   500  		config, resp := Client.GetOldClientConfig("")
   501  		CheckNoError(t, resp)
   502  
   503  		require.NotEmpty(t, config["Version"], "config not returned correctly")
   504  		require.Empty(t, config["GoogleDeveloperKey"], "config should be missing developer key")
   505  	})
   506  
   507  	t.Run("missing format", func(t *testing.T) {
   508  		Client := th.Client
   509  
   510  		_, err := Client.DoApiGet("/config/client", "")
   511  		require.NotNil(t, err)
   512  		require.Equal(t, http.StatusNotImplemented, err.StatusCode)
   513  	})
   514  
   515  	t.Run("invalid format", func(t *testing.T) {
   516  		Client := th.Client
   517  
   518  		_, err := Client.DoApiGet("/config/client?format=junk", "")
   519  		require.NotNil(t, err)
   520  		require.Equal(t, http.StatusBadRequest, err.StatusCode)
   521  	})
   522  }
   523  
   524  func TestPatchConfig(t *testing.T) {
   525  	th := Setup(t)
   526  	defer th.TearDown()
   527  
   528  	t.Run("config is missing", func(t *testing.T) {
   529  		_, response := th.Client.PatchConfig(nil)
   530  		CheckBadRequestStatus(t, response)
   531  	})
   532  
   533  	t.Run("user is not system admin", func(t *testing.T) {
   534  		_, response := th.Client.PatchConfig(&model.Config{})
   535  		CheckForbiddenStatus(t, response)
   536  	})
   537  
   538  	t.Run("should not update the restricted fields when restrict toggle is on for sysadmin", func(t *testing.T) {
   539  		*th.App.Config().ExperimentalSettings.RestrictSystemAdmin = true
   540  
   541  		config := model.Config{LogSettings: model.LogSettings{
   542  			ConsoleLevel: model.NewString("INFO"),
   543  		}}
   544  
   545  		updatedConfig, _ := th.SystemAdminClient.PatchConfig(&config)
   546  
   547  		assert.Equal(t, "DEBUG", *updatedConfig.LogSettings.ConsoleLevel)
   548  	})
   549  
   550  	t.Run("should not bypass the restrict toggle if local client", func(t *testing.T) {
   551  		*th.App.Config().ExperimentalSettings.RestrictSystemAdmin = true
   552  
   553  		config := model.Config{LogSettings: model.LogSettings{
   554  			ConsoleLevel: model.NewString("INFO"),
   555  		}}
   556  
   557  		oldConfig, _ := th.LocalClient.GetConfig()
   558  		updatedConfig, _ := th.LocalClient.PatchConfig(&config)
   559  
   560  		assert.Equal(t, "INFO", *updatedConfig.LogSettings.ConsoleLevel)
   561  		// reset the config
   562  		_, resp := th.LocalClient.UpdateConfig(oldConfig)
   563  		CheckNoError(t, resp)
   564  	})
   565  
   566  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
   567  		t.Run("check if config is valid", func(t *testing.T) {
   568  			config := model.Config{PasswordSettings: model.PasswordSettings{
   569  				MinimumLength: model.NewInt(4),
   570  			}}
   571  
   572  			_, response := client.PatchConfig(&config)
   573  
   574  			assert.Equal(t, http.StatusBadRequest, response.StatusCode)
   575  			assert.NotNil(t, response.Error)
   576  			assert.Equal(t, "model.config.is_valid.password_length.app_error", response.Error.Id)
   577  		})
   578  
   579  		t.Run("should patch the config", func(t *testing.T) {
   580  			*th.App.Config().ExperimentalSettings.RestrictSystemAdmin = false
   581  			th.App.UpdateConfig(func(cfg *model.Config) { cfg.TeamSettings.ExperimentalDefaultChannels = []string{"some-channel"} })
   582  
   583  			oldConfig, _ := client.GetConfig()
   584  
   585  			assert.False(t, *oldConfig.PasswordSettings.Lowercase)
   586  			assert.NotEqual(t, 15, *oldConfig.PasswordSettings.MinimumLength)
   587  			assert.Equal(t, "DEBUG", *oldConfig.LogSettings.ConsoleLevel)
   588  			assert.True(t, oldConfig.PluginSettings.PluginStates["com.mattermost.nps"].Enable)
   589  
   590  			states := make(map[string]*model.PluginState)
   591  			states["com.mattermost.nps"] = &model.PluginState{Enable: *model.NewBool(false)}
   592  			config := model.Config{PasswordSettings: model.PasswordSettings{
   593  				Lowercase:     model.NewBool(true),
   594  				MinimumLength: model.NewInt(15),
   595  			}, LogSettings: model.LogSettings{
   596  				ConsoleLevel: model.NewString("INFO"),
   597  			},
   598  				TeamSettings: model.TeamSettings{
   599  					ExperimentalDefaultChannels: []string{"another-channel"},
   600  				},
   601  				PluginSettings: model.PluginSettings{
   602  					PluginStates: states,
   603  				},
   604  			}
   605  
   606  			_, response := client.PatchConfig(&config)
   607  
   608  			updatedConfig, _ := client.GetConfig()
   609  			assert.True(t, *updatedConfig.PasswordSettings.Lowercase)
   610  			assert.Equal(t, "INFO", *updatedConfig.LogSettings.ConsoleLevel)
   611  			assert.Equal(t, []string{"another-channel"}, updatedConfig.TeamSettings.ExperimentalDefaultChannels)
   612  			assert.False(t, updatedConfig.PluginSettings.PluginStates["com.mattermost.nps"].Enable)
   613  			assert.Equal(t, "no-cache, no-store, must-revalidate", response.Header.Get("Cache-Control"))
   614  
   615  			// reset the config
   616  			_, resp := client.UpdateConfig(oldConfig)
   617  			CheckNoError(t, resp)
   618  		})
   619  
   620  		t.Run("should sanitize config", func(t *testing.T) {
   621  			config := model.Config{PasswordSettings: model.PasswordSettings{
   622  				Symbol: model.NewBool(true),
   623  			}}
   624  
   625  			updatedConfig, _ := client.PatchConfig(&config)
   626  
   627  			assert.Equal(t, model.FAKE_SETTING, *updatedConfig.SqlSettings.DataSource)
   628  		})
   629  
   630  		t.Run("not allowing to toggle enable uploads for plugin via api", func(t *testing.T) {
   631  			config := model.Config{PluginSettings: model.PluginSettings{
   632  				EnableUploads: model.NewBool(true),
   633  			}}
   634  
   635  			updatedConfig, _ := client.PatchConfig(&config)
   636  
   637  			assert.Equal(t, false, *updatedConfig.PluginSettings.EnableUploads)
   638  		})
   639  	})
   640  
   641  	t.Run("System Admin should not be able to clear Site URL", func(t *testing.T) {
   642  		cfg, resp := th.SystemAdminClient.GetConfig()
   643  		CheckNoError(t, resp)
   644  		siteURL := cfg.ServiceSettings.SiteURL
   645  		defer th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.SiteURL = siteURL })
   646  
   647  		// Set the SiteURL
   648  		nonEmptyURL := "http://localhost"
   649  		config := model.Config{
   650  			ServiceSettings: model.ServiceSettings{
   651  				SiteURL: model.NewString(nonEmptyURL),
   652  			},
   653  		}
   654  		updatedConfig, resp := th.SystemAdminClient.PatchConfig(&config)
   655  		CheckNoError(t, resp)
   656  		require.Equal(t, nonEmptyURL, *updatedConfig.ServiceSettings.SiteURL)
   657  
   658  		// Check that the Site URL can't be cleared
   659  		config = model.Config{
   660  			ServiceSettings: model.ServiceSettings{
   661  				SiteURL: model.NewString(""),
   662  			},
   663  		}
   664  		updatedConfig, resp = th.SystemAdminClient.PatchConfig(&config)
   665  		CheckBadRequestStatus(t, resp)
   666  		CheckErrorMessage(t, resp, "api.config.update_config.clear_siteurl.app_error")
   667  
   668  		// Check that the Site URL wasn't cleared
   669  		cfg, resp = th.SystemAdminClient.GetConfig()
   670  		CheckNoError(t, resp)
   671  		require.Equal(t, nonEmptyURL, *cfg.ServiceSettings.SiteURL)
   672  
   673  		// Check that sending an empty config returns no error.
   674  		_, resp = th.SystemAdminClient.PatchConfig(&model.Config{})
   675  		CheckNoError(t, resp)
   676  	})
   677  }
   678  
   679  func TestMigrateConfig(t *testing.T) {
   680  	th := Setup(t).InitBasic()
   681  	defer th.TearDown()
   682  
   683  	t.Run("user is not system admin", func(t *testing.T) {
   684  		_, response := th.Client.MigrateConfig("from", "to")
   685  		CheckForbiddenStatus(t, response)
   686  	})
   687  
   688  	th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
   689  		f, err := config.NewStore("from.json", false, nil)
   690  		require.NoError(t, err)
   691  		defer f.RemoveFile("from.json")
   692  
   693  		_, err = config.NewStore("to.json", false, nil)
   694  		require.NoError(t, err)
   695  		defer f.RemoveFile("to.json")
   696  
   697  		_, response := client.MigrateConfig("from.json", "to.json")
   698  		CheckNoError(t, response)
   699  	})
   700  }