diff --git a/api/admin.go b/api/admin.go
index 6465977550..568d8f6e87 100644
--- a/api/admin.go
+++ b/api/admin.go
@@ -24,6 +24,7 @@ func InitAdmin(r *mux.Router) {
sr.Handle("/config", ApiUserRequired(getConfig)).Methods("GET")
sr.Handle("/save_config", ApiUserRequired(saveConfig)).Methods("POST")
sr.Handle("/client_props", ApiAppHandler(getClientProperties)).Methods("GET")
+ sr.Handle("/test_email", ApiUserRequired(testEmail)).Methods("POST")
}
func getLogs(c *Context, w http.ResponseWriter, r *http.Request) {
@@ -34,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 {
@@ -81,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
}
@@ -98,3 +99,29 @@ func saveConfig(c *Context, w http.ResponseWriter, r *http.Request) {
json := utils.Cfg.ToJson()
w.Write([]byte(json))
}
+
+func testEmail(c *Context, w http.ResponseWriter, r *http.Request) {
+ if !c.HasSystemAdminPermissions("testEmail") {
+ return
+ }
+
+ cfg := model.ConfigFromJson(r.Body)
+ if cfg == nil {
+ c.SetInvalidParam("testEmail", "config")
+ return
+ }
+
+ if result := <-Srv.Store.User().Get(c.Session.UserId); result.Err != nil {
+ c.Err = result.Err
+ return
+ } else {
+ if err := utils.SendMailUsingConfig(result.Data.(*model.User).Email, "Mattermost - Testing Email Settings", "
It appears your Mattermost email is setup correctly!", cfg); err != nil {
+ c.Err = err
+ return
+ }
+ }
+
+ m := make(map[string]string)
+ m["SUCCESS"] = "true"
+ w.Write([]byte(model.MapToJson(m)))
+}
diff --git a/api/admin_test.go b/api/admin_test.go
index e1778b5ac2..ad7ac08f8f 100644
--- a/api/admin_test.go
+++ b/api/admin_test.go
@@ -83,7 +83,7 @@ func TestGetConfig(t *testing.T) {
} else {
cfg := result.Data.(*model.Config)
- if len(cfg.ServiceSettings.SiteName) == 0 {
+ if len(cfg.TeamSettings.SiteName) == 0 {
t.Fatal()
}
}
@@ -117,8 +117,36 @@ func TestSaveConfig(t *testing.T) {
} else {
cfg := result.Data.(*model.Config)
- if len(cfg.ServiceSettings.SiteName) == 0 {
+ if len(cfg.TeamSettings.SiteName) == 0 {
t.Fatal()
}
}
}
+
+func TestEmailTest(t *testing.T) {
+ Setup()
+
+ 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)
+
+ user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
+ user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
+ store.Must(Srv.Store.User().VerifyEmail(user.Id))
+
+ Client.LoginByEmail(team.Name, user.Email, "pwd")
+
+ if _, err := Client.TestEmail(utils.Cfg); err == nil {
+ t.Fatal("Shouldn't have permissions")
+ }
+
+ c := &Context{}
+ c.RequestId = model.NewId()
+ c.IpAddress = "cmd_line"
+ UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
+
+ Client.LoginByEmail(team.Name, user.Email, "pwd")
+
+ if _, err := Client.TestEmail(utils.Cfg); err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/api/api_test.go b/api/api_test.go
index 642db581e7..761f3e33f6 100644
--- a/api/api_test.go
+++ b/api/api_test.go
@@ -14,10 +14,11 @@ var Client *model.Client
func Setup() {
if Srv == nil {
utils.LoadConfig("config.json")
+ utils.Cfg.TeamSettings.MaxUsersPerTeam = 50
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 14bfe1cf79..7845ac499a 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 bc55f206bb..0d2f7597b5 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 02716bb331..9a276a1a18 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,20 +457,13 @@ 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)
m["Message"] = err.Message
m["Details"] = err.DetailedError
- m["SiteName"] = utils.Cfg.ServiceSettings.SiteName
+ m["SiteName"] = utils.Cfg.TeamSettings.SiteName
m["SiteURL"] = SiteURL
w.WriteHeader(err.StatusCode)
diff --git a/api/export.go b/api/export.go
index 9345f892fb..73142a0e49 100644
--- a/api/export.go
+++ b/api/export.go
@@ -278,11 +278,11 @@ func copyDirToExportWriter(writer ExportWriter, inPath string, outPath string) *
}
func ExportLocalStorage(writer ExportWriter, options *ExportOptions, teamId string) *model.AppError {
- teamDir := utils.Cfg.ServiceSettings.StorageDirectory + "teams/" + teamId
+ teamDir := utils.Cfg.FileSettings.Directory + "teams/" + teamId
- if utils.IsS3Configured() && !utils.Cfg.ServiceSettings.UseLocalStorage {
+ if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 {
return model.NewAppError("ExportLocalStorage", "S3 is not supported for local storage export.", "")
- } else if utils.Cfg.ServiceSettings.UseLocalStorage && len(utils.Cfg.ServiceSettings.StorageDirectory) > 0 {
+ } else if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_LOCAL {
if err := copyDirToExportWriter(writer, teamDir, EXPORT_LOCAL_STORAGE_FOLDER); err != nil {
return err
}
diff --git a/api/file.go b/api/file.go
index 3602b5ed46..694fc734c1 100644
--- a/api/file.go
+++ b/api/file.go
@@ -69,8 +69,8 @@ func InitFile(r *mux.Router) {
}
func uploadFile(c *Context, w http.ResponseWriter, r *http.Request) {
- if !utils.IsS3Configured() && !utils.Cfg.ServiceSettings.UseLocalStorage {
- c.Err = model.NewAppError("uploadFile", "Unable to upload file. Amazon S3 not configured and local server storage turned off. ", "")
+ if len(utils.Cfg.FileSettings.DriverName) == 0 {
+ c.Err = model.NewAppError("uploadFile", "Unable to upload file. Image storage is not configured.", "")
c.Err.StatusCode = http.StatusNotImplemented
return
}
@@ -217,8 +217,8 @@ func fireAndForgetHandleImages(filenames []string, fileData [][]byte, teamId, ch
// Create thumbnail
go func() {
- thumbWidth := float64(utils.Cfg.ImageSettings.ThumbnailWidth)
- thumbHeight := float64(utils.Cfg.ImageSettings.ThumbnailHeight)
+ thumbWidth := float64(utils.Cfg.FileSettings.ThumbnailWidth)
+ thumbHeight := float64(utils.Cfg.FileSettings.ThumbnailHeight)
imgWidth := float64(width)
imgHeight := float64(height)
@@ -226,9 +226,9 @@ func fireAndForgetHandleImages(filenames []string, fileData [][]byte, teamId, ch
if imgHeight < thumbHeight && imgWidth < thumbWidth {
thumbnail = img
} else if imgHeight/imgWidth < thumbHeight/thumbWidth {
- thumbnail = resize.Resize(0, utils.Cfg.ImageSettings.ThumbnailHeight, img, resize.Lanczos3)
+ thumbnail = resize.Resize(0, utils.Cfg.FileSettings.ThumbnailHeight, img, resize.Lanczos3)
} else {
- thumbnail = resize.Resize(utils.Cfg.ImageSettings.ThumbnailWidth, 0, img, resize.Lanczos3)
+ thumbnail = resize.Resize(utils.Cfg.FileSettings.ThumbnailWidth, 0, img, resize.Lanczos3)
}
buf := new(bytes.Buffer)
@@ -247,8 +247,8 @@ func fireAndForgetHandleImages(filenames []string, fileData [][]byte, teamId, ch
// Create preview
go func() {
var preview image.Image
- if width > int(utils.Cfg.ImageSettings.PreviewWidth) {
- preview = resize.Resize(utils.Cfg.ImageSettings.PreviewWidth, utils.Cfg.ImageSettings.PreviewHeight, img, resize.Lanczos3)
+ if width > int(utils.Cfg.FileSettings.PreviewWidth) {
+ preview = resize.Resize(utils.Cfg.FileSettings.PreviewWidth, utils.Cfg.FileSettings.PreviewHeight, img, resize.Lanczos3)
} else {
preview = img
}
@@ -294,8 +294,8 @@ type ImageGetResult struct {
}
func getFileInfo(c *Context, w http.ResponseWriter, r *http.Request) {
- if !utils.IsS3Configured() && !utils.Cfg.ServiceSettings.UseLocalStorage {
- c.Err = model.NewAppError("getFileInfo", "Unable to get file info. Amazon S3 not configured and local server storage turned off. ", "")
+ if len(utils.Cfg.FileSettings.DriverName) == 0 {
+ c.Err = model.NewAppError("uploadFile", "Unable to get file info. Image storage is not configured.", "")
c.Err.StatusCode = http.StatusNotImplemented
return
}
@@ -357,8 +357,8 @@ func getFileInfo(c *Context, w http.ResponseWriter, r *http.Request) {
}
func getFile(c *Context, w http.ResponseWriter, r *http.Request) {
- if !utils.IsS3Configured() && !utils.Cfg.ServiceSettings.UseLocalStorage {
- c.Err = model.NewAppError("getFile", "Unable to get file. Amazon S3 not configured and local server storage turned off. ", "")
+ if len(utils.Cfg.FileSettings.DriverName) == 0 {
+ c.Err = model.NewAppError("uploadFile", "Unable to get file. Image storage is not configured.", "")
c.Err.StatusCode = http.StatusNotImplemented
return
}
@@ -400,7 +400,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.FileSettings.PublicLinkSalt)) {
c.Err = model.NewAppError("getFile", "The public link does not appear to be valid", "")
return
}
@@ -442,17 +442,17 @@ func asyncGetFile(path string, fileData chan []byte) {
}
func getPublicLink(c *Context, w http.ResponseWriter, r *http.Request) {
- if !utils.Cfg.TeamSettings.AllowPublicLink {
- c.Err = model.NewAppError("getPublicLink", "Public links have been disabled", "")
- c.Err.StatusCode = http.StatusForbidden
- }
-
- if !utils.IsS3Configured() && !utils.Cfg.ServiceSettings.UseLocalStorage {
- c.Err = model.NewAppError("getPublicLink", "Unable to upload file. Amazon S3 not configured and local server storage turned off. ", "")
+ if len(utils.Cfg.FileSettings.DriverName) == 0 {
+ c.Err = model.NewAppError("uploadFile", "Unable to get link. Image storage is not configured.", "")
c.Err.StatusCode = http.StatusNotImplemented
return
}
+ if !utils.Cfg.FileSettings.EnablePublicLink {
+ c.Err = model.NewAppError("getPublicLink", "Public links have been disabled", "")
+ c.Err.StatusCode = http.StatusForbidden
+ }
+
props := model.MapFromJson(r.Body)
filename := props["filename"]
@@ -478,7 +478,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.FileSettings.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)
@@ -511,13 +511,13 @@ func getExport(c *Context, w http.ResponseWriter, r *http.Request) {
func writeFile(f []byte, path string) *model.AppError {
- if utils.IsS3Configured() && !utils.Cfg.ServiceSettings.UseLocalStorage {
+ if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 {
var auth aws.Auth
- auth.AccessKey = utils.Cfg.AWSSettings.S3AccessKeyId
- auth.SecretKey = utils.Cfg.AWSSettings.S3SecretAccessKey
+ auth.AccessKey = utils.Cfg.FileSettings.AmazonS3AccessKeyId
+ auth.SecretKey = utils.Cfg.FileSettings.AmazonS3SecretAccessKey
- s := s3.New(auth, aws.Regions[utils.Cfg.AWSSettings.S3Region])
- bucket := s.Bucket(utils.Cfg.AWSSettings.S3Bucket)
+ s := s3.New(auth, aws.Regions[utils.Cfg.FileSettings.AmazonS3Region])
+ bucket := s.Bucket(utils.Cfg.FileSettings.AmazonS3Bucket)
ext := filepath.Ext(path)
@@ -534,12 +534,12 @@ func writeFile(f []byte, path string) *model.AppError {
if err != nil {
return model.NewAppError("writeFile", "Encountered an error writing to S3", err.Error())
}
- } else if utils.Cfg.ServiceSettings.UseLocalStorage && len(utils.Cfg.ServiceSettings.StorageDirectory) > 0 {
- if err := os.MkdirAll(filepath.Dir(utils.Cfg.ServiceSettings.StorageDirectory+path), 0774); err != nil {
+ } else if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_LOCAL {
+ if err := os.MkdirAll(filepath.Dir(utils.Cfg.FileSettings.Directory+path), 0774); err != nil {
return model.NewAppError("writeFile", "Encountered an error creating the directory for the new file", err.Error())
}
- if err := ioutil.WriteFile(utils.Cfg.ServiceSettings.StorageDirectory+path, f, 0644); err != nil {
+ if err := ioutil.WriteFile(utils.Cfg.FileSettings.Directory+path, f, 0644); err != nil {
return model.NewAppError("writeFile", "Encountered an error writing to local server storage", err.Error())
}
} else {
@@ -551,13 +551,13 @@ func writeFile(f []byte, path string) *model.AppError {
func readFile(path string) ([]byte, *model.AppError) {
- if utils.IsS3Configured() && !utils.Cfg.ServiceSettings.UseLocalStorage {
+ if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 {
var auth aws.Auth
- auth.AccessKey = utils.Cfg.AWSSettings.S3AccessKeyId
- auth.SecretKey = utils.Cfg.AWSSettings.S3SecretAccessKey
+ auth.AccessKey = utils.Cfg.FileSettings.AmazonS3AccessKeyId
+ auth.SecretKey = utils.Cfg.FileSettings.AmazonS3SecretAccessKey
- s := s3.New(auth, aws.Regions[utils.Cfg.AWSSettings.S3Region])
- bucket := s.Bucket(utils.Cfg.AWSSettings.S3Bucket)
+ s := s3.New(auth, aws.Regions[utils.Cfg.FileSettings.AmazonS3Region])
+ bucket := s.Bucket(utils.Cfg.FileSettings.AmazonS3Bucket)
// try to get the file from S3 with some basic retry logic
tries := 0
@@ -573,8 +573,8 @@ func readFile(path string) ([]byte, *model.AppError) {
}
time.Sleep(3000 * time.Millisecond)
}
- } else if utils.Cfg.ServiceSettings.UseLocalStorage && len(utils.Cfg.ServiceSettings.StorageDirectory) > 0 {
- if f, err := ioutil.ReadFile(utils.Cfg.ServiceSettings.StorageDirectory + path); err != nil {
+ } else if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_LOCAL {
+ if f, err := ioutil.ReadFile(utils.Cfg.FileSettings.Directory + path); err != nil {
return nil, model.NewAppError("readFile", "Encountered an error reading from local server storage", err.Error())
} else {
return f, nil
@@ -585,14 +585,14 @@ func readFile(path string) ([]byte, *model.AppError) {
}
func openFileWriteStream(path string) (io.Writer, *model.AppError) {
- if utils.IsS3Configured() && !utils.Cfg.ServiceSettings.UseLocalStorage {
+ if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 {
return nil, model.NewAppError("openFileWriteStream", "S3 is not supported.", "")
- } else if utils.Cfg.ServiceSettings.UseLocalStorage && len(utils.Cfg.ServiceSettings.StorageDirectory) > 0 {
- if err := os.MkdirAll(filepath.Dir(utils.Cfg.ServiceSettings.StorageDirectory+path), 0774); err != nil {
+ } else if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_LOCAL {
+ if err := os.MkdirAll(filepath.Dir(utils.Cfg.FileSettings.Directory+path), 0774); err != nil {
return nil, model.NewAppError("openFileWriteStream", "Encountered an error creating the directory for the new file", err.Error())
}
- if fileHandle, err := os.Create(utils.Cfg.ServiceSettings.StorageDirectory + path); err != nil {
+ if fileHandle, err := os.Create(utils.Cfg.FileSettings.Directory + path); err != nil {
return nil, model.NewAppError("openFileWriteStream", "Encountered an error writing to local server storage", err.Error())
} else {
fileHandle.Chmod(0644)
diff --git a/api/file_benchmark_test.go b/api/file_benchmark_test.go
index 251ff7793c..47f8bff43d 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.FileSettings.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 eb1fcf2ceb..657c081310 100644
--- a/api/file_test.go
+++ b/api/file_test.go
@@ -68,7 +68,7 @@ func TestUploadFile(t *testing.T) {
}
resp, appErr := Client.UploadFile("/files/upload", body.Bytes(), writer.FormDataContentType())
- if utils.IsS3Configured() && !utils.Cfg.ServiceSettings.UseLocalStorage {
+ if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 {
if appErr != nil {
t.Fatal(appErr)
}
@@ -81,11 +81,11 @@ func TestUploadFile(t *testing.T) {
fileId := strings.Split(filename, ".")[0]
var auth aws.Auth
- auth.AccessKey = utils.Cfg.AWSSettings.S3AccessKeyId
- auth.SecretKey = utils.Cfg.AWSSettings.S3SecretAccessKey
+ auth.AccessKey = utils.Cfg.FileSettings.AmazonS3AccessKeyId
+ auth.SecretKey = utils.Cfg.FileSettings.AmazonS3SecretAccessKey
- s := s3.New(auth, aws.Regions[utils.Cfg.AWSSettings.S3Region])
- bucket := s.Bucket(utils.Cfg.AWSSettings.S3Bucket)
+ s := s3.New(auth, aws.Regions[utils.Cfg.FileSettings.AmazonS3Region])
+ bucket := s.Bucket(utils.Cfg.FileSettings.AmazonS3Bucket)
// wait a bit for files to ready
time.Sleep(5 * time.Second)
@@ -104,7 +104,7 @@ func TestUploadFile(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- } else if utils.Cfg.ServiceSettings.UseLocalStorage && len(utils.Cfg.ServiceSettings.StorageDirectory) > 0 {
+ } else if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_LOCAL {
filenames := strings.Split(resp.Data.(*model.FileUploadResponse).Filenames[0], "/")
filename := filenames[len(filenames)-2] + "/" + filenames[len(filenames)-1]
if strings.Contains(filename, "../") {
@@ -115,17 +115,17 @@ func TestUploadFile(t *testing.T) {
// wait a bit for files to ready
time.Sleep(5 * time.Second)
- path := utils.Cfg.ServiceSettings.StorageDirectory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + filename
+ path := utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + filename
if err := os.Remove(path); err != nil {
t.Fatal("Couldn't remove file at " + path)
}
- path = utils.Cfg.ServiceSettings.StorageDirectory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_thumb.jpg"
+ path = utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_thumb.jpg"
if err := os.Remove(path); err != nil {
t.Fatal("Couldn't remove file at " + path)
}
- path = utils.Cfg.ServiceSettings.StorageDirectory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_preview.jpg"
+ path = utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_preview.jpg"
if err := os.Remove(path); err != nil {
t.Fatal("Couldn't remove file at " + path)
}
@@ -151,7 +151,7 @@ func TestGetFile(t *testing.T) {
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
- if utils.IsS3Configured() || utils.Cfg.ServiceSettings.UseLocalStorage {
+ if utils.Cfg.FileSettings.DriverName != "" {
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
@@ -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.FileSettings.PublicLinkSalt))
Client.LoginByEmail(team2.Name, user2.Email, "pwd")
@@ -262,13 +262,13 @@ func TestGetFile(t *testing.T) {
t.Fatal("Should have errored - user not logged in and link not public")
}
- if utils.IsS3Configured() && !utils.Cfg.ServiceSettings.UseLocalStorage {
+ if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 {
var auth aws.Auth
- auth.AccessKey = utils.Cfg.AWSSettings.S3AccessKeyId
- auth.SecretKey = utils.Cfg.AWSSettings.S3SecretAccessKey
+ auth.AccessKey = utils.Cfg.FileSettings.AmazonS3AccessKeyId
+ auth.SecretKey = utils.Cfg.FileSettings.AmazonS3SecretAccessKey
- s := s3.New(auth, aws.Regions[utils.Cfg.AWSSettings.S3Region])
- bucket := s.Bucket(utils.Cfg.AWSSettings.S3Bucket)
+ s := s3.New(auth, aws.Regions[utils.Cfg.FileSettings.AmazonS3Region])
+ bucket := s.Bucket(utils.Cfg.FileSettings.AmazonS3Bucket)
filenames := strings.Split(resp.Data.(*model.FileUploadResponse).Filenames[0], "/")
filename := filenames[len(filenames)-2] + "/" + filenames[len(filenames)-1]
@@ -293,17 +293,17 @@ func TestGetFile(t *testing.T) {
filename := filenames[len(filenames)-2] + "/" + filenames[len(filenames)-1]
fileId := strings.Split(filename, ".")[0]
- path := utils.Cfg.ServiceSettings.StorageDirectory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + filename
+ path := utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + filename
if err := os.Remove(path); err != nil {
t.Fatal("Couldn't remove file at " + path)
}
- path = utils.Cfg.ServiceSettings.StorageDirectory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_thumb.jpg"
+ path = utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_thumb.jpg"
if err := os.Remove(path); err != nil {
t.Fatal("Couldn't remove file at " + path)
}
- path = utils.Cfg.ServiceSettings.StorageDirectory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_preview.jpg"
+ path = utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_preview.jpg"
if err := os.Remove(path); err != nil {
t.Fatal("Couldn't remove file at " + path)
}
@@ -334,7 +334,7 @@ func TestGetPublicLink(t *testing.T) {
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
- if utils.IsS3Configured() || utils.Cfg.ServiceSettings.UseLocalStorage {
+ if utils.Cfg.FileSettings.DriverName != "" {
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
@@ -410,14 +410,14 @@ func TestGetPublicLink(t *testing.T) {
t.Fatal("should have errored, user not member of channel")
}
- if utils.IsS3Configured() && !utils.Cfg.ServiceSettings.UseLocalStorage {
+ if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 {
// perform clean-up on s3
var auth aws.Auth
- auth.AccessKey = utils.Cfg.AWSSettings.S3AccessKeyId
- auth.SecretKey = utils.Cfg.AWSSettings.S3SecretAccessKey
+ auth.AccessKey = utils.Cfg.FileSettings.AmazonS3AccessKeyId
+ auth.SecretKey = utils.Cfg.FileSettings.AmazonS3SecretAccessKey
- s := s3.New(auth, aws.Regions[utils.Cfg.AWSSettings.S3Region])
- bucket := s.Bucket(utils.Cfg.AWSSettings.S3Bucket)
+ s := s3.New(auth, aws.Regions[utils.Cfg.FileSettings.AmazonS3Region])
+ bucket := s.Bucket(utils.Cfg.FileSettings.AmazonS3Bucket)
filenames := strings.Split(resp.Data.(*model.FileUploadResponse).Filenames[0], "/")
filename := filenames[len(filenames)-2] + "/" + filenames[len(filenames)-1]
@@ -442,17 +442,17 @@ func TestGetPublicLink(t *testing.T) {
filename := filenames[len(filenames)-2] + "/" + filenames[len(filenames)-1]
fileId := strings.Split(filename, ".")[0]
- path := utils.Cfg.ServiceSettings.StorageDirectory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + filename
+ path := utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + filename
if err := os.Remove(path); err != nil {
t.Fatal("Couldn't remove file at " + path)
}
- path = utils.Cfg.ServiceSettings.StorageDirectory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_thumb.jpg"
+ path = utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_thumb.jpg"
if err := os.Remove(path); err != nil {
t.Fatal("Couldn't remove file at " + path)
}
- path = utils.Cfg.ServiceSettings.StorageDirectory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_preview.jpg"
+ path = utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_preview.jpg"
if err := os.Remove(path); err != nil {
t.Fatal("Couldn't remove file at " + path)
}
diff --git a/api/post.go b/api/post.go
index bbbc93115a..0379f6af5b 100644
--- a/api/post.go
+++ b/api/post.go
@@ -25,7 +25,6 @@ func InitPost(r *mux.Router) {
sr := r.PathPrefix("/channels/{id:[A-Za-z0-9]+}").Subrouter()
sr.Handle("/create", ApiUserRequired(createPost)).Methods("POST")
- sr.Handle("/valet_create", ApiUserRequired(createValetPost)).Methods("POST")
sr.Handle("/update", ApiUserRequired(updatePost)).Methods("POST")
sr.Handle("/posts/{offset:[0-9]+}/{limit:[0-9]+}", ApiUserRequiredActivity(getPosts, false)).Methods("GET")
sr.Handle("/posts/{time:[0-9]+}", ApiUserRequiredActivity(getPostsSince, false)).Methods("GET")
@@ -60,75 +59,6 @@ func createPost(c *Context, w http.ResponseWriter, r *http.Request) {
}
}
-func createValetPost(c *Context, w http.ResponseWriter, r *http.Request) {
- tchan := Srv.Store.Team().Get(c.Session.TeamId)
-
- post := model.PostFromJson(r.Body)
- if post == nil {
- c.SetInvalidParam("createValetPost", "post")
- return
- }
-
- cchan := Srv.Store.Channel().CheckOpenChannelPermissions(c.Session.TeamId, post.ChannelId)
-
- // Any one with access to the team can post as valet to any open channel
- if !c.HasPermissionsToChannel(cchan, "createValetPost") {
- return
- }
-
- // Make sure this team has the valet feature enabled
- if tResult := <-tchan; tResult.Err != nil {
- c.Err = model.NewAppError("createValetPost", "Could not find the team for this session, team_id="+c.Session.TeamId, "")
- return
- } else {
- if !tResult.Data.(*model.Team).AllowValet {
- c.Err = model.NewAppError("createValetPost", "The valet feature is currently turned off. Please contact your team administrator for details.", "")
- c.Err.StatusCode = http.StatusNotImplemented
- return
- }
- }
-
- if rp, err := CreateValetPost(c, post); err != nil {
- c.Err = err
-
- if strings.Contains(c.Err.Message, "parameter") {
- c.Err.StatusCode = http.StatusBadRequest
- }
-
- return
- } else {
- w.Write([]byte(rp.ToJson()))
- }
-}
-
-func CreateValetPost(c *Context, post *model.Post) (*model.Post, *model.AppError) {
- post.Hashtags, _ = model.ParseHashtags(post.Message)
-
- post.Filenames = []string{} // no files allowed in valet posts yet
-
- if result := <-Srv.Store.User().GetByUsername(c.Session.TeamId, "valet"); result.Err != nil {
- // if the bot doesn't exist, create it
- if tresult := <-Srv.Store.Team().Get(c.Session.TeamId); tresult.Err != nil {
- return nil, tresult.Err
- } else {
- post.UserId = (CreateValet(c, tresult.Data.(*model.Team))).Id
- }
- } else {
- post.UserId = result.Data.(*model.User).Id
- }
-
- var rpost *model.Post
- if result := <-Srv.Store.Post().Save(post); result.Err != nil {
- return nil, result.Err
- } else {
- rpost = result.Data.(*model.Post)
- }
-
- fireAndForgetNotifications(rpost, c.Session.TeamId, c.GetSiteURL())
-
- return rpost, nil
-}
-
func CreatePost(c *Context, post *model.Post, doUpdateLastViewed bool) (*model.Post, *model.AppError) {
var pchan store.StoreChannel
if len(post.RootId) > 0 {
diff --git a/api/post_test.go b/api/post_test.go
index 4cccfd62ae..358611240b 100644
--- a/api/post_test.go
+++ b/api/post_test.go
@@ -123,98 +123,6 @@ func TestCreatePost(t *testing.T) {
}
}
-func TestCreateValetPost(t *testing.T) {
- Setup()
-
- 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)
-
- team2 := &model.Team{DisplayName: "Name Team 2", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
-
- user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
- user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
- store.Must(Srv.Store.User().VerifyEmail(user1.Id))
-
- user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
- user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
- store.Must(Srv.Store.User().VerifyEmail(user2.Id))
-
- Client.LoginByEmail(team.Name, user1.Email, "pwd")
-
- channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
-
- channel2 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
- channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
-
- if utils.Cfg.TeamSettings.AllowValetDefault {
- post1 := &model.Post{ChannelId: channel1.Id, Message: "#hashtag a" + model.NewId() + "a"}
- rpost1, err := Client.CreateValetPost(post1)
- if err != nil {
- t.Fatal(err)
- }
-
- if rpost1.Data.(*model.Post).Message != post1.Message {
- t.Fatal("message didn't match")
- }
-
- if rpost1.Data.(*model.Post).Hashtags != "#hashtag" {
- t.Fatal("hashtag didn't match")
- }
-
- post2 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a", RootId: rpost1.Data.(*model.Post).Id}
- rpost2, err := Client.CreateValetPost(post2)
- if err != nil {
- t.Fatal(err)
- }
-
- post3 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a", RootId: rpost1.Data.(*model.Post).Id, ParentId: rpost2.Data.(*model.Post).Id}
- _, err = Client.CreateValetPost(post3)
- if err != nil {
- t.Fatal(err)
- }
-
- post4 := &model.Post{ChannelId: "junk", Message: "a" + model.NewId() + "a"}
- _, err = Client.CreateValetPost(post4)
- if err.StatusCode != http.StatusForbidden {
- t.Fatal("Should have been forbidden")
- }
-
- Client.LoginByEmail(team.Name, user2.Email, "pwd")
- post5 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a"}
- _, err = Client.CreateValetPost(post5)
- if err != nil {
- t.Fatal(err)
- }
-
- user3 := &model.User{TeamId: team2.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
- user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
- store.Must(Srv.Store.User().VerifyEmail(user3.Id))
-
- Client.LoginByEmail(team2.Name, user3.Email, "pwd")
-
- channel3 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team2.Id}
- channel3 = Client.Must(Client.CreateChannel(channel3)).Data.(*model.Channel)
-
- post6 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a"}
- _, err = Client.CreateValetPost(post6)
- if err.StatusCode != http.StatusForbidden {
- t.Fatal("Should have been forbidden")
- }
-
- if _, err = Client.DoApiPost("/channels/"+channel3.Id+"/create", "garbage"); err == nil {
- t.Fatal("should have been an error")
- }
- } else {
- post1 := &model.Post{ChannelId: channel1.Id, Message: "#hashtag a" + model.NewId() + "a"}
- _, err := Client.CreateValetPost(post1)
- if err.StatusCode != http.StatusNotImplemented {
- t.Fatal("Should have failed with 501 - Not Implemented")
- }
- }
-}
-
func TestUpdatePost(t *testing.T) {
Setup()
diff --git a/api/server.go b/api/server.go
index 3273e766c3..3f23d8df63 100644
--- a/api/server.go
+++ b/api/server.go
@@ -38,11 +38,11 @@ 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
- if utils.Cfg.RateLimitSettings.UseRateLimiter {
+ if utils.Cfg.RateLimitSettings.EnableRateLimiter {
l4g.Info("RateLimiter is enabled")
vary := throttled.VaryBy{}
@@ -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 92fcbff934..c9d2412d37 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.ServiceSettings.DisableEmailSignUp {
+ if !utils.Cfg.EmailSettings.EnableSignUpWithEmail {
c.Err = model.NewAppError("signupTeam", "Team sign-up with email is disabled.", "")
c.Err.StatusCode = http.StatusNotImplemented
return
@@ -60,14 +60,13 @@ func signupTeam(c *Context, w http.ResponseWriter, r *http.Request) {
subjectPage.Props["SiteURL"] = c.GetSiteURL()
bodyPage := NewServerTemplatePage("signup_team_body")
bodyPage.Props["SiteURL"] = c.GetSiteURL()
- bodyPage.Props["TourUrl"] = utils.Cfg.TeamSettings.TourLink
props := make(map[string]string)
props["email"] = email
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))
@@ -76,10 +75,7 @@ func signupTeam(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
- if utils.Cfg.ServiceSettings.Mode == utils.MODE_DEV || utils.Cfg.EmailSettings.ByPassEmail {
- m["follow_link"] = bodyPage.Props["Link"]
- }
-
+ m["follow_link"] = bodyPage.Props["Link"]
w.Header().Set("Access-Control-Allow-Origin", " *")
w.Write([]byte(model.MapToJson(m)))
}
@@ -88,7 +84,8 @@ func createTeamFromSSO(c *Context, w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
service := params["service"]
- if !utils.IsServiceAllowed(service) {
+ sso := utils.Cfg.GetSSOService(service)
+ if sso != nil && !sso.Enable {
c.SetInvalidParam("createTeamFromSSO", "service")
return
}
@@ -126,8 +123,6 @@ func createTeamFromSSO(c *Context, w http.ResponseWriter, r *http.Request) {
}
}
- team.AllowValet = utils.Cfg.TeamSettings.AllowValetDefault
-
if result := <-Srv.Store.Team().Save(team); result.Err != nil {
c.Err = result.Err
return
@@ -147,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.ServiceSettings.DisableEmailSignUp {
+ if !utils.Cfg.EmailSettings.EnableSignUpWithEmail {
c.Err = model.NewAppError("createTeamFromSignup", "Team sign-up with email is disabled.", "")
c.Err.StatusCode = http.StatusNotImplemented
return
@@ -188,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
}
@@ -209,8 +204,6 @@ func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
- teamSignup.Team.AllowValet = utils.Cfg.TeamSettings.AllowValetDefault
-
if result := <-Srv.Store.Team().Save(&teamSignup.Team); result.Err != nil {
c.Err = result.Err
return
@@ -230,13 +223,6 @@ func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
- if teamSignup.Team.AllowValet {
- CreateValet(c, rteam)
- if c.Err != nil {
- return
- }
- }
-
InviteMembers(c, rteam, ruser, teamSignup.Invites)
teamSignup.Team = *rteam
@@ -257,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.ServiceSettings.DisableEmailSignUp {
+ if !utils.Cfg.EmailSettings.EnableSignUpWithEmail {
c.Err = model.NewAppError("createTeam", "Team sign-up with email is disabled.", "")
c.Err.StatusCode = http.StatusNotImplemented
return nil
@@ -272,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
@@ -288,13 +269,6 @@ func CreateTeam(c *Context, team *model.Team) *model.Team {
return nil
}
- if rteam.AllowValet {
- CreateValet(c, rteam)
- if c.Err != nil {
- return nil
- }
- }
-
return rteam
}
}
@@ -303,7 +277,7 @@ func isTreamCreationAllowed(c *Context, email string) bool {
email = strings.ToLower(email)
- if utils.Cfg.TeamSettings.DisableTeamCreation {
+ if !utils.Cfg.TeamSettings.EnableTeamCreation {
c.Err = model.NewAppError("isTreamCreationAllowed", "Team creation has been disabled. Please ask your systems administrator for details.", "")
return false
}
@@ -509,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"])
}
@@ -569,8 +543,6 @@ func updateValetFeature(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
- allowValet := allowValetStr == "true"
-
teamId := props["team_id"]
if len(teamId) > 0 && len(teamId) != 26 {
c.SetInvalidParam("updateValetFeature", "team_id")
@@ -599,8 +571,6 @@ func updateValetFeature(c *Context, w http.ResponseWriter, r *http.Request) {
team = tResult.Data.(*model.Team)
}
- team.AllowValet = allowValet
-
if result := <-Srv.Store.Team().Update(team); result.Err != nil {
c.Err = result.Err
return
diff --git a/api/team_test.go b/api/team_test.go
index 4f1b9e5f03..cd39dacfe5 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"}
@@ -330,79 +330,3 @@ func TestGetMyTeam(t *testing.T) {
}
}
}
-
-func TestUpdateValetFeature(t *testing.T) {
- Setup()
-
- 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)
-
- user := &model.User{TeamId: team.Id, Email: "test@nowhere.com", Nickname: "Corey Hulen", Password: "pwd"}
- user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
- store.Must(Srv.Store.User().VerifyEmail(user.Id))
-
- user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
- user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
- store.Must(Srv.Store.User().VerifyEmail(user2.Id))
-
- team2 := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
- team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
-
- user3 := &model.User{TeamId: team2.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
- user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
- store.Must(Srv.Store.User().VerifyEmail(user3.Id))
-
- Client.LoginByEmail(team.Name, user2.Email, "pwd")
-
- data := make(map[string]string)
- data["allow_valet"] = "true"
- if _, err := Client.UpdateValetFeature(data); err == nil {
- t.Fatal("Should have errored, not admin")
- }
-
- Client.LoginByEmail(team.Name, user.Email, "pwd")
-
- data["allow_valet"] = ""
- if _, err := Client.UpdateValetFeature(data); err == nil {
- t.Fatal("Should have errored, empty allow_valet field")
- }
-
- data["allow_valet"] = "true"
- if _, err := Client.UpdateValetFeature(data); err != nil {
- t.Fatal(err)
- }
-
- rteam := Client.Must(Client.GetMyTeam("")).Data.(*model.Team)
- if rteam.AllowValet != true {
- t.Fatal("Should have errored - allow valet property not updated")
- }
-
- data["team_id"] = "junk"
- if _, err := Client.UpdateValetFeature(data); err == nil {
- t.Fatal("Should have errored, junk team id")
- }
-
- data["team_id"] = "12345678901234567890123456"
- if _, err := Client.UpdateValetFeature(data); err == nil {
- t.Fatal("Should have errored, bad team id")
- }
-
- data["team_id"] = team.Id
- data["allow_valet"] = "false"
- if _, err := Client.UpdateValetFeature(data); err != nil {
- t.Fatal(err)
- }
-
- rteam = Client.Must(Client.GetMyTeam("")).Data.(*model.Team)
- if rteam.AllowValet != false {
- t.Fatal("Should have errored - allow valet property not updated")
- }
-
- Client.LoginByEmail(team2.Name, user3.Email, "pwd")
-
- data["team_id"] = team.Id
- data["allow_valet"] = "true"
- if _, err := Client.UpdateValetFeature(data); err == nil {
- t.Fatal("Should have errored, not part of team")
- }
-}
diff --git a/api/user.go b/api/user.go
index 2740696e1d..40410cc5ba 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.ServiceSettings.DisableEmailSignUp {
+ 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
}
@@ -155,19 +155,13 @@ func IsVerifyHashRequired(user *model.User, team *model.Team, hash string) bool
return shouldVerifyHash
}
-func CreateValet(c *Context, team *model.Team) *model.User {
- valet := &model.User{}
- valet.TeamId = team.Id
- valet.Email = utils.Cfg.EmailSettings.FeedbackEmail
- valet.EmailVerified = true
- valet.Username = model.BOT_USERNAME
- valet.Password = model.NewId()
-
- return CreateUser(c, team, valet)
-}
-
func CreateUser(c *Context, team *model.Team, user *model.User) *model.User {
+ if !utils.Cfg.TeamSettings.EnableUserCreation {
+ c.Err = model.NewAppError("CreateUser", "User creation has been disabled. Please ask your systems administrator for details.", "")
+ return nil
+ }
+
channelRole := ""
if team.Email == user.Email {
user.Roles = model.ROLE_TEAM_ADMIN
@@ -290,7 +284,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
@@ -321,7 +315,7 @@ func checkUserPassword(c *Context, user *model.User, password string) bool {
func Login(c *Context, w http.ResponseWriter, r *http.Request, user *model.User, deviceId string) {
c.LogAuditWithUserId(user.Id, "attempt")
- if !user.EmailVerified && !utils.Cfg.EmailSettings.ByPassEmail {
+ if !user.EmailVerified && utils.Cfg.EmailSettings.RequireEmailVerification {
c.Err = model.NewAppError("Login", "Login failed because email address has not been verified", "user_id="+user.Id)
c.Err.StatusCode = http.StatusForbidden
return
@@ -652,7 +646,7 @@ func createProfileImage(username string, userId string) ([]byte, *model.AppError
initial := string(strings.ToUpper(username)[0])
- fontBytes, err := ioutil.ReadFile(utils.FindDir("web/static/fonts") + utils.Cfg.ImageSettings.InitialFont)
+ fontBytes, err := ioutil.ReadFile(utils.FindDir("web/static/fonts") + utils.Cfg.FileSettings.InitialFont)
if err != nil {
return nil, model.NewAppError("createProfileImage", "Could not create default profile image font", err.Error())
}
@@ -661,8 +655,8 @@ func createProfileImage(username string, userId string) ([]byte, *model.AppError
return nil, model.NewAppError("createProfileImage", "Could not create default profile image font", err.Error())
}
- width := int(utils.Cfg.ImageSettings.ProfileWidth)
- height := int(utils.Cfg.ImageSettings.ProfileHeight)
+ width := int(utils.Cfg.FileSettings.ProfileWidth)
+ height := int(utils.Cfg.FileSettings.ProfileHeight)
color := colors[int64(seed)%int64(len(colors))]
dstImg := image.NewRGBA(image.Rect(0, 0, width, height))
srcImg := image.White
@@ -701,7 +695,7 @@ func getProfileImage(c *Context, w http.ResponseWriter, r *http.Request) {
} else {
var img []byte
- if !utils.IsS3Configured() && !utils.Cfg.ServiceSettings.UseLocalStorage {
+ if len(utils.Cfg.FileSettings.DriverName) == 0 {
var err *model.AppError
if img, err = createProfileImage(result.Data.(*model.User).Username, id); err != nil {
c.Err = err
@@ -738,8 +732,8 @@ func getProfileImage(c *Context, w http.ResponseWriter, r *http.Request) {
}
func uploadProfileImage(c *Context, w http.ResponseWriter, r *http.Request) {
- if !utils.IsS3Configured() && !utils.Cfg.ServiceSettings.UseLocalStorage {
- c.Err = model.NewAppError("uploadProfileImage", "Unable to upload file. Amazon S3 not configured and local server storage turned off. ", "")
+ if len(utils.Cfg.FileSettings.DriverName) == 0 {
+ c.Err = model.NewAppError("uploadProfileImage", "Unable to upload file. Image storage is not configured.", "")
c.Err.StatusCode = http.StatusNotImplemented
return
}
@@ -781,7 +775,7 @@ func uploadProfileImage(c *Context, w http.ResponseWriter, r *http.Request) {
}
// Scale profile image
- img = resize.Resize(utils.Cfg.ImageSettings.ProfileWidth, utils.Cfg.ImageSettings.ProfileHeight, img, resize.Lanczos3)
+ img = resize.Resize(utils.Cfg.FileSettings.ProfileWidth, utils.Cfg.FileSettings.ProfileHeight, img, resize.Lanczos3)
buf := new(bytes.Buffer)
err = png.Encode(buf, img)
@@ -1132,7 +1126,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))
@@ -1211,7 +1205,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
}
@@ -1359,15 +1353,16 @@ 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) {
- if s, ok := utils.Cfg.SSOSettings[service]; !ok || !s.Allow {
+ sso := utils.Cfg.GetSSOService(service)
+ if sso != nil && !sso.Enable {
c.Err = model.NewAppError("GetAuthorizationCode", "Unsupported OAuth service provider", "service="+service)
c.Err.StatusCode = http.StatusBadRequest
return
}
- clientId := utils.Cfg.SSOSettings[service].Id
- endpoint := utils.Cfg.SSOSettings[service].AuthEndpoint
- scope := utils.Cfg.SSOSettings[service].Scope
+ clientId := sso.Id
+ endpoint := sso.AuthEndpoint
+ scope := sso.Scope
stateProps := map[string]string{"team": teamName, "hash": model.HashPassword(clientId)}
state := b64.StdEncoding.EncodeToString([]byte(model.MapToJson(stateProps)))
@@ -1386,7 +1381,8 @@ func GetAuthorizationCode(c *Context, w http.ResponseWriter, r *http.Request, te
}
func AuthorizeOAuthUser(service, code, state, redirectUri string) (io.ReadCloser, *model.Team, *model.AppError) {
- if s, ok := utils.Cfg.SSOSettings[service]; !ok || !s.Allow {
+ sso := utils.Cfg.GetSSOService(service)
+ if sso != nil && !sso.Enable {
return nil, nil, model.NewAppError("AuthorizeOAuthUser", "Unsupported OAuth service provider", "service="+service)
}
@@ -1399,7 +1395,7 @@ func AuthorizeOAuthUser(service, code, state, redirectUri string) (io.ReadCloser
stateProps := model.MapFromJson(strings.NewReader(stateStr))
- if !model.ComparePassword(stateProps["hash"], utils.Cfg.SSOSettings[service].Id) {
+ if !model.ComparePassword(stateProps["hash"], sso.Id) {
return nil, nil, model.NewAppError("AuthorizeOAuthUser", "Invalid state", "")
}
@@ -1411,14 +1407,14 @@ func AuthorizeOAuthUser(service, code, state, redirectUri string) (io.ReadCloser
tchan := Srv.Store.Team().GetByName(teamName)
p := url.Values{}
- p.Set("client_id", utils.Cfg.SSOSettings[service].Id)
- p.Set("client_secret", utils.Cfg.SSOSettings[service].Secret)
+ p.Set("client_id", sso.Id)
+ p.Set("client_secret", sso.Secret)
p.Set("code", code)
p.Set("grant_type", model.ACCESS_TOKEN_GRANT_TYPE)
p.Set("redirect_uri", redirectUri)
client := &http.Client{}
- req, _ := http.NewRequest("POST", utils.Cfg.SSOSettings[service].TokenEndpoint, strings.NewReader(p.Encode()))
+ req, _ := http.NewRequest("POST", sso.TokenEndpoint, strings.NewReader(p.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Accept", "application/json")
@@ -1440,7 +1436,7 @@ func AuthorizeOAuthUser(service, code, state, redirectUri string) (io.ReadCloser
p = url.Values{}
p.Set("access_token", ar.AccessToken)
- req, _ = http.NewRequest("GET", utils.Cfg.SSOSettings[service].UserApiEndpoint, strings.NewReader(""))
+ req, _ = http.NewRequest("GET", sso.UserApiEndpoint, strings.NewReader(""))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Accept", "application/json")
diff --git a/api/user_test.go b/api/user_test.go
index 986365bd0a..669da4d208 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)
@@ -352,19 +352,19 @@ func TestUserCreateImage(t *testing.T) {
Client.DoApiGet("/users/"+user.Id+"/image", "", "")
- if utils.IsS3Configured() && !utils.Cfg.ServiceSettings.UseLocalStorage {
+ if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 {
var auth aws.Auth
- auth.AccessKey = utils.Cfg.AWSSettings.S3AccessKeyId
- auth.SecretKey = utils.Cfg.AWSSettings.S3SecretAccessKey
+ auth.AccessKey = utils.Cfg.FileSettings.AmazonS3AccessKeyId
+ auth.SecretKey = utils.Cfg.FileSettings.AmazonS3SecretAccessKey
- s := s3.New(auth, aws.Regions[utils.Cfg.AWSSettings.S3Region])
- bucket := s.Bucket(utils.Cfg.AWSSettings.S3Bucket)
+ s := s3.New(auth, aws.Regions[utils.Cfg.FileSettings.AmazonS3Region])
+ bucket := s.Bucket(utils.Cfg.FileSettings.AmazonS3Bucket)
if err := bucket.Del("teams/" + user.TeamId + "/users/" + user.Id + "/profile.png"); err != nil {
t.Fatal(err)
}
} else {
- path := utils.Cfg.ServiceSettings.StorageDirectory + "teams/" + user.TeamId + "/users/" + user.Id + "/profile.png"
+ path := utils.Cfg.FileSettings.Directory + "teams/" + user.TeamId + "/users/" + user.Id + "/profile.png"
if err := os.Remove(path); err != nil {
t.Fatal("Couldn't remove file at " + path)
}
@@ -382,7 +382,7 @@ func TestUserUploadProfileImage(t *testing.T) {
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
- if utils.IsS3Configured() || utils.Cfg.ServiceSettings.UseLocalStorage {
+ if utils.Cfg.FileSettings.DriverName != "" {
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
@@ -450,19 +450,19 @@ func TestUserUploadProfileImage(t *testing.T) {
Client.DoApiGet("/users/"+user.Id+"/image", "", "")
- if utils.IsS3Configured() && !utils.Cfg.ServiceSettings.UseLocalStorage {
+ if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 {
var auth aws.Auth
- auth.AccessKey = utils.Cfg.AWSSettings.S3AccessKeyId
- auth.SecretKey = utils.Cfg.AWSSettings.S3SecretAccessKey
+ auth.AccessKey = utils.Cfg.FileSettings.AmazonS3AccessKeyId
+ auth.SecretKey = utils.Cfg.FileSettings.AmazonS3SecretAccessKey
- s := s3.New(auth, aws.Regions[utils.Cfg.AWSSettings.S3Region])
- bucket := s.Bucket(utils.Cfg.AWSSettings.S3Bucket)
+ s := s3.New(auth, aws.Regions[utils.Cfg.FileSettings.AmazonS3Region])
+ bucket := s.Bucket(utils.Cfg.FileSettings.AmazonS3Bucket)
if err := bucket.Del("teams/" + user.TeamId + "/users/" + user.Id + "/profile.png"); err != nil {
t.Fatal(err)
}
} else {
- path := utils.Cfg.ServiceSettings.StorageDirectory + "teams/" + user.TeamId + "/users/" + user.Id + "/profile.png"
+ path := utils.Cfg.FileSettings.Directory + "teams/" + user.TeamId + "/users/" + user.Id + "/profile.png"
if err := os.Remove(path); err != nil {
t.Fatal("Couldn't remove file at " + path)
}
@@ -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 {
@@ -952,6 +952,7 @@ func TestUserUpdateNotify(t *testing.T) {
}
func TestFuzzyUserCreate(t *testing.T) {
+ Setup()
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
rteam, _ := Client.CreateTeam(&team)
diff --git a/api/web_socket_test.go b/api/web_socket_test.go
index 7f9ce024b2..49a4c68707 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/api/webhook.go b/api/webhook.go
index 9ca725d45d..b67655ff55 100644
--- a/api/webhook.go
+++ b/api/webhook.go
@@ -21,7 +21,7 @@ func InitWebhook(r *mux.Router) {
}
func createIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) {
- if !utils.Cfg.ServiceSettings.AllowIncomingWebhooks {
+ if !utils.Cfg.ServiceSettings.EnableIncomingWebhooks {
c.Err = model.NewAppError("createIncomingHook", "Incoming webhooks have been disabled by the system admin.", "")
c.Err.StatusCode = http.StatusNotImplemented
return
@@ -66,7 +66,7 @@ func createIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) {
}
func deleteIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) {
- if !utils.Cfg.ServiceSettings.AllowIncomingWebhooks {
+ if !utils.Cfg.ServiceSettings.EnableIncomingWebhooks {
c.Err = model.NewAppError("createIncomingHook", "Incoming webhooks have been disabled by the system admin.", "")
c.Err.StatusCode = http.StatusNotImplemented
return
@@ -103,7 +103,7 @@ func deleteIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) {
}
func getIncomingHooks(c *Context, w http.ResponseWriter, r *http.Request) {
- if !utils.Cfg.ServiceSettings.AllowIncomingWebhooks {
+ if !utils.Cfg.ServiceSettings.EnableIncomingWebhooks {
c.Err = model.NewAppError("createIncomingHook", "Incoming webhooks have been disabled by the system admin.", "")
c.Err.StatusCode = http.StatusNotImplemented
return
diff --git a/api/webhook_test.go b/api/webhook_test.go
index fd4c723b7a..22883f8ca4 100644
--- a/api/webhook_test.go
+++ b/api/webhook_test.go
@@ -31,7 +31,7 @@ func TestCreateIncomingHook(t *testing.T) {
hook := &model.IncomingWebhook{ChannelId: channel1.Id}
- if utils.Cfg.ServiceSettings.AllowIncomingWebhooks {
+ if utils.Cfg.ServiceSettings.EnableIncomingWebhooks {
var rhook *model.IncomingWebhook
if result, err := Client.CreateIncomingWebhook(hook); err != nil {
t.Fatal(err)
@@ -89,7 +89,7 @@ func TestListIncomingHooks(t *testing.T) {
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
- if utils.Cfg.ServiceSettings.AllowIncomingWebhooks {
+ if utils.Cfg.ServiceSettings.EnableIncomingWebhooks {
hook1 := &model.IncomingWebhook{ChannelId: channel1.Id}
hook1 = Client.Must(Client.CreateIncomingWebhook(hook1)).Data.(*model.IncomingWebhook)
@@ -127,7 +127,7 @@ func TestDeleteIncomingHook(t *testing.T) {
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
- if utils.Cfg.ServiceSettings.AllowIncomingWebhooks {
+ if utils.Cfg.ServiceSettings.EnableIncomingWebhooks {
hook := &model.IncomingWebhook{ChannelId: channel1.Id}
hook = Client.Must(Client.CreateIncomingWebhook(hook)).Data.(*model.IncomingWebhook)
diff --git a/config/config.json b/config/config.json
index c573a299f6..aa92ccf4eb 100644
--- a/config/config.json
+++ b/config/config.json
@@ -1,71 +1,74 @@
{
- "LogSettings": {
- "ConsoleEnable": true,
- "ConsoleLevel": "DEBUG",
- "FileEnable": true,
- "FileLevel": "INFO",
- "FileFormat": "",
- "FileLocation": ""
- },
"ServiceSettings": {
- "SiteName": "Mattermost",
- "Mode": "dev",
- "AllowTesting": false,
- "UseSSL": false,
- "Port": "8065",
- "Version": "developer",
- "InviteSalt": "gxHVDcKUyP2y1eiyW8S8na1UYQAfq6J6",
- "PublicLinkSalt": "TO3pTyXIZzwHiwyZgGql7lM7DG3zeId4",
- "ResetSalt": "IPxFzSfnDFsNsRafZxz8NaYqFKhf9y2t",
- "AnalyticsUrl": "",
- "UseLocalStorage": true,
- "StorageDirectory": "./data/",
- "AllowedLoginAttempts": 10,
- "DisableEmailSignUp": false,
+ "ListenAddress": ":8065",
+ "MaximumLoginAttempts": 10,
+ "SegmentDeveloperKey": "",
+ "GoogleDeveloperKey": "",
"EnableOAuthServiceProvider": false,
- "AllowIncomingWebhooks": false
+ "EnableIncomingWebhooks": 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": [
- "mmuser:mostest@tcp(dockerhost:3306)/mattermost_test?charset=utf8mb4,utf8"
- ],
+ "DataSourceReplicas": [],
"MaxIdleConns": 10,
"MaxOpenConns": 10,
"Trace": false,
- "AtRestEncryptKey": "Ya0xMrybACJ3sZZVWQC7e31h5nSDWZFS"
+ "AtRestEncryptKey": "7rAh6iwQCkV4cA1Gsg3fgGOXJAQ43QVg"
},
- "AWSSettings": {
- "S3AccessKeyId": "",
- "S3SecretAccessKey": "",
- "S3Bucket": "",
- "S3Region": ""
+ "LogSettings": {
+ "EnableConsole": true,
+ "ConsoleLevel": "DEBUG",
+ "EnableFile": true,
+ "FileLevel": "INFO",
+ "FileFormat": "",
+ "FileLocation": ""
},
- "ImageSettings": {
+ "FileSettings": {
+ "DriverName": "local",
+ "Directory": "./data/",
+ "EnablePublicLink": true,
+ "PublicLinkSalt": "A705AklYF8MFDOfcwh3I488G8vtLlVip",
"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": "bjlSR4QqkXFBr7TP4oDzlfZmcNuH9YoS",
+ "PasswordResetSalt": "vZ4DcKyVVRlKHHJpexcuXzojkE5PZ5eL",
"ApplePushServer": "",
"ApplePushCertPublic": "",
"ApplePushCertPrivate": ""
},
"RateLimitSettings": {
- "UseRateLimiter": true,
+ "EnableRateLimiter": true,
"PerSec": 10,
"MemoryStoreSize": 10000,
"VaryByRemoteAddr": true,
@@ -73,32 +76,15 @@
},
"PrivacySettings": {
"ShowEmailAddress": true,
- "ShowPhoneNumber": true,
- "ShowSkypeId": true,
"ShowFullName": true
},
- "ClientSettings": {
- "SegmentDeveloperKey": "",
- "GoogleDeveloperKey": ""
- },
- "TeamSettings": {
- "MaxUsersPerTeam": 150,
- "AllowPublicLink": true,
- "AllowValetDefault": false,
- "TourLink": "",
- "DefaultThemeColor": "#2389D7",
- "DisableTeamCreation": false,
- "RestrictCreationToDomains": ""
- },
- "SSOSettings": {
- "gitlab": {
- "Allow": false,
- "Secret": "",
- "Id": "",
- "Scope": "",
- "AuthEndpoint": "",
- "TokenEndpoint": "",
- "UserApiEndpoint": ""
- }
+ "GitLabSettings": {
+ "Enable": false,
+ "Secret": "",
+ "Id": "",
+ "Scope": "",
+ "AuthEndpoint": "",
+ "TokenEndpoint": "",
+ "UserApiEndpoint": ""
}
}
\ No newline at end of file
diff --git a/docker/dev/config_docker.json b/docker/dev/config_docker.json
index d50439f2c4..16a4007fa0 100644
--- a/docker/dev/config_docker.json
+++ b/docker/dev/config_docker.json
@@ -1,82 +1,74 @@
{
+ "ServiceSettings": {
+ "ListenAddress": ":80",
+ "MaximumLoginAttempts": 10,
+ "SegmentDeveloperKey": "",
+ "GoogleDeveloperKey": "",
+ "EnableOAuthServiceProvider": false,
+ "EnableIncomingWebhooks": 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": {
- "ConsoleEnable": true,
+ "EnableConsole": false,
"ConsoleLevel": "INFO",
- "FileEnable": true,
+ "EnableFile": 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,
- "AllowIncomingWebhooks": 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": {
+ "FileSettings": {
+ "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,
@@ -84,22 +76,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 b6e02635cf..16a4007fa0 100644
--- a/docker/local/config_docker.json
+++ b/docker/local/config_docker.json
@@ -1,82 +1,74 @@
{
+ "ServiceSettings": {
+ "ListenAddress": ":80",
+ "MaximumLoginAttempts": 10,
+ "SegmentDeveloperKey": "",
+ "GoogleDeveloperKey": "",
+ "EnableOAuthServiceProvider": false,
+ "EnableIncomingWebhooks": 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": {
- "ConsoleEnable": true,
+ "EnableConsole": false,
"ConsoleLevel": "INFO",
- "FileEnable": true,
+ "EnableFile": 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,
- "AllowIncomingWebhooks": 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": {
+ "FileSettings": {
+ "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,
@@ -84,22 +76,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 86b173c6a2..a517b0c0e1 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 f54bcf15fb..4608bfff3e 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 6817a80f6e..cc75ce3705 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"
@@ -403,6 +404,15 @@ func (c *Client) SaveConfig(config *Config) (*Result, *AppError) {
}
}
+func (c *Client) TestEmail(config *Config) (*Result, *AppError) {
+ if r, err := c.DoApiPost("/admin/test_email", config.ToJson()); err != nil {
+ return nil, err
+ } else {
+ return &Result{r.Header.Get(HEADER_REQUEST_ID),
+ r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
+ }
+}
+
func (c *Client) CreateChannel(channel *Channel) (*Result, *AppError) {
if r, err := c.DoApiPost("/channels/create", channel.ToJson()); err != nil {
return nil, err
diff --git a/model/config.go b/model/config.go
index 436f063c81..69f2127b27 100644
--- a/model/config.go
+++ b/model/config.go
@@ -8,27 +8,29 @@ import (
"io"
)
+const (
+ CONN_SECURITY_NONE = ""
+ CONN_SECURITY_TLS = "TLS"
+ CONN_SECURITY_STARTTLS = "STARTTLS"
+
+ IMAGE_DRIVER_LOCAL = "local"
+ IMAGE_DRIVER_S3 = "amazons3"
+
+ SERVICE_GITLAB = "gitlab"
+)
+
type ServiceSettings struct {
- SiteName string
- Mode string
- AllowTesting bool
- UseSSL bool
- Port string
- Version string
- InviteSalt string
- PublicLinkSalt string
- ResetSalt string
- AnalyticsUrl string
- UseLocalStorage bool
- StorageDirectory string
- AllowedLoginAttempts int
- DisableEmailSignUp bool
+ ListenAddress string
+ MaximumLoginAttempts int
+ SegmentDeveloperKey string
+ GoogleDeveloperKey string
EnableOAuthServiceProvider bool
- AllowIncomingWebhooks bool
+ EnableIncomingWebhooks bool
+ EnableTesting bool
}
-type SSOSetting struct {
- Allow bool
+type SSOSettings struct {
+ Enable bool
Secret string
Id string
Scope string
@@ -48,87 +50,84 @@ type SqlSettings struct {
}
type LogSettings struct {
- ConsoleEnable bool
+ EnableConsole bool
ConsoleLevel string
- FileEnable bool
+ EnableFile bool
FileLevel string
FileFormat string
FileLocation string
}
-type AWSSettings struct {
- S3AccessKeyId string
- S3SecretAccessKey string
- S3Bucket string
- S3Region string
-}
-
-type ImageSettings struct {
- ThumbnailWidth uint
- ThumbnailHeight uint
- PreviewWidth uint
- PreviewHeight uint
- ProfileWidth uint
- ProfileHeight uint
- InitialFont string
+type FileSettings struct {
+ DriverName string
+ Directory string
+ EnablePublicLink bool
+ PublicLinkSalt string
+ ThumbnailWidth uint
+ ThumbnailHeight uint
+ PreviewWidth uint
+ PreviewHeight uint
+ ProfileWidth uint
+ ProfileHeight uint
+ InitialFont string
+ AmazonS3AccessKeyId string
+ AmazonS3SecretAccessKey string
+ AmazonS3Bucket string
+ AmazonS3Region string
}
type EmailSettings struct {
- ByPassEmail bool
- SMTPUsername string
- SMTPPassword string
- SMTPServer string
- UseTLS bool
- UseStartTLS bool
- FeedbackEmail string
- FeedbackName string
+ EnableSignUpWithEmail bool
+ SendEmailNotifications bool
+ RequireEmailVerification bool
+ FeedbackName string
+ FeedbackEmail string
+ SMTPUsername string
+ SMTPPassword string
+ SMTPServer string
+ SMTPPort string
+ ConnectionSecurity string
+ InviteSalt string
+ PasswordResetSalt string
+
+ // For Future Use
ApplePushServer string
ApplePushCertPublic string
ApplePushCertPrivate string
}
type RateLimitSettings struct {
- UseRateLimiter bool
- PerSec int
- MemoryStoreSize int
- VaryByRemoteAddr bool
- VaryByHeader string
+ EnableRateLimiter bool
+ PerSec int
+ MemoryStoreSize int
+ VaryByRemoteAddr bool
+ VaryByHeader string
}
type PrivacySettings struct {
ShowEmailAddress bool
- ShowPhoneNumber bool
- ShowSkypeId bool
ShowFullName bool
}
-type ClientSettings struct {
- SegmentDeveloperKey string
- GoogleDeveloperKey string
-}
-
type TeamSettings struct {
+ SiteName string
MaxUsersPerTeam int
- AllowPublicLink bool
- AllowValetDefault bool
- TourLink string
DefaultThemeColor string
- DisableTeamCreation bool
+ EnableTeamCreation bool
+ EnableUserCreation bool
RestrictCreationToDomains string
}
type Config struct {
- LogSettings LogSettings
ServiceSettings ServiceSettings
+ TeamSettings TeamSettings
SqlSettings SqlSettings
- AWSSettings AWSSettings
- ImageSettings ImageSettings
+ LogSettings LogSettings
+ FileSettings FileSettings
EmailSettings EmailSettings
RateLimitSettings RateLimitSettings
PrivacySettings PrivacySettings
- ClientSettings ClientSettings
- TeamSettings TeamSettings
- SSOSettings map[string]SSOSetting
+ GitLabSettings SSOSettings
}
func (o *Config) ToJson() string {
@@ -140,6 +139,14 @@ func (o *Config) ToJson() string {
}
}
+func (o *Config) GetSSOService(service string) *SSOSettings {
+ if service == SERVICE_GITLAB {
+ return &o.GitLabSettings
+ }
+
+ return nil
+}
+
func ConfigFromJson(data io.Reader) *Config {
decoder := json.NewDecoder(data)
var o Config
diff --git a/model/team.go b/model/team.go
index 8b4f82830c..0d740dde27 100644
--- a/model/team.go
+++ b/model/team.go
@@ -27,7 +27,6 @@ type Team struct {
Type string `json:"type"`
CompanyName string `json:"company_name"`
AllowedDomains string `json:"allowed_domains"`
- AllowValet bool `json:"allow_valet"`
}
type Invites struct {
diff --git a/store/sql_store.go b/store/sql_store.go
index 98703841a4..6dcf2e8cd8 100644
--- a/store/sql_store.go
+++ b/store/sql_store.go
@@ -51,11 +51,18 @@ func NewSqlStore() Store {
utils.Cfg.SqlSettings.DataSource, utils.Cfg.SqlSettings.MaxIdleConns,
utils.Cfg.SqlSettings.MaxOpenConns, utils.Cfg.SqlSettings.Trace)
- sqlStore.replicas = make([]*gorp.DbMap, len(utils.Cfg.SqlSettings.DataSourceReplicas))
- for i, replica := range utils.Cfg.SqlSettings.DataSourceReplicas {
- sqlStore.replicas[i] = setupConnection(fmt.Sprintf("replica-%v", i), utils.Cfg.SqlSettings.DriverName, replica,
+ if len(utils.Cfg.SqlSettings.DataSourceReplicas) == 0 {
+ sqlStore.replicas = make([]*gorp.DbMap, 1)
+ sqlStore.replicas[0] = setupConnection(fmt.Sprintf("replica-%v", 0), utils.Cfg.SqlSettings.DriverName, utils.Cfg.SqlSettings.DataSource,
utils.Cfg.SqlSettings.MaxIdleConns, utils.Cfg.SqlSettings.MaxOpenConns,
utils.Cfg.SqlSettings.Trace)
+ } else {
+ sqlStore.replicas = make([]*gorp.DbMap, len(utils.Cfg.SqlSettings.DataSourceReplicas))
+ for i, replica := range utils.Cfg.SqlSettings.DataSourceReplicas {
+ sqlStore.replicas[i] = setupConnection(fmt.Sprintf("replica-%v", i), utils.Cfg.SqlSettings.DriverName, replica,
+ utils.Cfg.SqlSettings.MaxIdleConns, utils.Cfg.SqlSettings.MaxOpenConns,
+ utils.Cfg.SqlSettings.Trace)
+ }
}
schemaVersion := sqlStore.GetCurrentSchemaVersion()
@@ -308,26 +315,21 @@ func (ss SqlStore) CreateColumnIfNotExists(tableName string, columnName string,
}
}
-// func (ss SqlStore) RemoveColumnIfExists(tableName string, columnName string) bool {
+func (ss SqlStore) RemoveColumnIfExists(tableName string, columnName string) bool {
-// // XXX TODO FIXME this should be removed after 0.6.0
-// if utils.Cfg.SqlSettings.DriverName == "postgres" {
-// return false
-// }
+ if !ss.DoesColumnExist(tableName, columnName) {
+ return false
+ }
-// if !ss.DoesColumnExist(tableName, columnName) {
-// return false
-// }
+ _, err := ss.GetMaster().Exec("ALTER TABLE " + tableName + " DROP COLUMN " + columnName)
+ if err != nil {
+ l4g.Critical("Failed to drop column %v", err)
+ time.Sleep(time.Second)
+ panic("Failed to drop column " + err.Error())
+ }
-// _, err := ss.GetMaster().Exec("ALTER TABLE " + tableName + " DROP COLUMN " + columnName)
-// if err != nil {
-// l4g.Critical("Failed to drop column %v", err)
-// time.Sleep(time.Second)
-// panic("Failed to drop column " + err.Error())
-// }
-
-// return true
-// }
+ return true
+}
// func (ss SqlStore) RenameColumnIfExists(tableName string, oldColumnName string, newColumnName string, colType string) bool {
diff --git a/store/sql_team_store.go b/store/sql_team_store.go
index d2148c2e3c..3d644e5776 100644
--- a/store/sql_team_store.go
+++ b/store/sql_team_store.go
@@ -28,6 +28,7 @@ func NewSqlTeamStore(sqlStore *SqlStore) TeamStore {
}
func (s SqlTeamStore) UpgradeSchemaIfNeeded() {
+ s.RemoveColumnIfExists("Teams", "AllowValet")
}
func (s SqlTeamStore) CreateIndexesIfNotExists() {
diff --git a/store/sql_user_store_test.go b/store/sql_user_store_test.go
index ddd7e5bb87..466da28452 100644
--- a/store/sql_user_store_test.go
+++ b/store/sql_user_store_test.go
@@ -42,7 +42,7 @@ func TestUserStoreSave(t *testing.T) {
t.Fatal("should be unique username")
}
- for i := 0; i < 150; i++ {
+ for i := 0; i < 50; i++ {
u1.Id = ""
u1.Email = model.NewId()
u1.Username = model.NewId()
diff --git a/utils/config.go b/utils/config.go
index 35631358b6..5d786699bb 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
@@ -161,8 +161,6 @@ func getSanitizeOptions(c *model.Config) map[string]bool {
options := map[string]bool{}
options["fullname"] = c.PrivacySettings.ShowFullName
options["email"] = c.PrivacySettings.ShowEmailAddress
- options["skypeid"] = c.PrivacySettings.ShowSkypeId
- options["phonenumber"] = c.PrivacySettings.ShowPhoneNumber
return options
}
@@ -175,57 +173,24 @@ func getClientProperties(c *model.Config) map[string]string {
props["BuildDate"] = model.BuildDate
props["BuildHash"] = model.BuildHash
- props["SiteName"] = c.ServiceSettings.SiteName
- props["ByPassEmail"] = strconv.FormatBool(c.EmailSettings.ByPassEmail)
- props["FeedbackEmail"] = c.EmailSettings.FeedbackEmail
- props["ShowEmailAddress"] = strconv.FormatBool(c.PrivacySettings.ShowEmailAddress)
- props["AllowPublicLink"] = strconv.FormatBool(c.TeamSettings.AllowPublicLink)
- props["SegmentDeveloperKey"] = c.ClientSettings.SegmentDeveloperKey
- props["GoogleDeveloperKey"] = c.ClientSettings.GoogleDeveloperKey
- props["AnalyticsUrl"] = c.ServiceSettings.AnalyticsUrl
- props["ByPassEmail"] = strconv.FormatBool(c.EmailSettings.ByPassEmail)
- props["ProfileHeight"] = fmt.Sprintf("%v", c.ImageSettings.ProfileHeight)
- props["ProfileWidth"] = fmt.Sprintf("%v", c.ImageSettings.ProfileWidth)
- props["ProfileWidth"] = fmt.Sprintf("%v", c.ImageSettings.ProfileWidth)
+ props["SiteName"] = c.TeamSettings.SiteName
props["EnableOAuthServiceProvider"] = strconv.FormatBool(c.ServiceSettings.EnableOAuthServiceProvider)
- props["AllowIncomingWebhooks"] = strconv.FormatBool(c.ServiceSettings.AllowIncomingWebhooks)
+
+ props["SegmentDeveloperKey"] = c.ServiceSettings.SegmentDeveloperKey
+ props["GoogleDeveloperKey"] = c.ServiceSettings.GoogleDeveloperKey
+ props["EnableIncomingWebhooks"] = strconv.FormatBool(c.ServiceSettings.EnableIncomingWebhooks)
+
+ props["SendEmailNotifications"] = strconv.FormatBool(c.EmailSettings.SendEmailNotifications)
+ props["EnableSignUpWithEmail"] = strconv.FormatBool(c.EmailSettings.EnableSignUpWithEmail)
+ props["FeedbackEmail"] = c.EmailSettings.FeedbackEmail
+
+ props["EnableSignUpWithGitLab"] = strconv.FormatBool(c.GitLabSettings.Enable)
+
+ props["ShowEmailAddress"] = strconv.FormatBool(c.PrivacySettings.ShowEmailAddress)
+
+ props["EnablePublicLink"] = strconv.FormatBool(c.FileSettings.EnablePublicLink)
+ props["ProfileHeight"] = fmt.Sprintf("%v", c.FileSettings.ProfileHeight)
+ props["ProfileWidth"] = fmt.Sprintf("%v", c.FileSettings.ProfileWidth)
return props
}
-
-func IsS3Configured() bool {
- if Cfg.AWSSettings.S3AccessKeyId == "" || Cfg.AWSSettings.S3SecretAccessKey == "" || Cfg.AWSSettings.S3Region == "" || Cfg.AWSSettings.S3Bucket == "" {
- return false
- }
-
- return true
-}
-
-func GetAllowedAuthServices() []string {
- authServices := []string{}
- for name, service := range Cfg.SSOSettings {
- if service.Allow {
- authServices = append(authServices, name)
- }
- }
-
- if !Cfg.ServiceSettings.DisableEmailSignUp {
- authServices = append(authServices, "email")
- }
-
- return authServices
-}
-
-func IsServiceAllowed(s string) bool {
- if len(s) == 0 {
- return false
- }
-
- if service, ok := Cfg.SSOSettings[s]; ok {
- if service.Allow {
- return true
- }
- }
-
- return false
-}
diff --git a/utils/mail.go b/utils/mail.go
index 7cb1786267..dd975155d2 100644
--- a/utils/mail.go
+++ b/utils/mail.go
@@ -15,43 +15,22 @@ import (
"time"
)
-func CheckMailSettings() *model.AppError {
- if len(Cfg.EmailSettings.SMTPServer) == 0 || Cfg.EmailSettings.ByPassEmail {
- return model.NewAppError("CheckMailSettings", "No email settings present, mail will not be sent", "")
- }
- conn, err := connectToSMTPServer()
- if err != nil {
- return err
- }
- defer conn.Close()
- c, err2 := newSMTPClient(conn)
- if err2 != nil {
- return err
- }
- defer c.Quit()
- defer c.Close()
-
- return nil
-}
-
-func connectToSMTPServer() (net.Conn, *model.AppError) {
- host, _, _ := net.SplitHostPort(Cfg.EmailSettings.SMTPServer)
-
+func connectToSMTPServer(config *model.Config) (net.Conn, *model.AppError) {
var conn net.Conn
var err error
- if Cfg.EmailSettings.UseTLS {
+ if config.EmailSettings.ConnectionSecurity == model.CONN_SECURITY_TLS {
tlsconfig := &tls.Config{
InsecureSkipVerify: true,
- ServerName: host,
+ ServerName: config.EmailSettings.SMTPServer,
}
- conn, err = tls.Dial("tcp", Cfg.EmailSettings.SMTPServer, tlsconfig)
+ conn, err = tls.Dial("tcp", config.EmailSettings.SMTPServer+":"+config.EmailSettings.SMTPPort, tlsconfig)
if err != nil {
return nil, model.NewAppError("SendMail", "Failed to open TLS connection", err.Error())
}
} else {
- conn, err = net.Dial("tcp", Cfg.EmailSettings.SMTPServer)
+ conn, err = net.Dial("tcp", config.EmailSettings.SMTPServer+":"+config.EmailSettings.SMTPPort)
if err != nil {
return nil, model.NewAppError("SendMail", "Failed to open connection", err.Error())
}
@@ -60,24 +39,23 @@ func connectToSMTPServer() (net.Conn, *model.AppError) {
return conn, nil
}
-func newSMTPClient(conn net.Conn) (*smtp.Client, *model.AppError) {
- host, _, _ := net.SplitHostPort(Cfg.EmailSettings.SMTPServer)
- c, err := smtp.NewClient(conn, host)
+func newSMTPClient(conn net.Conn, config *model.Config) (*smtp.Client, *model.AppError) {
+ c, err := smtp.NewClient(conn, config.EmailSettings.SMTPServer+":"+config.EmailSettings.SMTPPort)
if err != nil {
l4g.Error("Failed to open a connection to SMTP server %v", err)
return nil, model.NewAppError("SendMail", "Failed to open TLS connection", err.Error())
}
// GO does not support plain auth over a non encrypted connection.
// so if not tls then no auth
- auth := smtp.PlainAuth("", Cfg.EmailSettings.SMTPUsername, Cfg.EmailSettings.SMTPPassword, host)
- if Cfg.EmailSettings.UseTLS {
+ auth := smtp.PlainAuth("", config.EmailSettings.SMTPUsername, config.EmailSettings.SMTPPassword, config.EmailSettings.SMTPServer+":"+config.EmailSettings.SMTPPort)
+ if config.EmailSettings.ConnectionSecurity == model.CONN_SECURITY_TLS {
if err = c.Auth(auth); err != nil {
return nil, model.NewAppError("SendMail", "Failed to authenticate on SMTP server", err.Error())
}
- } else if Cfg.EmailSettings.UseStartTLS {
+ } else if config.EmailSettings.ConnectionSecurity == model.CONN_SECURITY_STARTTLS {
tlsconfig := &tls.Config{
InsecureSkipVerify: true,
- ServerName: host,
+ ServerName: config.EmailSettings.SMTPServer,
}
c.StartTLS(tlsconfig)
if err = c.Auth(auth); err != nil {
@@ -88,12 +66,16 @@ func newSMTPClient(conn net.Conn) (*smtp.Client, *model.AppError) {
}
func SendMail(to, subject, body string) *model.AppError {
+ return SendMailUsingConfig(to, subject, body, Cfg)
+}
- if len(Cfg.EmailSettings.SMTPServer) == 0 || Cfg.EmailSettings.ByPassEmail {
+func SendMailUsingConfig(to, subject, body string, config *model.Config) *model.AppError {
+
+ if !config.EmailSettings.SendEmailNotifications {
return nil
}
- fromMail := mail.Address{Cfg.EmailSettings.FeedbackName, Cfg.EmailSettings.FeedbackEmail}
+ fromMail := mail.Address{config.EmailSettings.FeedbackName, config.EmailSettings.FeedbackEmail}
toMail := mail.Address{"", to}
headers := make(map[string]string)
@@ -110,13 +92,13 @@ func SendMail(to, subject, body string) *model.AppError {
}
message += "\r\n
{'This is some sample help text for the Bypass Email field'}
+{'Typically set to true in production. When true Mattermost will allow team creation and account signup utilizing email and password. You would set this to false if you only wanted to allow signup from a service like OAuth or LDAP.'}
{'This is some sample help text for the SMTP username field'}
+ + +{'Typically set to true in production. When true Mattermost will attempt to send email notifications. Developers may set this field to false skipping sending emails for faster development.'}
{'Typically set to true in production. When true Mattermost will not allow a user to login without first having recieved an email with a verification link. Developers may set this field to false so skip sending verification emails for faster development.'}
{'Name displayed on email account used when sending notification emails from Mattermost.'}
{' Obtain this credential from administrator setting up your email server.'}
{' Obtain this credential from administrator setting up your email server.'}
+{'Location of SMTP email server.'}
+{'Port of SMTP email server.'}
+| {'None'} | {'Mattermost will send email over an unsecure connection.'} |
| {'TLS'} | {'Encrypts the communication between Mattermost and your email server.'} |
| {'STARTTLS'} | {'Takes an existing insecure connection and attempts to upgrade it to a secure connection using TLS.'} |
{'32-character salt added to signing of email invites.'}
+{'This is some sample help text for the Apple push server field'}
-{'32-character salt added to signing of password reset emails.'}
+{'File to which log files are written. If blank, will be set to ./logs/mattermost.log. Log rotation is enabled and new files may be created in the same directory.'}
{'Format of log message output. If blank will be set to "[%D %T] [%L] %M", where:'} diff --git a/web/react/components/admin_console/privacy_settings.jsx b/web/react/components/admin_console/privacy_settings.jsx new file mode 100644 index 0000000000..8ce6939258 --- /dev/null +++ b/web/react/components/admin_console/privacy_settings.jsx @@ -0,0 +1,163 @@ +// 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 PrivacySettings 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.PrivacySettings.ShowEmailAddress = React.findDOMNode(this.refs.ShowEmailAddress).checked; + config.PrivacySettings.ShowFullName = React.findDOMNode(this.refs.ShowFullName).checked; + + 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 =
; + } + + var saveClass = 'btn'; + if (this.state.saveNeeded) { + saveClass = 'btn btn-primary'; + } + + return ( +{'Changing properties in this section will require a server restart before taking effect.'}
+{'Changing properties in this section will require a server restart before taking effect.'}
+