summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
author=Corey Hulen <corey@hulen.com>2015-09-22 12:12:50 -0700
committer=Corey Hulen <corey@hulen.com>2015-09-22 12:12:50 -0700
commit88e5a71e8c93b495cedaa07931a4f8052d9f12ed (patch)
tree603174fc3758d56b8a027b9e1fbe1a5d8690b3e6
parent08a3acbb44b043b9bb56f9b96e91432352d06d1a (diff)
downloadchat-88e5a71e8c93b495cedaa07931a4f8052d9f12ed.tar.gz
chat-88e5a71e8c93b495cedaa07931a4f8052d9f12ed.tar.bz2
chat-88e5a71e8c93b495cedaa07931a4f8052d9f12ed.zip
Adding service settings to admin console
-rw-r--r--api/admin.go4
-rw-r--r--api/api_test.go2
-rw-r--r--api/channel_test.go2
-rw-r--r--api/command.go4
-rw-r--r--api/context.go38
-rw-r--r--api/file.go4
-rw-r--r--api/file_benchmark_test.go2
-rw-r--r--api/file_test.go2
-rw-r--r--api/server.go4
-rw-r--r--api/team.go21
-rw-r--r--api/team_test.go2
-rw-r--r--api/user.go14
-rw-r--r--api/user_test.go4
-rw-r--r--api/web_socket_test.go2
-rw-r--r--config/config.json28
-rw-r--r--docker/dev/config_docker.json117
-rw-r--r--docker/local/config_docker.json117
-rw-r--r--manualtesting/manual_testing.go2
-rw-r--r--mattermost.go2
-rw-r--r--model/client.go1
-rw-r--r--model/config.go26
-rw-r--r--utils/config.go13
-rw-r--r--web/react/components/admin_console/admin_controller.jsx6
-rw-r--r--web/react/components/admin_console/admin_sidebar.jsx9
-rw-r--r--web/react/components/admin_console/email_settings.jsx98
-rw-r--r--web/react/components/admin_console/image_settings.jsx45
-rw-r--r--web/react/components/admin_console/log_settings.jsx24
-rw-r--r--web/react/components/admin_console/service_settings.jsx262
-rw-r--r--web/react/components/admin_console/sql_settings.jsx2
-rw-r--r--web/react/components/login.jsx4
-rw-r--r--web/react/components/signup_team.jsx8
-rw-r--r--web/react/components/signup_user_complete.jsx4
-rw-r--r--web/react/components/team_signup_choose_auth.jsx4
-rw-r--r--web/react/utils/client.jsx2
-rw-r--r--web/templates/head.html23
-rw-r--r--web/web.go8
-rw-r--r--web/web_test.go2
37 files changed, 623 insertions, 289 deletions
diff --git a/api/admin.go b/api/admin.go
index ca66b7cb4..568d8f6e8 100644
--- a/api/admin.go
+++ b/api/admin.go
@@ -35,7 +35,7 @@ func getLogs(c *Context, w http.ResponseWriter, r *http.Request) {
var lines []string
- if utils.Cfg.LogSettings.FileEnable {
+ if utils.Cfg.LogSettings.EnableFile {
file, err := os.Open(utils.GetLogFileLocation(utils.Cfg.LogSettings.FileLocation))
if err != nil {
@@ -82,7 +82,7 @@ func saveConfig(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
- if len(cfg.ServiceSettings.Port) == 0 {
+ if len(cfg.ServiceSettings.ListenAddress) == 0 {
c.SetInvalidParam("saveConfig", "config")
return
}
diff --git a/api/api_test.go b/api/api_test.go
index 490f8ab5b..761f3e33f 100644
--- a/api/api_test.go
+++ b/api/api_test.go
@@ -18,7 +18,7 @@ func Setup() {
NewServer()
StartServer()
InitApi()
- Client = model.NewClient("http://localhost:" + utils.Cfg.ServiceSettings.Port)
+ Client = model.NewClient("http://localhost" + utils.Cfg.ServiceSettings.ListenAddress)
}
}
diff --git a/api/channel_test.go b/api/channel_test.go
index 14bfe1cf7..7845ac499 100644
--- a/api/channel_test.go
+++ b/api/channel_test.go
@@ -627,7 +627,7 @@ func TestGetChannelExtraInfo(t *testing.T) {
currentEtag = cache_result.Etag
}
- Client2 := model.NewClient("http://localhost:" + utils.Cfg.ServiceSettings.Port)
+ Client2 := model.NewClient("http://localhost" + utils.Cfg.ServiceSettings.ListenAddress)
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "tester2@test.com", Nickname: "Tester 2", Password: "pwd"}
user2 = Client2.Must(Client2.CreateUser(user2, "")).Data.(*model.User)
diff --git a/api/command.go b/api/command.go
index bc55f206b..0d2f7597b 100644
--- a/api/command.go
+++ b/api/command.go
@@ -215,8 +215,8 @@ func joinCommand(c *Context, command *model.Command) bool {
func loadTestCommand(c *Context, command *model.Command) bool {
cmd := "/loadtest"
- // This command is only available when AllowTesting is true
- if !utils.Cfg.ServiceSettings.AllowTesting {
+ // This command is only available when EnableTesting is true
+ if !utils.Cfg.ServiceSettings.EnableTesting {
return false
}
diff --git a/api/context.go b/api/context.go
index c4684221d..9a276a1a1 100644
--- a/api/context.go
+++ b/api/context.go
@@ -107,21 +107,7 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
isTokenFromQueryString = true
}
- protocol := "http"
-
- // If the request came from the ELB then assume this is produciton
- // and redirect all http requests to https
- if utils.Cfg.ServiceSettings.UseSSL {
- forwardProto := r.Header.Get(model.HEADER_FORWARDED_PROTO)
- if forwardProto == "http" {
- l4g.Info("redirecting http request to https for %v", r.URL.Path)
- http.Redirect(w, r, "https://"+r.Host, http.StatusTemporaryRedirect)
- return
- } else {
- protocol = "https"
- }
- }
-
+ protocol := GetProtocol(r)
c.setSiteURL(protocol + "://" + r.Host)
w.Header().Set(model.HEADER_REQUEST_ID, c.RequestId)
@@ -209,6 +195,14 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
}
+func GetProtocol(r *http.Request) string {
+ if r.Header.Get(model.HEADER_FORWARDED_PROTO) == "https" {
+ return "https"
+ } else {
+ return "http"
+ }
+}
+
func (c *Context) LogAudit(extraInfo string) {
audit := &model.Audit{UserId: c.Session.UserId, IpAddress: c.IpAddress, Action: c.Path, ExtraInfo: extraInfo, SessionId: c.Session.Id}
if r := <-Srv.Store.Audit().Save(audit); r.Err != nil {
@@ -385,6 +379,11 @@ func (c *Context) GetSiteURL() string {
func GetIpAddress(r *http.Request) string {
address := r.Header.Get(model.HEADER_FORWARDED)
+
+ if len(address) == 0 {
+ address = r.Header.Get(model.HEADER_REAL_IP)
+ }
+
if len(address) == 0 {
address, _, _ = net.SplitHostPort(r.RemoteAddr)
}
@@ -458,14 +457,7 @@ func IsPrivateIpAddress(ipAddress string) bool {
func RenderWebError(err *model.AppError, w http.ResponseWriter, r *http.Request) {
- protocol := "http"
- if utils.Cfg.ServiceSettings.UseSSL {
- forwardProto := r.Header.Get(model.HEADER_FORWARDED_PROTO)
- if forwardProto != "http" {
- protocol = "https"
- }
- }
-
+ protocol := GetProtocol(r)
SiteURL := protocol + "://" + r.Host
m := make(map[string]string)
diff --git a/api/file.go b/api/file.go
index 61d0df413..c85d241f3 100644
--- a/api/file.go
+++ b/api/file.go
@@ -399,7 +399,7 @@ func getFile(c *Context, w http.ResponseWriter, r *http.Request) {
asyncGetFile(path, fileData)
if len(hash) > 0 && len(data) > 0 && len(teamId) == 26 {
- if !model.ComparePassword(hash, fmt.Sprintf("%v:%v", data, utils.Cfg.ServiceSettings.PublicLinkSalt)) {
+ if !model.ComparePassword(hash, fmt.Sprintf("%v:%v", data, utils.Cfg.ImageSettings.PublicLinkSalt)) {
c.Err = model.NewAppError("getFile", "The public link does not appear to be valid", "")
return
}
@@ -477,7 +477,7 @@ func getPublicLink(c *Context, w http.ResponseWriter, r *http.Request) {
newProps["time"] = fmt.Sprintf("%v", model.GetMillis())
data := model.MapToJson(newProps)
- hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.ServiceSettings.PublicLinkSalt))
+ hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.ImageSettings.PublicLinkSalt))
url := fmt.Sprintf("%s/api/v1/files/get/%s/%s/%s?d=%s&h=%s&t=%s", c.GetSiteURL(), channelId, userId, filename, url.QueryEscape(data), url.QueryEscape(hash), c.Session.TeamId)
diff --git a/api/file_benchmark_test.go b/api/file_benchmark_test.go
index 251ff7793..f7d5de1d9 100644
--- a/api/file_benchmark_test.go
+++ b/api/file_benchmark_test.go
@@ -38,7 +38,7 @@ func BenchmarkGetFile(b *testing.B) {
newProps["time"] = fmt.Sprintf("%v", model.GetMillis())
data := model.MapToJson(newProps)
- hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.ServiceSettings.PublicLinkSalt))
+ hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.ImageSettings.PublicLinkSalt))
// wait a bit for files to ready
time.Sleep(5 * time.Second)
diff --git a/api/file_test.go b/api/file_test.go
index a0a2f3255..072a3fab1 100644
--- a/api/file_test.go
+++ b/api/file_test.go
@@ -222,7 +222,7 @@ func TestGetFile(t *testing.T) {
newProps["time"] = fmt.Sprintf("%v", model.GetMillis())
data := model.MapToJson(newProps)
- hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.ServiceSettings.PublicLinkSalt))
+ hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.ImageSettings.PublicLinkSalt))
Client.LoginByEmail(team2.Name, user2.Email, "pwd")
diff --git a/api/server.go b/api/server.go
index a2f5fe552..3f23d8df6 100644
--- a/api/server.go
+++ b/api/server.go
@@ -38,7 +38,7 @@ func NewServer() {
func StartServer() {
l4g.Info("Starting Server...")
- l4g.Info("Server is listening on " + utils.Cfg.ServiceSettings.Port)
+ l4g.Info("Server is listening on " + utils.Cfg.ServiceSettings.ListenAddress)
var handler http.Handler = Srv.Router
@@ -71,7 +71,7 @@ func StartServer() {
}
go func() {
- err := Srv.Server.ListenAndServe(":"+utils.Cfg.ServiceSettings.Port, handler)
+ err := Srv.Server.ListenAndServe(utils.Cfg.ServiceSettings.ListenAddress, handler)
if err != nil {
l4g.Critical("Error starting server, err:%v", err)
time.Sleep(time.Second)
diff --git a/api/team.go b/api/team.go
index 8802208f7..c9d2412d3 100644
--- a/api/team.go
+++ b/api/team.go
@@ -38,7 +38,7 @@ func InitTeam(r *mux.Router) {
}
func signupTeam(c *Context, w http.ResponseWriter, r *http.Request) {
- if !utils.Cfg.EmailSettings.AllowSignUpWithEmail {
+ if !utils.Cfg.EmailSettings.EnableSignUpWithEmail {
c.Err = model.NewAppError("signupTeam", "Team sign-up with email is disabled.", "")
c.Err.StatusCode = http.StatusNotImplemented
return
@@ -66,7 +66,7 @@ func signupTeam(c *Context, w http.ResponseWriter, r *http.Request) {
props["time"] = fmt.Sprintf("%v", model.GetMillis())
data := model.MapToJson(props)
- hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.ServiceSettings.InviteSalt))
+ hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt))
bodyPage.Props["Link"] = fmt.Sprintf("%s/signup_team_complete/?d=%s&h=%s", c.GetSiteURL(), url.QueryEscape(data), url.QueryEscape(hash))
@@ -85,7 +85,7 @@ func createTeamFromSSO(c *Context, w http.ResponseWriter, r *http.Request) {
service := params["service"]
sso := utils.Cfg.GetSSOService(service)
- if sso != nil && !sso.Allow {
+ if sso != nil && !sso.Enable {
c.SetInvalidParam("createTeamFromSSO", "service")
return
}
@@ -142,7 +142,7 @@ func createTeamFromSSO(c *Context, w http.ResponseWriter, r *http.Request) {
}
func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) {
- if !utils.Cfg.EmailSettings.AllowSignUpWithEmail {
+ if !utils.Cfg.EmailSettings.EnableSignUpWithEmail {
c.Err = model.NewAppError("createTeamFromSignup", "Team sign-up with email is disabled.", "")
c.Err.StatusCode = http.StatusNotImplemented
return
@@ -183,7 +183,7 @@ func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) {
teamSignup.User.TeamId = ""
teamSignup.User.Password = password
- if !model.ComparePassword(teamSignup.Hash, fmt.Sprintf("%v:%v", teamSignup.Data, utils.Cfg.ServiceSettings.InviteSalt)) {
+ if !model.ComparePassword(teamSignup.Hash, fmt.Sprintf("%v:%v", teamSignup.Data, utils.Cfg.EmailSettings.InviteSalt)) {
c.Err = model.NewAppError("createTeamFromSignup", "The signup link does not appear to be valid", "")
return
}
@@ -243,7 +243,7 @@ func createTeam(c *Context, w http.ResponseWriter, r *http.Request) {
}
func CreateTeam(c *Context, team *model.Team) *model.Team {
- if !utils.Cfg.EmailSettings.AllowSignUpWithEmail {
+ if !utils.Cfg.EmailSettings.EnableSignUpWithEmail {
c.Err = model.NewAppError("createTeam", "Team sign-up with email is disabled.", "")
c.Err.StatusCode = http.StatusNotImplemented
return nil
@@ -258,11 +258,6 @@ func CreateTeam(c *Context, team *model.Team) *model.Team {
return nil
}
- if utils.Cfg.ServiceSettings.Mode != utils.MODE_DEV {
- c.Err = model.NewAppError("CreateTeam", "The mode does not allow network creation without a valid invite", "")
- return nil
- }
-
if result := <-Srv.Store.Team().Save(team); result.Err != nil {
c.Err = result.Err
return nil
@@ -488,10 +483,10 @@ func InviteMembers(c *Context, team *model.Team, user *model.User, invites []str
props["name"] = team.Name
props["time"] = fmt.Sprintf("%v", model.GetMillis())
data := model.MapToJson(props)
- hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.ServiceSettings.InviteSalt))
+ hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt))
bodyPage.Props["Link"] = fmt.Sprintf("%s/signup_user_complete/?d=%s&h=%s", c.GetSiteURL(), url.QueryEscape(data), url.QueryEscape(hash))
- if utils.Cfg.ServiceSettings.Mode == utils.MODE_DEV {
+ if !utils.Cfg.EmailSettings.SendEmailNotifications {
l4g.Info("sending invitation to %v %v", invite, bodyPage.Props["Link"])
}
diff --git a/api/team_test.go b/api/team_test.go
index 48c73c638..cd39dacfe 100644
--- a/api/team_test.go
+++ b/api/team_test.go
@@ -30,7 +30,7 @@ func TestCreateFromSignupTeam(t *testing.T) {
props["time"] = fmt.Sprintf("%v", model.GetMillis())
data := model.MapToJson(props)
- hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.ServiceSettings.InviteSalt))
+ hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt))
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
user := model.User{Email: props["email"], Nickname: "Corey Hulen", Password: "hello"}
diff --git a/api/user.go b/api/user.go
index ba5323d77..d61afb027 100644
--- a/api/user.go
+++ b/api/user.go
@@ -58,7 +58,7 @@ func InitUser(r *mux.Router) {
}
func createUser(c *Context, w http.ResponseWriter, r *http.Request) {
- if !utils.Cfg.EmailSettings.AllowSignUpWithEmail {
+ if !utils.Cfg.EmailSettings.EnableSignUpWithEmail {
c.Err = model.NewAppError("signupTeam", "User sign-up with email is disabled.", "")
c.Err.StatusCode = http.StatusNotImplemented
return
@@ -90,7 +90,7 @@ func createUser(c *Context, w http.ResponseWriter, r *http.Request) {
data := r.URL.Query().Get("d")
props := model.MapFromJson(strings.NewReader(data))
- if !model.ComparePassword(hash, fmt.Sprintf("%v:%v", data, utils.Cfg.ServiceSettings.InviteSalt)) {
+ if !model.ComparePassword(hash, fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt)) {
c.Err = model.NewAppError("createUser", "The signup link does not appear to be valid", "")
return
}
@@ -287,7 +287,7 @@ func LoginByEmail(c *Context, w http.ResponseWriter, r *http.Request, email, nam
func checkUserPassword(c *Context, user *model.User, password string) bool {
- if user.FailedAttempts >= utils.Cfg.ServiceSettings.AllowedLoginAttempts {
+ if user.FailedAttempts >= utils.Cfg.ServiceSettings.MaximumLoginAttempts {
c.LogAuditWithUserId(user.Id, "fail")
c.Err = model.NewAppError("checkUserPassword", "Your account is locked because of too many failed password attempts. Please reset your password.", "user_id="+user.Id)
c.Err.StatusCode = http.StatusForbidden
@@ -1129,7 +1129,7 @@ func sendPasswordReset(c *Context, w http.ResponseWriter, r *http.Request) {
newProps["time"] = fmt.Sprintf("%v", model.GetMillis())
data := model.MapToJson(newProps)
- hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.ServiceSettings.ResetSalt))
+ hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.PasswordResetSalt))
link := fmt.Sprintf("%s/reset_password?d=%s&h=%s", c.GetTeamURLFromTeam(team), url.QueryEscape(data), url.QueryEscape(hash))
@@ -1208,7 +1208,7 @@ func resetPassword(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
- if !model.ComparePassword(hash, fmt.Sprintf("%v:%v", props["data"], utils.Cfg.ServiceSettings.ResetSalt)) {
+ if !model.ComparePassword(hash, fmt.Sprintf("%v:%v", props["data"], utils.Cfg.EmailSettings.PasswordResetSalt)) {
c.Err = model.NewAppError("resetPassword", "The reset password link does not appear to be valid", "")
return
}
@@ -1357,7 +1357,7 @@ func getStatuses(c *Context, w http.ResponseWriter, r *http.Request) {
func GetAuthorizationCode(c *Context, w http.ResponseWriter, r *http.Request, teamName, service, redirectUri, loginHint string) {
sso := utils.Cfg.GetSSOService(service)
- if sso != nil && !sso.Allow {
+ if sso != nil && !sso.Enable {
c.Err = model.NewAppError("GetAuthorizationCode", "Unsupported OAuth service provider", "service="+service)
c.Err.StatusCode = http.StatusBadRequest
return
@@ -1385,7 +1385,7 @@ func GetAuthorizationCode(c *Context, w http.ResponseWriter, r *http.Request, te
func AuthorizeOAuthUser(service, code, state, redirectUri string) (io.ReadCloser, *model.Team, *model.AppError) {
sso := utils.Cfg.GetSSOService(service)
- if sso != nil && !sso.Allow {
+ if sso != nil && !sso.Enable {
return nil, nil, model.NewAppError("AuthorizeOAuthUser", "Unsupported OAuth service provider", "service="+service)
}
diff --git a/api/user_test.go b/api/user_test.go
index 7451cb615..34eefce59 100644
--- a/api/user_test.go
+++ b/api/user_test.go
@@ -151,7 +151,7 @@ func TestLogin(t *testing.T) {
props["display_name"] = rteam2.Data.(*model.Team).DisplayName
props["time"] = fmt.Sprintf("%v", model.GetMillis())
data := model.MapToJson(props)
- hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.ServiceSettings.InviteSalt))
+ hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt))
ruser2, _ := Client.CreateUserFromSignup(&user2, data, hash)
@@ -814,7 +814,7 @@ func TestResetPassword(t *testing.T) {
props["user_id"] = user.Id
props["time"] = fmt.Sprintf("%v", model.GetMillis())
data["data"] = model.MapToJson(props)
- data["hash"] = model.HashPassword(fmt.Sprintf("%v:%v", data["data"], utils.Cfg.ServiceSettings.ResetSalt))
+ data["hash"] = model.HashPassword(fmt.Sprintf("%v:%v", data["data"], utils.Cfg.EmailSettings.PasswordResetSalt))
data["name"] = team.Name
if _, err := Client.ResetPassword(data); err != nil {
diff --git a/api/web_socket_test.go b/api/web_socket_test.go
index 161274ff7..d086308bf 100644
--- a/api/web_socket_test.go
+++ b/api/web_socket_test.go
@@ -16,7 +16,7 @@ import (
func TestSocket(t *testing.T) {
Setup()
- url := "ws://localhost:" + utils.Cfg.ServiceSettings.Port + "/api/v1/websocket"
+ url := "ws://localhost" + utils.Cfg.ServiceSettings.ListenAddress + "/api/v1/websocket"
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
diff --git a/config/config.json b/config/config.json
index 12926bee5..4b5a16300 100644
--- a/config/config.json
+++ b/config/config.json
@@ -1,18 +1,11 @@
{
"ServiceSettings": {
- "Mode": "dev",
- "AllowTesting": false,
- "UseSSL": false,
- "Port": "8065",
- "Version": "developer",
- "InviteSalt": "gxHVDcKUyP2y1eiyW8S8na1UYQAfq6J6",
- "PublicLinkSalt": "TO3pTyXIZzwHiwyZgGql7lM7DG3zeId4",
- "ResetSalt": "IPxFzSfnDFsNsRafZxz8NaYqFKhf9y2t",
- "AnalyticsUrl": "",
- "AllowedLoginAttempts": 10,
- "EnableOAuthServiceProvider": false,
+ "ListenAddress": ":8065",
+ "MaximumLoginAttempts": 10,
"SegmentDeveloperKey": "",
- "GoogleDeveloperKey": ""
+ "GoogleDeveloperKey": "",
+ "EnableOAuthServiceProvider": false,
+ "EnableTesting": false
},
"TeamSettings": {
"SiteName": "Mattermost",
@@ -32,9 +25,9 @@
"AtRestEncryptKey": "7rAh6iwQCkV4cA1Gsg3fgGOXJAQ43QV"
},
"LogSettings": {
- "ConsoleEnable": true,
+ "EnableConsole": true,
"ConsoleLevel": "DEBUG",
- "FileEnable": true,
+ "EnableFile": true,
"FileLevel": "INFO",
"FileFormat": "",
"FileLocation": ""
@@ -43,6 +36,7 @@
"DriverName": "local",
"Directory": "./data/",
"EnablePublicLink": true,
+ "PublicLinkSalt": "LhaAWC6lYEKHTkBKsvyXNIOfUIT37AX",
"ThumbnailWidth": 120,
"ThumbnailHeight": 100,
"PreviewWidth": 1024,
@@ -56,7 +50,7 @@
"AmazonS3Region": ""
},
"EmailSettings": {
- "AllowSignUpWithEmail": true,
+ "EnableSignUpWithEmail": true,
"SendEmailNotifications": false,
"RequireEmailVerification": false,
"FeedbackName": "",
@@ -66,6 +60,8 @@
"SMTPServer": "",
"SMTPPort": "",
"ConnectionSecurity": "",
+ "InviteSalt": "bjlSR4QqkXFBr7TP4oDzlfZmcNuH9Yo",
+ "PasswordResetSalt": "vZ4DcKyVVRlKHHJpexcuXzojkE5PZ5e",
"ApplePushServer": "",
"ApplePushCertPublic": "",
"ApplePushCertPrivate": ""
@@ -82,7 +78,7 @@
"ShowFullName": true
},
"GitLabSettings": {
- "Allow": false,
+ "Enable": false,
"Secret": "",
"Id": "",
"Scope": "",
diff --git a/docker/dev/config_docker.json b/docker/dev/config_docker.json
index aceeb95b4..8bd5f1b0a 100644
--- a/docker/dev/config_docker.json
+++ b/docker/dev/config_docker.json
@@ -1,81 +1,73 @@
{
- "LogSettings": {
- "ConsoleEnable": true,
- "ConsoleLevel": "INFO",
- "FileEnable": true,
- "FileLevel": "INFO",
- "FileFormat": "",
- "FileLocation": ""
- },
"ServiceSettings": {
- "SiteName": "Mattermost",
- "Mode" : "dev",
- "AllowTesting" : true,
- "UseSSL": false,
- "Port": "80",
- "Version": "developer",
- "Shards": {
- },
- "InviteSalt": "gxHVDcKUyP2y1eiyW8S8na1UYQAfq6J6",
- "PublicLinkSalt": "TO3pTyXIZzwHiwyZgGql7lM7DG3zeId4",
- "ResetSalt": "IPxFzSfnDFsNsRafZxz8NaYqFKhf9y2t",
- "AnalyticsUrl": "",
- "UseLocalStorage": true,
- "StorageDirectory": "/mattermost/data/",
- "AllowedLoginAttempts": 10,
- "DisableEmailSignUp": false,
- "EnableOAuthServiceProvider": false
+ "ListenAddress": ":80",
+ "MaximumLoginAttempts": 10,
+ "SegmentDeveloperKey": "",
+ "GoogleDeveloperKey": "",
+ "EnableOAuthServiceProvider": false,
+ "EnableTesting": false
},
- "SSOSettings": {
- "gitlab": {
- "Allow": false,
- "Secret" : "",
- "Id": "",
- "Scope": "",
- "AuthEndpoint": "",
- "TokenEndpoint": "",
- "UserApiEndpoint": ""
- }
+ "TeamSettings": {
+ "SiteName": "Mattermost",
+ "MaxUsersPerTeam": 50,
+ "DefaultThemeColor": "#2389D7",
+ "EnableTeamCreation": true,
+ "EnableUserCreation": true,
+ "RestrictCreationToDomains": ""
},
"SqlSettings": {
"DriverName": "mysql",
- "DataSource": "mmuser:mostest@tcp(localhost:3306)/mattermost_test?charset=utf8mb4,utf8",
- "DataSourceReplicas": ["mmuser:mostest@tcp(localhost:3306)/mattermost_test?charset=utf8mb4,utf8"],
+ "DataSource": "mmuser:mostest@tcp(dockerhost:3306)/mattermost_test?charset=utf8mb4,utf8",
+ "DataSourceReplicas": [],
"MaxIdleConns": 10,
"MaxOpenConns": 10,
"Trace": false,
- "AtRestEncryptKey": "Ya0xMrybACJ3sZZVWQC7e31h5nSDWZFS"
+ "AtRestEncryptKey": "7rAh6iwQCkV4cA1Gsg3fgGOXJAQ43QV"
},
- "AWSSettings": {
- "S3AccessKeyId": "",
- "S3SecretAccessKey": "",
- "S3Bucket": "",
- "S3Region": ""
+ "LogSettings": {
+ "EnableConsole": false,
+ "ConsoleLevel": "INFO",
+ "EnableFile": true,
+ "FileLevel": "INFO",
+ "FileFormat": "",
+ "FileLocation": ""
},
"ImageSettings": {
+ "DriverName": "local",
+ "Directory": "/mattermost/data/",
+ "EnablePublicLink": true,
+ "PublicLinkSalt": "LhaAWC6lYEKHTkBKsvyXNIOfUIT37AX",
"ThumbnailWidth": 120,
"ThumbnailHeight": 100,
"PreviewWidth": 1024,
"PreviewHeight": 0,
"ProfileWidth": 128,
"ProfileHeight": 128,
- "InitialFont": "luximbi.ttf"
+ "InitialFont": "luximbi.ttf",
+ "AmazonS3AccessKeyId": "",
+ "AmazonS3SecretAccessKey": "",
+ "AmazonS3Bucket": "",
+ "AmazonS3Region": ""
},
"EmailSettings": {
- "ByPassEmail" : true,
+ "EnableSignUpWithEmail": true,
+ "SendEmailNotifications": false,
+ "RequireEmailVerification": false,
+ "FeedbackName": "",
+ "FeedbackEmail": "",
"SMTPUsername": "",
"SMTPPassword": "",
"SMTPServer": "",
- "UseTLS": false,
- "UseStartTLS": false,
- "FeedbackEmail": "",
- "FeedbackName": "",
+ "SMTPPort": "",
+ "ConnectionSecurity": "",
+ "InviteSalt": "bjlSR4QqkXFBr7TP4oDzlfZmcNuH9Yo",
+ "PasswordResetSalt": "vZ4DcKyVVRlKHHJpexcuXzojkE5PZ5e",
"ApplePushServer": "",
"ApplePushCertPublic": "",
"ApplePushCertPrivate": ""
},
"RateLimitSettings": {
- "UseRateLimiter": true,
+ "EnableRateLimiter": true,
"PerSec": 10,
"MemoryStoreSize": 10000,
"VaryByRemoteAddr": true,
@@ -83,22 +75,15 @@
},
"PrivacySettings": {
"ShowEmailAddress": true,
- "ShowPhoneNumber": true,
- "ShowSkypeId": true,
"ShowFullName": true
},
- "TeamSettings": {
- "MaxUsersPerTeam": 150,
- "AllowPublicLink": true,
- "AllowValetDefault": false,
- "TermsLink": "/static/help/configure_links.html",
- "PrivacyLink": "/static/help/configure_links.html",
- "AboutLink": "/static/help/configure_links.html",
- "HelpLink": "/static/help/configure_links.html",
- "ReportProblemLink": "/static/help/configure_links.html",
- "TourLink": "/static/help/configure_links.html",
- "DefaultThemeColor": "#2389D7",
- "DisableTeamCreation": false,
- "RestrictCreationToDomains": ""
+ "GitLabSettings": {
+ "Enable": false,
+ "Secret": "",
+ "Id": "",
+ "Scope": "",
+ "AuthEndpoint": "",
+ "TokenEndpoint": "",
+ "UserApiEndpoint": ""
}
-}
+} \ No newline at end of file
diff --git a/docker/local/config_docker.json b/docker/local/config_docker.json
index bc42951b8..8bd5f1b0a 100644
--- a/docker/local/config_docker.json
+++ b/docker/local/config_docker.json
@@ -1,81 +1,73 @@
{
- "LogSettings": {
- "ConsoleEnable": true,
- "ConsoleLevel": "INFO",
- "FileEnable": true,
- "FileLevel": "INFO",
- "FileFormat": "",
- "FileLocation": ""
- },
"ServiceSettings": {
- "SiteName": "Mattermost",
- "Mode" : "dev",
- "AllowTesting" : true,
- "UseSSL": false,
- "Port": "80",
- "Version": "developer",
- "Shards": {
- },
- "InviteSalt": "gxHVDcKUyP2y1eiyW8S8na1UYQAfq6J6",
- "PublicLinkSalt": "TO3pTyXIZzwHiwyZgGql7lM7DG3zeId4",
- "ResetSalt": "IPxFzSfnDFsNsRafZxz8NaYqFKhf9y2t",
- "AnalyticsUrl": "",
- "UseLocalStorage": true,
- "StorageDirectory": "/mattermost/data/",
- "AllowedLoginAttempts": 10,
- "DisableEmailSignUp": false,
- "EnableOAuthServiceProvider": false
+ "ListenAddress": ":80",
+ "MaximumLoginAttempts": 10,
+ "SegmentDeveloperKey": "",
+ "GoogleDeveloperKey": "",
+ "EnableOAuthServiceProvider": false,
+ "EnableTesting": false
},
- "SSOSettings": {
- "gitlab": {
- "Allow": false,
- "Secret" : "",
- "Id": "",
- "Scope": "",
- "AuthEndpoint": "",
- "TokenEndpoint": "",
- "UserApiEndpoint": ""
- }
+ "TeamSettings": {
+ "SiteName": "Mattermost",
+ "MaxUsersPerTeam": 50,
+ "DefaultThemeColor": "#2389D7",
+ "EnableTeamCreation": true,
+ "EnableUserCreation": true,
+ "RestrictCreationToDomains": ""
},
"SqlSettings": {
"DriverName": "mysql",
- "DataSource": "mmuser:mostest@tcp(localhost:3306)/mattermost_test?charset=utf8mb4,utf8",
- "DataSourceReplicas": ["mmuser:mostest@tcp(localhost:3306)/mattermost_test?charset=utf8mb4,utf8"],
+ "DataSource": "mmuser:mostest@tcp(dockerhost:3306)/mattermost_test?charset=utf8mb4,utf8",
+ "DataSourceReplicas": [],
"MaxIdleConns": 10,
"MaxOpenConns": 10,
"Trace": false,
- "AtRestEncryptKey": "Ya0xMrybACJ3sZZVWQC7e31h5nSDWZFS"
+ "AtRestEncryptKey": "7rAh6iwQCkV4cA1Gsg3fgGOXJAQ43QV"
},
- "AWSSettings": {
- "S3AccessKeyId": "",
- "S3SecretAccessKey": "",
- "S3Bucket": "",
- "S3Region": ""
+ "LogSettings": {
+ "EnableConsole": false,
+ "ConsoleLevel": "INFO",
+ "EnableFile": true,
+ "FileLevel": "INFO",
+ "FileFormat": "",
+ "FileLocation": ""
},
"ImageSettings": {
+ "DriverName": "local",
+ "Directory": "/mattermost/data/",
+ "EnablePublicLink": true,
+ "PublicLinkSalt": "LhaAWC6lYEKHTkBKsvyXNIOfUIT37AX",
"ThumbnailWidth": 120,
"ThumbnailHeight": 100,
"PreviewWidth": 1024,
"PreviewHeight": 0,
"ProfileWidth": 128,
"ProfileHeight": 128,
- "InitialFont": "luximbi.ttf"
+ "InitialFont": "luximbi.ttf",
+ "AmazonS3AccessKeyId": "",
+ "AmazonS3SecretAccessKey": "",
+ "AmazonS3Bucket": "",
+ "AmazonS3Region": ""
},
"EmailSettings": {
- "ByPassEmail" : true,
+ "EnableSignUpWithEmail": true,
+ "SendEmailNotifications": false,
+ "RequireEmailVerification": false,
+ "FeedbackName": "",
+ "FeedbackEmail": "",
"SMTPUsername": "",
"SMTPPassword": "",
"SMTPServer": "",
- "UseTLS": false,
- "UseStartTLS": false,
- "FeedbackEmail": "",
- "FeedbackName": "",
+ "SMTPPort": "",
+ "ConnectionSecurity": "",
+ "InviteSalt": "bjlSR4QqkXFBr7TP4oDzlfZmcNuH9Yo",
+ "PasswordResetSalt": "vZ4DcKyVVRlKHHJpexcuXzojkE5PZ5e",
"ApplePushServer": "",
"ApplePushCertPublic": "",
"ApplePushCertPrivate": ""
},
"RateLimitSettings": {
- "UseRateLimiter": true,
+ "EnableRateLimiter": true,
"PerSec": 10,
"MemoryStoreSize": 10000,
"VaryByRemoteAddr": true,
@@ -83,22 +75,15 @@
},
"PrivacySettings": {
"ShowEmailAddress": true,
- "ShowPhoneNumber": true,
- "ShowSkypeId": true,
"ShowFullName": true
},
- "TeamSettings": {
- "MaxUsersPerTeam": 150,
- "AllowPublicLink": true,
- "AllowValetDefault": false,
- "TermsLink": "/static/help/configure_links.html",
- "PrivacyLink": "/static/help/configure_links.html",
- "AboutLink": "/static/help/configure_links.html",
- "HelpLink": "/static/help/configure_links.html",
- "ReportProblemLink": "/static/help/configure_links.html",
- "TourLink": "/static/help/configure_links.html",
- "DefaultThemeColor": "#2389D7",
- "DisableTeamCreation": false,
- "RestrictCreationToDomains": ""
+ "GitLabSettings": {
+ "Enable": false,
+ "Secret": "",
+ "Id": "",
+ "Scope": "",
+ "AuthEndpoint": "",
+ "TokenEndpoint": "",
+ "UserApiEndpoint": ""
}
-}
+} \ No newline at end of file
diff --git a/manualtesting/manual_testing.go b/manualtesting/manual_testing.go
index 86b173c6a..a517b0c0e 100644
--- a/manualtesting/manual_testing.go
+++ b/manualtesting/manual_testing.go
@@ -53,7 +53,7 @@ func manualTest(c *api.Context, w http.ResponseWriter, r *http.Request) {
}
// Create a client for tests to use
- client := model.NewClient("http://localhost:" + utils.Cfg.ServiceSettings.Port)
+ client := model.NewClient("http://localhost" + utils.Cfg.ServiceSettings.ListenAddress)
// Check for username parameter and create a user if present
username, ok1 := params["username"]
diff --git a/mattermost.go b/mattermost.go
index f54bcf15f..4608bfff3 100644
--- a/mattermost.go
+++ b/mattermost.go
@@ -57,7 +57,7 @@ func main() {
api.StartServer()
// If we allow testing then listen for manual testing URL hits
- if utils.Cfg.ServiceSettings.AllowTesting {
+ if utils.Cfg.ServiceSettings.EnableTesting {
manualtesting.InitManualTesting()
}
diff --git a/model/client.go b/model/client.go
index 823e859cf..d13ffa6cb 100644
--- a/model/client.go
+++ b/model/client.go
@@ -21,6 +21,7 @@ const (
HEADER_ETAG_SERVER = "ETag"
HEADER_ETAG_CLIENT = "If-None-Match"
HEADER_FORWARDED = "X-Forwarded-For"
+ HEADER_REAL_IP = "X-Real-IP"
HEADER_FORWARDED_PROTO = "X-Forwarded-Proto"
HEADER_TOKEN = "token"
HEADER_BEARER = "BEARER"
diff --git a/model/config.go b/model/config.go
index 876c36e98..7791c4021 100644
--- a/model/config.go
+++ b/model/config.go
@@ -20,23 +20,16 @@ const (
)
type ServiceSettings struct {
- Mode string
- AllowTesting bool
- UseSSL bool
- Port string
- Version string
- InviteSalt string
- PublicLinkSalt string
- ResetSalt string
- AnalyticsUrl string
- AllowedLoginAttempts int
- EnableOAuthServiceProvider bool
+ ListenAddress string
+ MaximumLoginAttempts int
SegmentDeveloperKey string
GoogleDeveloperKey string
+ EnableOAuthServiceProvider bool
+ EnableTesting bool
}
type SSOSettings struct {
- Allow bool
+ Enable bool
Secret string
Id string
Scope string
@@ -56,9 +49,9 @@ type SqlSettings struct {
}
type LogSettings struct {
- ConsoleEnable bool
+ EnableConsole bool
ConsoleLevel string
- FileEnable bool
+ EnableFile bool
FileLevel string
FileFormat string
FileLocation string
@@ -68,6 +61,7 @@ type ImageSettings struct {
DriverName string
Directory string
EnablePublicLink bool
+ PublicLinkSalt string
ThumbnailWidth uint
ThumbnailHeight uint
PreviewWidth uint
@@ -82,7 +76,7 @@ type ImageSettings struct {
}
type EmailSettings struct {
- AllowSignUpWithEmail bool
+ EnableSignUpWithEmail bool
SendEmailNotifications bool
RequireEmailVerification bool
FeedbackName string
@@ -92,6 +86,8 @@ type EmailSettings struct {
SMTPServer string
SMTPPort string
ConnectionSecurity string
+ InviteSalt string
+ PasswordResetSalt string
// For Future Use
ApplePushServer string
diff --git a/utils/config.go b/utils/config.go
index 45f62dc19..c2466800e 100644
--- a/utils/config.go
+++ b/utils/config.go
@@ -58,9 +58,9 @@ func FindDir(dir string) string {
func ConfigureCmdLineLog() {
ls := model.LogSettings{}
- ls.ConsoleEnable = true
+ ls.EnableConsole = true
ls.ConsoleLevel = "ERROR"
- ls.FileEnable = false
+ ls.EnableFile = false
configureLog(&ls)
}
@@ -68,7 +68,7 @@ func configureLog(s *model.LogSettings) {
l4g.Close()
- if s.ConsoleEnable {
+ if s.EnableConsole {
level := l4g.DEBUG
if s.ConsoleLevel == "INFO" {
level = l4g.INFO
@@ -79,7 +79,7 @@ func configureLog(s *model.LogSettings) {
l4g.AddFilter("stdout", level, l4g.NewConsoleLogWriter())
}
- if s.FileEnable {
+ if s.EnableFile {
var fileFormat = s.FileFormat
@@ -174,16 +174,15 @@ func getClientProperties(c *model.Config) map[string]string {
props["BuildHash"] = model.BuildHash
props["SiteName"] = c.TeamSettings.SiteName
- props["AnalyticsUrl"] = c.ServiceSettings.AnalyticsUrl
props["EnableOAuthServiceProvider"] = strconv.FormatBool(c.ServiceSettings.EnableOAuthServiceProvider)
props["SegmentDeveloperKey"] = c.ServiceSettings.SegmentDeveloperKey
props["GoogleDeveloperKey"] = c.ServiceSettings.GoogleDeveloperKey
props["SendEmailNotifications"] = strconv.FormatBool(c.EmailSettings.SendEmailNotifications)
- props["AllowSignUpWithEmail"] = strconv.FormatBool(c.EmailSettings.AllowSignUpWithEmail)
+ props["EnableSignUpWithEmail"] = strconv.FormatBool(c.EmailSettings.EnableSignUpWithEmail)
props["FeedbackEmail"] = c.EmailSettings.FeedbackEmail
- props["AllowSignUpWithGitLab"] = strconv.FormatBool(c.GitLabSettings.Allow)
+ props["EnableSignUpWithGitLab"] = strconv.FormatBool(c.GitLabSettings.Enable)
props["ShowEmailAddress"] = strconv.FormatBool(c.PrivacySettings.ShowEmailAddress)
diff --git a/web/react/components/admin_console/admin_controller.jsx b/web/react/components/admin_console/admin_controller.jsx
index 72b5d5c9d..ce7d61ca9 100644
--- a/web/react/components/admin_console/admin_controller.jsx
+++ b/web/react/components/admin_console/admin_controller.jsx
@@ -15,7 +15,7 @@ var RateSettingsTab = require('./rate_settings.jsx');
var GitLabSettingsTab = require('./gitlab_settings.jsx');
var SqlSettingsTab = require('./sql_settings.jsx');
var TeamSettingsTab = require('./team_settings.jsx');
-
+var ServiceSettingsTab = require('./service_settings.jsx');
export default class AdminController extends React.Component {
constructor(props) {
@@ -26,7 +26,7 @@ export default class AdminController extends React.Component {
this.state = {
config: null,
- selected: 'team_settings'
+ selected: 'service_settings'
};
}
@@ -72,6 +72,8 @@ export default class AdminController extends React.Component {
tab = <SqlSettingsTab config={this.state.config} />;
} else if (this.state.selected === 'team_settings') {
tab = <TeamSettingsTab config={this.state.config} />;
+ } else if (this.state.selected === 'service_settings') {
+ tab = <ServiceSettingsTab config={this.state.config} />;
}
}
diff --git a/web/react/components/admin_console/admin_sidebar.jsx b/web/react/components/admin_console/admin_sidebar.jsx
index 2b7159e1d..0983c1276 100644
--- a/web/react/components/admin_console/admin_sidebar.jsx
+++ b/web/react/components/admin_console/admin_sidebar.jsx
@@ -41,6 +41,15 @@ export default class AdminSidebar extends React.Component {
<li>
<a
href='#'
+ className={this.isSelected('service_settings')}
+ onClick={this.handleClick.bind(this, 'service_settings')}
+ >
+ {'Service Settings'}
+ </a>
+ </li>
+ <li>
+ <a
+ href='#'
className={this.isSelected('team_settings')}
onClick={this.handleClick.bind(this, 'team_settings')}
>
diff --git a/web/react/components/admin_console/email_settings.jsx b/web/react/components/admin_console/email_settings.jsx
index a87dfc4da..d94859cdd 100644
--- a/web/react/components/admin_console/email_settings.jsx
+++ b/web/react/components/admin_console/email_settings.jsx
@@ -3,6 +3,7 @@
var Client = require('../../utils/client.jsx');
var AsyncClient = require('../../utils/async_client.jsx');
+var crypto = require('crypto');
export default class EmailSettings extends React.Component {
constructor(props) {
@@ -12,6 +13,8 @@ export default class EmailSettings extends React.Component {
this.handleTestConnection = this.handleTestConnection.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.buildConfig = this.buildConfig.bind(this);
+ this.handleGenerateInvite = this.handleGenerateInvite.bind(this);
+ this.handleGenerateReset = this.handleGenerateReset.bind(this);
this.state = {
sendEmailNotifications: this.props.config.EmailSettings.SendEmailNotifications,
@@ -38,7 +41,7 @@ export default class EmailSettings extends React.Component {
buildConfig() {
var config = this.props.config;
- config.EmailSettings.AllowSignUpWithEmail = React.findDOMNode(this.refs.allowSignUpWithEmail).checked;
+ config.EmailSettings.EnableSignUpWithEmail = React.findDOMNode(this.refs.allowSignUpWithEmail).checked;
config.EmailSettings.SendEmailNotifications = React.findDOMNode(this.refs.sendEmailNotifications).checked;
config.EmailSettings.RequireEmailVerification = React.findDOMNode(this.refs.requireEmailVerification).checked;
config.EmailSettings.SendEmailNotifications = React.findDOMNode(this.refs.sendEmailNotifications).checked;
@@ -49,9 +52,36 @@ export default class EmailSettings extends React.Component {
config.EmailSettings.SMTPUsername = React.findDOMNode(this.refs.SMTPUsername).value.trim();
config.EmailSettings.SMTPPassword = React.findDOMNode(this.refs.SMTPPassword).value.trim();
config.EmailSettings.ConnectionSecurity = React.findDOMNode(this.refs.ConnectionSecurity).value.trim();
+
+ config.EmailSettings.InviteSalt = React.findDOMNode(this.refs.InviteSalt).value.trim();
+ if (config.EmailSettings.InviteSalt === '') {
+ config.EmailSettings.InviteSalt = crypto.randomBytes(256).toString('base64').substring(0, 31);
+ React.findDOMNode(this.refs.InviteSalt).value = config.EmailSettings.InviteSalt;
+ }
+
+ config.EmailSettings.PasswordResetSalt = React.findDOMNode(this.refs.PasswordResetSalt).value.trim();
+ if (config.EmailSettings.PasswordResetSalt === '') {
+ config.EmailSettings.PasswordResetSalt = crypto.randomBytes(256).toString('base64').substring(0, 31);
+ React.findDOMNode(this.refs.PasswordResetSalt).value = config.EmailSettings.PasswordResetSalt;
+ }
+
return config;
}
+ handleGenerateInvite(e) {
+ e.preventDefault();
+ React.findDOMNode(this.refs.InviteSalt).value = crypto.randomBytes(256).toString('base64').substring(0, 31);
+ var s = {saveNeeded: true, serverError: this.state.serverError};
+ this.setState(s);
+ }
+
+ handleGenerateReset(e) {
+ e.preventDefault();
+ React.findDOMNode(this.refs.PasswordResetSalt).value = crypto.randomBytes(256).toString('base64').substring(0, 31);
+ var s = {saveNeeded: true, serverError: this.state.serverError};
+ this.setState(s);
+ }
+
handleTestConnection(e) {
e.preventDefault();
$('#connection-button').button('loading');
@@ -166,7 +196,7 @@ export default class EmailSettings extends React.Component {
name='allowSignUpWithEmail'
value='true'
ref='allowSignUpWithEmail'
- defaultChecked={this.props.config.EmailSettings.AllowSignUpWithEmail}
+ defaultChecked={this.props.config.EmailSettings.EnableSignUpWithEmail}
onChange={this.handleChange.bind(this, 'allowSignUpWithEmail_true')}
/>
{'true'}
@@ -176,7 +206,7 @@ export default class EmailSettings extends React.Component {
type='radio'
name='allowSignUpWithEmail'
value='false'
- defaultChecked={!this.props.config.EmailSettings.AllowSignUpWithEmail}
+ defaultChecked={!this.props.config.EmailSettings.EnableSignUpWithEmail}
onChange={this.handleChange.bind(this, 'allowSignUpWithEmail_false')}
/>
{'false'}
@@ -432,6 +462,68 @@ export default class EmailSettings extends React.Component {
</div>
<div className='form-group'>
+ <label
+ className='control-label col-sm-4'
+ htmlFor='InviteSalt'
+ >
+ {'Invite Salt:'}
+ </label>
+ <div className='col-sm-8'>
+ <input
+ type='text'
+ className='form-control'
+ id='InviteSalt'
+ ref='InviteSalt'
+ placeholder='Ex "bjlSR4QqkXFBr7TP4oDzlfZmcNuH9Yo"'
+ defaultValue={this.props.config.EmailSettings.InviteSalt}
+ onChange={this.handleChange}
+ disabled={!this.state.sendEmailNotifications}
+ />
+ <p className='help-text'>{'32-character salt added to signing of email invites.'}</p>
+ <div className='help-text'>
+ <button
+ className='help-link'
+ onClick={this.handleGenerateInvite}
+ disabled={!this.state.sendEmailNotifications}
+ >
+ {'Re-Generate'}
+ </button>
+ </div>
+ </div>
+ </div>
+
+ <div className='form-group'>
+ <label
+ className='control-label col-sm-4'
+ htmlFor='PasswordResetSalt'
+ >
+ {'Password Reset Salt:'}
+ </label>
+ <div className='col-sm-8'>
+ <input
+ type='text'
+ className='form-control'
+ id='PasswordResetSalt'
+ ref='PasswordResetSalt'
+ placeholder='Ex "bjlSR4QqkXFBr7TP4oDzlfZmcNuH9Yo"'
+ defaultValue={this.props.config.EmailSettings.PasswordResetSalt}
+ onChange={this.handleChange}
+ disabled={!this.state.sendEmailNotifications}
+ />
+ <p className='help-text'>{'32-character salt added to signing of password reset emails.'}</p>
+ <div className='help-text'>
+ <button
+ className='help-link'
+ onClick={this.handleGenerateReset}
+ disabled={!this.state.sendEmailNotifications}
+ >
+ {'Re-Generate'}
+ </button>
+ </div>
+ </div>
+ </div>
+
+ <div className='form-group'>
<div className='col-sm-12'>
{serverError}
<button
diff --git a/web/react/components/admin_console/image_settings.jsx b/web/react/components/admin_console/image_settings.jsx
index c0cbb5aa6..80da0a47f 100644
--- a/web/react/components/admin_console/image_settings.jsx
+++ b/web/react/components/admin_console/image_settings.jsx
@@ -3,6 +3,7 @@
var Client = require('../../utils/client.jsx');
var AsyncClient = require('../../utils/async_client.jsx');
+var crypto = require('crypto');
export default class ImageSettings extends React.Component {
constructor(props) {
@@ -10,6 +11,7 @@ export default class ImageSettings extends React.Component {
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
+ this.handleGenerate = this.handleGenerate.bind(this);
this.state = {
saveNeeded: false,
@@ -28,6 +30,13 @@ export default class ImageSettings extends React.Component {
this.setState(s);
}
+ handleGenerate(e) {
+ e.preventDefault();
+ React.findDOMNode(this.refs.PublicLinkSalt).value = crypto.randomBytes(256).toString('base64').substring(0, 31);
+ var s = {saveNeeded: true, serverError: this.state.serverError};
+ this.setState(s);
+ }
+
handleSubmit(e) {
e.preventDefault();
$('#save-button').button('loading');
@@ -41,6 +50,13 @@ export default class ImageSettings extends React.Component {
config.ImageSettings.AmazonS3Region = React.findDOMNode(this.refs.AmazonS3Region).value;
config.ImageSettings.EnablePublicLink = React.findDOMNode(this.refs.EnablePublicLink).checked;
+ config.ImageSettings.PublicLinkSalt = React.findDOMNode(this.refs.PublicLinkSalt).value.trim();
+
+ if (config.ImageSettings.PublicLinkSalt === '') {
+ config.ImageSettings.PublicLinkSalt = crypto.randomBytes(256).toString('base64').substring(0, 31);
+ React.findDOMNode(this.refs.PublicLinkSalt).value = config.ImageSettings.PublicLinkSalt;
+ }
+
var thumbnailWidth = 120;
if (!isNaN(parseInt(React.findDOMNode(this.refs.ThumbnailWidth).value, 10))) {
thumbnailWidth = parseInt(React.findDOMNode(this.refs.ThumbnailWidth).value, 10);
@@ -425,6 +441,35 @@ export default class ImageSettings extends React.Component {
</div>
<div className='form-group'>
+ <label
+ className='control-label col-sm-4'
+ htmlFor='PublicLinkSalt'
+ >
+ {'Public Link Salt:'}
+ </label>
+ <div className='col-sm-8'>
+ <input
+ type='text'
+ className='form-control'
+ id='PublicLinkSalt'
+ ref='PublicLinkSalt'
+ placeholder='Ex "gxHVDcKUyP2y1eiyW8S8na1UYQAfq6J6"'
+ defaultValue={this.props.config.ImageSettings.PublicLinkSalt}
+ onChange={this.handleChange}
+ />
+ <p className='help-text'>{'32-character salt added to signing of public image links.'}</p>
+ <div className='help-text'>
+ <button
+ className='help-link'
+ onClick={this.handleGenerate}
+ >
+ {'Re-Generate'}
+ </button>
+ </div>
+ </div>
+ </div>
+
+ <div className='form-group'>
<div className='col-sm-12'>
{serverError}
<button
diff --git a/web/react/components/admin_console/log_settings.jsx b/web/react/components/admin_console/log_settings.jsx
index 2707ce6b6..d66801431 100644
--- a/web/react/components/admin_console/log_settings.jsx
+++ b/web/react/components/admin_console/log_settings.jsx
@@ -12,8 +12,8 @@ export default class LogSettings extends React.Component {
this.handleSubmit = this.handleSubmit.bind(this);
this.state = {
- consoleEnable: this.props.config.LogSettings.ConsoleEnable,
- fileEnable: this.props.config.LogSettings.FileEnable,
+ consoleEnable: this.props.config.LogSettings.EnableConsole,
+ fileEnable: this.props.config.LogSettings.EnableFile,
saveNeeded: false,
serverError: null
};
@@ -46,9 +46,9 @@ export default class LogSettings extends React.Component {
$('#save-button').button('loading');
var config = this.props.config;
- config.LogSettings.ConsoleEnable = React.findDOMNode(this.refs.consoleEnable).checked;
+ config.LogSettings.EnableConsole = React.findDOMNode(this.refs.consoleEnable).checked;
config.LogSettings.ConsoleLevel = React.findDOMNode(this.refs.consoleLevel).value;
- config.LogSettings.FileEnable = React.findDOMNode(this.refs.fileEnable).checked;
+ config.LogSettings.EnableFile = React.findDOMNode(this.refs.fileEnable).checked;
config.LogSettings.FileLevel = React.findDOMNode(this.refs.fileLevel).value;
config.LogSettings.FileLocation = React.findDOMNode(this.refs.fileLocation).value.trim();
config.LogSettings.FileFormat = React.findDOMNode(this.refs.fileFormat).value.trim();
@@ -58,8 +58,8 @@ export default class LogSettings extends React.Component {
() => {
AsyncClient.getConfig();
this.setState({
- consoleEnable: config.LogSettings.ConsoleEnable,
- fileEnable: config.LogSettings.FileEnable,
+ consoleEnable: config.LogSettings.EnableConsole,
+ fileEnable: config.LogSettings.EnableFile,
serverError: null,
saveNeeded: false
});
@@ -67,8 +67,8 @@ export default class LogSettings extends React.Component {
},
(err) => {
this.setState({
- consoleEnable: config.LogSettings.ConsoleEnable,
- fileEnable: config.LogSettings.FileEnable,
+ consoleEnable: config.LogSettings.EnableConsole,
+ fileEnable: config.LogSettings.EnableFile,
serverError: err.message,
saveNeeded: true
});
@@ -110,7 +110,7 @@ export default class LogSettings extends React.Component {
name='consoleEnable'
value='true'
ref='consoleEnable'
- defaultChecked={this.props.config.LogSettings.ConsoleEnable}
+ defaultChecked={this.props.config.LogSettings.EnableConsole}
onChange={this.handleChange.bind(this, 'console_true')}
/>
{'true'}
@@ -120,7 +120,7 @@ export default class LogSettings extends React.Component {
type='radio'
name='consoleEnable'
value='false'
- defaultChecked={!this.props.config.LogSettings.ConsoleEnable}
+ defaultChecked={!this.props.config.LogSettings.EnableConsole}
onChange={this.handleChange.bind(this, 'console_false')}
/>
{'false'}
@@ -166,7 +166,7 @@ export default class LogSettings extends React.Component {
name='fileEnable'
ref='fileEnable'
value='true'
- defaultChecked={this.props.config.LogSettings.FileEnable}
+ defaultChecked={this.props.config.LogSettings.EnableFile}
onChange={this.handleChange.bind(this, 'file_true')}
/>
{'true'}
@@ -176,7 +176,7 @@ export default class LogSettings extends React.Component {
type='radio'
name='fileEnable'
value='false'
- defaultChecked={!this.props.config.LogSettings.FileEnable}
+ defaultChecked={!this.props.config.LogSettings.EnableFile}
onChange={this.handleChange.bind(this, 'file_false')}
/>
{'false'}
diff --git a/web/react/components/admin_console/service_settings.jsx b/web/react/components/admin_console/service_settings.jsx
new file mode 100644
index 000000000..fcb8f800d
--- /dev/null
+++ b/web/react/components/admin_console/service_settings.jsx
@@ -0,0 +1,262 @@
+// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+var Client = require('../../utils/client.jsx');
+var AsyncClient = require('../../utils/async_client.jsx');
+
+export default class ServiceSettings extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.handleChange = this.handleChange.bind(this);
+ this.handleSubmit = this.handleSubmit.bind(this);
+
+ this.state = {
+ saveNeeded: false,
+ serverError: null
+ };
+ }
+
+ handleChange() {
+ var s = {saveNeeded: true, serverError: this.state.serverError};
+ this.setState(s);
+ }
+
+ handleSubmit(e) {
+ e.preventDefault();
+ $('#save-button').button('loading');
+
+ var config = this.props.config;
+ config.ServiceSettings.ListenAddress = React.findDOMNode(this.refs.ListenAddress).value.trim();
+ if (config.ServiceSettings.ListenAddress === '') {
+ config.ServiceSettings.ListenAddress = ':8065';
+ React.findDOMNode(this.refs.ListenAddress).value = config.ServiceSettings.ListenAddress;
+ }
+
+ config.ServiceSettings.SegmentDeveloperKey = React.findDOMNode(this.refs.SegmentDeveloperKey).value.trim();
+ config.ServiceSettings.GoogleDeveloperKey = React.findDOMNode(this.refs.GoogleDeveloperKey).value.trim();
+ config.ServiceSettings.EnableOAuthServiceProvider = React.findDOMNode(this.refs.EnableOAuthServiceProvider).checked;
+ config.ServiceSettings.EnableTesting = React.findDOMNode(this.refs.EnableTesting).checked;
+
+ var MaximumLoginAttempts = 10;
+ if (!isNaN(parseInt(React.findDOMNode(this.refs.MaximumLoginAttempts).value, 10))) {
+ MaximumLoginAttempts = parseInt(React.findDOMNode(this.refs.MaximumLoginAttempts).value, 10);
+ }
+ config.ServiceSettings.MaximumLoginAttempts = MaximumLoginAttempts;
+ React.findDOMNode(this.refs.MaximumLoginAttempts).value = MaximumLoginAttempts;
+
+ Client.saveConfig(
+ config,
+ () => {
+ AsyncClient.getConfig();
+ this.setState({
+ serverError: null,
+ saveNeeded: false
+ });
+ $('#save-button').button('reset');
+ },
+ (err) => {
+ this.setState({
+ serverError: err.message,
+ saveNeeded: true
+ });
+ $('#save-button').button('reset');
+ }
+ );
+ }
+
+ render() {
+ var serverError = '';
+ if (this.state.serverError) {
+ serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
+ }
+
+ var saveClass = 'btn';
+ if (this.state.saveNeeded) {
+ saveClass = 'btn btn-primary';
+ }
+
+ return (
+ <div className='wrapper--fixed'>
+
+ <h3>{'Service Settings'}</h3>
+ <form
+ className='form-horizontal'
+ role='form'
+ >
+
+ <div className='form-group'>
+ <label
+ className='control-label col-sm-4'
+ htmlFor='ListenAddress'
+ >
+ {'Listen Address:'}
+ </label>
+ <div className='col-sm-8'>
+ <input
+ type='text'
+ className='form-control'
+ id='ListenAddress'
+ ref='ListenAddress'
+ placeholder='Ex ":8065"'
+ defaultValue={this.props.config.ServiceSettings.ListenAddress}
+ onChange={this.handleChange}
+ />
+ <p className='help-text'>{'The address to bind to and listen. ":8065" will bind to all interfaces or you can choose one like "127.0.0.1:8065". Changing this will require a server restart before taking effect.'}</p>
+ </div>
+ </div>
+
+ <div className='form-group'>
+ <label
+ className='control-label col-sm-4'
+ htmlFor='MaximumLoginAttempts'
+ >
+ {'Maximum Login Attempts:'}
+ </label>
+ <div className='col-sm-8'>
+ <input
+ type='text'
+ className='form-control'
+ id='MaximumLoginAttempts'
+ ref='MaximumLoginAttempts'
+ placeholder='Ex "10"'
+ defaultValue={this.props.config.ServiceSettings.MaximumLoginAttempts}
+ onChange={this.handleChange}
+ />
+ <p className='help-text'>{'Login attempts allowed before user is locked out and required to reset password via email.'}</p>
+ </div>
+ </div>
+
+ <div className='form-group'>
+ <label
+ className='control-label col-sm-4'
+ htmlFor='SegmentDeveloperKey'
+ >
+ {'Segment Developer Key:'}
+ </label>
+ <div className='col-sm-8'>
+ <input
+ type='text'
+ className='form-control'
+ id='SegmentDeveloperKey'
+ ref='SegmentDeveloperKey'
+ placeholder='Ex "g3fgGOXJAQ43QV7rAh6iwQCkV4cA1Gs"'
+ defaultValue={this.props.config.ServiceSettings.SegmentDeveloperKey}
+ onChange={this.handleChange}
+ />
+ <p className='help-text'>{'For users running a SaaS services, sign up for a key at Segment.com to track metrics.'}</p>
+ </div>
+ </div>
+
+ <div className='form-group'>
+ <label
+ className='control-label col-sm-4'
+ htmlFor='GoogleDeveloperKey'
+ >
+ {'Google Developer Key:'}
+ </label>
+ <div className='col-sm-8'>
+ <input
+ type='text'
+ className='form-control'
+ id='GoogleDeveloperKey'
+ ref='GoogleDeveloperKey'
+ placeholder='Ex "7rAh6iwQCkV4cA1Gsg3fgGOXJAQ43QV"'
+ defaultValue={this.props.config.ServiceSettings.GoogleDeveloperKey}
+ onChange={this.handleChange}
+ />
+ <p className='help-text'>{'Set this key to enable embedding of YouTube video previews based on hyperlinks appearing in messages or comments. Instructions to obtain a key available at '}<a href='https://www.youtube.com/watch?v=Im69kzhpR3I'>{'https://www.youtube.com/watch?v=Im69kzhpR3I'}</a>{'. Leaving field blank disables the automatic generation of YouTube video previews from links.'}</p>
+ </div>
+ </div>
+
+ <div className='form-group'>
+ <label
+ className='control-label col-sm-4'
+ htmlFor='EnableOAuthServiceProvider'
+ >
+ {'Enable OAuth Service Provider: '}
+ </label>
+ <div className='col-sm-8'>
+ <label className='radio-inline'>
+ <input
+ type='radio'
+ name='EnableOAuthServiceProvider'
+ value='true'
+ ref='EnableOAuthServiceProvider'
+ defaultChecked={this.props.config.ServiceSettings.EnableOAuthServiceProvider}
+ onChange={this.handleChange}
+ />
+ {'true'}
+ </label>
+ <label className='radio-inline'>
+ <input
+ type='radio'
+ name='EnableOAuthServiceProvider'
+ value='false'
+ defaultChecked={!this.props.config.ServiceSettings.EnableOAuthServiceProvider}
+ onChange={this.handleChange}
+ />
+ {'false'}
+ </label>
+ <p className='help-text'>{'When enabled Mattermost will act as an Oauth2 Provider. Changing this will require a server restart before taking effect.'}</p>
+ </div>
+ </div>
+
+ <div className='form-group'>
+ <label
+ className='control-label col-sm-4'
+ htmlFor='EnableTesting'
+ >
+ {'Enable Testing: '}
+ </label>
+ <div className='col-sm-8'>
+ <label className='radio-inline'>
+ <input
+ type='radio'
+ name='EnableTesting'
+ value='true'
+ ref='EnableTesting'
+ defaultChecked={this.props.config.ServiceSettings.EnableTesting}
+ onChange={this.handleChange}
+ />
+ {'true'}
+ </label>
+ <label className='radio-inline'>
+ <input
+ type='radio'
+ name='EnableTesting'
+ value='false'
+ defaultChecked={!this.props.config.ServiceSettings.EnableTesting}
+ onChange={this.handleChange}
+ />
+ {'false'}
+ </label>
+ <p className='help-text'>{'When true slash commands like /loadtest are enabled in the add comment box. Changing this will require a server restart before taking effect. Typically used for development.'}</p>
+ </div>
+ </div>
+
+ <div className='form-group'>
+ <div className='col-sm-12'>
+ {serverError}
+ <button
+ disabled={!this.state.saveNeeded}
+ type='submit'
+ className={saveClass}
+ onClick={this.handleSubmit}
+ id='save-button'
+ data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> Saving Config...'}
+ >
+ {'Save'}
+ </button>
+ </div>
+ </div>
+
+ </form>
+ </div>
+ );
+ }
+}
+
+ServiceSettings.propTypes = {
+ config: React.PropTypes.object
+};
diff --git a/web/react/components/admin_console/sql_settings.jsx b/web/react/components/admin_console/sql_settings.jsx
index 35810f7ee..cac017770 100644
--- a/web/react/components/admin_console/sql_settings.jsx
+++ b/web/react/components/admin_console/sql_settings.jsx
@@ -207,7 +207,7 @@ export default class SqlSettings extends React.Component {
className='form-control'
id='AtRestEncryptKey'
ref='AtRestEncryptKey'
- placeholder='Ex "10"'
+ placeholder='Ex "gxHVDcKUyP2y1eiyW8S8na1UYQAfq6J6"'
defaultValue={this.props.config.SqlSettings.AtRestEncryptKey}
onChange={this.handleChange}
/>
diff --git a/web/react/components/login.jsx b/web/react/components/login.jsx
index b12c5d988..8cc4f1483 100644
--- a/web/react/components/login.jsx
+++ b/web/react/components/login.jsx
@@ -95,7 +95,7 @@ export default class Login extends React.Component {
}
let loginMessage = [];
- if (global.window.config.AllowSignUpWithGitLab === 'true') {
+ if (global.window.config.EnableSignUpWithGitLab === 'true') {
loginMessage.push(
<a
className='btn btn-custom-login gitlab'
@@ -113,7 +113,7 @@ export default class Login extends React.Component {
}
let emailSignup;
- if (global.window.config.AllowSignUpWithEmail === 'true') {
+ if (global.window.config.EnableSignUpWithEmail === 'true') {
emailSignup = (
<div>
<div className={'form-group' + errorClass}>
diff --git a/web/react/components/signup_team.jsx b/web/react/components/signup_team.jsx
index d08608c9b..7f320e0b2 100644
--- a/web/react/components/signup_team.jsx
+++ b/web/react/components/signup_team.jsx
@@ -14,19 +14,19 @@ export default class TeamSignUp extends React.Component {
var count = 0;
- if (global.window.config.AllowSignUpWithEmail === 'true') {
+ if (global.window.config.EnableSignUpWithEmail === 'true') {
count = count + 1;
}
- if (global.window.config.AllowSignUpWithGitLab === 'true') {
+ if (global.window.config.EnableSignUpWithGitLab === 'true') {
count = count + 1;
}
if (count > 1) {
this.state = {page: 'choose'};
- } else if (global.window.config.AllowSignUpWithEmail === 'true') {
+ } else if (global.window.config.EnableSignUpWithEmail === 'true') {
this.state = {page: 'email'};
- } else if (global.window.config.AllowSignUpWithGitLab === 'true') {
+ } else if (global.window.config.EnableSignUpWithGitLab === 'true') {
this.state = {page: 'gitlab'};
}
}
diff --git a/web/react/components/signup_user_complete.jsx b/web/react/components/signup_user_complete.jsx
index 237169f17..4dad1ef4f 100644
--- a/web/react/components/signup_user_complete.jsx
+++ b/web/react/components/signup_user_complete.jsx
@@ -161,7 +161,7 @@ export default class SignupUserComplete extends React.Component {
);
var signupMessage = [];
- if (global.window.config.AllowSignUpWithGitLab === 'true') {
+ if (global.window.config.EnableSignUpWithGitLab === 'true') {
signupMessage.push(
<a
className='btn btn-custom-login gitlab'
@@ -174,7 +174,7 @@ export default class SignupUserComplete extends React.Component {
}
var emailSignup;
- if (global.window.config.AllowSignUpWithEmail === 'true') {
+ if (global.window.config.EnableSignUpWithEmail === 'true') {
emailSignup = (
<div>
<div className='inner__content'>
diff --git a/web/react/components/team_signup_choose_auth.jsx b/web/react/components/team_signup_choose_auth.jsx
index 4aeae8f08..b8264b887 100644
--- a/web/react/components/team_signup_choose_auth.jsx
+++ b/web/react/components/team_signup_choose_auth.jsx
@@ -8,7 +8,7 @@ export default class ChooseAuthPage extends React.Component {
}
render() {
var buttons = [];
- if (global.window.config.AllowSignUpWithGitLab === 'true') {
+ if (global.window.config.EnableSignUpWithGitLab === 'true') {
buttons.push(
<a
className='btn btn-custom-login gitlab btn-full'
@@ -26,7 +26,7 @@ export default class ChooseAuthPage extends React.Component {
);
}
- if (global.window.config.AllowSignUpWithEmail === 'true') {
+ if (global.window.config.EnableSignUpWithEmail === 'true') {
buttons.push(
<a
className='btn btn-custom-login email btn-full'
diff --git a/web/react/utils/client.jsx b/web/react/utils/client.jsx
index b3fb28e99..b01e2bb24 100644
--- a/web/react/utils/client.jsx
+++ b/web/react/utils/client.jsx
@@ -4,12 +4,10 @@ var BrowserStore = require('../stores/browser_store.jsx');
var TeamStore = require('../stores/team_store.jsx');
export function track(category, action, label, prop, val) {
- global.window.snowplow('trackStructEvent', category, action, label, prop, val);
global.window.analytics.track(action, {category: category, label: label, property: prop, value: val});
}
export function trackPage() {
- global.window.snowplow('trackPageView');
global.window.analytics.page();
}
diff --git a/web/templates/head.html b/web/templates/head.html
index af5c86bba..39d5a262c 100644
--- a/web/templates/head.html
+++ b/web/templates/head.html
@@ -77,28 +77,5 @@
analytics.track = function(){};
}
</script>
- <!-- Snowplow starts plowing -->
- <script type="text/javascript">
- if ('{{ .Props.AnalyticsUrl }}'.trim() !== '') {
- ;(function(p,l,o,w,i,n,g){if(!p[i]){p.GlobalSnowplowNamespace=p.GlobalSnowplowNamespace||[];
- p.GlobalSnowplowNamespace.push(i);p[i]=function(){(p[i].q=p[i].q||[]).push(arguments)
- };p[i].q=p[i].q||[];n=l.createElement(o);g=l.getElementsByTagName(o)[0];n.async=1;
- n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.4.2/sp.js","snowplow"));
-
- window.snowplow('newTracker', 'cf', '{{ .Props.AnalyticsUrl }}', {
- appId: window.config.SiteName
- });
-
- var user = window.UserStore.getCurrentUser(true);
- if (user) {
- window.snowplow('setUserId', user.id);
- }
-
- window.snowplow('trackPageView');
- } else {
- window.snowplow = function(){};
- }
- </script>
- <!-- Snowplow stops plowing -->
</head>
{{end}}
diff --git a/web/web.go b/web/web.go
index 86769dd54..9847d0b5e 100644
--- a/web/web.go
+++ b/web/web.go
@@ -204,7 +204,7 @@ func signupTeamComplete(c *api.Context, w http.ResponseWriter, r *http.Request)
data := r.FormValue("d")
hash := r.FormValue("h")
- if !model.ComparePassword(hash, fmt.Sprintf("%v:%v", data, utils.Cfg.ServiceSettings.InviteSalt)) {
+ if !model.ComparePassword(hash, fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt)) {
c.Err = model.NewAppError("signupTeamComplete", "The signup link does not appear to be valid", "")
return
}
@@ -253,7 +253,7 @@ func signupUserComplete(c *api.Context, w http.ResponseWriter, r *http.Request)
}
} else {
- if !model.ComparePassword(hash, fmt.Sprintf("%v:%v", data, utils.Cfg.ServiceSettings.InviteSalt)) {
+ if !model.ComparePassword(hash, fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt)) {
c.Err = model.NewAppError("signupTeamComplete", "The signup link does not appear to be valid", "")
return
}
@@ -414,7 +414,7 @@ func resetPassword(c *api.Context, w http.ResponseWriter, r *http.Request) {
if len(hash) == 0 || len(data) == 0 {
isResetLink = false
} else {
- if !model.ComparePassword(hash, fmt.Sprintf("%v:%v", data, utils.Cfg.ServiceSettings.ResetSalt)) {
+ if !model.ComparePassword(hash, fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.PasswordResetSalt)) {
c.Err = model.NewAppError("resetPassword", "The reset link does not appear to be valid", "")
return
}
@@ -476,7 +476,7 @@ func signupWithOAuth(c *api.Context, w http.ResponseWriter, r *http.Request) {
data := r.URL.Query().Get("d")
props := model.MapFromJson(strings.NewReader(data))
- if !model.ComparePassword(hash, fmt.Sprintf("%v:%v", data, utils.Cfg.ServiceSettings.InviteSalt)) {
+ if !model.ComparePassword(hash, fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt)) {
c.Err = model.NewAppError("signupWithOAuth", "The signup link does not appear to be valid", "")
return
}
diff --git a/web/web_test.go b/web/web_test.go
index 3da7eb2dc..c1d5dd6f9 100644
--- a/web/web_test.go
+++ b/web/web_test.go
@@ -25,7 +25,7 @@ func Setup() {
api.StartServer()
api.InitApi()
InitWeb()
- URL = "http://localhost:" + utils.Cfg.ServiceSettings.Port
+ URL = "http://localhost" + utils.Cfg.ServiceSettings.ListenAddress
ApiClient = model.NewClient(URL)
}
}