From f182d196fffc9da89ad63bdbd7bbb2e41da3146e Mon Sep 17 00:00:00 2001 From: George Goldberg Date: Fri, 24 Feb 2017 17:33:59 +0000 Subject: PLT-5070: Server side component of Telemetry. (#5514) --- app/diagnostics.go | 394 ++++++++++++++++++++++++++++++++++++++++ app/security_update_check.go | 125 +++++++++++++ cmd/platform/server.go | 153 ++-------------- config/config.json | 1 - i18n/en.json | 12 ++ model/config.go | 121 ++++++++---- store/sql_channel_store.go | 27 +++ store/sql_channel_store_test.go | 92 ++++++++++ store/sql_user_store.go | 39 ++++ store/sql_user_store_test.go | 67 +++++++ store/store.go | 3 + utils/config.go | 4 +- utils/diagnostic.go | 177 ------------------ 13 files changed, 861 insertions(+), 354 deletions(-) create mode 100644 app/diagnostics.go create mode 100644 app/security_update_check.go delete mode 100644 utils/diagnostic.go diff --git a/app/diagnostics.go b/app/diagnostics.go new file mode 100644 index 000000000..f110f15d3 --- /dev/null +++ b/app/diagnostics.go @@ -0,0 +1,394 @@ +// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package app + +import ( + "runtime" + + "github.com/mattermost/platform/model" + "github.com/mattermost/platform/utils" + "github.com/segmentio/analytics-go" +) + +const ( + SEGMENT_KEY = "fwb7VPbFeQ7SKp3wHm1RzFUuXZudqVok" + + TRACK_CONFIG_SERVICE = "config_service" + TRACK_CONFIG_TEAM = "config_team" + TRACK_CONFIG_SQL = "config_sql" + TRACK_CONFIG_LOG = "config_log" + TRACK_CONFIG_FILE = "config_file" + TRACK_CONFIG_RATE = "config_rate" + TRACK_CONFIG_EMAIL = "config_email" + TRACK_CONFIG_PRIVACY = "config_privacy" + TRACK_CONFIG_OAUTH = "config_oauth" + TRACK_CONFIG_LDAP = "config_ldap" + TRACK_CONFIG_COMPLIANCE = "config_compliance" + TRACK_CONFIG_LOCALIZATION = "config_localization" + TRACK_CONFIG_SAML = "config_saml" + TRACK_CONFIG_PASSWORD = "config_password" + TRACK_CONFIG_CLUSTER = "config_cluster" + TRACK_CONFIG_METRICS = "config_metrics" + TRACK_CONFIG_WEBRTC = "config_webrtc" + TRACK_CONFIG_SUPPORT = "config_support" + TRACK_CONFIG_NATIVEAPP = "config_nativeapp" + TRACK_CONFIG_ANALYTICS = "config_analytics" + + TRACK_ACTIVITY = "activity" + TRACK_LICENSE = "license" + TRACK_SERVER = "server" +) + +var client *analytics.Client + +func SendDailyDiagnostics() { + if *utils.Cfg.LogSettings.EnableDiagnostics { + initDiagnostics() + trackActivity() + trackConfig() + trackLicense() + trackServer() + } +} + +func initDiagnostics() { + if client == nil { + client = analytics.New(SEGMENT_KEY) + client.Identify(&analytics.Identify{ + UserId: utils.CfgDiagnosticId, + }) + } +} + +func SendDiagnostic(event string, properties map[string]interface{}) { + client.Track(&analytics.Track{ + Event: event, + UserId: utils.CfgDiagnosticId, + Properties: properties, + }) +} + +func isDefault(setting interface{}, defaultValue interface{}) bool { + if setting == defaultValue { + return true + } + return false +} + +func trackActivity() { + var userCount int64 + var activeUserCount int64 + var inactiveUserCount int64 + var teamCount int64 + var publicChannelCount int64 + var privateChannelCount int64 + var directChannelCount int64 + var deletedPublicChannelCount int64 + var deletedPrivateChannelCount int64 + var postsCount int64 + + if ucr := <-Srv.Store.User().GetTotalUsersCount(); ucr.Err == nil { + userCount = ucr.Data.(int64) + } + + if ucr := <-Srv.Store.Status().GetTotalActiveUsersCount(); ucr.Err == nil { + activeUserCount = ucr.Data.(int64) + } + + if iucr := <-Srv.Store.Status().GetTotalActiveUsersCount(); iucr.Err == nil { + inactiveUserCount = iucr.Data.(int64) + } + + if tcr := <-Srv.Store.Team().AnalyticsTeamCount(); tcr.Err == nil { + teamCount = tcr.Data.(int64) + } + + if ucc := <-Srv.Store.Channel().AnalyticsTypeCount("", "O"); ucc.Err == nil { + publicChannelCount = ucc.Data.(int64) + } + + if pcc := <-Srv.Store.Channel().AnalyticsTypeCount("", "P"); pcc.Err == nil { + privateChannelCount = pcc.Data.(int64) + } + + if dcc := <-Srv.Store.Channel().AnalyticsTypeCount("", "D"); dcc.Err == nil { + directChannelCount = dcc.Data.(int64) + } + + if duccr := <-Srv.Store.Channel().AnalyticsDeletedTypeCount("", "O"); duccr.Err == nil { + deletedPublicChannelCount = duccr.Data.(int64) + } + + if dpccr := <-Srv.Store.Channel().AnalyticsDeletedTypeCount("", "P"); dpccr.Err == nil { + deletedPrivateChannelCount = dpccr.Data.(int64) + } + + if pcr := <-Srv.Store.Post().AnalyticsPostCount("", false, false); pcr.Err == nil { + postsCount = pcr.Data.(int64) + } + + SendDiagnostic(TRACK_ACTIVITY, map[string]interface{}{ + "registered_users": userCount, + "active_users": activeUserCount, + "registered_inactive_users": inactiveUserCount, + "teams": teamCount, + "public_channels": publicChannelCount, + "private_channels": privateChannelCount, + "direct_message_channels": directChannelCount, + "public_channels_deleted": deletedPublicChannelCount, + "private_channels_deleted": deletedPrivateChannelCount, + "posts": postsCount, + }) +} + +func trackConfig() { + SendDiagnostic(TRACK_CONFIG_SERVICE, map[string]interface{}{ + "web_server_mode": *utils.Cfg.ServiceSettings.WebserverMode, + "enable_security_fix_alert": *utils.Cfg.ServiceSettings.EnableSecurityFixAlert, + "enable_insecure_outgoing_connections": *utils.Cfg.ServiceSettings.EnableInsecureOutgoingConnections, + "enable_incoming_webhooks": utils.Cfg.ServiceSettings.EnableIncomingWebhooks, + "enable_outgoing_webhooks": utils.Cfg.ServiceSettings.EnableOutgoingWebhooks, + "enable_commands": *utils.Cfg.ServiceSettings.EnableCommands, + "enable_only_admin_integrations": *utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations, + "enable_post_username_override": utils.Cfg.ServiceSettings.EnablePostUsernameOverride, + "enable_post_icon_override": utils.Cfg.ServiceSettings.EnablePostIconOverride, + "enable_custom_emoji": *utils.Cfg.ServiceSettings.EnableCustomEmoji, + "restrict_custom_emoji_creation": *utils.Cfg.ServiceSettings.RestrictCustomEmojiCreation, + "enable_testing": utils.Cfg.ServiceSettings.EnableTesting, + "enable_developer": *utils.Cfg.ServiceSettings.EnableDeveloper, + "enable_multifactor_authentication": *utils.Cfg.ServiceSettings.EnableMultifactorAuthentication, + "enforce_multifactor_authentication": *utils.Cfg.ServiceSettings.EnforceMultifactorAuthentication, + "enable_oauth_service_provider": utils.Cfg.ServiceSettings.EnableOAuthServiceProvider, + "connection_security": *utils.Cfg.ServiceSettings.ConnectionSecurity, + "uses_letsencrypt": *utils.Cfg.ServiceSettings.UseLetsEncrypt, + "forward_80_to_443": *utils.Cfg.ServiceSettings.Forward80To443, + "maximum_login_attempts": utils.Cfg.ServiceSettings.MaximumLoginAttempts, + "session_length_web_in_days": *utils.Cfg.ServiceSettings.SessionLengthWebInDays, + "session_length_mobile_in_days": *utils.Cfg.ServiceSettings.SessionLengthMobileInDays, + "session_length_sso_in_days": *utils.Cfg.ServiceSettings.SessionLengthSSOInDays, + "session_cache_in_minutes": *utils.Cfg.ServiceSettings.SessionCacheInMinutes, + "isdefault_site_url": isDefault(*utils.Cfg.ServiceSettings.SiteURL, model.SERVICE_SETTINGS_DEFAULT_SITE_URL), + "isdefault_tls_cert_file": isDefault(*utils.Cfg.ServiceSettings.TLSCertFile, model.SERVICE_SETTINGS_DEFAULT_TLS_CERT_FILE), + "isdefault_tls_key_file": isDefault(*utils.Cfg.ServiceSettings.TLSKeyFile, model.SERVICE_SETTINGS_DEFAULT_TLS_KEY_FILE), + "isdefault_read_timeout": isDefault(*utils.Cfg.ServiceSettings.ReadTimeout, model.SERVICE_SETTINGS_DEFAULT_READ_TIMEOUT), + "isdefault_write_timeout": isDefault(*utils.Cfg.ServiceSettings.WriteTimeout, model.SERVICE_SETTINGS_DEFAULT_WRITE_TIMEOUT), + "isdefault_google_developer_key": isDefault(utils.Cfg.ServiceSettings.GoogleDeveloperKey, ""), + "isdefault_allow_cors_from": isDefault(*utils.Cfg.ServiceSettings.AllowCorsFrom, model.SERVICE_SETTINGS_DEFAULT_ALLOW_CORS_FROM), + "restrict_post_delete": *utils.Cfg.ServiceSettings.RestrictPostDelete, + "allow_edit_post": *utils.Cfg.ServiceSettings.AllowEditPost, + "post_edit_time_limit": *utils.Cfg.ServiceSettings.PostEditTimeLimit, + "enable_user_typing_messages": *utils.Cfg.ServiceSettings.EnableUserTypingMessages, + "time_between_user_typing_updates_milliseconds": *utils.Cfg.ServiceSettings.TimeBetweenUserTypingUpdatesMilliseconds, + "cluster_log_timeout_milliseconds": *utils.Cfg.ServiceSettings.ClusterLogTimeoutMilliseconds, + }) + + SendDiagnostic(TRACK_CONFIG_TEAM, map[string]interface{}{ + "enable_user_creation": utils.Cfg.TeamSettings.EnableUserCreation, + "enable_team_creation": utils.Cfg.TeamSettings.EnableTeamCreation, + "restrict_team_invite": *utils.Cfg.TeamSettings.RestrictTeamInvite, + "restrict_public_channel_creation": *utils.Cfg.TeamSettings.RestrictPublicChannelCreation, + "restrict_private_channel_creation": *utils.Cfg.TeamSettings.RestrictPrivateChannelCreation, + "restrict_public_channel_management": *utils.Cfg.TeamSettings.RestrictPublicChannelManagement, + "restrict_private_channel_management": *utils.Cfg.TeamSettings.RestrictPrivateChannelManagement, + "restrict_public_channel_deletion": *utils.Cfg.TeamSettings.RestrictPublicChannelDeletion, + "restrict_private_channel_deletion": *utils.Cfg.TeamSettings.RestrictPrivateChannelDeletion, + "enable_open_server": *utils.Cfg.TeamSettings.EnableOpenServer, + "enable_custom_brand": *utils.Cfg.TeamSettings.EnableCustomBrand, + "restrict_direct_message": *utils.Cfg.TeamSettings.RestrictDirectMessage, + "max_notifications_per_channel": *utils.Cfg.TeamSettings.MaxNotificationsPerChannel, + "max_users_per_team": utils.Cfg.TeamSettings.MaxUsersPerTeam, + "max_channels_per_team": *utils.Cfg.TeamSettings.MaxChannelsPerTeam, + "isdefault_site_name": isDefault(utils.Cfg.TeamSettings.SiteName, "Mattermost"), + "isdefault_custom_brand_text": isDefault(*utils.Cfg.TeamSettings.CustomBrandText, model.TEAM_SETTINGS_DEFAULT_CUSTOM_BRAND_TEXT), + "isdefault_custom_description_text": isDefault(*utils.Cfg.TeamSettings.CustomDescriptionText, model.TEAM_SETTINGS_DEFAULT_CUSTOM_DESCRIPTION_TEXT), + "isdefault_user_status_away_timeout": isDefault(*utils.Cfg.TeamSettings.UserStatusAwayTimeout, model.TEAM_SETTINGS_DEFAULT_USER_STATUS_AWAY_TIMEOUT), + }) + + SendDiagnostic(TRACK_CONFIG_SQL, map[string]interface{}{ + "driver_name": utils.Cfg.SqlSettings.DriverName, + "trace": utils.Cfg.SqlSettings.Trace, + "max_idle_conns": utils.Cfg.SqlSettings.MaxIdleConns, + "max_open_conns": utils.Cfg.SqlSettings.MaxOpenConns, + "data_source_replicas": len(utils.Cfg.SqlSettings.DataSourceReplicas), + }) + + SendDiagnostic(TRACK_CONFIG_LOG, map[string]interface{}{ + "enable_console": utils.Cfg.LogSettings.EnableConsole, + "console_level": utils.Cfg.LogSettings.ConsoleLevel, + "enable_file": utils.Cfg.LogSettings.EnableFile, + "file_level": utils.Cfg.LogSettings.FileLevel, + "enable_webhook_debugging": utils.Cfg.LogSettings.EnableWebhookDebugging, + "isdefault_file_format": isDefault(utils.Cfg.LogSettings.FileFormat, ""), + "isdefault_file_location": isDefault(utils.Cfg.LogSettings.FileLocation, ""), + }) + + SendDiagnostic(TRACK_CONFIG_PASSWORD, map[string]interface{}{ + "minimum_length": *utils.Cfg.PasswordSettings.MinimumLength, + "lowercase": *utils.Cfg.PasswordSettings.Lowercase, + "number": *utils.Cfg.PasswordSettings.Number, + "uppercase": *utils.Cfg.PasswordSettings.Uppercase, + "symbol": *utils.Cfg.PasswordSettings.Symbol, + }) + + SendDiagnostic(TRACK_CONFIG_FILE, map[string]interface{}{ + "enable_public_links": utils.Cfg.FileSettings.EnablePublicLink, + "driver_name": utils.Cfg.FileSettings.DriverName, + "amazon_s3_ssl": *utils.Cfg.FileSettings.AmazonS3SSL, + "thumbnail_width": utils.Cfg.FileSettings.ThumbnailWidth, + "thumbnail_height": utils.Cfg.FileSettings.ThumbnailHeight, + "preview_width": utils.Cfg.FileSettings.PreviewWidth, + "preview_height": utils.Cfg.FileSettings.PreviewHeight, + "profile_width": utils.Cfg.FileSettings.ProfileWidth, + "profile_height": utils.Cfg.FileSettings.ProfileHeight, + "max_file_size": *utils.Cfg.FileSettings.MaxFileSize, + }) + + SendDiagnostic(TRACK_CONFIG_EMAIL, map[string]interface{}{ + "enable_sign_up_with_email": utils.Cfg.EmailSettings.EnableSignUpWithEmail, + "enable_sign_in_with_email": *utils.Cfg.EmailSettings.EnableSignInWithEmail, + "enable_sign_in_with_username": *utils.Cfg.EmailSettings.EnableSignInWithUsername, + "require_email_verification": utils.Cfg.EmailSettings.RequireEmailVerification, + "send_email_notifications": utils.Cfg.EmailSettings.SendEmailNotifications, + "connection_security": utils.Cfg.EmailSettings.ConnectionSecurity, + "send_push_notifications": *utils.Cfg.EmailSettings.SendPushNotifications, + "push_notification_contents": *utils.Cfg.EmailSettings.PushNotificationContents, + "enable_email_batching": *utils.Cfg.EmailSettings.EnableEmailBatching, + "email_batching_buffer_size": *utils.Cfg.EmailSettings.EmailBatchingBufferSize, + "email_batching_interval": *utils.Cfg.EmailSettings.EmailBatchingInterval, + "isdefault_feedback_name": isDefault(utils.Cfg.EmailSettings.FeedbackName, ""), + "isdefault_feedback_email": isDefault(utils.Cfg.EmailSettings.FeedbackEmail, ""), + "isdefault_feedback_organization": isDefault(*utils.Cfg.EmailSettings.FeedbackOrganization, model.EMAIL_SETTINGS_DEFAULT_FEEDBACK_ORGANIZATION), + }) + + SendDiagnostic(TRACK_CONFIG_RATE, map[string]interface{}{ + "enable_rate_limiter": *utils.Cfg.RateLimitSettings.Enable, + "vary_by_remote_address": utils.Cfg.RateLimitSettings.VaryByRemoteAddr, + "per_sec": utils.Cfg.RateLimitSettings.PerSec, + "max_burst": *utils.Cfg.RateLimitSettings.MaxBurst, + "memory_store_size": utils.Cfg.RateLimitSettings.MemoryStoreSize, + "isdefault_vary_by_header": isDefault(utils.Cfg.RateLimitSettings.VaryByHeader, ""), + }) + + SendDiagnostic(TRACK_CONFIG_PRIVACY, map[string]interface{}{ + "show_email_address": utils.Cfg.PrivacySettings.ShowEmailAddress, + "show_full_name": utils.Cfg.PrivacySettings.ShowFullName, + }) + + SendDiagnostic(TRACK_CONFIG_OAUTH, map[string]interface{}{ + "enable_gitlab": utils.Cfg.GitLabSettings.Enable, + "enable_google": utils.Cfg.GoogleSettings.Enable, + "enable_office365": utils.Cfg.Office365Settings.Enable, + }) + + SendDiagnostic(TRACK_CONFIG_SUPPORT, map[string]interface{}{ + "isdefault_terms_of_service_link": isDefault(*utils.Cfg.SupportSettings.TermsOfServiceLink, model.SUPPORT_SETTINGS_DEFAULT_TERMS_OF_SERVICE_LINK), + "isdefault_privacy_policy_link": isDefault(*utils.Cfg.SupportSettings.PrivacyPolicyLink, model.SUPPORT_SETTINGS_DEFAULT_PRIVACY_POLICY_LINK), + "isdefault_about_link": isDefault(*utils.Cfg.SupportSettings.AboutLink, model.SUPPORT_SETTINGS_DEFAULT_ABOUT_LINK), + "isdefault_help_link": isDefault(*utils.Cfg.SupportSettings.HelpLink, model.SUPPORT_SETTINGS_DEFAULT_HELP_LINK), + "isdefault_report_a_problem_link": isDefault(*utils.Cfg.SupportSettings.ReportAProblemLink, model.SUPPORT_SETTINGS_DEFAULT_REPORT_A_PROBLEM_LINK), + "isdefault_support_email": isDefault(*utils.Cfg.SupportSettings.SupportEmail, model.SUPPORT_SETTINGS_DEFAULT_SUPPORT_EMAIL), + }) + + SendDiagnostic(TRACK_CONFIG_LDAP, map[string]interface{}{ + "enable": *utils.Cfg.LdapSettings.Enable, + "connection_security": *utils.Cfg.LdapSettings.ConnectionSecurity, + "skip_certificate_verification": *utils.Cfg.LdapSettings.SkipCertificateVerification, + "sync_interval_minutes": *utils.Cfg.LdapSettings.SyncIntervalMinutes, + "query_timeout": *utils.Cfg.LdapSettings.QueryTimeout, + "max_page_size": *utils.Cfg.LdapSettings.MaxPageSize, + "isdefault_first_name_attribute": isDefault(*utils.Cfg.LdapSettings.FirstNameAttribute, model.LDAP_SETTINGS_DEFAULT_FIRST_NAME_ATTRIBUTE), + "isdefault_last_name_attribute": isDefault(*utils.Cfg.LdapSettings.LastNameAttribute, model.LDAP_SETTINGS_DEFAULT_LAST_NAME_ATTRIBUTE), + "isdefault_email_attribute": isDefault(*utils.Cfg.LdapSettings.EmailAttribute, model.LDAP_SETTINGS_DEFAULT_EMAIL_ATTRIBUTE), + "isdefault_username_attribute": isDefault(*utils.Cfg.LdapSettings.UsernameAttribute, model.LDAP_SETTINGS_DEFAULT_USERNAME_ATTRIBUTE), + "isdefault_nickname_attribute": isDefault(*utils.Cfg.LdapSettings.NicknameAttribute, model.LDAP_SETTINGS_DEFAULT_NICKNAME_ATTRIBUTE), + "isdefault_id_attribute": isDefault(*utils.Cfg.LdapSettings.IdAttribute, model.LDAP_SETTINGS_DEFAULT_ID_ATTRIBUTE), + "isdefault_position_attribute": isDefault(*utils.Cfg.LdapSettings.PositionAttribute, model.LDAP_SETTINGS_DEFAULT_POSITION_ATTRIBUTE), + "isdefault_login_field_name": isDefault(*utils.Cfg.LdapSettings.LoginFieldName, model.LDAP_SETTINGS_DEFAULT_LOGIN_FIELD_NAME), + }) + + SendDiagnostic(TRACK_CONFIG_COMPLIANCE, map[string]interface{}{ + "enable": *utils.Cfg.ComplianceSettings.Enable, + "enable_daily": *utils.Cfg.ComplianceSettings.EnableDaily, + }) + + SendDiagnostic(TRACK_CONFIG_LOCALIZATION, map[string]interface{}{ + "default_server_locale": *utils.Cfg.LocalizationSettings.DefaultServerLocale, + "default_client_locale": *utils.Cfg.LocalizationSettings.DefaultClientLocale, + "available_locales": *utils.Cfg.LocalizationSettings.AvailableLocales, + }) + + SendDiagnostic(TRACK_CONFIG_SAML, map[string]interface{}{ + "enable": *utils.Cfg.SamlSettings.Enable, + "verify": *utils.Cfg.SamlSettings.Verify, + "encrypt": *utils.Cfg.SamlSettings.Encrypt, + "isdefault_first_name_attribute": isDefault(*utils.Cfg.SamlSettings.FirstNameAttribute, model.SAML_SETTINGS_DEFAULT_FIRST_NAME_ATTRIBUTE), + "isdefault_last_name_attribute": isDefault(*utils.Cfg.SamlSettings.LastNameAttribute, model.SAML_SETTINGS_DEFAULT_LAST_NAME_ATTRIBUTE), + "isdefault_email_attribute": isDefault(*utils.Cfg.SamlSettings.EmailAttribute, model.SAML_SETTINGS_DEFAULT_EMAIL_ATTRIBUTE), + "isdefault_username_attribute": isDefault(*utils.Cfg.SamlSettings.UsernameAttribute, model.SAML_SETTINGS_DEFAULT_USERNAME_ATTRIBUTE), + "isdefault_nickname_attribute": isDefault(*utils.Cfg.SamlSettings.NicknameAttribute, model.SAML_SETTINGS_DEFAULT_NICKNAME_ATTRIBUTE), + "isdefault_locale_attribute": isDefault(*utils.Cfg.SamlSettings.LocaleAttribute, model.SAML_SETTINGS_DEFAULT_LOCALE_ATTRIBUTE), + "isdefault_position_attribute": isDefault(*utils.Cfg.SamlSettings.PositionAttribute, model.SAML_SETTINGS_DEFAULT_POSITION_ATTRIBUTE), + "isdefault_login_button_text": isDefault(*utils.Cfg.SamlSettings.LoginButtonText, model.USER_AUTH_SERVICE_SAML_TEXT), + }) + + SendDiagnostic(TRACK_CONFIG_CLUSTER, map[string]interface{}{ + "enable": *utils.Cfg.ClusterSettings.Enable, + }) + + SendDiagnostic(TRACK_CONFIG_METRICS, map[string]interface{}{ + "enable": *utils.Cfg.MetricsSettings.Enable, + "block_profile_rate": *utils.Cfg.MetricsSettings.BlockProfileRate, + }) + + SendDiagnostic(TRACK_CONFIG_NATIVEAPP, map[string]interface{}{ + "isdefault_app_download_link": isDefault(*utils.Cfg.NativeAppSettings.AppDownloadLink, model.NATIVEAPP_SETTINGS_DEFAULT_APP_DOWNLOAD_LINK), + "isdefault_android_app_download_link": isDefault(*utils.Cfg.NativeAppSettings.AndroidAppDownloadLink, model.NATIVEAPP_SETTINGS_DEFAULT_ANDROID_APP_DOWNLOAD_LINK), + "isdefault_iosapp_download_link": isDefault(*utils.Cfg.NativeAppSettings.IosAppDownloadLink, model.NATIVEAPP_SETTINGS_DEFAULT_IOS_APP_DOWNLOAD_LINK), + }) + + SendDiagnostic(TRACK_CONFIG_WEBRTC, map[string]interface{}{ + "enable": *utils.Cfg.WebrtcSettings.Enable, + "isdefault_stun_uri": isDefault(*utils.Cfg.WebrtcSettings.StunURI, model.WEBRTC_SETTINGS_DEFAULT_STUN_URI), + "isdefault_turn_uri": isDefault(*utils.Cfg.WebrtcSettings.TurnURI, model.WEBRTC_SETTINGS_DEFAULT_TURN_URI), + }) + + SendDiagnostic(TRACK_CONFIG_ANALYTICS, map[string]interface{}{ + "isdefault_max_users_for_statistics": isDefault(*utils.Cfg.AnalyticsSettings.MaxUsersForStatistics, model.ANALYTICS_SETTINGS_DEFAULT_MAX_USERS_FOR_STATISTICS), + }) +} + +func trackLicense() { + if utils.IsLicensed { + data := map[string]interface{}{ + "name": utils.License.Customer.Name, + "company": utils.License.Customer.Company, + "issued": utils.License.IssuedAt, + "start": utils.License.StartsAt, + "expire": utils.License.ExpiresAt, + "users": *utils.License.Features.Users, + } + + features := utils.License.Features.ToMap() + for featureName, featureValue := range features { + data["feature_"+featureName] = featureValue + } + + SendDiagnostic(TRACK_LICENSE, data) + } +} + +func trackServer() { + data := map[string]interface{}{ + "edition": model.BuildEnterpriseReady, + "version": model.CurrentVersion, + "database_type": utils.Cfg.SqlSettings.DriverName, + "operating_system": runtime.GOOS, + } + + if scr := <-Srv.Store.User().AnalyticsGetSystemAdminCount(); scr.Err == nil { + data["system_admins"] = scr.Data.(int64) + } + + SendDiagnostic(TRACK_SERVER, data) +} diff --git a/app/security_update_check.go b/app/security_update_check.go new file mode 100644 index 000000000..9ad6572c1 --- /dev/null +++ b/app/security_update_check.go @@ -0,0 +1,125 @@ +// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package app + +import ( + "io/ioutil" + "net/http" + "net/url" + "runtime" + "strconv" + + l4g "github.com/alecthomas/log4go" + "github.com/mattermost/platform/model" + "github.com/mattermost/platform/utils" +) + +const ( + SECURITY_URL = "https://d7zmvsa9e04kk.cloudfront.net" + SECURITY_UPDATE_PERIOD = 86400000 // 24 hours in milliseconds. + + PROP_SECURITY_ID = "id" + PROP_SECURITY_CATEGORY = "c" + VAL_SECURITY_CATEGORY_DEFAULT = "d" + PROP_SECURITY_BUILD = "b" + PROP_SECURITY_ENTERPRISE_READY = "be" + PROP_SECURITY_DATABASE = "db" + PROP_SECURITY_OS = "os" + PROP_SECURITY_USER_COUNT = "uc" + PROP_SECURITY_TEAM_COUNT = "tc" + PROP_SECURITY_ACTIVE_USER_COUNT = "auc" + PROP_SECURITY_UNIT_TESTS = "ut" +) + +func DoSecurityUpdateCheck() { + if *utils.Cfg.ServiceSettings.EnableSecurityFixAlert { + if result := <-Srv.Store.System().Get(); result.Err == nil { + props := result.Data.(model.StringMap) + lastSecurityTime, _ := strconv.ParseInt(props[model.SYSTEM_LAST_SECURITY_TIME], 10, 0) + currentTime := model.GetMillis() + + if (currentTime - lastSecurityTime) > SECURITY_UPDATE_PERIOD { + l4g.Debug(utils.T("mattermost.security_checks.debug")) + + v := url.Values{} + + v.Set(PROP_SECURITY_ID, utils.CfgDiagnosticId) + v.Set(PROP_SECURITY_BUILD, model.CurrentVersion+"."+model.BuildNumber) + v.Set(PROP_SECURITY_ENTERPRISE_READY, model.BuildEnterpriseReady) + v.Set(PROP_SECURITY_DATABASE, utils.Cfg.SqlSettings.DriverName) + v.Set(PROP_SECURITY_OS, runtime.GOOS) + v.Set(PROP_SECURITY_CATEGORY, VAL_SECURITY_CATEGORY_DEFAULT) + + if len(props[model.SYSTEM_RAN_UNIT_TESTS]) > 0 { + v.Set(PROP_SECURITY_UNIT_TESTS, "1") + } else { + v.Set(PROP_SECURITY_UNIT_TESTS, "0") + } + + systemSecurityLastTime := &model.System{Name: model.SYSTEM_LAST_SECURITY_TIME, Value: strconv.FormatInt(currentTime, 10)} + if lastSecurityTime == 0 { + <-Srv.Store.System().Save(systemSecurityLastTime) + } else { + <-Srv.Store.System().Update(systemSecurityLastTime) + } + + if ucr := <-Srv.Store.User().GetTotalUsersCount(); ucr.Err == nil { + v.Set(PROP_SECURITY_USER_COUNT, strconv.FormatInt(ucr.Data.(int64), 10)) + } + + if ucr := <-Srv.Store.Status().GetTotalActiveUsersCount(); ucr.Err == nil { + v.Set(PROP_SECURITY_ACTIVE_USER_COUNT, strconv.FormatInt(ucr.Data.(int64), 10)) + } + + if tcr := <-Srv.Store.Team().AnalyticsTeamCount(); tcr.Err == nil { + v.Set(PROP_SECURITY_TEAM_COUNT, strconv.FormatInt(tcr.Data.(int64), 10)) + } + + res, err := http.Get(SECURITY_URL + "/security?" + v.Encode()) + if err != nil { + l4g.Error(utils.T("mattermost.security_info.error")) + return + } + + bulletins := model.SecurityBulletinsFromJson(res.Body) + ioutil.ReadAll(res.Body) + res.Body.Close() + + for _, bulletin := range bulletins { + if bulletin.AppliesToVersion == model.CurrentVersion { + if props["SecurityBulletin_"+bulletin.Id] == "" { + if results := <-Srv.Store.User().GetSystemAdminProfiles(); results.Err != nil { + l4g.Error(utils.T("mattermost.system_admins.error")) + return + } else { + users := results.Data.(map[string]*model.User) + + resBody, err := http.Get(SECURITY_URL + "/bulletins/" + bulletin.Id) + if err != nil { + l4g.Error(utils.T("mattermost.security_bulletin.error")) + return + } + + body, err := ioutil.ReadAll(resBody.Body) + res.Body.Close() + if err != nil || resBody.StatusCode != 200 { + l4g.Error(utils.T("mattermost.security_bulletin_read.error")) + return + } + + for _, user := range users { + l4g.Info(utils.T("mattermost.send_bulletin.info"), bulletin.Id, user.Email) + utils.SendMail(user.Email, utils.T("mattermost.bulletin.subject"), string(body)) + } + } + + bulletinSeen := &model.System{Name: "SecurityBulletin_" + bulletin.Id, Value: bulletin.Id} + <-Srv.Store.System().Save(bulletinSeen) + } + } + } + } + } + } +} diff --git a/cmd/platform/server.go b/cmd/platform/server.go index 1aade29dd..00cdb1429 100644 --- a/cmd/platform/server.go +++ b/cmd/platform/server.go @@ -4,13 +4,8 @@ package main import ( - "io/ioutil" - "net/http" - "net/url" "os" "os/signal" - "runtime" - "strconv" "syscall" "time" @@ -101,7 +96,9 @@ func runServer(configFileLocation string) { } setDiagnosticId() - go runSecurityAndDiagnosticsJob() + utils.RegenerateClientConfig() + go runSecurityJob() + go runDiagnosticsJob() if complianceI := einterfaces.GetComplianceInterface(); complianceI != nil { complianceI.StartComplianceDailyJob() @@ -132,9 +129,14 @@ func runServer(configFileLocation string) { app.StopServer() } -func runSecurityAndDiagnosticsJob() { - doSecurityAndDiagnostics() - model.CreateRecurringTask("Security and Diagnostics", doSecurityAndDiagnostics, time.Hour*4) +func runSecurityJob() { + doSecurity() + model.CreateRecurringTask("Security", doSecurity, time.Hour*4) +} + +func runDiagnosticsJob() { + doDiagnostics() + model.CreateRecurringTask("Diagnostics", doDiagnostics, time.Hour*24) } func resetStatuses() { @@ -158,135 +160,12 @@ func setDiagnosticId() { } } -func doSecurityAndDiagnostics() { - if *utils.Cfg.ServiceSettings.EnableSecurityFixAlert { - if result := <-app.Srv.Store.System().Get(); result.Err == nil { - props := result.Data.(model.StringMap) - lastSecurityTime, _ := strconv.ParseInt(props[model.SYSTEM_LAST_SECURITY_TIME], 10, 0) - currentTime := model.GetMillis() - - if (currentTime - lastSecurityTime) > 1000*60*60*24*1 { - l4g.Debug(utils.T("mattermost.security_checks.debug")) - - v := url.Values{} - - v.Set(utils.PROP_DIAGNOSTIC_ID, utils.CfgDiagnosticId) - v.Set(utils.PROP_DIAGNOSTIC_BUILD, model.CurrentVersion+"."+model.BuildNumber) - v.Set(utils.PROP_DIAGNOSTIC_ENTERPRISE_READY, model.BuildEnterpriseReady) - v.Set(utils.PROP_DIAGNOSTIC_DATABASE, utils.Cfg.SqlSettings.DriverName) - v.Set(utils.PROP_DIAGNOSTIC_OS, runtime.GOOS) - v.Set(utils.PROP_DIAGNOSTIC_CATEGORY, utils.VAL_DIAGNOSTIC_CATEGORY_DEFAULT) - - if len(props[model.SYSTEM_RAN_UNIT_TESTS]) > 0 { - v.Set(utils.PROP_DIAGNOSTIC_UNIT_TESTS, "1") - } else { - v.Set(utils.PROP_DIAGNOSTIC_UNIT_TESTS, "0") - } - - systemSecurityLastTime := &model.System{Name: model.SYSTEM_LAST_SECURITY_TIME, Value: strconv.FormatInt(currentTime, 10)} - if lastSecurityTime == 0 { - <-app.Srv.Store.System().Save(systemSecurityLastTime) - } else { - <-app.Srv.Store.System().Update(systemSecurityLastTime) - } - - if ucr := <-app.Srv.Store.User().GetTotalUsersCount(); ucr.Err == nil { - v.Set(utils.PROP_DIAGNOSTIC_USER_COUNT, strconv.FormatInt(ucr.Data.(int64), 10)) - } - - if ucr := <-app.Srv.Store.Status().GetTotalActiveUsersCount(); ucr.Err == nil { - v.Set(utils.PROP_DIAGNOSTIC_ACTIVE_USER_COUNT, strconv.FormatInt(ucr.Data.(int64), 10)) - } - - if tcr := <-app.Srv.Store.Team().AnalyticsTeamCount(); tcr.Err == nil { - v.Set(utils.PROP_DIAGNOSTIC_TEAM_COUNT, strconv.FormatInt(tcr.Data.(int64), 10)) - } - - res, err := http.Get(utils.DIAGNOSTIC_URL + "/security?" + v.Encode()) - if err != nil { - l4g.Error(utils.T("mattermost.security_info.error")) - return - } - - bulletins := model.SecurityBulletinsFromJson(res.Body) - ioutil.ReadAll(res.Body) - res.Body.Close() - - for _, bulletin := range bulletins { - if bulletin.AppliesToVersion == model.CurrentVersion { - if props["SecurityBulletin_"+bulletin.Id] == "" { - if results := <-app.Srv.Store.User().GetSystemAdminProfiles(); results.Err != nil { - l4g.Error(utils.T("mattermost.system_admins.error")) - return - } else { - users := results.Data.(map[string]*model.User) - - resBody, err := http.Get(utils.DIAGNOSTIC_URL + "/bulletins/" + bulletin.Id) - if err != nil { - l4g.Error(utils.T("mattermost.security_bulletin.error")) - return - } - - body, err := ioutil.ReadAll(resBody.Body) - res.Body.Close() - if err != nil || resBody.StatusCode != 200 { - l4g.Error(utils.T("mattermost.security_bulletin_read.error")) - return - } - - for _, user := range users { - l4g.Info(utils.T("mattermost.send_bulletin.info"), bulletin.Id, user.Email) - utils.SendMail(user.Email, utils.T("mattermost.bulletin.subject"), string(body)) - } - } - - bulletinSeen := &model.System{Name: "SecurityBulletin_" + bulletin.Id, Value: bulletin.Id} - <-app.Srv.Store.System().Save(bulletinSeen) - } - } - } - } - } - } - - if *utils.Cfg.LogSettings.EnableDiagnostics { - utils.SendGeneralDiagnostics() - sendServerDiagnostics() - } +func doSecurity() { + app.DoSecurityUpdateCheck() } -func sendServerDiagnostics() { - var userCount int64 - var activeUserCount int64 - var teamCount int64 - - if ucr := <-app.Srv.Store.User().GetTotalUsersCount(); ucr.Err == nil { - userCount = ucr.Data.(int64) - } - - if ucr := <-app.Srv.Store.Status().GetTotalActiveUsersCount(); ucr.Err == nil { - activeUserCount = ucr.Data.(int64) - } - - if tcr := <-app.Srv.Store.Team().AnalyticsTeamCount(); tcr.Err == nil { - teamCount = tcr.Data.(int64) +func doDiagnostics() { + if *utils.Cfg.LogSettings.EnableDiagnostics { + app.SendDailyDiagnostics() } - - utils.SendDiagnostic(utils.TRACK_ACTIVITY, map[string]interface{}{ - "registered_users": userCount, - "active_users": activeUserCount, - "teams": teamCount, - }) - - edition := model.BuildEnterpriseReady - version := model.CurrentVersion - database := utils.Cfg.SqlSettings.DriverName - operatingSystem := runtime.GOOS - - utils.SendDiagnostic(utils.TRACK_VERSION, map[string]interface{}{ - "edition": edition, - "version": version, - "database": database, - "operating_system": operatingSystem, - }) } diff --git a/config/config.json b/config/config.json index 9ff502435..3c4ed9bf3 100644 --- a/config/config.json +++ b/config/config.json @@ -11,7 +11,6 @@ "ReadTimeout": 300, "WriteTimeout": 300, "MaximumLoginAttempts": 10, - "SegmentDeveloperKey": "", "GoogleDeveloperKey": "", "EnableOAuthServiceProvider": false, "EnableIncomingWebhooks": true, diff --git a/i18n/en.json b/i18n/en.json index bfeb9bc89..c4256851f 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -4483,6 +4483,10 @@ "id": "store.sql_channel.analytics_type_count.app_error", "translation": "We couldn't get channel type counts" }, + { + "id": "store.sql_channel.analytics_deleted_type_count.app_error", + "translation": "We couldn't get deleted channel type counts" + }, { "id": "store.sql_channel.check_open_channel_permissions.app_error", "translation": "We couldn't check the permissions" @@ -5303,6 +5307,10 @@ "id": "store.sql_user.analytics_unique_user_count.app_error", "translation": "We couldn't get the unique user count" }, + { + "id": "store.sql_user.analytics_get_system_admin_count.app_error", + "translation": "We couldn't get the system admin count" + }, { "id": "store.sql_user.get.app_error", "translation": "We encountered an error finding the account" @@ -5347,6 +5355,10 @@ "id": "store.sql_user.get_total_users_count.app_error", "translation": "We could not count the users" }, + { + "id": "store.sql_user.analytics_get_inactive_users_count.app_error", + "translation": "We could not count the inactive users" + }, { "id": "store.sql_user.get_unread_count.app_error", "translation": "We could not get the unread message count for the user" diff --git a/model/config.go b/model/config.go index 2401f0291..f0ac1a52d 100644 --- a/model/config.go +++ b/model/config.go @@ -61,6 +61,52 @@ const ( EMAIL_BATCHING_INTERVAL = 30 SITENAME_MAX_LENGTH = 30 + + SERVICE_SETTINGS_DEFAULT_SITE_URL = "" + SERVICE_SETTINGS_DEFAULT_TLS_CERT_FILE = "" + SERVICE_SETTINGS_DEFAULT_TLS_KEY_FILE = "" + SERVICE_SETTINGS_DEFAULT_READ_TIMEOUT = 300 + SERVICE_SETTINGS_DEFAULT_WRITE_TIMEOUT = 300 + SERVICE_SETTINGS_DEFAULT_ALLOW_CORS_FROM = "" + + TEAM_SETTINGS_DEFAULT_CUSTOM_BRAND_TEXT = "" + TEAM_SETTINGS_DEFAULT_CUSTOM_DESCRIPTION_TEXT = "" + TEAM_SETTINGS_DEFAULT_USER_STATUS_AWAY_TIMEOUT = 300 + + EMAIL_SETTINGS_DEFAULT_FEEDBACK_ORGANIZATION = "" + + SUPPORT_SETTINGS_DEFAULT_TERMS_OF_SERVICE_LINK = "https://about.mattermost.com/default-terms/" + SUPPORT_SETTINGS_DEFAULT_PRIVACY_POLICY_LINK = "" + SUPPORT_SETTINGS_DEFAULT_ABOUT_LINK = "" + SUPPORT_SETTINGS_DEFAULT_HELP_LINK = "" + SUPPORT_SETTINGS_DEFAULT_REPORT_A_PROBLEM_LINK = "" + SUPPORT_SETTINGS_DEFAULT_SUPPORT_EMAIL = "feedback@mattermost.com" + + LDAP_SETTINGS_DEFAULT_FIRST_NAME_ATTRIBUTE = "" + LDAP_SETTINGS_DEFAULT_LAST_NAME_ATTRIBUTE = "" + LDAP_SETTINGS_DEFAULT_EMAIL_ATTRIBUTE = "" + LDAP_SETTINGS_DEFAULT_USERNAME_ATTRIBUTE = "" + LDAP_SETTINGS_DEFAULT_NICKNAME_ATTRIBUTE = "" + LDAP_SETTINGS_DEFAULT_ID_ATTRIBUTE = "" + LDAP_SETTINGS_DEFAULT_POSITION_ATTRIBUTE = "" + LDAP_SETTINGS_DEFAULT_LOGIN_FIELD_NAME = "" + + SAML_SETTINGS_DEFAULT_FIRST_NAME_ATTRIBUTE = "" + SAML_SETTINGS_DEFAULT_LAST_NAME_ATTRIBUTE = "" + SAML_SETTINGS_DEFAULT_EMAIL_ATTRIBUTE = "" + SAML_SETTINGS_DEFAULT_USERNAME_ATTRIBUTE = "" + SAML_SETTINGS_DEFAULT_NICKNAME_ATTRIBUTE = "" + SAML_SETTINGS_DEFAULT_LOCALE_ATTRIBUTE = "" + SAML_SETTINGS_DEFAULT_POSITION_ATTRIBUTE = "" + + NATIVEAPP_SETTINGS_DEFAULT_APP_DOWNLOAD_LINK = "https://about.mattermost.com/downloads/" + NATIVEAPP_SETTINGS_DEFAULT_ANDROID_APP_DOWNLOAD_LINK = "https://about.mattermost.com/mattermost-android-app/" + NATIVEAPP_SETTINGS_DEFAULT_IOS_APP_DOWNLOAD_LINK = "https://about.mattermost.com/mattermost-ios-app/" + + WEBRTC_SETTINGS_DEFAULT_STUN_URI = "" + WEBRTC_SETTINGS_DEFAULT_TURN_URI = "" + + ANALYTICS_SETTINGS_DEFAULT_MAX_USERS_FOR_STATISTICS = 2500 ) type ServiceSettings struct { @@ -75,7 +121,6 @@ type ServiceSettings struct { ReadTimeout *int WriteTimeout *int MaximumLoginAttempts int - SegmentDeveloperKey string GoogleDeveloperKey string EnableOAuthServiceProvider bool EnableIncomingWebhooks bool @@ -447,7 +492,7 @@ func (o *Config) SetDefaults() { if o.ServiceSettings.SiteURL == nil { o.ServiceSettings.SiteURL = new(string) - *o.ServiceSettings.SiteURL = "" + *o.ServiceSettings.SiteURL = SERVICE_SETTINGS_DEFAULT_SITE_URL } if o.ServiceSettings.EnableDeveloper == nil { @@ -507,12 +552,12 @@ func (o *Config) SetDefaults() { if o.TeamSettings.CustomBrandText == nil { o.TeamSettings.CustomBrandText = new(string) - *o.TeamSettings.CustomBrandText = "" + *o.TeamSettings.CustomBrandText = TEAM_SETTINGS_DEFAULT_CUSTOM_BRAND_TEXT } if o.TeamSettings.CustomDescriptionText == nil { o.TeamSettings.CustomDescriptionText = new(string) - *o.TeamSettings.CustomDescriptionText = "" + *o.TeamSettings.CustomDescriptionText = TEAM_SETTINGS_DEFAULT_CUSTOM_DESCRIPTION_TEXT } if o.TeamSettings.EnableOpenServer == nil { @@ -566,7 +611,7 @@ func (o *Config) SetDefaults() { if o.TeamSettings.UserStatusAwayTimeout == nil { o.TeamSettings.UserStatusAwayTimeout = new(int64) - *o.TeamSettings.UserStatusAwayTimeout = 300 + *o.TeamSettings.UserStatusAwayTimeout = TEAM_SETTINGS_DEFAULT_USER_STATUS_AWAY_TIMEOUT } if o.TeamSettings.MaxChannelsPerTeam == nil { @@ -611,7 +656,7 @@ func (o *Config) SetDefaults() { if o.EmailSettings.FeedbackOrganization == nil { o.EmailSettings.FeedbackOrganization = new(string) - *o.EmailSettings.FeedbackOrganization = "" + *o.EmailSettings.FeedbackOrganization = EMAIL_SETTINGS_DEFAULT_FEEDBACK_ORGANIZATION } if o.EmailSettings.EnableEmailBatching == nil { @@ -635,7 +680,7 @@ func (o *Config) SetDefaults() { if o.SupportSettings.TermsOfServiceLink == nil { o.SupportSettings.TermsOfServiceLink = new(string) - *o.SupportSettings.TermsOfServiceLink = "https://about.mattermost.com/default-terms/" + *o.SupportSettings.TermsOfServiceLink = SUPPORT_SETTINGS_DEFAULT_TERMS_OF_SERVICE_LINK } if !IsSafeLink(o.SupportSettings.PrivacyPolicyLink) { @@ -644,7 +689,7 @@ func (o *Config) SetDefaults() { if o.SupportSettings.PrivacyPolicyLink == nil { o.SupportSettings.PrivacyPolicyLink = new(string) - *o.SupportSettings.PrivacyPolicyLink = "" + *o.SupportSettings.PrivacyPolicyLink = SUPPORT_SETTINGS_DEFAULT_PRIVACY_POLICY_LINK } if !IsSafeLink(o.SupportSettings.AboutLink) { @@ -653,7 +698,7 @@ func (o *Config) SetDefaults() { if o.SupportSettings.AboutLink == nil { o.SupportSettings.AboutLink = new(string) - *o.SupportSettings.AboutLink = "" + *o.SupportSettings.AboutLink = SUPPORT_SETTINGS_DEFAULT_ABOUT_LINK } if !IsSafeLink(o.SupportSettings.HelpLink) { @@ -662,7 +707,7 @@ func (o *Config) SetDefaults() { if o.SupportSettings.HelpLink == nil { o.SupportSettings.HelpLink = new(string) - *o.SupportSettings.HelpLink = "" + *o.SupportSettings.HelpLink = SUPPORT_SETTINGS_DEFAULT_HELP_LINK } if !IsSafeLink(o.SupportSettings.ReportAProblemLink) { @@ -671,12 +716,12 @@ func (o *Config) SetDefaults() { if o.SupportSettings.ReportAProblemLink == nil { o.SupportSettings.ReportAProblemLink = new(string) - *o.SupportSettings.ReportAProblemLink = "" + *o.SupportSettings.ReportAProblemLink = SUPPORT_SETTINGS_DEFAULT_REPORT_A_PROBLEM_LINK } if o.SupportSettings.SupportEmail == nil { o.SupportSettings.SupportEmail = new(string) - *o.SupportSettings.SupportEmail = "feedback@mattermost.com" + *o.SupportSettings.SupportEmail = SUPPORT_SETTINGS_DEFAULT_SUPPORT_EMAIL } if o.LdapSettings.Enable == nil { @@ -721,37 +766,37 @@ func (o *Config) SetDefaults() { if o.LdapSettings.FirstNameAttribute == nil { o.LdapSettings.FirstNameAttribute = new(string) - *o.LdapSettings.FirstNameAttribute = "" + *o.LdapSettings.FirstNameAttribute = LDAP_SETTINGS_DEFAULT_FIRST_NAME_ATTRIBUTE } if o.LdapSettings.LastNameAttribute == nil { o.LdapSettings.LastNameAttribute = new(string) - *o.LdapSettings.LastNameAttribute = "" + *o.LdapSettings.LastNameAttribute = LDAP_SETTINGS_DEFAULT_LAST_NAME_ATTRIBUTE } if o.LdapSettings.EmailAttribute == nil { o.LdapSettings.EmailAttribute = new(string) - *o.LdapSettings.EmailAttribute = "" + *o.LdapSettings.EmailAttribute = LDAP_SETTINGS_DEFAULT_EMAIL_ATTRIBUTE } if o.LdapSettings.UsernameAttribute == nil { o.LdapSettings.UsernameAttribute = new(string) - *o.LdapSettings.UsernameAttribute = "" + *o.LdapSettings.UsernameAttribute = LDAP_SETTINGS_DEFAULT_USERNAME_ATTRIBUTE } if o.LdapSettings.NicknameAttribute == nil { o.LdapSettings.NicknameAttribute = new(string) - *o.LdapSettings.NicknameAttribute = "" + *o.LdapSettings.NicknameAttribute = LDAP_SETTINGS_DEFAULT_NICKNAME_ATTRIBUTE } if o.LdapSettings.IdAttribute == nil { o.LdapSettings.IdAttribute = new(string) - *o.LdapSettings.IdAttribute = "" + *o.LdapSettings.IdAttribute = LDAP_SETTINGS_DEFAULT_ID_ATTRIBUTE } if o.LdapSettings.PositionAttribute == nil { o.LdapSettings.PositionAttribute = new(string) - *o.LdapSettings.PositionAttribute = "" + *o.LdapSettings.PositionAttribute = LDAP_SETTINGS_DEFAULT_POSITION_ATTRIBUTE } if o.LdapSettings.SyncIntervalMinutes == nil { @@ -776,7 +821,7 @@ func (o *Config) SetDefaults() { if o.LdapSettings.LoginFieldName == nil { o.LdapSettings.LoginFieldName = new(string) - *o.LdapSettings.LoginFieldName = "" + *o.LdapSettings.LoginFieldName = LDAP_SETTINGS_DEFAULT_LOGIN_FIELD_NAME } if o.ServiceSettings.SessionLengthWebInDays == nil { @@ -821,7 +866,7 @@ func (o *Config) SetDefaults() { if o.ServiceSettings.AllowCorsFrom == nil { o.ServiceSettings.AllowCorsFrom = new(string) - *o.ServiceSettings.AllowCorsFrom = "" + *o.ServiceSettings.AllowCorsFrom = SERVICE_SETTINGS_DEFAULT_ALLOW_CORS_FROM } if o.ServiceSettings.WebserverMode == nil { @@ -882,7 +927,7 @@ func (o *Config) SetDefaults() { if o.AnalyticsSettings.MaxUsersForStatistics == nil { o.AnalyticsSettings.MaxUsersForStatistics = new(int) - *o.AnalyticsSettings.MaxUsersForStatistics = 2500 + *o.AnalyticsSettings.MaxUsersForStatistics = ANALYTICS_SETTINGS_DEFAULT_MAX_USERS_FOR_STATISTICS } if o.ComplianceSettings.Enable == nil { @@ -972,52 +1017,52 @@ func (o *Config) SetDefaults() { if o.SamlSettings.FirstNameAttribute == nil { o.SamlSettings.FirstNameAttribute = new(string) - *o.SamlSettings.FirstNameAttribute = "" + *o.SamlSettings.FirstNameAttribute = SAML_SETTINGS_DEFAULT_FIRST_NAME_ATTRIBUTE } if o.SamlSettings.LastNameAttribute == nil { o.SamlSettings.LastNameAttribute = new(string) - *o.SamlSettings.LastNameAttribute = "" + *o.SamlSettings.LastNameAttribute = SAML_SETTINGS_DEFAULT_LAST_NAME_ATTRIBUTE } if o.SamlSettings.EmailAttribute == nil { o.SamlSettings.EmailAttribute = new(string) - *o.SamlSettings.EmailAttribute = "" + *o.SamlSettings.EmailAttribute = SAML_SETTINGS_DEFAULT_EMAIL_ATTRIBUTE } if o.SamlSettings.UsernameAttribute == nil { o.SamlSettings.UsernameAttribute = new(string) - *o.SamlSettings.UsernameAttribute = "" + *o.SamlSettings.UsernameAttribute = SAML_SETTINGS_DEFAULT_USERNAME_ATTRIBUTE } if o.SamlSettings.NicknameAttribute == nil { o.SamlSettings.NicknameAttribute = new(string) - *o.SamlSettings.NicknameAttribute = "" + *o.SamlSettings.NicknameAttribute = SAML_SETTINGS_DEFAULT_NICKNAME_ATTRIBUTE } if o.SamlSettings.PositionAttribute == nil { o.SamlSettings.PositionAttribute = new(string) - *o.SamlSettings.PositionAttribute = "" + *o.SamlSettings.PositionAttribute = SAML_SETTINGS_DEFAULT_POSITION_ATTRIBUTE } if o.SamlSettings.LocaleAttribute == nil { o.SamlSettings.LocaleAttribute = new(string) - *o.SamlSettings.LocaleAttribute = "" + *o.SamlSettings.LocaleAttribute = SAML_SETTINGS_DEFAULT_LOCALE_ATTRIBUTE } if o.NativeAppSettings.AppDownloadLink == nil { o.NativeAppSettings.AppDownloadLink = new(string) - *o.NativeAppSettings.AppDownloadLink = "https://about.mattermost.com/downloads/" + *o.NativeAppSettings.AppDownloadLink = NATIVEAPP_SETTINGS_DEFAULT_APP_DOWNLOAD_LINK } if o.NativeAppSettings.AndroidAppDownloadLink == nil { o.NativeAppSettings.AndroidAppDownloadLink = new(string) - *o.NativeAppSettings.AndroidAppDownloadLink = "https://about.mattermost.com/mattermost-android-app/" + *o.NativeAppSettings.AndroidAppDownloadLink = NATIVEAPP_SETTINGS_DEFAULT_ANDROID_APP_DOWNLOAD_LINK } if o.NativeAppSettings.IosAppDownloadLink == nil { o.NativeAppSettings.IosAppDownloadLink = new(string) - *o.NativeAppSettings.IosAppDownloadLink = "https://about.mattermost.com/mattermost-ios-app/" + *o.NativeAppSettings.IosAppDownloadLink = NATIVEAPP_SETTINGS_DEFAULT_IOS_APP_DOWNLOAD_LINK } if o.RateLimitSettings.Enable == nil { @@ -1037,12 +1082,12 @@ func (o *Config) SetDefaults() { if o.ServiceSettings.TLSKeyFile == nil { o.ServiceSettings.TLSKeyFile = new(string) - *o.ServiceSettings.TLSKeyFile = "" + *o.ServiceSettings.TLSKeyFile = SERVICE_SETTINGS_DEFAULT_TLS_KEY_FILE } if o.ServiceSettings.TLSCertFile == nil { o.ServiceSettings.TLSCertFile = new(string) - *o.ServiceSettings.TLSCertFile = "" + *o.ServiceSettings.TLSCertFile = SERVICE_SETTINGS_DEFAULT_TLS_CERT_FILE } if o.ServiceSettings.UseLetsEncrypt == nil { @@ -1057,12 +1102,12 @@ func (o *Config) SetDefaults() { if o.ServiceSettings.ReadTimeout == nil { o.ServiceSettings.ReadTimeout = new(int) - *o.ServiceSettings.ReadTimeout = 300 + *o.ServiceSettings.ReadTimeout = SERVICE_SETTINGS_DEFAULT_READ_TIMEOUT } if o.ServiceSettings.WriteTimeout == nil { o.ServiceSettings.WriteTimeout = new(int) - *o.ServiceSettings.WriteTimeout = 300 + *o.ServiceSettings.WriteTimeout = SERVICE_SETTINGS_DEFAULT_WRITE_TIMEOUT } if o.ServiceSettings.Forward80To443 == nil { @@ -1387,12 +1432,12 @@ func (o *Config) defaultWebrtcSettings() { if o.WebrtcSettings.StunURI == nil { o.WebrtcSettings.StunURI = new(string) - *o.WebrtcSettings.StunURI = "" + *o.WebrtcSettings.StunURI = WEBRTC_SETTINGS_DEFAULT_STUN_URI } if o.WebrtcSettings.TurnURI == nil { o.WebrtcSettings.TurnURI = new(string) - *o.WebrtcSettings.TurnURI = "" + *o.WebrtcSettings.TurnURI = WEBRTC_SETTINGS_DEFAULT_TURN_URI } if o.WebrtcSettings.TurnUsername == nil { diff --git a/store/sql_channel_store.go b/store/sql_channel_store.go index e7501ae69..068692074 100644 --- a/store/sql_channel_store.go +++ b/store/sql_channel_store.go @@ -1362,6 +1362,32 @@ func (s SqlChannelStore) AnalyticsTypeCount(teamId string, channelType string) S return storeChannel } +func (s SqlChannelStore) AnalyticsDeletedTypeCount(teamId string, channelType string) StoreChannel { + storeChannel := make(StoreChannel, 1) + + go func() { + result := StoreResult{} + + query := "SELECT COUNT(Id) AS Value FROM Channels WHERE Type = :ChannelType AND DeleteAt > 0" + + if len(teamId) > 0 { + query += " AND TeamId = :TeamId" + } + + v, err := s.GetReplica().SelectInt(query, map[string]interface{}{"TeamId": teamId, "ChannelType": channelType}) + if err != nil { + result.Err = model.NewLocAppError("SqlChannelStore.AnalyticsDeletedTypeCount", "store.sql_channel.analytics_deleted_type_count.app_error", nil, err.Error()) + } else { + result.Data = v + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + func (s SqlChannelStore) ExtraUpdateByUser(userId string, time int64) StoreChannel { storeChannel := make(StoreChannel, 1) @@ -1546,6 +1572,7 @@ func (s SqlChannelStore) GetMembersByIds(channelId string, userIds []string) Sto result.Err = model.NewLocAppError("SqlChannelStore.GetMembersByIds", "store.sql_channel.get_members_by_ids.app_error", nil, "channelId="+channelId+" "+err.Error()) } else { result.Data = &members + } storeChannel <- result diff --git a/store/sql_channel_store_test.go b/store/sql_channel_store_test.go index 3075498f7..a43b97706 100644 --- a/store/sql_channel_store_test.go +++ b/store/sql_channel_store_test.go @@ -1401,3 +1401,95 @@ func TestChannelStoreGetMembersByIds(t *testing.T) { t.Fatal("empty user ids - should have failed") } } + +func TestChannelStoreAnalyticsDeletedTypeCount(t *testing.T) { + Setup() + + o1 := model.Channel{} + o1.TeamId = model.NewId() + o1.DisplayName = "ChannelA" + o1.Name = "a" + model.NewId() + "b" + o1.Type = model.CHANNEL_OPEN + Must(store.Channel().Save(&o1)) + + o2 := model.Channel{} + o2.TeamId = model.NewId() + o2.DisplayName = "Channel2" + o2.Name = "a" + model.NewId() + "b" + o2.Type = model.CHANNEL_OPEN + Must(store.Channel().Save(&o2)) + + p3 := model.Channel{} + p3.TeamId = model.NewId() + p3.DisplayName = "Channel3" + p3.Name = "a" + model.NewId() + "b" + p3.Type = model.CHANNEL_PRIVATE + Must(store.Channel().Save(&p3)) + + u1 := &model.User{} + u1.Email = model.NewId() + u1.Nickname = model.NewId() + Must(store.User().Save(u1)) + + u2 := &model.User{} + u2.Email = model.NewId() + u2.Nickname = model.NewId() + Must(store.User().Save(u2)) + + var d4 *model.Channel + if result := <-store.Channel().CreateDirectChannel(u1.Id, u2.Id); result.Err != nil { + t.Fatalf(result.Err.Error()) + } else { + d4 = result.Data.(*model.Channel) + } + + var openStartCount int64 + if result := <-store.Channel().AnalyticsDeletedTypeCount("", "O"); result.Err != nil { + t.Fatal(result.Err.Error()) + } else { + openStartCount = result.Data.(int64) + } + + var privateStartCount int64 + if result := <-store.Channel().AnalyticsDeletedTypeCount("", "P"); result.Err != nil { + t.Fatal(result.Err.Error()) + } else { + privateStartCount = result.Data.(int64) + } + + var directStartCount int64 + if result := <-store.Channel().AnalyticsDeletedTypeCount("", "D"); result.Err != nil { + t.Fatal(result.Err.Error()) + } else { + directStartCount = result.Data.(int64) + } + + Must(store.Channel().Delete(o1.Id, model.GetMillis())) + Must(store.Channel().Delete(o2.Id, model.GetMillis())) + Must(store.Channel().Delete(p3.Id, model.GetMillis())) + Must(store.Channel().Delete(d4.Id, model.GetMillis())) + + if result := <-store.Channel().AnalyticsDeletedTypeCount("", "O"); result.Err != nil { + t.Fatal(result.Err.Error()) + } else { + if result.Data.(int64) != openStartCount+2 { + t.Fatalf("Wrong open channel deleted count.") + } + } + + if result := <-store.Channel().AnalyticsDeletedTypeCount("", "P"); result.Err != nil { + t.Fatal(result.Err.Error()) + } else { + if result.Data.(int64) != privateStartCount+1 { + t.Fatalf("Wrong private channel deleted count.") + } + } + + if result := <-store.Channel().AnalyticsDeletedTypeCount("", "D"); result.Err != nil { + t.Fatal(result.Err.Error()) + } else { + if result.Data.(int64) != directStartCount+1 { + t.Fatalf("Wrong direct channel deleted count.") + } + } +} diff --git a/store/sql_user_store.go b/store/sql_user_store.go index 68c1ffec7..a2a9c8347 100644 --- a/store/sql_user_store.go +++ b/store/sql_user_store.go @@ -1438,3 +1438,42 @@ func (us SqlUserStore) performSearch(searchQuery string, term string, options ma return result } + +func (us SqlUserStore) AnalyticsGetInactiveUsersCount() StoreChannel { + storeChannel := make(StoreChannel, 1) + + go func() { + result := StoreResult{} + + if count, err := us.GetReplica().SelectInt("SELECT COUNT(Id) FROM Users WHERE DeleteAt > 0"); err != nil { + result.Err = model.NewLocAppError("SqlUserStore.AnalyticsGetInactiveUsersCount", "store.sql_user.analytics_get_inactive_users_count.app_error", nil, err.Error()) + } else { + result.Data = count + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + +func (us SqlUserStore) AnalyticsGetSystemAdminCount() StoreChannel { + + storeChannel := make(StoreChannel, 1) + + go func() { + result := StoreResult{} + + if count, err := us.GetReplica().SelectInt("SELECT count(*) FROM Users WHERE Roles LIKE :Roles and DeleteAt = 0", map[string]interface{}{"Roles": "%system_admin%"}); err != nil { + result.Err = model.NewLocAppError("SqlUserStore.AnalyticsGetSystemAdminCount", "store.sql_user.analytics_get_system_admin_count.app_error", nil, err.Error()) + } else { + result.Data = count + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} diff --git a/store/sql_user_store_test.go b/store/sql_user_store_test.go index f7236659b..c46a32ec1 100644 --- a/store/sql_user_store_test.go +++ b/store/sql_user_store_test.go @@ -1477,3 +1477,70 @@ func TestUserStoreSearch(t *testing.T) { } } } + +func TestUserStoreAnalyticsGetInactiveUsersCount(t *testing.T) { + Setup() + + u1 := &model.User{} + u1.Email = model.NewId() + Must(store.User().Save(u1)) + + var count int64 + + if result := <-store.User().AnalyticsGetInactiveUsersCount(); result.Err != nil { + t.Fatal(result.Err) + } else { + count = result.Data.(int64) + } + + u2 := &model.User{} + u2.Email = model.NewId() + u2.DeleteAt = model.GetMillis() + Must(store.User().Save(u2)) + + if result := <-store.User().AnalyticsGetInactiveUsersCount(); result.Err != nil { + t.Fatal(result.Err) + } else { + newCount := result.Data.(int64) + if count != newCount-1 { + t.Fatal("Expected 1 more inactive users but found otherwise.", count, newCount) + } + } +} + +func TestUserStoreAnalyticsGetSystemAdminCount(t *testing.T) { + Setup() + + var countBefore int64 + if result := <-store.User().AnalyticsGetSystemAdminCount(); result.Err != nil { + t.Fatal(result.Err) + } else { + countBefore = result.Data.(int64) + } + + u1 := model.User{} + u1.Email = model.NewId() + u1.Username = model.NewId() + u1.Roles = "system_user system_admin" + + u2 := model.User{} + u2.Email = model.NewId() + u2.Username = model.NewId() + + if err := (<-store.User().Save(&u1)).Err; err != nil { + t.Fatal("couldn't save user", err) + } + + if err := (<-store.User().Save(&u2)).Err; err != nil { + t.Fatal("couldn't save user", err) + } + + if result := <-store.User().AnalyticsGetSystemAdminCount(); result.Err != nil { + t.Fatal(result.Err) + } else { + // We expect to find 1 more system admin than there was at the start of this test function. + if count := result.Data.(int64); count != countBefore+1 { + t.Fatal("Did not get the expected number of system admins. Expected, got: ", countBefore+1, count) + } + } +} diff --git a/store/store.go b/store/store.go index 752b6cc28..34a709568 100644 --- a/store/store.go +++ b/store/store.go @@ -129,6 +129,7 @@ type ChannelStore interface { SearchInTeam(teamId string, term string) StoreChannel SearchMore(userId string, teamId string, term string) StoreChannel GetMembersByIds(channelId string, userIds []string) StoreChannel + AnalyticsDeletedTypeCount(teamId string, channelType string) StoreChannel } type PostStore interface { @@ -193,6 +194,8 @@ type UserStore interface { Search(teamId string, term string, options map[string]bool) StoreChannel SearchInChannel(channelId string, term string, options map[string]bool) StoreChannel SearchNotInChannel(teamId string, channelId string, term string, options map[string]bool) StoreChannel + AnalyticsGetInactiveUsersCount() StoreChannel + AnalyticsGetSystemAdminCount() StoreChannel } type SessionStore interface { diff --git a/utils/config.go b/utils/config.go index a1f647b3f..0908f2297 100644 --- a/utils/config.go +++ b/utils/config.go @@ -256,7 +256,6 @@ func getClientConfig(c *model.Config) map[string]string { props["RestrictPrivateChannelDeletion"] = *c.TeamSettings.RestrictPrivateChannelDeletion props["EnableOAuthServiceProvider"] = strconv.FormatBool(c.ServiceSettings.EnableOAuthServiceProvider) - props["SegmentDeveloperKey"] = c.ServiceSettings.SegmentDeveloperKey props["GoogleDeveloperKey"] = c.ServiceSettings.GoogleDeveloperKey props["EnableIncomingWebhooks"] = strconv.FormatBool(c.ServiceSettings.EnableIncomingWebhooks) props["EnableOutgoingWebhooks"] = strconv.FormatBool(c.ServiceSettings.EnableOutgoingWebhooks) @@ -315,6 +314,9 @@ func getClientConfig(c *model.Config) map[string]string { props["TimeBetweenUserTypingUpdatesMilliseconds"] = strconv.FormatInt(*c.ServiceSettings.TimeBetweenUserTypingUpdatesMilliseconds, 10) props["EnableUserTypingMessages"] = strconv.FormatBool(*c.ServiceSettings.EnableUserTypingMessages) + props["DiagnosticId"] = CfgDiagnosticId + props["DiagnosticsEnabled"] = strconv.FormatBool(*c.LogSettings.EnableDiagnostics) + if IsLicensed { if *License.Features.CustomBrand { props["EnableCustomBrand"] = strconv.FormatBool(*c.TeamSettings.EnableCustomBrand) diff --git a/utils/diagnostic.go b/utils/diagnostic.go deleted file mode 100644 index 525dfd794..000000000 --- a/utils/diagnostic.go +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -package utils - -import "github.com/segmentio/analytics-go" - -const ( - DIAGNOSTIC_URL = "https://d7zmvsa9e04kk.cloudfront.net" - SEGMENT_KEY = "ua1qQtmgOZWIM23YjD842tQAsN7Ydi5X" - - PROP_DIAGNOSTIC_ID = "id" - PROP_DIAGNOSTIC_CATEGORY = "c" - VAL_DIAGNOSTIC_CATEGORY_DEFAULT = "d" - PROP_DIAGNOSTIC_BUILD = "b" - PROP_DIAGNOSTIC_ENTERPRISE_READY = "be" - PROP_DIAGNOSTIC_DATABASE = "db" - PROP_DIAGNOSTIC_OS = "os" - PROP_DIAGNOSTIC_USER_COUNT = "uc" - PROP_DIAGNOSTIC_TEAM_COUNT = "tc" - PROP_DIAGNOSTIC_ACTIVE_USER_COUNT = "auc" - PROP_DIAGNOSTIC_UNIT_TESTS = "ut" - - TRACK_CONFIG_SERVICE = "service" - TRACK_CONFIG_TEAM = "team" - TRACK_CONFIG_SQL = "sql" - TRACK_CONFIG_LOG = "log" - TRACK_CONFIG_FILE = "file" - TRACK_CONFIG_RATE = "rate" - TRACK_CONFIG_EMAIL = "email" - TRACK_CONFIG_PRIVACY = "privacy" - TRACK_CONFIG_OAUTH = "oauth" - TRACK_CONFIG_LDAP = "ldap" - TRACK_CONFIG_COMPLIANCE = "compliance" - TRACK_CONFIG_LOCALIZATION = "localization" - TRACK_CONFIG_SAML = "saml" - - TRACK_LICENSE = "license" - TRACK_ACTIVITY = "activity" - TRACK_VERSION = "version" -) - -var client *analytics.Client - -func SendGeneralDiagnostics() { - if *Cfg.LogSettings.EnableDiagnostics { - initDiagnostics() - trackConfig() - trackLicense() - } -} - -func initDiagnostics() { - if client == nil { - client = analytics.New(SEGMENT_KEY) - client.Identify(&analytics.Identify{ - UserId: CfgDiagnosticId, - }) - } -} - -func SendDiagnostic(event string, properties map[string]interface{}) { - client.Track(&analytics.Track{ - Event: event, - UserId: CfgDiagnosticId, - Properties: properties, - }) -} - -func trackConfig() { - SendDiagnostic(TRACK_CONFIG_SERVICE, map[string]interface{}{ - "web_server_mode": *Cfg.ServiceSettings.WebserverMode, - "enable_security_fix_alert": *Cfg.ServiceSettings.EnableSecurityFixAlert, - "enable_insecure_outgoing_connections": *Cfg.ServiceSettings.EnableInsecureOutgoingConnections, - "enable_incoming_webhooks": Cfg.ServiceSettings.EnableIncomingWebhooks, - "enable_outgoing_webhooks": Cfg.ServiceSettings.EnableOutgoingWebhooks, - "enable_commands": *Cfg.ServiceSettings.EnableCommands, - "enable_only_admin_integrations": *Cfg.ServiceSettings.EnableOnlyAdminIntegrations, - "enable_post_username_override": Cfg.ServiceSettings.EnablePostUsernameOverride, - "enable_post_icon_override": Cfg.ServiceSettings.EnablePostIconOverride, - "enable_custom_emoji": *Cfg.ServiceSettings.EnableCustomEmoji, - "restrict_custom_emoji_creation": *Cfg.ServiceSettings.RestrictCustomEmojiCreation, - "enable_testing": Cfg.ServiceSettings.EnableTesting, - "enable_developer": *Cfg.ServiceSettings.EnableDeveloper, - "restrict_post_delete": *Cfg.ServiceSettings.RestrictPostDelete, - "allow_edit_post": *Cfg.ServiceSettings.AllowEditPost, - "post_edit_time_limit": *Cfg.ServiceSettings.PostEditTimeLimit, - }) - - SendDiagnostic(TRACK_CONFIG_TEAM, map[string]interface{}{ - "enable_user_creation": Cfg.TeamSettings.EnableUserCreation, - "enable_team_creation": Cfg.TeamSettings.EnableTeamCreation, - "restrict_team_invite": *Cfg.TeamSettings.RestrictTeamInvite, - "restrict_public_channel_management": *Cfg.TeamSettings.RestrictPublicChannelManagement, - "restrict_private_channel_management": *Cfg.TeamSettings.RestrictPrivateChannelManagement, - "enable_open_server": *Cfg.TeamSettings.EnableOpenServer, - "enable_custom_brand": *Cfg.TeamSettings.EnableCustomBrand, - }) - - SendDiagnostic(TRACK_CONFIG_SQL, map[string]interface{}{ - "driver_name": Cfg.SqlSettings.DriverName, - }) - - SendDiagnostic(TRACK_CONFIG_LOG, map[string]interface{}{ - "enable_console": Cfg.LogSettings.EnableConsole, - "console_level": Cfg.LogSettings.ConsoleLevel, - "enable_file": Cfg.LogSettings.EnableFile, - "file_level": Cfg.LogSettings.FileLevel, - "enable_webhook_debugging": Cfg.LogSettings.EnableWebhookDebugging, - }) - - SendDiagnostic(TRACK_CONFIG_FILE, map[string]interface{}{ - "enable_public_links": Cfg.FileSettings.EnablePublicLink, - }) - - SendDiagnostic(TRACK_CONFIG_RATE, map[string]interface{}{ - "enable_rate_limiter": *Cfg.RateLimitSettings.Enable, - "vary_by_remote_address": Cfg.RateLimitSettings.VaryByRemoteAddr, - }) - - SendDiagnostic(TRACK_CONFIG_EMAIL, map[string]interface{}{ - "enable_sign_up_with_email": Cfg.EmailSettings.EnableSignUpWithEmail, - "enable_sign_in_with_email": *Cfg.EmailSettings.EnableSignInWithEmail, - "enable_sign_in_with_username": *Cfg.EmailSettings.EnableSignInWithUsername, - "require_email_verification": Cfg.EmailSettings.RequireEmailVerification, - "send_email_notifications": Cfg.EmailSettings.SendEmailNotifications, - "connection_security": Cfg.EmailSettings.ConnectionSecurity, - "send_push_notifications": *Cfg.EmailSettings.SendPushNotifications, - "push_notification_contents": *Cfg.EmailSettings.PushNotificationContents, - }) - - SendDiagnostic(TRACK_CONFIG_PRIVACY, map[string]interface{}{ - "show_email_address": Cfg.PrivacySettings.ShowEmailAddress, - "show_full_name": Cfg.PrivacySettings.ShowFullName, - }) - - SendDiagnostic(TRACK_CONFIG_OAUTH, map[string]interface{}{ - "gitlab": Cfg.GitLabSettings.Enable, - "google": Cfg.GoogleSettings.Enable, - "office365": Cfg.Office365Settings.Enable, - }) - - SendDiagnostic(TRACK_CONFIG_LDAP, map[string]interface{}{ - "enable": *Cfg.LdapSettings.Enable, - "connection_security": *Cfg.LdapSettings.ConnectionSecurity, - "skip_certificate_verification": *Cfg.LdapSettings.SkipCertificateVerification, - }) - - SendDiagnostic(TRACK_CONFIG_COMPLIANCE, map[string]interface{}{ - "enable": *Cfg.ComplianceSettings.Enable, - "enable_daily": *Cfg.ComplianceSettings.EnableDaily, - }) - - SendDiagnostic(TRACK_CONFIG_LOCALIZATION, map[string]interface{}{ - "default_server_locale": *Cfg.LocalizationSettings.DefaultServerLocale, - "default_client_locale": *Cfg.LocalizationSettings.DefaultClientLocale, - "available_locales": *Cfg.LocalizationSettings.AvailableLocales, - }) - - SendDiagnostic(TRACK_CONFIG_SAML, map[string]interface{}{ - "enable": *Cfg.SamlSettings.Enable, - }) -} - -func trackLicense() { - if IsLicensed { - SendDiagnostic(TRACK_LICENSE, map[string]interface{}{ - "name": License.Customer.Name, - "company": License.Customer.Company, - "issued": License.IssuedAt, - "start": License.StartsAt, - "expire": License.ExpiresAt, - "users": *License.Features.Users, - "features": License.Features.ToMap(), - }) - } -} -- cgit v1.2.3-1-g7c22