diff --git a/api/admin.go b/api/admin.go index 2167868e09..cd1e5d2dee 100644 --- a/api/admin.go +++ b/api/admin.go @@ -104,6 +104,8 @@ func saveConfig(c *Context, w http.ResponseWriter, r *http.Request) { return } + cfg.SetDefaults() + if err := cfg.IsValid(); err != nil { c.Err = err return diff --git a/config/config.json b/config/config.json index 919737da7e..8ef1513503 100644 --- a/config/config.json +++ b/config/config.json @@ -8,7 +8,8 @@ "EnableIncomingWebhooks": true, "EnablePostUsernameOverride": false, "EnablePostIconOverride": false, - "EnableTesting": false + "EnableTesting": false, + "EnableSecurityFixAlert": true }, "TeamSettings": { "SiteName": "Mattermost", @@ -77,8 +78,7 @@ }, "PrivacySettings": { "ShowEmailAddress": true, - "ShowFullName": true, - "EnableSecurityFixAlert": true + "ShowFullName": true }, "GitLabSettings": { "Enable": false, diff --git a/docker/1.1/config_docker.json b/docker/1.1/config_docker.json index ab5b0a7bec..653b6ffd74 100644 --- a/docker/1.1/config_docker.json +++ b/docker/1.1/config_docker.json @@ -8,7 +8,8 @@ "EnableIncomingWebhooks": true, "EnablePostUsernameOverride": false, "EnablePostIconOverride": false, - "EnableTesting": false + "EnableTesting": false, + "EnableSecurityFixAlert": true }, "TeamSettings": { "SiteName": "Mattermost", @@ -77,8 +78,7 @@ }, "PrivacySettings": { "ShowEmailAddress": true, - "ShowFullName": true, - "EnableSecurityFixAlert": true + "ShowFullName": true }, "GitLabSettings": { "Enable": false, diff --git a/docker/dev/config_docker.json b/docker/dev/config_docker.json index ab5b0a7bec..653b6ffd74 100644 --- a/docker/dev/config_docker.json +++ b/docker/dev/config_docker.json @@ -8,7 +8,8 @@ "EnableIncomingWebhooks": true, "EnablePostUsernameOverride": false, "EnablePostIconOverride": false, - "EnableTesting": false + "EnableTesting": false, + "EnableSecurityFixAlert": true }, "TeamSettings": { "SiteName": "Mattermost", @@ -77,8 +78,7 @@ }, "PrivacySettings": { "ShowEmailAddress": true, - "ShowFullName": true, - "EnableSecurityFixAlert": true + "ShowFullName": true }, "GitLabSettings": { "Enable": false, diff --git a/docker/local/config_docker.json b/docker/local/config_docker.json index ab5b0a7bec..653b6ffd74 100644 --- a/docker/local/config_docker.json +++ b/docker/local/config_docker.json @@ -8,7 +8,8 @@ "EnableIncomingWebhooks": true, "EnablePostUsernameOverride": false, "EnablePostIconOverride": false, - "EnableTesting": false + "EnableTesting": false, + "EnableSecurityFixAlert": true }, "TeamSettings": { "SiteName": "Mattermost", @@ -77,8 +78,7 @@ }, "PrivacySettings": { "ShowEmailAddress": true, - "ShowFullName": true, - "EnableSecurityFixAlert": true + "ShowFullName": true }, "GitLabSettings": { "Enable": false, diff --git a/mattermost.go b/mattermost.go index 6c0f0a1bfa..b8a44d26e5 100644 --- a/mattermost.go +++ b/mattermost.go @@ -81,28 +81,28 @@ func main() { func securityAndDiagnosticsJob() { go func() { for { - if utils.Cfg.PrivacySettings.EnableSecurityFixAlert && model.IsOfficalBuild() { + if *utils.Cfg.ServiceSettings.EnableSecurityFixAlert { // && model.IsOfficalBuild() { if result := <-api.Srv.Store.System().Get(); result.Err == nil { props := result.Data.(model.StringMap) lastSecurityTime, _ := strconv.ParseInt(props["LastSecurityTime"], 10, 0) currentTime := model.GetMillis() - id := props["DiagnosticId"] - if len(id) == 0 { - id = model.NewId() - systemId := &model.System{Name: "DiagnosticId", Value: id} - <-api.Srv.Store.System().Save(systemId) - } - - v := url.Values{} - v.Set(utils.PROP_DIAGNOSTIC_ID, id) - v.Set(utils.PROP_DIAGNOSTIC_BUILD, model.CurrentVersion+"."+model.BuildNumber) - 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 (currentTime - lastSecurityTime) > 1000*60*60*24*1 { - l4g.Info("Checking for security update from Mattermost") + l4g.Debug("Checking for security update from Mattermost") + + id := props["DiagnosticId"] + if len(id) == 0 { + id = model.NewId() + systemId := &model.System{Name: "DiagnosticId", Value: id} + <-api.Srv.Store.System().Save(systemId) + } + + v := url.Values{} + v.Set(utils.PROP_DIAGNOSTIC_ID, id) + v.Set(utils.PROP_DIAGNOSTIC_BUILD, model.CurrentVersion+"."+model.BuildNumber) + 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) systemSecurityLastTime := &model.System{Name: "LastSecurityTime", Value: strconv.FormatInt(currentTime, 10)} if lastSecurityTime == 0 { @@ -111,6 +111,14 @@ func securityAndDiagnosticsJob() { <-api.Srv.Store.System().Update(systemSecurityLastTime) } + if ucr := <-api.Srv.Store.User().GetTotalUsersCount(); ucr.Err == nil { + v.Set(utils.PROP_DIAGNOSTIC_USER_COUNT, strconv.FormatInt(ucr.Data.(int64), 10)) + } + + if ucr := <-api.Srv.Store.User().GetTotalActiveUsersCount(); ucr.Err == nil { + v.Set(utils.PROP_DIAGNOSTIC_ACTIVE_USER_COUNT, strconv.FormatInt(ucr.Data.(int64), 10)) + } + res, err := http.Get(utils.DIAGNOSTIC_URL + "/security?" + v.Encode()) if err != nil { l4g.Error("Failed to get security update information from Mattermost.") diff --git a/model/config.go b/model/config.go index e4b99ad4a9..8a11b7bb72 100644 --- a/model/config.go +++ b/model/config.go @@ -32,6 +32,7 @@ type ServiceSettings struct { EnablePostUsernameOverride bool EnablePostIconOverride bool EnableTesting bool + EnableSecurityFixAlert *bool } type SSOSettings struct { @@ -110,9 +111,8 @@ type RateLimitSettings struct { } type PrivacySettings struct { - ShowEmailAddress bool - ShowFullName bool - EnableSecurityFixAlert bool + ShowEmailAddress bool + ShowFullName bool } type TeamSettings struct { @@ -163,6 +163,13 @@ func ConfigFromJson(data io.Reader) *Config { } } +func (o *Config) SetDefaults() { + if o.ServiceSettings.EnableSecurityFixAlert == nil { + o.ServiceSettings.EnableSecurityFixAlert = new(bool) + *o.ServiceSettings.EnableSecurityFixAlert = true + } +} + func (o *Config) IsValid() *AppError { if o.ServiceSettings.MaximumLoginAttempts <= 0 { diff --git a/store/sql_user_store.go b/store/sql_user_store.go index 011acd7e40..dc6b07a160 100644 --- a/store/sql_user_store.go +++ b/store/sql_user_store.go @@ -530,3 +530,24 @@ func (us SqlUserStore) GetTotalUsersCount() StoreChannel { return storeChannel } + +func (us SqlUserStore) GetTotalActiveUsersCount() StoreChannel { + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + time := model.GetMillis() - (1000 * 60 * 60 * 12) + + if count, err := us.GetReplica().SelectInt("SELECT COUNT(Id) FROM Users WHERE LastActivityAt > :Time", map[string]interface{}{"Time": time}); err != nil { + result.Err = model.NewAppError("SqlUserStore.GetTotalActiveUsersCount", "We could not count the users", 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 be21c8bd2b..874baf6347 100644 --- a/store/sql_user_store_test.go +++ b/store/sql_user_store_test.go @@ -206,7 +206,7 @@ func TestUserStoreGet(t *testing.T) { } } -func TestUserCountt(t *testing.T) { +func TestUserCount(t *testing.T) { Setup() u1 := model.User{} @@ -224,6 +224,24 @@ func TestUserCountt(t *testing.T) { } } +func TestActiveUserCount(t *testing.T) { + Setup() + + u1 := model.User{} + u1.TeamId = model.NewId() + u1.Email = model.NewId() + Must(store.User().Save(&u1)) + + if result := <-store.User().GetTotalActiveUsersCount(); result.Err != nil { + t.Fatal(result.Err) + } else { + count := result.Data.(int64) + if count <= 0 { + t.Fatal() + } + } +} + func TestUserStoreGetProfiles(t *testing.T) { Setup() diff --git a/store/store.go b/store/store.go index 1c4d08e360..e539bc98ae 100644 --- a/store/store.go +++ b/store/store.go @@ -104,6 +104,7 @@ type UserStore interface { UpdateFailedPasswordAttempts(userId string, attempts int) StoreChannel GetForExport(teamId string) StoreChannel GetTotalUsersCount() StoreChannel + GetTotalActiveUsersCount() StoreChannel GetSystemAdminProfiles() StoreChannel } diff --git a/utils/config.go b/utils/config.go index 44ee14a6eb..2c6f30bf07 100644 --- a/utils/config.go +++ b/utils/config.go @@ -150,6 +150,8 @@ func LoadConfig(fileName string) { CfgFileName = fileName } + config.SetDefaults() + if err := config.IsValid(); err != nil { panic("Error validating config file=" + fileName + ", err=" + err.Message) } diff --git a/utils/diagnostic.go b/utils/diagnostic.go index da02e771be..7d13e0e52b 100644 --- a/utils/diagnostic.go +++ b/utils/diagnostic.go @@ -13,17 +13,18 @@ import ( const ( DIAGNOSTIC_URL = "https://d7zmvsa9e04kk.cloudfront.net" - PROP_DIAGNOSTIC_ID = "id" - PROP_DIAGNOSTIC_CATEGORY = "c" - VAL_DIAGNOSTIC_CATEGORY_DEFAULT = "d" - PROP_DIAGNOSTIC_BUILD = "b" - PROP_DIAGNOSTIC_DATABASE = "db" - PROP_DIAGNOSTIC_OS = "os" - PROP_DIAGNOSTIC_USER_COUNT = "uc" + PROP_DIAGNOSTIC_ID = "id" + PROP_DIAGNOSTIC_CATEGORY = "c" + VAL_DIAGNOSTIC_CATEGORY_DEFAULT = "d" + PROP_DIAGNOSTIC_BUILD = "b" + PROP_DIAGNOSTIC_DATABASE = "db" + PROP_DIAGNOSTIC_OS = "os" + PROP_DIAGNOSTIC_USER_COUNT = "uc" + PROP_DIAGNOSTIC_ACTIVE_USER_COUNT = "auc" ) func SendDiagnostic(values url.Values) { - if Cfg.PrivacySettings.EnableSecurityFixAlert && model.IsOfficalBuild() { + if *Cfg.ServiceSettings.EnableSecurityFixAlert && model.IsOfficalBuild() { res, err := http.Get(DIAGNOSTIC_URL + "/i?" + values.Encode()) if err != nil { diff --git a/web/react/components/admin_console/privacy_settings.jsx b/web/react/components/admin_console/privacy_settings.jsx index a32ca31365..70ec04f4a1 100644 --- a/web/react/components/admin_console/privacy_settings.jsx +++ b/web/react/components/admin_console/privacy_settings.jsx @@ -30,7 +30,6 @@ export default class PrivacySettings extends React.Component { var config = this.props.config; config.PrivacySettings.ShowEmailAddress = React.findDOMNode(this.refs.ShowEmailAddress).checked; config.PrivacySettings.ShowFullName = React.findDOMNode(this.refs.ShowFullName).checked; - config.PrivacySettings.EnableSecurityFixAlert = React.findDOMNode(this.refs.EnableSecurityFixAlert).checked; Client.saveConfig( config, @@ -137,39 +136,6 @@ export default class PrivacySettings extends React.Component { -
{'When true, System Administrators are notified by email if a relevant security fix alert has been announced in the last 12 hours. Requires email to be enabled.'}
-{'When true, System Administrators are notified by email if a relevant security fix alert has been announced in the last 12 hours. Requires email to be enabled.'}
+