diff --git a/Makefile b/Makefile index 7f056bfdbf..5caa89ef68 100644 --- a/Makefile +++ b/Makefile @@ -535,7 +535,7 @@ config-ldap: ## Configures LDAP. config-reset: ## Resets the config/config.json file to the default. @echo Resetting configuration to default rm -f config/config.json - cp config/default.json config/config.json + OUTPUT_CONFIG=$(PWD)/config/config.json go generate ./config clean: stop-docker ## Clean up everything except persistant server data. @echo Cleaning diff --git a/build/Jenkinsfile.k8s b/build/Jenkinsfile.k8s index fdb0d57d7a..b3d3d8abaa 100644 --- a/build/Jenkinsfile.k8s +++ b/build/Jenkinsfile.k8s @@ -136,7 +136,7 @@ podTemplate(label: 'jenkins-slave', sh 'apt-get update && apt-get install zip -y' // Modify config to run on jenkins - sh 'mv /go/src/github.com/mattermost/mattermost-server/config/default.json /go/src/github.com/mattermost/mattermost-server/config/config.json' + sh 'cd /go/src/github.com/mattermost/mattermost-server && make config-reset' sh 'cd /go/src/github.com/mattermost/mattermost-server && sed -i \'s/dockerhost/localhost/g\' config/config.json' sh 'cd /go/src/github.com/mattermost/mattermost-server && sed -i \'s/2500/10025/g\' config/config.json' } diff --git a/build/Jenkinsfile.pr b/build/Jenkinsfile.pr index 8f80e83f18..7b1fd35102 100644 --- a/build/Jenkinsfile.pr +++ b/build/Jenkinsfile.pr @@ -100,7 +100,7 @@ pipeline { ansiColor('xterm') { sh """ cd /go/src/github.com/mattermost/mattermost-server - mv config/default.json config/config.json || echo "" + make config-reset make check-style BUILD_NUMBER='${BRANCH_NAME}-${BUILD_NUMBER}' make build BUILD_NUMBER='${BRANCH_NAME}-${BUILD_NUMBER}' make package BUILD_NUMBER='${BRANCH_NAME}-${BUILD_NUMBER}' diff --git a/build/release.mk b/build/release.mk index 9d66597261..9dccd7afeb 100644 --- a/build/release.mk +++ b/build/release.mk @@ -34,7 +34,7 @@ package: @# Resource directories mkdir -p $(DIST_PATH)/config cp -L config/README.md $(DIST_PATH)/config - cp -L config/config.json $(DIST_PATH)/config + OUTPUT_CONFIG=$(PWD)/$(DIST_PATH)/config/config.json go generate ./config cp -RL fonts $(DIST_PATH) cp -RL templates $(DIST_PATH) cp -RL i18n $(DIST_PATH) diff --git a/config/config_generator/generator/generator.go b/config/config_generator/generator/generator.go new file mode 100644 index 0000000000..70698742e2 --- /dev/null +++ b/config/config_generator/generator/generator.go @@ -0,0 +1,22 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package generator + +import ( + "encoding/json" + "os" + + "github.com/mattermost/mattermost-server/model" +) + +func GenerateDefaultConfig(outputFile *os.File) error { + defaultCfg := &model.Config{} + defaultCfg.SetDefaults() + if data, err := json.MarshalIndent(defaultCfg, "", " "); err != nil { + return err + } else if _, err := outputFile.Write(data); err != nil { + return err + } + return nil +} diff --git a/config/config_generator/main.go b/config/config_generator/main.go new file mode 100644 index 0000000000..fce68404e8 --- /dev/null +++ b/config/config_generator/main.go @@ -0,0 +1,34 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package main + +import ( + "fmt" + "os" + + "github.com/mattermost/mattermost-server/config/config_generator/generator" +) + +func main() { + outputFile := os.Getenv("OUTPUT_CONFIG") + if outputFile == "" { + fmt.Println("Output file name is missing. Please set OUTPUT_CONFIG env variable to absolute path") + os.Exit(2) + } + if _, err := os.Stat(outputFile); !os.IsNotExist(err) { + _, _ = fmt.Fprintf(os.Stderr, "File %s already exists. Not overwriting!\n", outputFile) + os.Exit(2) + } + + if file, err := os.Create(outputFile); err == nil { + err = generator.GenerateDefaultConfig(file) + _ = file.Close() + if err != nil { + panic(err) + } + } else { + panic(err) + } + +} diff --git a/config/database_test.go b/config/database_test.go index 2793f76d96..677a5b4280 100644 --- a/config/database_test.go +++ b/config/database_test.go @@ -101,7 +101,7 @@ func TestDatabaseStoreNew(t *testing.T) { require.NoError(t, err) defer ds.Close() - assert.Equal(t, model.SERVICE_SETTINGS_DEFAULT_SITE_URL, *ds.Get().ServiceSettings.SiteURL) + assert.Equal(t, "", *ds.Get().ServiceSettings.SiteURL) }) t.Run("existing config, initialization required", func(t *testing.T) { @@ -221,7 +221,7 @@ func TestDatabaseStoreSet(t *testing.T) { require.NoError(t, err) assert.Equal(t, oldCfg, retCfg) - assert.Equal(t, model.SERVICE_SETTINGS_DEFAULT_SITE_URL, *ds.Get().ServiceSettings.SiteURL) + assert.Equal(t, "", *ds.Get().ServiceSettings.SiteURL) }) t.Run("desanitization required", func(t *testing.T) { @@ -260,7 +260,7 @@ func TestDatabaseStoreSet(t *testing.T) { assert.EqualError(t, err, "new configuration is invalid: Config.IsValid: model.config.is_valid.site_url.app_error, ") } - assert.Equal(t, model.SERVICE_SETTINGS_DEFAULT_SITE_URL, *ds.Get().ServiceSettings.SiteURL) + assert.Equal(t, "", *ds.Get().ServiceSettings.SiteURL) }) t.Run("duplicate ignored", func(t *testing.T) { @@ -345,7 +345,7 @@ func TestDatabaseStoreSet(t *testing.T) { assert.True(t, strings.HasPrefix(err.Error(), "failed to persist: failed to write to database")) } - assert.Equal(t, model.SERVICE_SETTINGS_DEFAULT_SITE_URL, *ds.Get().ServiceSettings.SiteURL) + assert.Equal(t, "", *ds.Get().ServiceSettings.SiteURL) }) t.Run("listeners notified", func(t *testing.T) { diff --git a/config/default.go b/config/default.go new file mode 100644 index 0000000000..4cdb5d6d14 --- /dev/null +++ b/config/default.go @@ -0,0 +1,6 @@ +//go:generate go run config_generator/main.go + +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package config diff --git a/config/default.json b/config/default.json deleted file mode 100644 index 021c54b562..0000000000 --- a/config/default.json +++ /dev/null @@ -1,442 +0,0 @@ -{ - "ServiceSettings": { - "SiteURL": "", - "WebsocketURL": "", - "LicenseFileLocation": "", - "ListenAddress": ":8065", - "ConnectionSecurity": "", - "TLSCertFile": "", - "TLSKeyFile": "", - "TLSMinVer": "1.2", - "TLSStrictTransport": false, - "TLSStrictTransportMaxAge": 63072000, - "TLSOverwriteCiphers": [], - "UseLetsEncrypt": false, - "LetsEncryptCertificateCacheFile": "./config/letsencrypt.cache", - "Forward80To443": false, - "TrustedProxyIPHeader": [], - "ReadTimeout": 300, - "WriteTimeout": 300, - "MaximumLoginAttempts": 10, - "GoroutineHealthThreshold": -1, - "GoogleDeveloperKey": "", - "EnableOAuthServiceProvider": false, - "EnableIncomingWebhooks": true, - "EnableOutgoingWebhooks": true, - "EnableCommands": true, - "EnableOnlyAdminIntegrations": true, - "EnablePostUsernameOverride": false, - "EnablePostIconOverride": false, - "EnableAPIv3": false, - "EnableLinkPreviews": false, - "EnableTesting": false, - "EnableDeveloper": false, - "EnableSecurityFixAlert": true, - "EnableInsecureOutgoingConnections": false, - "AllowedUntrustedInternalConnections": "", - "EnableMultifactorAuthentication": false, - "EnforceMultifactorAuthentication": false, - "EnableUserAccessTokens": false, - "AllowCorsFrom": "", - "CorsExposedHeaders": "", - "CorsAllowCredentials": false, - "CorsDebug": false, - "AllowCookiesForSubdomains": false, - "SessionLengthWebInDays": 180, - "SessionLengthMobileInDays": 180, - "SessionLengthSSOInDays": 30, - "SessionCacheInMinutes": 10, - "SessionIdleTimeoutInMinutes": 43200, - "WebsocketSecurePort": 443, - "WebsocketPort": 80, - "WebserverMode": "gzip", - "EnableCustomEmoji": false, - "EnableEmojiPicker": true, - "EnableGifPicker": false, - "GfycatApiKey": "2_KtH_W5", - "GfycatApiSecret": "3wLVZPiswc3DnaiaFoLkDvB4X0IV6CpMkj4tf2inJRsBY6-FnkT08zGmppWFgeof", - "RestrictCustomEmojiCreation": "all", - "RestrictPostDelete": "all", - "AllowEditPost": "always", - "PostEditTimeLimit": -1, - "ExperimentalEnableAuthenticationTransfer": true, - "TimeBetweenUserTypingUpdatesMilliseconds": 5000, - "EnablePostSearch": true, - "MinimumHashtagLength": 3, - "EnableUserTypingMessages": true, - "EnableChannelViewedMessages": true, - "EnableUserStatuses": true, - "ClusterLogTimeoutMilliseconds": 2000, - "EnablePreviewFeatures": true, - "CloseUnusedDirectMessages": false, - "EnableTutorial": true, - "ExperimentalEnableDefaultChannelLeaveJoinMessages": true, - "ExperimentalGroupUnreadChannels": "disabled", - "ExperimentalChannelOrganization": false, - "EnableAPITeamDeletion": false, - "ExperimentalEnableHardenedMode": false, - "DisableLegacyMFA": true, - "EnableEmailInvitations": false, - "ExperimentalLdapGroupSync": false, - "ExperimentalStrictCSRFEnforcement": false, - "EnableBotAccountCreation": false, - "DisableBotsWhenOwnerIsDeactivated": true - }, - "TeamSettings": { - "SiteName": "Mattermost", - "MaxUsersPerTeam": 50, - "EnableTeamCreation": true, - "EnableUserCreation": true, - "EnableOpenServer": false, - "EnableUserDeactivation": false, - "RestrictCreationToDomains": "", - "EnableCustomBrand": false, - "CustomBrandText": "", - "CustomDescriptionText": "", - "RestrictDirectMessage": "any", - "RestrictTeamInvite": "all", - "RestrictPublicChannelManagement": "all", - "RestrictPrivateChannelManagement": "all", - "RestrictPublicChannelCreation": "all", - "RestrictPrivateChannelCreation": "all", - "RestrictPublicChannelDeletion": "all", - "RestrictPrivateChannelDeletion": "all", - "RestrictPrivateChannelManageMembers": "all", - "EnableXToLeaveChannelsFromLHS": false, - "UserStatusAwayTimeout": 300, - "MaxChannelsPerTeam": 2000, - "MaxNotificationsPerChannel": 1000, - "EnableConfirmNotificationsToChannel": true, - "TeammateNameDisplay": "username", - "ExperimentalViewArchivedChannels": false, - "ExperimentalEnableAutomaticReplies": false, - "ExperimentalHideTownSquareinLHS": false, - "ExperimentalTownSquareIsReadOnly": false, - "ExperimentalPrimaryTeam": "", - "ExperimentalDefaultChannels": "" - }, - "DisplaySettings": { - "CustomUrlSchemes": [], - "ExperimentalTimezone": false - }, - "ClientRequirements": { - "AndroidLatestVersion": "", - "AndroidMinVersion": "", - "DesktopLatestVersion": "", - "DesktopMinVersion": "", - "IosLatestVersion": "", - "IosMinVersion": "" - }, - "SqlSettings": { - "DriverName": "mysql", - "DataSource": "mmuser:mostest@tcp(dockerhost:3306)/mattermost_test?charset=utf8mb4,utf8&readTimeout=30s&writeTimeout=30s", - "DataSourceReplicas": [], - "DataSourceSearchReplicas": [], - "MaxIdleConns": 20, - "ConnMaxLifetimeMilliseconds": 3600000, - "MaxOpenConns": 300, - "Trace": false, - "AtRestEncryptKey": "", - "QueryTimeout": 30 - }, - "LogSettings": { - "EnableConsole": true, - "ConsoleLevel": "DEBUG", - "ConsoleJson": true, - "EnableFile": true, - "FileLevel": "INFO", - "FileJson": true, - "FileLocation": "", - "EnableWebhookDebugging": true, - "EnableDiagnostics": true - }, - "NotificationLogSettings": { - "EnableConsole": true, - "ConsoleLevel": "DEBUG", - "ConsoleJson": true, - "EnableFile": true, - "FileLevel": "INFO", - "FileJson": true, - "FileLocation": "" - }, - "PasswordSettings": { - "MinimumLength": 10, - "Lowercase": true, - "Number": true, - "Uppercase": true, - "Symbol": true - }, - "FileSettings": { - "EnableFileAttachments": true, - "EnableMobileUpload": true, - "EnableMobileDownload": true, - "MaxFileSize": 52428800, - "DriverName": "local", - "Directory": "./data/", - "EnablePublicLink": false, - "PublicLinkSalt": "", - "InitialFont": "nunito-bold.ttf", - "AmazonS3AccessKeyId": "", - "AmazonS3SecretAccessKey": "", - "AmazonS3Bucket": "", - "AmazonS3Region": "", - "AmazonS3Endpoint": "s3.amazonaws.com", - "AmazonS3SSL": true, - "AmazonS3SignV2": false, - "AmazonS3SSE": false, - "AmazonS3Trace": false - }, - "EmailSettings": { - "EnableSignUpWithEmail": true, - "EnableSignInWithEmail": true, - "EnableSignInWithUsername": true, - "SendEmailNotifications": true, - "UseChannelInEmailNotifications": false, - "RequireEmailVerification": false, - "FeedbackName": "", - "FeedbackEmail": "test@example.com", - "ReplyToAddress": "test@example.com", - "FeedbackOrganization": "", - "EnableSMTPAuth": false, - "SMTPUsername": "", - "SMTPPassword": "", - "SMTPServer": "dockerhost", - "SMTPPort": "2500", - "ConnectionSecurity": "", - "SendPushNotifications": true, - "PushNotificationServer": "https://push-test.mattermost.com", - "PushNotificationContents": "generic", - "EnableEmailBatching": false, - "EmailBatchingBufferSize": 256, - "EmailBatchingInterval": 30, - "EnablePreviewModeBanner": true, - "SkipServerCertificateVerification": false, - "EmailNotificationContentsType": "full", - "LoginButtonColor": "#0000", - "LoginButtonBorderColor": "#2389D7", - "LoginButtonTextColor": "#2389D7" - }, - "RateLimitSettings": { - "Enable": false, - "PerSec": 10, - "MaxBurst": 100, - "MemoryStoreSize": 10000, - "VaryByRemoteAddr": true, - "VaryByUser": false, - "VaryByHeader": "" - }, - "PrivacySettings": { - "ShowEmailAddress": true, - "ShowFullName": true - }, - "SupportSettings": { - "TermsOfServiceLink": "https://about.mattermost.com/default-terms/", - "PrivacyPolicyLink": "https://about.mattermost.com/default-privacy-policy/", - "AboutLink": "https://about.mattermost.com/default-about/", - "HelpLink": "https://about.mattermost.com/default-help/", - "ReportAProblemLink": "https://about.mattermost.com/default-report-a-problem/", - "SupportEmail": "feedback@mattermost.com" - }, - "AnnouncementSettings": { - "EnableBanner": false, - "BannerText": "", - "BannerColor": "#f2a93b", - "BannerTextColor": "#333333", - "AllowBannerDismissal": true - }, - "ThemeSettings": { - "EnableThemeSelection": true, - "DefaultTheme": "default", - "AllowCustomThemes": true, - "AllowedThemes": [] - }, - "GitLabSettings": { - "Enable": false, - "Secret": "", - "Id": "", - "Scope": "", - "AuthEndpoint": "", - "TokenEndpoint": "", - "UserApiEndpoint": "" - }, - "GoogleSettings": { - "Enable": false, - "Secret": "", - "Id": "", - "Scope": "profile email", - "AuthEndpoint": "https://accounts.google.com/o/oauth2/v2/auth", - "TokenEndpoint": "https://www.googleapis.com/oauth2/v4/token", - "UserApiEndpoint": "https://people.googleapis.com/v1/people/me?personFields=names,emailAddresses,nicknames,metadata" - }, - "Office365Settings": { - "Enable": false, - "Secret": "", - "Id": "", - "Scope": "User.Read", - "AuthEndpoint": "https://login.microsoftonline.com/common/oauth2/v2.0/authorize", - "TokenEndpoint": "https://login.microsoftonline.com/common/oauth2/v2.0/token", - "UserApiEndpoint": "https://graph.microsoft.com/v1.0/me" - }, - "LdapSettings": { - "Enable": false, - "EnableSync": false, - "LdapServer": "", - "LdapPort": 389, - "ConnectionSecurity": "", - "BaseDN": "", - "BindUsername": "", - "BindPassword": "", - "UserFilter": "", - "GroupFilter": "", - "GroupDisplayNameAttribute": "", - "GroupIdAttribute": "", - "FirstNameAttribute": "", - "LastNameAttribute": "", - "EmailAttribute": "", - "UsernameAttribute": "", - "NicknameAttribute": "", - "IdAttribute": "", - "PositionAttribute": "", - "LoginIdAttribute": "", - "SyncIntervalMinutes": 60, - "SkipCertificateVerification": false, - "QueryTimeout": 60, - "MaxPageSize": 0, - "LoginFieldName": "", - "LoginButtonColor": "", - "LoginButtonBorderColor": "", - "LoginButtonTextColor": "" - }, - "ComplianceSettings": { - "Enable": false, - "Directory": "./data/", - "EnableDaily": false - }, - "LocalizationSettings": { - "DefaultServerLocale": "en", - "DefaultClientLocale": "en", - "AvailableLocales": "" - }, - "SamlSettings": { - "Enable": false, - "EnableSyncWithLdap": false, - "EnableSyncWithLdapIncludeAuth": false, - "Verify": true, - "Encrypt": true, - "IdpUrl": "", - "IdpDescriptorUrl": "", - "AssertionConsumerServiceURL": "", - "ScopingIDPProviderId": "", - "ScopingIDPName": "", - "IdpCertificateFile": "", - "PublicCertificateFile": "", - "PrivateKeyFile": "", - "IdAttribute": "", - "FirstNameAttribute": "", - "LastNameAttribute": "", - "EmailAttribute": "", - "UsernameAttribute": "", - "NicknameAttribute": "", - "LocaleAttribute": "", - "PositionAttribute": "", - "LoginButtonText": "SAML", - "LoginButtonColor": "", - "LoginButtonBorderColor": "", - "LoginButtonTextColor": "" - }, - "NativeAppSettings": { - "AppDownloadLink": "https://about.mattermost.com/downloads/", - "AndroidAppDownloadLink": "https://about.mattermost.com/mattermost-android-app/", - "IosAppDownloadLink": "https://about.mattermost.com/mattermost-ios-app/" - }, - "ClusterSettings": { - "Enable": false, - "ClusterName": "", - "OverrideHostname": "", - "UseIpAddress": true, - "UseExperimentalGossip": false, - "ReadOnlyConfig": true, - "GossipPort": 8074, - "StreamingPort": 8075, - "MaxIdleConns": 100, - "MaxIdleConnsPerHost": 128, - "IdleConnTimeoutMilliseconds": 90000 - }, - "MetricsSettings": { - "Enable": false, - "BlockProfileRate": 0, - "ListenAddress": ":8067" - }, - "ExperimentalSettings": { - "ClientSideCertEnable": false, - "ClientSideCertCheck": "secondary", - "DisablePostMetadata": false, - "LinkMetadataTimeoutMilliseconds": 5000, - "RestrictSystemAdmin": false, - "EnableClickToReply": false - }, - "AnalyticsSettings": { - "MaxUsersForStatistics": 2500 - }, - "ElasticsearchSettings": { - "ConnectionUrl": "http://dockerhost:9200", - "Username": "elastic", - "Password": "changeme", - "EnableIndexing": false, - "EnableSearching": false, - "EnableAutocomplete": false, - "Sniff": true, - "PostIndexReplicas": 1, - "PostIndexShards": 1, - "ChannelIndexReplicas": 1, - "ChannelIndexShards": 1, - "UserIndexReplicas": 1, - "UserIndexShards": 1, - "AggregatePostsAfterDays": 365, - "PostsAggregatorJobStartTime": "03:00", - "IndexPrefix": "", - "LiveIndexingBatchSize": 1, - "BulkIndexingTimeWindowSeconds": 3600, - "RequestTimeoutSeconds": 30, - "Trace": "" - }, - "DataRetentionSettings": { - "EnableMessageDeletion": false, - "EnableFileDeletion": false, - "MessageRetentionDays": 365, - "FileRetentionDays": 365, - "DeletionJobStartTime": "02:00" - }, - "MessageExportSettings": { - "EnableExport": false, - "DailyRunTime": "01:00", - "ExportFromTimestamp": 0, - "FileLocation": "export", - "BatchSize": 10000, - "GlobalRelaySettings": { - "CustomerType": "A9", - "SmtpUsername": "", - "SmtpPassword": "", - "EmailAddress": "" - } - }, - "JobSettings": { - "RunJobs": true, - "RunScheduler": true - }, - "PluginSettings": { - "Enable": true, - "EnableUploads": false, - "EnableHealthCheck": true, - "Directory": "./plugins", - "ClientDirectory": "./client/plugins", - "Plugins": {}, - "PluginStates": {} - }, - "ImageProxySettings": { - "Enable": false, - "ImageProxyType": "local", - "RemoteImageProxyURL": "", - "RemoteImageProxyOptions": "" - } -} diff --git a/config/default_test.go b/config/default_test.go new file mode 100644 index 0000000000..af824df6b6 --- /dev/null +++ b/config/default_test.go @@ -0,0 +1,42 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package config + +import ( + "encoding/json" + "io/ioutil" + "os" + "testing" + + "github.com/mattermost/mattermost-server/model" + + "github.com/mattermost/mattermost-server/config/config_generator/generator" + "github.com/stretchr/testify/require" +) + +func TestDefaultsGenerator(t *testing.T) { + tmpFile, err := ioutil.TempFile("", "tempconfig") + defer os.Remove(tmpFile.Name()) + require.NoError(t, err) + require.NoError(t, generator.GenerateDefaultConfig(tmpFile)) + _ = tmpFile.Close() + var config model.Config + + b, err := ioutil.ReadFile(tmpFile.Name()) + require.NoError(t, err) + require.NoError(t, json.Unmarshal(b, &config)) + require.True(t, *config.ServiceSettings.DisableLegacyMFA) + require.Equal(t, *config.SqlSettings.AtRestEncryptKey, "") + require.Equal(t, *config.FileSettings.PublicLinkSalt, "") + + require.Equal(t, *config.Office365Settings.Scope, model.OFFICE365_SETTINGS_DEFAULT_SCOPE) + require.Equal(t, *config.Office365Settings.AuthEndpoint, model.OFFICE365_SETTINGS_DEFAULT_AUTH_ENDPOINT) + require.Equal(t, *config.Office365Settings.UserApiEndpoint, model.OFFICE365_SETTINGS_DEFAULT_USER_API_ENDPOINT) + require.Equal(t, *config.Office365Settings.TokenEndpoint, model.OFFICE365_SETTINGS_DEFAULT_TOKEN_ENDPOINT) + + require.Equal(t, *config.GoogleSettings.Scope, model.GOOGLE_SETTINGS_DEFAULT_SCOPE) + require.Equal(t, *config.GoogleSettings.AuthEndpoint, model.GOOGLE_SETTINGS_DEFAULT_AUTH_ENDPOINT) + require.Equal(t, *config.GoogleSettings.UserApiEndpoint, model.GOOGLE_SETTINGS_DEFAULT_USER_API_ENDPOINT) + require.Equal(t, *config.GoogleSettings.TokenEndpoint, model.GOOGLE_SETTINGS_DEFAULT_TOKEN_ENDPOINT) +} diff --git a/config/file_test.go b/config/file_test.go index 12b9ac619d..a22c90f193 100644 --- a/config/file_test.go +++ b/config/file_test.go @@ -122,7 +122,7 @@ func TestFileStoreNew(t *testing.T) { require.NoError(t, err) defer fs.Close() - assert.Equal(t, model.SERVICE_SETTINGS_DEFAULT_SITE_URL, *fs.Get().ServiceSettings.SiteURL) + assert.Equal(t, "", *fs.Get().ServiceSettings.SiteURL) assertFileNotEqualsConfig(t, testConfig, path) }) @@ -175,7 +175,7 @@ func TestFileStoreNew(t *testing.T) { require.NoError(t, err) defer fs.Close() - assert.Equal(t, model.SERVICE_SETTINGS_DEFAULT_SITE_URL, *fs.Get().ServiceSettings.SiteURL) + assert.Equal(t, "", *fs.Get().ServiceSettings.SiteURL) assertFileNotEqualsConfig(t, testConfig, filepath.Join("config", path)) }) } @@ -257,7 +257,7 @@ func TestFileStoreSet(t *testing.T) { require.NoError(t, err) assert.Equal(t, oldCfg, retCfg) - assert.Equal(t, model.SERVICE_SETTINGS_DEFAULT_SITE_URL, *fs.Get().ServiceSettings.SiteURL) + assert.Equal(t, "", *fs.Get().ServiceSettings.SiteURL) }) t.Run("desanitization required", func(t *testing.T) { @@ -296,7 +296,7 @@ func TestFileStoreSet(t *testing.T) { assert.EqualError(t, err, "new configuration is invalid: Config.IsValid: model.config.is_valid.site_url.app_error, ") } - assert.Equal(t, model.SERVICE_SETTINGS_DEFAULT_SITE_URL, *fs.Get().ServiceSettings.SiteURL) + assert.Equal(t, "", *fs.Get().ServiceSettings.SiteURL) }) t.Run("read-only", func(t *testing.T) { @@ -314,7 +314,7 @@ func TestFileStoreSet(t *testing.T) { assert.Equal(t, config.ErrReadOnlyConfiguration, errors.Cause(err)) } - assert.Equal(t, model.SERVICE_SETTINGS_DEFAULT_SITE_URL, *fs.Get().ServiceSettings.SiteURL) + assert.Equal(t, "", *fs.Get().ServiceSettings.SiteURL) }) t.Run("persist failed", func(t *testing.T) { @@ -335,7 +335,7 @@ func TestFileStoreSet(t *testing.T) { assert.True(t, strings.HasPrefix(err.Error(), "failed to persist: failed to write file")) } - assert.Equal(t, model.SERVICE_SETTINGS_DEFAULT_SITE_URL, *fs.Get().ServiceSettings.SiteURL) + assert.Equal(t, "", *fs.Get().ServiceSettings.SiteURL) }) t.Run("listeners notified", func(t *testing.T) { diff --git a/config/memory_test.go b/config/memory_test.go index 9c76bc3df1..0570a0ed73 100644 --- a/config/memory_test.go +++ b/config/memory_test.go @@ -26,7 +26,7 @@ func TestMemoryStoreNew(t *testing.T) { require.NoError(t, err) defer ms.Close() - assert.Equal(t, model.SERVICE_SETTINGS_DEFAULT_SITE_URL, *ms.Get().ServiceSettings.SiteURL) + assert.Equal(t, "", *ms.Get().ServiceSettings.SiteURL) }) t.Run("existing config, initialization required", func(t *testing.T) { @@ -134,7 +134,7 @@ func TestMemoryStoreSet(t *testing.T) { require.NoError(t, err) assert.Equal(t, oldCfg, retCfg) - assert.Equal(t, model.SERVICE_SETTINGS_DEFAULT_SITE_URL, *ms.Get().ServiceSettings.SiteURL) + assert.Equal(t, "", *ms.Get().ServiceSettings.SiteURL) }) t.Run("desanitization required", func(t *testing.T) { @@ -171,7 +171,7 @@ func TestMemoryStoreSet(t *testing.T) { assert.EqualError(t, err, "new configuration is invalid: Config.IsValid: model.config.is_valid.site_url.app_error, ") } - assert.Equal(t, model.SERVICE_SETTINGS_DEFAULT_SITE_URL, *ms.Get().ServiceSettings.SiteURL) + assert.Equal(t, "", *ms.Get().ServiceSettings.SiteURL) }) t.Run("read-only ignored", func(t *testing.T) { diff --git a/model/config.go b/model/config.go index 5524a393ec..5bef47beff 100644 --- a/model/config.go +++ b/model/config.go @@ -46,6 +46,7 @@ const ( GENERIC_NO_CHANNEL_NOTIFICATION = "generic_no_channel" GENERIC_NOTIFICATION = "generic" + GENERIC_NOTIFICATION_SERVER = "https://push-test.mattermost.com" FULL_NOTIFICATION = "full" DIRECT_MESSAGE_ANY = "any" @@ -184,6 +185,16 @@ const ( IMAGE_PROXY_TYPE_LOCAL = "local" IMAGE_PROXY_TYPE_ATMOS_CAMO = "atmos/camo" + + GOOGLE_SETTINGS_DEFAULT_SCOPE = "profile email" + GOOGLE_SETTINGS_DEFAULT_AUTH_ENDPOINT = "https://accounts.google.com/o/oauth2/v2/auth" + GOOGLE_SETTINGS_DEFAULT_TOKEN_ENDPOINT = "https://www.googleapis.com/oauth2/v4/token" + GOOGLE_SETTINGS_DEFAULT_USER_API_ENDPOINT = "https://people.googleapis.com/v1/people/me?personFields=names,emailAddresses,nicknames,metadata" + + OFFICE365_SETTINGS_DEFAULT_SCOPE = "User.Read" + OFFICE365_SETTINGS_DEFAULT_AUTH_ENDPOINT = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize" + OFFICE365_SETTINGS_DEFAULT_TOKEN_ENDPOINT = "https://login.microsoftonline.com/common/oauth2/v2.0/token" + OFFICE365_SETTINGS_DEFAULT_USER_API_ENDPOINT = "https://graph.microsoft.com/v1.0/me" ) var ServerTLSSupportedCiphers = map[string]uint16{ @@ -297,7 +308,7 @@ type ServiceSettings struct { EnableBotAccountCreation *bool } -func (s *ServiceSettings) SetDefaults() { +func (s *ServiceSettings) SetDefaults(isUpdate bool) { if s.EnableEmailInvitations == nil { // If the site URL is also not present then assume this is a clean install if s.SiteURL == nil { @@ -308,7 +319,11 @@ func (s *ServiceSettings) SetDefaults() { } if s.SiteURL == nil { - s.SiteURL = NewString(SERVICE_SETTINGS_DEFAULT_SITE_URL) + if s.EnableDeveloper != nil && *s.EnableDeveloper { + s.SiteURL = NewString(SERVICE_SETTINGS_DEFAULT_SITE_URL) + } else { + s.SiteURL = NewString("") + } } if s.WebsocketURL == nil { @@ -435,8 +450,14 @@ func (s *ServiceSettings) SetDefaults() { s.Forward80To443 = NewBool(false) } - if s.TrustedProxyIPHeader == nil { - s.TrustedProxyIPHeader = []string{HEADER_FORWARDED, HEADER_REAL_IP} + if isUpdate { + // When updating an existing configuration, ensure that defaults are set. + if s.TrustedProxyIPHeader == nil { + s.TrustedProxyIPHeader = []string{HEADER_FORWARDED, HEADER_REAL_IP} + } + } else { + // When generating a blank configuration, leave the list empty. + s.TrustedProxyIPHeader = []string{} } if s.TimeBetweenUserTypingUpdatesMilliseconds == nil { @@ -627,7 +648,7 @@ func (s *ServiceSettings) SetDefaults() { } if s.DisableLegacyMFA == nil { - s.DisableLegacyMFA = NewBool(false) + s.DisableLegacyMFA = NewBool(!isUpdate) } if s.ExperimentalLdapGroupSync == nil { @@ -782,7 +803,7 @@ type SSOSettings struct { UserApiEndpoint *string } -func (s *SSOSettings) setDefaults() { +func (s *SSOSettings) setDefaults(scope, authEndpoint, tokenEndpoint, userApiEndpoint string) { if s.Enable == nil { s.Enable = NewBool(false) } @@ -796,19 +817,19 @@ func (s *SSOSettings) setDefaults() { } if s.Scope == nil { - s.Scope = NewString("") + s.Scope = NewString(scope) } if s.AuthEndpoint == nil { - s.AuthEndpoint = NewString("") + s.AuthEndpoint = NewString(authEndpoint) } if s.TokenEndpoint == nil { - s.TokenEndpoint = NewString("") + s.TokenEndpoint = NewString(tokenEndpoint) } if s.UserApiEndpoint == nil { - s.UserApiEndpoint = NewString("") + s.UserApiEndpoint = NewString(userApiEndpoint) } } @@ -825,7 +846,7 @@ type SqlSettings struct { QueryTimeout *int `restricted:"true"` } -func (s *SqlSettings) SetDefaults() { +func (s *SqlSettings) SetDefaults(isUpdate bool) { if s.DriverName == nil { s.DriverName = NewString(DATABASE_DRIVER_MYSQL) } @@ -842,8 +863,14 @@ func (s *SqlSettings) SetDefaults() { s.DataSourceSearchReplicas = []string{} } - if s.AtRestEncryptKey == nil || len(*s.AtRestEncryptKey) == 0 { - s.AtRestEncryptKey = NewString(NewRandomString(32)) + if isUpdate { + // When updating an existing configuration, ensure an encryption key has been specified. + if s.AtRestEncryptKey == nil || len(*s.AtRestEncryptKey) == 0 { + s.AtRestEncryptKey = NewString(NewRandomString(32)) + } + } else { + // When generating a blank configuration, leave this key empty to be generated on server start. + s.AtRestEncryptKey = NewString("") } if s.MaxIdleConns == nil { @@ -1008,7 +1035,7 @@ type FileSettings struct { AmazonS3Trace *bool `restricted:"true"` } -func (s *FileSettings) SetDefaults() { +func (s *FileSettings) SetDefaults(isUpdate bool) { if s.EnableFileAttachments == nil { s.EnableFileAttachments = NewBool(true) } @@ -1037,8 +1064,14 @@ func (s *FileSettings) SetDefaults() { s.EnablePublicLink = NewBool(false) } - if s.PublicLinkSalt == nil || len(*s.PublicLinkSalt) == 0 { - s.PublicLinkSalt = NewString(NewRandomString(32)) + if isUpdate { + // When updating an existing configuration, ensure link salt has been specified. + if s.PublicLinkSalt == nil || len(*s.PublicLinkSalt) == 0 { + s.PublicLinkSalt = NewString(NewRandomString(32)) + } + } else { + // When generating a blank configuration, leave link salt empty to be generated on server start. + s.PublicLinkSalt = NewString("") } if s.InitialFont == nil { @@ -1116,7 +1149,7 @@ type EmailSettings struct { LoginButtonTextColor *string } -func (s *EmailSettings) SetDefaults() { +func (s *EmailSettings) SetDefaults(isUpdate bool) { if s.EnableSignUpWithEmail == nil { s.EnableSignUpWithEmail = NewBool(true) } @@ -1186,11 +1219,15 @@ func (s *EmailSettings) SetDefaults() { } if s.SendPushNotifications == nil { - s.SendPushNotifications = NewBool(false) + s.SendPushNotifications = NewBool(!isUpdate) } if s.PushNotificationServer == nil { - s.PushNotificationServer = NewString("") + if isUpdate { + s.PushNotificationServer = NewString("") + } else { + s.PushNotificationServer = NewString(GENERIC_NOTIFICATION_SERVER) + } } if s.PushNotificationContents == nil { @@ -2364,7 +2401,14 @@ func ConfigFromJson(data io.Reader) *Config { return o } +// isUpdate detects a pre-existing config based on whether SiteURL has been changed +func (o *Config) isUpdate() bool { + return o.ServiceSettings.SiteURL != nil +} + func (o *Config) SetDefaults() { + isUpdate := o.isUpdate() + o.LdapSettings.SetDefaults() o.SamlSettings.SetDefaults() @@ -2376,14 +2420,14 @@ func (o *Config) SetDefaults() { } } - o.SqlSettings.SetDefaults() - o.FileSettings.SetDefaults() - o.EmailSettings.SetDefaults() + o.SqlSettings.SetDefaults(isUpdate) + o.FileSettings.SetDefaults(isUpdate) + o.EmailSettings.SetDefaults(isUpdate) o.PrivacySettings.setDefaults() - o.Office365Settings.setDefaults() - o.GitLabSettings.setDefaults() - o.GoogleSettings.setDefaults() - o.ServiceSettings.SetDefaults() + o.Office365Settings.setDefaults(OFFICE365_SETTINGS_DEFAULT_SCOPE, OFFICE365_SETTINGS_DEFAULT_AUTH_ENDPOINT, OFFICE365_SETTINGS_DEFAULT_TOKEN_ENDPOINT, OFFICE365_SETTINGS_DEFAULT_USER_API_ENDPOINT) + o.GitLabSettings.setDefaults("", "", "", "") + o.GoogleSettings.setDefaults(GOOGLE_SETTINGS_DEFAULT_SCOPE, GOOGLE_SETTINGS_DEFAULT_AUTH_ENDPOINT, GOOGLE_SETTINGS_DEFAULT_TOKEN_ENDPOINT, GOOGLE_SETTINGS_DEFAULT_USER_API_ENDPOINT) + o.ServiceSettings.SetDefaults(isUpdate) o.PasswordSettings.SetDefaults() o.TeamSettings.SetDefaults() o.MetricsSettings.SetDefaults() @@ -2517,7 +2561,7 @@ func (ts *TeamSettings) isValid() *AppError { } func (ss *SqlSettings) isValid() *AppError { - if len(*ss.AtRestEncryptKey) < 32 { + if *ss.AtRestEncryptKey != "" && len(*ss.AtRestEncryptKey) < 32 { return NewAppError("Config.IsValid", "model.config.is_valid.encrypt_sql.app_error", nil, "", http.StatusBadRequest) } @@ -2557,7 +2601,7 @@ func (fs *FileSettings) isValid() *AppError { return NewAppError("Config.IsValid", "model.config.is_valid.file_driver.app_error", nil, "", http.StatusBadRequest) } - if len(*fs.PublicLinkSalt) < 32 { + if *fs.PublicLinkSalt != "" && len(*fs.PublicLinkSalt) < 32 { return NewAppError("Config.IsValid", "model.config.is_valid.file_salt.app_error", nil, "", http.StatusBadRequest) } diff --git a/model/config_test.go b/model/config_test.go index 9ea287f00b..04531ad458 100644 --- a/model/config_test.go +++ b/model/config_test.go @@ -593,7 +593,7 @@ func TestListenAddressIsValidated(t *testing.T) { ss := &ServiceSettings{ ListenAddress: NewString(key), } - ss.SetDefaults() + ss.SetDefaults(true) if expected { require.Nil(t, ss.isValid(), fmt.Sprintf("Got an error from '%v'.", key)) } else { diff --git a/services/filesstore/s3store.go b/services/filesstore/s3store.go index 517aa9d9b1..6ba6789ce3 100644 --- a/services/filesstore/s3store.go +++ b/services/filesstore/s3store.go @@ -287,7 +287,7 @@ func CheckMandatoryS3Fields(settings *model.FileSettings) *model.AppError { // if S3 endpoint is not set call the set defaults to set that if settings.AmazonS3Endpoint == nil || len(*settings.AmazonS3Endpoint) == 0 { - settings.SetDefaults() + settings.SetDefaults(true) } return nil diff --git a/testlib/resources.go b/testlib/resources.go index 0880826806..da62ff4375 100644 --- a/testlib/resources.go +++ b/testlib/resources.go @@ -141,16 +141,10 @@ func setupConfig(configDir string) error { return errors.Wrapf(err, "failed to create config directory %s", configDir) } - defaultJson := path.Join(configDir, "default.json") - err = ioutil.WriteFile(defaultJson, []byte(config.ToJson()), 0644) - if err != nil { - return errors.Wrapf(err, "failed to write config to %s", defaultJson) - } - configJson := path.Join(configDir, "config.json") - err = utils.CopyFile(defaultJson, configJson) + err = ioutil.WriteFile(configJson, []byte(config.ToJson()), 0644) if err != nil { - return errors.Wrapf(err, "failed to copy file %s to %s", defaultJson, configJson) + return errors.Wrapf(err, "failed to write config to %s", configJson) } return nil