Adding service settings to admin console

Этот коммит содержится в:
=Corey Hulen
2015-09-22 12:12:50 -07:00
родитель 08a3acbb44
Коммит 88e5a71e8c
37 изменённых файлов: 631 добавлений и 297 удалений

Просмотреть файл

@@ -35,7 +35,7 @@ func getLogs(c *Context, w http.ResponseWriter, r *http.Request) {
var lines []string var lines []string
if utils.Cfg.LogSettings.FileEnable { if utils.Cfg.LogSettings.EnableFile {
file, err := os.Open(utils.GetLogFileLocation(utils.Cfg.LogSettings.FileLocation)) file, err := os.Open(utils.GetLogFileLocation(utils.Cfg.LogSettings.FileLocation))
if err != nil { if err != nil {
@@ -82,7 +82,7 @@ func saveConfig(c *Context, w http.ResponseWriter, r *http.Request) {
return return
} }
if len(cfg.ServiceSettings.Port) == 0 { if len(cfg.ServiceSettings.ListenAddress) == 0 {
c.SetInvalidParam("saveConfig", "config") c.SetInvalidParam("saveConfig", "config")
return return
} }

Просмотреть файл

@@ -18,7 +18,7 @@ func Setup() {
NewServer() NewServer()
StartServer() StartServer()
InitApi() InitApi()
Client = model.NewClient("http://localhost:" + utils.Cfg.ServiceSettings.Port) Client = model.NewClient("http://localhost" + utils.Cfg.ServiceSettings.ListenAddress)
} }
} }

Просмотреть файл

@@ -627,7 +627,7 @@ func TestGetChannelExtraInfo(t *testing.T) {
currentEtag = cache_result.Etag 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 := &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) user2 = Client2.Must(Client2.CreateUser(user2, "")).Data.(*model.User)

Просмотреть файл

@@ -215,8 +215,8 @@ func joinCommand(c *Context, command *model.Command) bool {
func loadTestCommand(c *Context, command *model.Command) bool { func loadTestCommand(c *Context, command *model.Command) bool {
cmd := "/loadtest" cmd := "/loadtest"
// This command is only available when AllowTesting is true // This command is only available when EnableTesting is true
if !utils.Cfg.ServiceSettings.AllowTesting { if !utils.Cfg.ServiceSettings.EnableTesting {
return false return false
} }

Просмотреть файл

@@ -107,21 +107,7 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
isTokenFromQueryString = true isTokenFromQueryString = true
} }
protocol := "http" protocol := GetProtocol(r)
// 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"
}
}
c.setSiteURL(protocol + "://" + r.Host) c.setSiteURL(protocol + "://" + r.Host)
w.Header().Set(model.HEADER_REQUEST_ID, c.RequestId) 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) { 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} 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 { 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 { func GetIpAddress(r *http.Request) string {
address := r.Header.Get(model.HEADER_FORWARDED) address := r.Header.Get(model.HEADER_FORWARDED)
if len(address) == 0 {
address = r.Header.Get(model.HEADER_REAL_IP)
}
if len(address) == 0 { if len(address) == 0 {
address, _, _ = net.SplitHostPort(r.RemoteAddr) 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) { func RenderWebError(err *model.AppError, w http.ResponseWriter, r *http.Request) {
protocol := "http" protocol := GetProtocol(r)
if utils.Cfg.ServiceSettings.UseSSL {
forwardProto := r.Header.Get(model.HEADER_FORWARDED_PROTO)
if forwardProto != "http" {
protocol = "https"
}
}
SiteURL := protocol + "://" + r.Host SiteURL := protocol + "://" + r.Host
m := make(map[string]string) m := make(map[string]string)

Просмотреть файл

@@ -399,7 +399,7 @@ func getFile(c *Context, w http.ResponseWriter, r *http.Request) {
asyncGetFile(path, fileData) asyncGetFile(path, fileData)
if len(hash) > 0 && len(data) > 0 && len(teamId) == 26 { 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", "") c.Err = model.NewAppError("getFile", "The public link does not appear to be valid", "")
return return
} }
@@ -477,7 +477,7 @@ func getPublicLink(c *Context, w http.ResponseWriter, r *http.Request) {
newProps["time"] = fmt.Sprintf("%v", model.GetMillis()) newProps["time"] = fmt.Sprintf("%v", model.GetMillis())
data := model.MapToJson(newProps) 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) 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)

Просмотреть файл

@@ -38,7 +38,7 @@ func BenchmarkGetFile(b *testing.B) {
newProps["time"] = fmt.Sprintf("%v", model.GetMillis()) newProps["time"] = fmt.Sprintf("%v", model.GetMillis())
data := model.MapToJson(newProps) 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 // wait a bit for files to ready
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)

Просмотреть файл

@@ -222,7 +222,7 @@ func TestGetFile(t *testing.T) {
newProps["time"] = fmt.Sprintf("%v", model.GetMillis()) newProps["time"] = fmt.Sprintf("%v", model.GetMillis())
data := model.MapToJson(newProps) 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") Client.LoginByEmail(team2.Name, user2.Email, "pwd")

Просмотреть файл

@@ -38,7 +38,7 @@ func NewServer() {
func StartServer() { func StartServer() {
l4g.Info("Starting Server...") 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 var handler http.Handler = Srv.Router
@@ -71,7 +71,7 @@ func StartServer() {
} }
go func() { go func() {
err := Srv.Server.ListenAndServe(":"+utils.Cfg.ServiceSettings.Port, handler) err := Srv.Server.ListenAndServe(utils.Cfg.ServiceSettings.ListenAddress, handler)
if err != nil { if err != nil {
l4g.Critical("Error starting server, err:%v", err) l4g.Critical("Error starting server, err:%v", err)
time.Sleep(time.Second) time.Sleep(time.Second)

Просмотреть файл

@@ -38,7 +38,7 @@ func InitTeam(r *mux.Router) {
} }
func signupTeam(c *Context, w http.ResponseWriter, r *http.Request) { 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 = model.NewAppError("signupTeam", "Team sign-up with email is disabled.", "")
c.Err.StatusCode = http.StatusNotImplemented c.Err.StatusCode = http.StatusNotImplemented
return return
@@ -66,7 +66,7 @@ func signupTeam(c *Context, w http.ResponseWriter, r *http.Request) {
props["time"] = fmt.Sprintf("%v", model.GetMillis()) props["time"] = fmt.Sprintf("%v", model.GetMillis())
data := model.MapToJson(props) 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)) 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"] service := params["service"]
sso := utils.Cfg.GetSSOService(service) sso := utils.Cfg.GetSSOService(service)
if sso != nil && !sso.Allow { if sso != nil && !sso.Enable {
c.SetInvalidParam("createTeamFromSSO", "service") c.SetInvalidParam("createTeamFromSSO", "service")
return 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) { 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 = model.NewAppError("createTeamFromSignup", "Team sign-up with email is disabled.", "")
c.Err.StatusCode = http.StatusNotImplemented c.Err.StatusCode = http.StatusNotImplemented
return return
@@ -183,7 +183,7 @@ func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) {
teamSignup.User.TeamId = "" teamSignup.User.TeamId = ""
teamSignup.User.Password = password 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", "") c.Err = model.NewAppError("createTeamFromSignup", "The signup link does not appear to be valid", "")
return return
} }
@@ -243,7 +243,7 @@ func createTeam(c *Context, w http.ResponseWriter, r *http.Request) {
} }
func CreateTeam(c *Context, team *model.Team) *model.Team { 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 = model.NewAppError("createTeam", "Team sign-up with email is disabled.", "")
c.Err.StatusCode = http.StatusNotImplemented c.Err.StatusCode = http.StatusNotImplemented
return nil return nil
@@ -258,11 +258,6 @@ func CreateTeam(c *Context, team *model.Team) *model.Team {
return nil 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 { if result := <-Srv.Store.Team().Save(team); result.Err != nil {
c.Err = result.Err c.Err = result.Err
return nil return nil
@@ -488,10 +483,10 @@ func InviteMembers(c *Context, team *model.Team, user *model.User, invites []str
props["name"] = team.Name props["name"] = team.Name
props["time"] = fmt.Sprintf("%v", model.GetMillis()) props["time"] = fmt.Sprintf("%v", model.GetMillis())
data := model.MapToJson(props) 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)) 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"]) l4g.Info("sending invitation to %v %v", invite, bodyPage.Props["Link"])
} }

Просмотреть файл

@@ -30,7 +30,7 @@ func TestCreateFromSignupTeam(t *testing.T) {
props["time"] = fmt.Sprintf("%v", model.GetMillis()) props["time"] = fmt.Sprintf("%v", model.GetMillis())
data := model.MapToJson(props) 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} 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"} user := model.User{Email: props["email"], Nickname: "Corey Hulen", Password: "hello"}

Просмотреть файл

@@ -58,7 +58,7 @@ func InitUser(r *mux.Router) {
} }
func createUser(c *Context, w http.ResponseWriter, r *http.Request) { 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 = model.NewAppError("signupTeam", "User sign-up with email is disabled.", "")
c.Err.StatusCode = http.StatusNotImplemented c.Err.StatusCode = http.StatusNotImplemented
return return
@@ -90,7 +90,7 @@ func createUser(c *Context, w http.ResponseWriter, r *http.Request) {
data := r.URL.Query().Get("d") data := r.URL.Query().Get("d")
props := model.MapFromJson(strings.NewReader(data)) 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", "") c.Err = model.NewAppError("createUser", "The signup link does not appear to be valid", "")
return 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 { 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.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 = 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 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()) newProps["time"] = fmt.Sprintf("%v", model.GetMillis())
data := model.MapToJson(newProps) 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)) 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 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", "") c.Err = model.NewAppError("resetPassword", "The reset password link does not appear to be valid", "")
return 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) { func GetAuthorizationCode(c *Context, w http.ResponseWriter, r *http.Request, teamName, service, redirectUri, loginHint string) {
sso := utils.Cfg.GetSSOService(service) 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 = model.NewAppError("GetAuthorizationCode", "Unsupported OAuth service provider", "service="+service)
c.Err.StatusCode = http.StatusBadRequest c.Err.StatusCode = http.StatusBadRequest
return 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) { func AuthorizeOAuthUser(service, code, state, redirectUri string) (io.ReadCloser, *model.Team, *model.AppError) {
sso := utils.Cfg.GetSSOService(service) 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) return nil, nil, model.NewAppError("AuthorizeOAuthUser", "Unsupported OAuth service provider", "service="+service)
} }

Просмотреть файл

@@ -151,7 +151,7 @@ func TestLogin(t *testing.T) {
props["display_name"] = rteam2.Data.(*model.Team).DisplayName props["display_name"] = rteam2.Data.(*model.Team).DisplayName
props["time"] = fmt.Sprintf("%v", model.GetMillis()) props["time"] = fmt.Sprintf("%v", model.GetMillis())
data := model.MapToJson(props) 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) ruser2, _ := Client.CreateUserFromSignup(&user2, data, hash)
@@ -814,7 +814,7 @@ func TestResetPassword(t *testing.T) {
props["user_id"] = user.Id props["user_id"] = user.Id
props["time"] = fmt.Sprintf("%v", model.GetMillis()) props["time"] = fmt.Sprintf("%v", model.GetMillis())
data["data"] = model.MapToJson(props) 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 data["name"] = team.Name
if _, err := Client.ResetPassword(data); err != nil { if _, err := Client.ResetPassword(data); err != nil {

Просмотреть файл

@@ -16,7 +16,7 @@ import (
func TestSocket(t *testing.T) { func TestSocket(t *testing.T) {
Setup() 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 := &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) team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)

Просмотреть файл

@@ -1,18 +1,11 @@
{ {
"ServiceSettings": { "ServiceSettings": {
"Mode": "dev", "ListenAddress": ":8065",
"AllowTesting": false, "MaximumLoginAttempts": 10,
"UseSSL": false,
"Port": "8065",
"Version": "developer",
"InviteSalt": "gxHVDcKUyP2y1eiyW8S8na1UYQAfq6J6",
"PublicLinkSalt": "TO3pTyXIZzwHiwyZgGql7lM7DG3zeId4",
"ResetSalt": "IPxFzSfnDFsNsRafZxz8NaYqFKhf9y2t",
"AnalyticsUrl": "",
"AllowedLoginAttempts": 10,
"EnableOAuthServiceProvider": false,
"SegmentDeveloperKey": "", "SegmentDeveloperKey": "",
"GoogleDeveloperKey": "" "GoogleDeveloperKey": "",
"EnableOAuthServiceProvider": false,
"EnableTesting": false
}, },
"TeamSettings": { "TeamSettings": {
"SiteName": "Mattermost", "SiteName": "Mattermost",
@@ -32,9 +25,9 @@
"AtRestEncryptKey": "7rAh6iwQCkV4cA1Gsg3fgGOXJAQ43QV" "AtRestEncryptKey": "7rAh6iwQCkV4cA1Gsg3fgGOXJAQ43QV"
}, },
"LogSettings": { "LogSettings": {
"ConsoleEnable": true, "EnableConsole": true,
"ConsoleLevel": "DEBUG", "ConsoleLevel": "DEBUG",
"FileEnable": true, "EnableFile": true,
"FileLevel": "INFO", "FileLevel": "INFO",
"FileFormat": "", "FileFormat": "",
"FileLocation": "" "FileLocation": ""
@@ -43,6 +36,7 @@
"DriverName": "local", "DriverName": "local",
"Directory": "./data/", "Directory": "./data/",
"EnablePublicLink": true, "EnablePublicLink": true,
"PublicLinkSalt": "LhaAWC6lYEKHTkBKsvyXNIOfUIT37AX",
"ThumbnailWidth": 120, "ThumbnailWidth": 120,
"ThumbnailHeight": 100, "ThumbnailHeight": 100,
"PreviewWidth": 1024, "PreviewWidth": 1024,
@@ -56,7 +50,7 @@
"AmazonS3Region": "" "AmazonS3Region": ""
}, },
"EmailSettings": { "EmailSettings": {
"AllowSignUpWithEmail": true, "EnableSignUpWithEmail": true,
"SendEmailNotifications": false, "SendEmailNotifications": false,
"RequireEmailVerification": false, "RequireEmailVerification": false,
"FeedbackName": "", "FeedbackName": "",
@@ -66,6 +60,8 @@
"SMTPServer": "", "SMTPServer": "",
"SMTPPort": "", "SMTPPort": "",
"ConnectionSecurity": "", "ConnectionSecurity": "",
"InviteSalt": "bjlSR4QqkXFBr7TP4oDzlfZmcNuH9Yo",
"PasswordResetSalt": "vZ4DcKyVVRlKHHJpexcuXzojkE5PZ5e",
"ApplePushServer": "", "ApplePushServer": "",
"ApplePushCertPublic": "", "ApplePushCertPublic": "",
"ApplePushCertPrivate": "" "ApplePushCertPrivate": ""
@@ -82,7 +78,7 @@
"ShowFullName": true "ShowFullName": true
}, },
"GitLabSettings": { "GitLabSettings": {
"Allow": false, "Enable": false,
"Secret": "", "Secret": "",
"Id": "", "Id": "",
"Scope": "", "Scope": "",

Просмотреть файл

@@ -1,81 +1,73 @@
{ {
"ServiceSettings": {
"ListenAddress": ":80",
"MaximumLoginAttempts": 10,
"SegmentDeveloperKey": "",
"GoogleDeveloperKey": "",
"EnableOAuthServiceProvider": false,
"EnableTesting": false
},
"TeamSettings": {
"SiteName": "Mattermost",
"MaxUsersPerTeam": 50,
"DefaultThemeColor": "#2389D7",
"EnableTeamCreation": true,
"EnableUserCreation": true,
"RestrictCreationToDomains": ""
},
"SqlSettings": {
"DriverName": "mysql",
"DataSource": "mmuser:mostest@tcp(dockerhost:3306)/mattermost_test?charset=utf8mb4,utf8",
"DataSourceReplicas": [],
"MaxIdleConns": 10,
"MaxOpenConns": 10,
"Trace": false,
"AtRestEncryptKey": "7rAh6iwQCkV4cA1Gsg3fgGOXJAQ43QV"
},
"LogSettings": { "LogSettings": {
"ConsoleEnable": true, "EnableConsole": false,
"ConsoleLevel": "INFO", "ConsoleLevel": "INFO",
"FileEnable": true, "EnableFile": true,
"FileLevel": "INFO", "FileLevel": "INFO",
"FileFormat": "", "FileFormat": "",
"FileLocation": "" "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
},
"SSOSettings": {
"gitlab": {
"Allow": false,
"Secret" : "",
"Id": "",
"Scope": "",
"AuthEndpoint": "",
"TokenEndpoint": "",
"UserApiEndpoint": ""
}
},
"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"],
"MaxIdleConns": 10,
"MaxOpenConns": 10,
"Trace": false,
"AtRestEncryptKey": "Ya0xMrybACJ3sZZVWQC7e31h5nSDWZFS"
},
"AWSSettings": {
"S3AccessKeyId": "",
"S3SecretAccessKey": "",
"S3Bucket": "",
"S3Region": ""
},
"ImageSettings": { "ImageSettings": {
"DriverName": "local",
"Directory": "/mattermost/data/",
"EnablePublicLink": true,
"PublicLinkSalt": "LhaAWC6lYEKHTkBKsvyXNIOfUIT37AX",
"ThumbnailWidth": 120, "ThumbnailWidth": 120,
"ThumbnailHeight": 100, "ThumbnailHeight": 100,
"PreviewWidth": 1024, "PreviewWidth": 1024,
"PreviewHeight": 0, "PreviewHeight": 0,
"ProfileWidth": 128, "ProfileWidth": 128,
"ProfileHeight": 128, "ProfileHeight": 128,
"InitialFont": "luximbi.ttf" "InitialFont": "luximbi.ttf",
"AmazonS3AccessKeyId": "",
"AmazonS3SecretAccessKey": "",
"AmazonS3Bucket": "",
"AmazonS3Region": ""
}, },
"EmailSettings": { "EmailSettings": {
"ByPassEmail" : true, "EnableSignUpWithEmail": true,
"SendEmailNotifications": false,
"RequireEmailVerification": false,
"FeedbackName": "",
"FeedbackEmail": "",
"SMTPUsername": "", "SMTPUsername": "",
"SMTPPassword": "", "SMTPPassword": "",
"SMTPServer": "", "SMTPServer": "",
"UseTLS": false, "SMTPPort": "",
"UseStartTLS": false, "ConnectionSecurity": "",
"FeedbackEmail": "", "InviteSalt": "bjlSR4QqkXFBr7TP4oDzlfZmcNuH9Yo",
"FeedbackName": "", "PasswordResetSalt": "vZ4DcKyVVRlKHHJpexcuXzojkE5PZ5e",
"ApplePushServer": "", "ApplePushServer": "",
"ApplePushCertPublic": "", "ApplePushCertPublic": "",
"ApplePushCertPrivate": "" "ApplePushCertPrivate": ""
}, },
"RateLimitSettings": { "RateLimitSettings": {
"UseRateLimiter": true, "EnableRateLimiter": true,
"PerSec": 10, "PerSec": 10,
"MemoryStoreSize": 10000, "MemoryStoreSize": 10000,
"VaryByRemoteAddr": true, "VaryByRemoteAddr": true,
@@ -83,22 +75,15 @@
}, },
"PrivacySettings": { "PrivacySettings": {
"ShowEmailAddress": true, "ShowEmailAddress": true,
"ShowPhoneNumber": true,
"ShowSkypeId": true,
"ShowFullName": true "ShowFullName": true
}, },
"TeamSettings": { "GitLabSettings": {
"MaxUsersPerTeam": 150, "Enable": false,
"AllowPublicLink": true, "Secret": "",
"AllowValetDefault": false, "Id": "",
"TermsLink": "/static/help/configure_links.html", "Scope": "",
"PrivacyLink": "/static/help/configure_links.html", "AuthEndpoint": "",
"AboutLink": "/static/help/configure_links.html", "TokenEndpoint": "",
"HelpLink": "/static/help/configure_links.html", "UserApiEndpoint": ""
"ReportProblemLink": "/static/help/configure_links.html",
"TourLink": "/static/help/configure_links.html",
"DefaultThemeColor": "#2389D7",
"DisableTeamCreation": false,
"RestrictCreationToDomains": ""
} }
} }

Просмотреть файл

@@ -1,81 +1,73 @@
{ {
"ServiceSettings": {
"ListenAddress": ":80",
"MaximumLoginAttempts": 10,
"SegmentDeveloperKey": "",
"GoogleDeveloperKey": "",
"EnableOAuthServiceProvider": false,
"EnableTesting": false
},
"TeamSettings": {
"SiteName": "Mattermost",
"MaxUsersPerTeam": 50,
"DefaultThemeColor": "#2389D7",
"EnableTeamCreation": true,
"EnableUserCreation": true,
"RestrictCreationToDomains": ""
},
"SqlSettings": {
"DriverName": "mysql",
"DataSource": "mmuser:mostest@tcp(dockerhost:3306)/mattermost_test?charset=utf8mb4,utf8",
"DataSourceReplicas": [],
"MaxIdleConns": 10,
"MaxOpenConns": 10,
"Trace": false,
"AtRestEncryptKey": "7rAh6iwQCkV4cA1Gsg3fgGOXJAQ43QV"
},
"LogSettings": { "LogSettings": {
"ConsoleEnable": true, "EnableConsole": false,
"ConsoleLevel": "INFO", "ConsoleLevel": "INFO",
"FileEnable": true, "EnableFile": true,
"FileLevel": "INFO", "FileLevel": "INFO",
"FileFormat": "", "FileFormat": "",
"FileLocation": "" "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
},
"SSOSettings": {
"gitlab": {
"Allow": false,
"Secret" : "",
"Id": "",
"Scope": "",
"AuthEndpoint": "",
"TokenEndpoint": "",
"UserApiEndpoint": ""
}
},
"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"],
"MaxIdleConns": 10,
"MaxOpenConns": 10,
"Trace": false,
"AtRestEncryptKey": "Ya0xMrybACJ3sZZVWQC7e31h5nSDWZFS"
},
"AWSSettings": {
"S3AccessKeyId": "",
"S3SecretAccessKey": "",
"S3Bucket": "",
"S3Region": ""
},
"ImageSettings": { "ImageSettings": {
"DriverName": "local",
"Directory": "/mattermost/data/",
"EnablePublicLink": true,
"PublicLinkSalt": "LhaAWC6lYEKHTkBKsvyXNIOfUIT37AX",
"ThumbnailWidth": 120, "ThumbnailWidth": 120,
"ThumbnailHeight": 100, "ThumbnailHeight": 100,
"PreviewWidth": 1024, "PreviewWidth": 1024,
"PreviewHeight": 0, "PreviewHeight": 0,
"ProfileWidth": 128, "ProfileWidth": 128,
"ProfileHeight": 128, "ProfileHeight": 128,
"InitialFont": "luximbi.ttf" "InitialFont": "luximbi.ttf",
"AmazonS3AccessKeyId": "",
"AmazonS3SecretAccessKey": "",
"AmazonS3Bucket": "",
"AmazonS3Region": ""
}, },
"EmailSettings": { "EmailSettings": {
"ByPassEmail" : true, "EnableSignUpWithEmail": true,
"SendEmailNotifications": false,
"RequireEmailVerification": false,
"FeedbackName": "",
"FeedbackEmail": "",
"SMTPUsername": "", "SMTPUsername": "",
"SMTPPassword": "", "SMTPPassword": "",
"SMTPServer": "", "SMTPServer": "",
"UseTLS": false, "SMTPPort": "",
"UseStartTLS": false, "ConnectionSecurity": "",
"FeedbackEmail": "", "InviteSalt": "bjlSR4QqkXFBr7TP4oDzlfZmcNuH9Yo",
"FeedbackName": "", "PasswordResetSalt": "vZ4DcKyVVRlKHHJpexcuXzojkE5PZ5e",
"ApplePushServer": "", "ApplePushServer": "",
"ApplePushCertPublic": "", "ApplePushCertPublic": "",
"ApplePushCertPrivate": "" "ApplePushCertPrivate": ""
}, },
"RateLimitSettings": { "RateLimitSettings": {
"UseRateLimiter": true, "EnableRateLimiter": true,
"PerSec": 10, "PerSec": 10,
"MemoryStoreSize": 10000, "MemoryStoreSize": 10000,
"VaryByRemoteAddr": true, "VaryByRemoteAddr": true,
@@ -83,22 +75,15 @@
}, },
"PrivacySettings": { "PrivacySettings": {
"ShowEmailAddress": true, "ShowEmailAddress": true,
"ShowPhoneNumber": true,
"ShowSkypeId": true,
"ShowFullName": true "ShowFullName": true
}, },
"TeamSettings": { "GitLabSettings": {
"MaxUsersPerTeam": 150, "Enable": false,
"AllowPublicLink": true, "Secret": "",
"AllowValetDefault": false, "Id": "",
"TermsLink": "/static/help/configure_links.html", "Scope": "",
"PrivacyLink": "/static/help/configure_links.html", "AuthEndpoint": "",
"AboutLink": "/static/help/configure_links.html", "TokenEndpoint": "",
"HelpLink": "/static/help/configure_links.html", "UserApiEndpoint": ""
"ReportProblemLink": "/static/help/configure_links.html",
"TourLink": "/static/help/configure_links.html",
"DefaultThemeColor": "#2389D7",
"DisableTeamCreation": false,
"RestrictCreationToDomains": ""
} }
} }

Просмотреть файл

@@ -53,7 +53,7 @@ func manualTest(c *api.Context, w http.ResponseWriter, r *http.Request) {
} }
// Create a client for tests to use // 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 // Check for username parameter and create a user if present
username, ok1 := params["username"] username, ok1 := params["username"]

Просмотреть файл

@@ -57,7 +57,7 @@ func main() {
api.StartServer() api.StartServer()
// If we allow testing then listen for manual testing URL hits // If we allow testing then listen for manual testing URL hits
if utils.Cfg.ServiceSettings.AllowTesting { if utils.Cfg.ServiceSettings.EnableTesting {
manualtesting.InitManualTesting() manualtesting.InitManualTesting()
} }

Просмотреть файл

@@ -21,6 +21,7 @@ const (
HEADER_ETAG_SERVER = "ETag" HEADER_ETAG_SERVER = "ETag"
HEADER_ETAG_CLIENT = "If-None-Match" HEADER_ETAG_CLIENT = "If-None-Match"
HEADER_FORWARDED = "X-Forwarded-For" HEADER_FORWARDED = "X-Forwarded-For"
HEADER_REAL_IP = "X-Real-IP"
HEADER_FORWARDED_PROTO = "X-Forwarded-Proto" HEADER_FORWARDED_PROTO = "X-Forwarded-Proto"
HEADER_TOKEN = "token" HEADER_TOKEN = "token"
HEADER_BEARER = "BEARER" HEADER_BEARER = "BEARER"

Просмотреть файл

@@ -20,23 +20,16 @@ const (
) )
type ServiceSettings struct { type ServiceSettings struct {
Mode string ListenAddress string
AllowTesting bool MaximumLoginAttempts int
UseSSL bool
Port string
Version string
InviteSalt string
PublicLinkSalt string
ResetSalt string
AnalyticsUrl string
AllowedLoginAttempts int
EnableOAuthServiceProvider bool
SegmentDeveloperKey string SegmentDeveloperKey string
GoogleDeveloperKey string GoogleDeveloperKey string
EnableOAuthServiceProvider bool
EnableTesting bool
} }
type SSOSettings struct { type SSOSettings struct {
Allow bool Enable bool
Secret string Secret string
Id string Id string
Scope string Scope string
@@ -56,9 +49,9 @@ type SqlSettings struct {
} }
type LogSettings struct { type LogSettings struct {
ConsoleEnable bool EnableConsole bool
ConsoleLevel string ConsoleLevel string
FileEnable bool EnableFile bool
FileLevel string FileLevel string
FileFormat string FileFormat string
FileLocation string FileLocation string
@@ -68,6 +61,7 @@ type ImageSettings struct {
DriverName string DriverName string
Directory string Directory string
EnablePublicLink bool EnablePublicLink bool
PublicLinkSalt string
ThumbnailWidth uint ThumbnailWidth uint
ThumbnailHeight uint ThumbnailHeight uint
PreviewWidth uint PreviewWidth uint
@@ -82,7 +76,7 @@ type ImageSettings struct {
} }
type EmailSettings struct { type EmailSettings struct {
AllowSignUpWithEmail bool EnableSignUpWithEmail bool
SendEmailNotifications bool SendEmailNotifications bool
RequireEmailVerification bool RequireEmailVerification bool
FeedbackName string FeedbackName string
@@ -92,6 +86,8 @@ type EmailSettings struct {
SMTPServer string SMTPServer string
SMTPPort string SMTPPort string
ConnectionSecurity string ConnectionSecurity string
InviteSalt string
PasswordResetSalt string
// For Future Use // For Future Use
ApplePushServer string ApplePushServer string

Просмотреть файл

@@ -58,9 +58,9 @@ func FindDir(dir string) string {
func ConfigureCmdLineLog() { func ConfigureCmdLineLog() {
ls := model.LogSettings{} ls := model.LogSettings{}
ls.ConsoleEnable = true ls.EnableConsole = true
ls.ConsoleLevel = "ERROR" ls.ConsoleLevel = "ERROR"
ls.FileEnable = false ls.EnableFile = false
configureLog(&ls) configureLog(&ls)
} }
@@ -68,7 +68,7 @@ func configureLog(s *model.LogSettings) {
l4g.Close() l4g.Close()
if s.ConsoleEnable { if s.EnableConsole {
level := l4g.DEBUG level := l4g.DEBUG
if s.ConsoleLevel == "INFO" { if s.ConsoleLevel == "INFO" {
level = l4g.INFO level = l4g.INFO
@@ -79,7 +79,7 @@ func configureLog(s *model.LogSettings) {
l4g.AddFilter("stdout", level, l4g.NewConsoleLogWriter()) l4g.AddFilter("stdout", level, l4g.NewConsoleLogWriter())
} }
if s.FileEnable { if s.EnableFile {
var fileFormat = s.FileFormat var fileFormat = s.FileFormat
@@ -174,16 +174,15 @@ func getClientProperties(c *model.Config) map[string]string {
props["BuildHash"] = model.BuildHash props["BuildHash"] = model.BuildHash
props["SiteName"] = c.TeamSettings.SiteName props["SiteName"] = c.TeamSettings.SiteName
props["AnalyticsUrl"] = c.ServiceSettings.AnalyticsUrl
props["EnableOAuthServiceProvider"] = strconv.FormatBool(c.ServiceSettings.EnableOAuthServiceProvider) props["EnableOAuthServiceProvider"] = strconv.FormatBool(c.ServiceSettings.EnableOAuthServiceProvider)
props["SegmentDeveloperKey"] = c.ServiceSettings.SegmentDeveloperKey props["SegmentDeveloperKey"] = c.ServiceSettings.SegmentDeveloperKey
props["GoogleDeveloperKey"] = c.ServiceSettings.GoogleDeveloperKey props["GoogleDeveloperKey"] = c.ServiceSettings.GoogleDeveloperKey
props["SendEmailNotifications"] = strconv.FormatBool(c.EmailSettings.SendEmailNotifications) 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["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) props["ShowEmailAddress"] = strconv.FormatBool(c.PrivacySettings.ShowEmailAddress)

Просмотреть файл

@@ -15,7 +15,7 @@ var RateSettingsTab = require('./rate_settings.jsx');
var GitLabSettingsTab = require('./gitlab_settings.jsx'); var GitLabSettingsTab = require('./gitlab_settings.jsx');
var SqlSettingsTab = require('./sql_settings.jsx'); var SqlSettingsTab = require('./sql_settings.jsx');
var TeamSettingsTab = require('./team_settings.jsx'); var TeamSettingsTab = require('./team_settings.jsx');
var ServiceSettingsTab = require('./service_settings.jsx');
export default class AdminController extends React.Component { export default class AdminController extends React.Component {
constructor(props) { constructor(props) {
@@ -26,7 +26,7 @@ export default class AdminController extends React.Component {
this.state = { this.state = {
config: null, 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} />; tab = <SqlSettingsTab config={this.state.config} />;
} else if (this.state.selected === 'team_settings') { } else if (this.state.selected === 'team_settings') {
tab = <TeamSettingsTab config={this.state.config} />; tab = <TeamSettingsTab config={this.state.config} />;
} else if (this.state.selected === 'service_settings') {
tab = <ServiceSettingsTab config={this.state.config} />;
} }
} }

Просмотреть файл

@@ -38,6 +38,15 @@ export default class AdminSidebar extends React.Component {
<ul className='nav nav-pills nav-stacked'> <ul className='nav nav-pills nav-stacked'>
<li> <li>
<ul className='nav nav__sub-menu'> <ul className='nav nav__sub-menu'>
<li>
<a
href='#'
className={this.isSelected('service_settings')}
onClick={this.handleClick.bind(this, 'service_settings')}
>
{'Service Settings'}
</a>
</li>
<li> <li>
<a <a
href='#' href='#'

Просмотреть файл

@@ -3,6 +3,7 @@
var Client = require('../../utils/client.jsx'); var Client = require('../../utils/client.jsx');
var AsyncClient = require('../../utils/async_client.jsx'); var AsyncClient = require('../../utils/async_client.jsx');
var crypto = require('crypto');
export default class EmailSettings extends React.Component { export default class EmailSettings extends React.Component {
constructor(props) { constructor(props) {
@@ -12,6 +13,8 @@ export default class EmailSettings extends React.Component {
this.handleTestConnection = this.handleTestConnection.bind(this); this.handleTestConnection = this.handleTestConnection.bind(this);
this.handleSubmit = this.handleSubmit.bind(this); this.handleSubmit = this.handleSubmit.bind(this);
this.buildConfig = this.buildConfig.bind(this); this.buildConfig = this.buildConfig.bind(this);
this.handleGenerateInvite = this.handleGenerateInvite.bind(this);
this.handleGenerateReset = this.handleGenerateReset.bind(this);
this.state = { this.state = {
sendEmailNotifications: this.props.config.EmailSettings.SendEmailNotifications, sendEmailNotifications: this.props.config.EmailSettings.SendEmailNotifications,
@@ -38,7 +41,7 @@ export default class EmailSettings extends React.Component {
buildConfig() { buildConfig() {
var config = this.props.config; 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.SendEmailNotifications = React.findDOMNode(this.refs.sendEmailNotifications).checked;
config.EmailSettings.RequireEmailVerification = React.findDOMNode(this.refs.requireEmailVerification).checked; config.EmailSettings.RequireEmailVerification = React.findDOMNode(this.refs.requireEmailVerification).checked;
config.EmailSettings.SendEmailNotifications = React.findDOMNode(this.refs.sendEmailNotifications).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.SMTPUsername = React.findDOMNode(this.refs.SMTPUsername).value.trim();
config.EmailSettings.SMTPPassword = React.findDOMNode(this.refs.SMTPPassword).value.trim(); config.EmailSettings.SMTPPassword = React.findDOMNode(this.refs.SMTPPassword).value.trim();
config.EmailSettings.ConnectionSecurity = React.findDOMNode(this.refs.ConnectionSecurity).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; 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) { handleTestConnection(e) {
e.preventDefault(); e.preventDefault();
$('#connection-button').button('loading'); $('#connection-button').button('loading');
@@ -166,7 +196,7 @@ export default class EmailSettings extends React.Component {
name='allowSignUpWithEmail' name='allowSignUpWithEmail'
value='true' value='true'
ref='allowSignUpWithEmail' ref='allowSignUpWithEmail'
defaultChecked={this.props.config.EmailSettings.AllowSignUpWithEmail} defaultChecked={this.props.config.EmailSettings.EnableSignUpWithEmail}
onChange={this.handleChange.bind(this, 'allowSignUpWithEmail_true')} onChange={this.handleChange.bind(this, 'allowSignUpWithEmail_true')}
/> />
{'true'} {'true'}
@@ -176,7 +206,7 @@ export default class EmailSettings extends React.Component {
type='radio' type='radio'
name='allowSignUpWithEmail' name='allowSignUpWithEmail'
value='false' value='false'
defaultChecked={!this.props.config.EmailSettings.AllowSignUpWithEmail} defaultChecked={!this.props.config.EmailSettings.EnableSignUpWithEmail}
onChange={this.handleChange.bind(this, 'allowSignUpWithEmail_false')} onChange={this.handleChange.bind(this, 'allowSignUpWithEmail_false')}
/> />
{'false'} {'false'}
@@ -431,6 +461,68 @@ export default class EmailSettings extends React.Component {
</div> </div>
</div> </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='form-group'>
<div className='col-sm-12'> <div className='col-sm-12'>
{serverError} {serverError}

Просмотреть файл

@@ -3,6 +3,7 @@
var Client = require('../../utils/client.jsx'); var Client = require('../../utils/client.jsx');
var AsyncClient = require('../../utils/async_client.jsx'); var AsyncClient = require('../../utils/async_client.jsx');
var crypto = require('crypto');
export default class ImageSettings extends React.Component { export default class ImageSettings extends React.Component {
constructor(props) { constructor(props) {
@@ -10,6 +11,7 @@ export default class ImageSettings extends React.Component {
this.handleChange = this.handleChange.bind(this); this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this); this.handleSubmit = this.handleSubmit.bind(this);
this.handleGenerate = this.handleGenerate.bind(this);
this.state = { this.state = {
saveNeeded: false, saveNeeded: false,
@@ -28,6 +30,13 @@ export default class ImageSettings extends React.Component {
this.setState(s); 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) { handleSubmit(e) {
e.preventDefault(); e.preventDefault();
$('#save-button').button('loading'); $('#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.AmazonS3Region = React.findDOMNode(this.refs.AmazonS3Region).value;
config.ImageSettings.EnablePublicLink = React.findDOMNode(this.refs.EnablePublicLink).checked; 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; var thumbnailWidth = 120;
if (!isNaN(parseInt(React.findDOMNode(this.refs.ThumbnailWidth).value, 10))) { if (!isNaN(parseInt(React.findDOMNode(this.refs.ThumbnailWidth).value, 10))) {
thumbnailWidth = parseInt(React.findDOMNode(this.refs.ThumbnailWidth).value, 10); thumbnailWidth = parseInt(React.findDOMNode(this.refs.ThumbnailWidth).value, 10);
@@ -424,6 +440,35 @@ export default class ImageSettings extends React.Component {
</div> </div>
</div> </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='form-group'>
<div className='col-sm-12'> <div className='col-sm-12'>
{serverError} {serverError}

Просмотреть файл

@@ -12,8 +12,8 @@ export default class LogSettings extends React.Component {
this.handleSubmit = this.handleSubmit.bind(this); this.handleSubmit = this.handleSubmit.bind(this);
this.state = { this.state = {
consoleEnable: this.props.config.LogSettings.ConsoleEnable, consoleEnable: this.props.config.LogSettings.EnableConsole,
fileEnable: this.props.config.LogSettings.FileEnable, fileEnable: this.props.config.LogSettings.EnableFile,
saveNeeded: false, saveNeeded: false,
serverError: null serverError: null
}; };
@@ -46,9 +46,9 @@ export default class LogSettings extends React.Component {
$('#save-button').button('loading'); $('#save-button').button('loading');
var config = this.props.config; 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.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.FileLevel = React.findDOMNode(this.refs.fileLevel).value;
config.LogSettings.FileLocation = React.findDOMNode(this.refs.fileLocation).value.trim(); config.LogSettings.FileLocation = React.findDOMNode(this.refs.fileLocation).value.trim();
config.LogSettings.FileFormat = React.findDOMNode(this.refs.fileFormat).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(); AsyncClient.getConfig();
this.setState({ this.setState({
consoleEnable: config.LogSettings.ConsoleEnable, consoleEnable: config.LogSettings.EnableConsole,
fileEnable: config.LogSettings.FileEnable, fileEnable: config.LogSettings.EnableFile,
serverError: null, serverError: null,
saveNeeded: false saveNeeded: false
}); });
@@ -67,8 +67,8 @@ export default class LogSettings extends React.Component {
}, },
(err) => { (err) => {
this.setState({ this.setState({
consoleEnable: config.LogSettings.ConsoleEnable, consoleEnable: config.LogSettings.EnableConsole,
fileEnable: config.LogSettings.FileEnable, fileEnable: config.LogSettings.EnableFile,
serverError: err.message, serverError: err.message,
saveNeeded: true saveNeeded: true
}); });
@@ -110,7 +110,7 @@ export default class LogSettings extends React.Component {
name='consoleEnable' name='consoleEnable'
value='true' value='true'
ref='consoleEnable' ref='consoleEnable'
defaultChecked={this.props.config.LogSettings.ConsoleEnable} defaultChecked={this.props.config.LogSettings.EnableConsole}
onChange={this.handleChange.bind(this, 'console_true')} onChange={this.handleChange.bind(this, 'console_true')}
/> />
{'true'} {'true'}
@@ -120,7 +120,7 @@ export default class LogSettings extends React.Component {
type='radio' type='radio'
name='consoleEnable' name='consoleEnable'
value='false' value='false'
defaultChecked={!this.props.config.LogSettings.ConsoleEnable} defaultChecked={!this.props.config.LogSettings.EnableConsole}
onChange={this.handleChange.bind(this, 'console_false')} onChange={this.handleChange.bind(this, 'console_false')}
/> />
{'false'} {'false'}
@@ -166,7 +166,7 @@ export default class LogSettings extends React.Component {
name='fileEnable' name='fileEnable'
ref='fileEnable' ref='fileEnable'
value='true' value='true'
defaultChecked={this.props.config.LogSettings.FileEnable} defaultChecked={this.props.config.LogSettings.EnableFile}
onChange={this.handleChange.bind(this, 'file_true')} onChange={this.handleChange.bind(this, 'file_true')}
/> />
{'true'} {'true'}
@@ -176,7 +176,7 @@ export default class LogSettings extends React.Component {
type='radio' type='radio'
name='fileEnable' name='fileEnable'
value='false' value='false'
defaultChecked={!this.props.config.LogSettings.FileEnable} defaultChecked={!this.props.config.LogSettings.EnableFile}
onChange={this.handleChange.bind(this, 'file_false')} onChange={this.handleChange.bind(this, 'file_false')}
/> />
{'false'} {'false'}

Просмотреть файл

@@ -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
};

Просмотреть файл

@@ -207,7 +207,7 @@ export default class SqlSettings extends React.Component {
className='form-control' className='form-control'
id='AtRestEncryptKey' id='AtRestEncryptKey'
ref='AtRestEncryptKey' ref='AtRestEncryptKey'
placeholder='Ex "10"' placeholder='Ex "gxHVDcKUyP2y1eiyW8S8na1UYQAfq6J6"'
defaultValue={this.props.config.SqlSettings.AtRestEncryptKey} defaultValue={this.props.config.SqlSettings.AtRestEncryptKey}
onChange={this.handleChange} onChange={this.handleChange}
/> />

Просмотреть файл

@@ -95,7 +95,7 @@ export default class Login extends React.Component {
} }
let loginMessage = []; let loginMessage = [];
if (global.window.config.AllowSignUpWithGitLab === 'true') { if (global.window.config.EnableSignUpWithGitLab === 'true') {
loginMessage.push( loginMessage.push(
<a <a
className='btn btn-custom-login gitlab' className='btn btn-custom-login gitlab'
@@ -113,7 +113,7 @@ export default class Login extends React.Component {
} }
let emailSignup; let emailSignup;
if (global.window.config.AllowSignUpWithEmail === 'true') { if (global.window.config.EnableSignUpWithEmail === 'true') {
emailSignup = ( emailSignup = (
<div> <div>
<div className={'form-group' + errorClass}> <div className={'form-group' + errorClass}>

Просмотреть файл

@@ -14,19 +14,19 @@ export default class TeamSignUp extends React.Component {
var count = 0; var count = 0;
if (global.window.config.AllowSignUpWithEmail === 'true') { if (global.window.config.EnableSignUpWithEmail === 'true') {
count = count + 1; count = count + 1;
} }
if (global.window.config.AllowSignUpWithGitLab === 'true') { if (global.window.config.EnableSignUpWithGitLab === 'true') {
count = count + 1; count = count + 1;
} }
if (count > 1) { if (count > 1) {
this.state = {page: 'choose'}; this.state = {page: 'choose'};
} else if (global.window.config.AllowSignUpWithEmail === 'true') { } else if (global.window.config.EnableSignUpWithEmail === 'true') {
this.state = {page: 'email'}; this.state = {page: 'email'};
} else if (global.window.config.AllowSignUpWithGitLab === 'true') { } else if (global.window.config.EnableSignUpWithGitLab === 'true') {
this.state = {page: 'gitlab'}; this.state = {page: 'gitlab'};
} }
} }

Просмотреть файл

@@ -161,7 +161,7 @@ export default class SignupUserComplete extends React.Component {
); );
var signupMessage = []; var signupMessage = [];
if (global.window.config.AllowSignUpWithGitLab === 'true') { if (global.window.config.EnableSignUpWithGitLab === 'true') {
signupMessage.push( signupMessage.push(
<a <a
className='btn btn-custom-login gitlab' className='btn btn-custom-login gitlab'
@@ -174,7 +174,7 @@ export default class SignupUserComplete extends React.Component {
} }
var emailSignup; var emailSignup;
if (global.window.config.AllowSignUpWithEmail === 'true') { if (global.window.config.EnableSignUpWithEmail === 'true') {
emailSignup = ( emailSignup = (
<div> <div>
<div className='inner__content'> <div className='inner__content'>

Просмотреть файл

@@ -8,7 +8,7 @@ export default class ChooseAuthPage extends React.Component {
} }
render() { render() {
var buttons = []; var buttons = [];
if (global.window.config.AllowSignUpWithGitLab === 'true') { if (global.window.config.EnableSignUpWithGitLab === 'true') {
buttons.push( buttons.push(
<a <a
className='btn btn-custom-login gitlab btn-full' 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( buttons.push(
<a <a
className='btn btn-custom-login email btn-full' className='btn btn-custom-login email btn-full'

Просмотреть файл

@@ -4,12 +4,10 @@ var BrowserStore = require('../stores/browser_store.jsx');
var TeamStore = require('../stores/team_store.jsx'); var TeamStore = require('../stores/team_store.jsx');
export function track(category, action, label, prop, val) { 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}); global.window.analytics.track(action, {category: category, label: label, property: prop, value: val});
} }
export function trackPage() { export function trackPage() {
global.window.snowplow('trackPageView');
global.window.analytics.page(); global.window.analytics.page();
} }

Просмотреть файл

@@ -77,28 +77,5 @@
analytics.track = function(){}; analytics.track = function(){};
} }
</script> </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> </head>
{{end}} {{end}}

Просмотреть файл

@@ -204,7 +204,7 @@ func signupTeamComplete(c *api.Context, w http.ResponseWriter, r *http.Request)
data := r.FormValue("d") data := r.FormValue("d")
hash := r.FormValue("h") 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", "") c.Err = model.NewAppError("signupTeamComplete", "The signup link does not appear to be valid", "")
return return
} }
@@ -253,7 +253,7 @@ func signupUserComplete(c *api.Context, w http.ResponseWriter, r *http.Request)
} }
} else { } 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", "") c.Err = model.NewAppError("signupTeamComplete", "The signup link does not appear to be valid", "")
return return
} }
@@ -414,7 +414,7 @@ func resetPassword(c *api.Context, w http.ResponseWriter, r *http.Request) {
if len(hash) == 0 || len(data) == 0 { if len(hash) == 0 || len(data) == 0 {
isResetLink = false isResetLink = false
} else { } 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", "") c.Err = model.NewAppError("resetPassword", "The reset link does not appear to be valid", "")
return return
} }
@@ -476,7 +476,7 @@ func signupWithOAuth(c *api.Context, w http.ResponseWriter, r *http.Request) {
data := r.URL.Query().Get("d") data := r.URL.Query().Get("d")
props := model.MapFromJson(strings.NewReader(data)) 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", "") c.Err = model.NewAppError("signupWithOAuth", "The signup link does not appear to be valid", "")
return return
} }

Просмотреть файл

@@ -25,7 +25,7 @@ func Setup() {
api.StartServer() api.StartServer()
api.InitApi() api.InitApi()
InitWeb() InitWeb()
URL = "http://localhost:" + utils.Cfg.ServiceSettings.Port URL = "http://localhost" + utils.Cfg.ServiceSettings.ListenAddress
ApiClient = model.NewClient(URL) ApiClient = model.NewClient(URL)
} }
} }