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 }