summaryrefslogtreecommitdiffstats
path: root/api
diff options
context:
space:
mode:
Diffstat (limited to 'api')
-rw-r--r--api/admin.go2
-rw-r--r--api/api.go4
-rw-r--r--api/api_test.go1
-rw-r--r--api/command_test.go8
-rw-r--r--api/context.go8
-rw-r--r--api/file.go20
-rw-r--r--api/license.go100
-rw-r--r--api/post.go37
-rw-r--r--api/user.go33
9 files changed, 187 insertions, 26 deletions
diff --git a/api/admin.go b/api/admin.go
index 885a95d95..72a95ba6a 100644
--- a/api/admin.go
+++ b/api/admin.go
@@ -41,7 +41,7 @@ func getLogs(c *Context, w http.ResponseWriter, r *http.Request) {
file, err := os.Open(utils.GetLogFileLocation(utils.Cfg.LogSettings.FileLocation))
if err != nil {
- c.Err = model.NewAppError("getLogs", "Error reading log file", err.Error())
+ c.Err = model.NewLocAppError("getLogs", "api.admin.file_read_error", nil, err.Error())
}
defer file.Close()
diff --git a/api/api.go b/api/api.go
index a6bb22982..3b35a08fa 100644
--- a/api/api.go
+++ b/api/api.go
@@ -10,6 +10,9 @@ import (
"github.com/mattermost/platform/utils"
"html/template"
"net/http"
+
+ _ "github.com/cloudfoundry/jibber_jabber"
+ _ "github.com/nicksnyder/go-i18n/i18n"
)
var ServerTemplates *template.Template
@@ -46,6 +49,7 @@ func InitApi() {
InitOAuth(r)
InitWebhook(r)
InitPreference(r)
+ InitLicense(r)
templatesDir := utils.FindDir("api/templates")
l4g.Debug("Parsing server templates at %v", templatesDir)
diff --git a/api/api_test.go b/api/api_test.go
index 2ef4e196d..4d7192e4b 100644
--- a/api/api_test.go
+++ b/api/api_test.go
@@ -14,6 +14,7 @@ var Client *model.Client
func Setup() {
if Srv == nil {
utils.LoadConfig("config.json")
+ utils.InitTranslations()
utils.Cfg.TeamSettings.MaxUsersPerTeam = 50
NewServer()
StartServer()
diff --git a/api/command_test.go b/api/command_test.go
index f38cf1397..b31aec03a 100644
--- a/api/command_test.go
+++ b/api/command_test.go
@@ -214,10 +214,10 @@ func TestLoadTestUrlCommand(t *testing.T) {
t.Fatal("/loadtest url with no url should've failed")
}
- command = "/loadtest url http://www.hopefullynonexistent.file/path/asdf/qwerty"
- if _, err := Client.Command(channel.Id, command, false); err == nil {
- t.Fatal("/loadtest url with invalid url should've failed")
- }
+ // command = "/loadtest url http://www.hopefullynonexistent.file/path/asdf/qwerty"
+ // if _, err := Client.Command(channel.Id, command, false); err == nil {
+ // t.Fatal("/loadtest url with invalid url should've failed")
+ // }
command = "/loadtest url https://raw.githubusercontent.com/mattermost/platform/master/README.md"
if r := Client.Must(Client.Command(channel.Id, command, false)).Data.(*model.Command); r.Response != model.RESP_EXECUTED {
diff --git a/api/context.go b/api/context.go
index 561884c14..a3311a971 100644
--- a/api/context.go
+++ b/api/context.go
@@ -15,6 +15,7 @@ import (
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/store"
"github.com/mattermost/platform/utils"
+ goi18n "github.com/nicksnyder/go-i18n/i18n"
)
var sessionCache *utils.Cache = utils.NewLru(model.SESSION_CACHE_SIZE)
@@ -29,12 +30,14 @@ type Context struct {
teamURL string
siteURL string
SessionTokenIndex int64
+ T goi18n.TranslateFunc
}
type Page struct {
TemplateName string
Props map[string]string
ClientCfg map[string]string
+ ClientLicense map[string]string
User *model.User
Team *model.Team
Channel *model.Channel
@@ -80,10 +83,10 @@ type handler struct {
}
func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-
l4g.Debug("%v", r.URL.Path)
c := &Context{}
+ c.T = utils.GetTranslations(w, r)
c.RequestId = model.NewId()
c.IpAddress = GetIpAddress(r)
@@ -203,6 +206,7 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
if c.Err != nil {
+ c.Err.Translate(c.T)
c.Err.RequestId = c.RequestId
c.LogError(c.Err)
c.Err.Where = r.URL.Path
@@ -370,7 +374,7 @@ func (c *Context) RemoveSessionCookie(w http.ResponseWriter, r *http.Request) {
}
func (c *Context) SetInvalidParam(where string, name string) {
- c.Err = model.NewAppError(where, "Invalid "+name+" parameter", "")
+ c.Err = model.NewLocAppError(where, "api.context.invalid_param", map[string]interface{}{"Name": name}, "")
c.Err.StatusCode = http.StatusBadRequest
}
diff --git a/api/file.go b/api/file.go
index d023515af..46e81691e 100644
--- a/api/file.go
+++ b/api/file.go
@@ -541,12 +541,8 @@ func writeFile(f []byte, path string) *model.AppError {
return model.NewAppError("writeFile", "Encountered an error writing to S3", err.Error())
}
} 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.FileSettings.Directory+path, f, 0644); err != nil {
- return model.NewAppError("writeFile", "Encountered an error writing to local server storage", err.Error())
+ if err := writeFileLocally(f, utils.Cfg.FileSettings.Directory+path); err != nil {
+ return err
}
} else {
return model.NewAppError("writeFile", "File storage not configured properly. Please configure for either S3 or local server file storage.", "")
@@ -555,6 +551,18 @@ func writeFile(f []byte, path string) *model.AppError {
return nil
}
+func writeFileLocally(f []byte, path string) *model.AppError {
+ if err := os.MkdirAll(filepath.Dir(path), 0774); err != nil {
+ return model.NewAppError("writeFile", "Encountered an error creating the directory for the new file", err.Error())
+ }
+
+ if err := ioutil.WriteFile(path, f, 0644); err != nil {
+ return model.NewAppError("writeFile", "Encountered an error writing to local server storage", err.Error())
+ }
+
+ return nil
+}
+
func readFile(path string) ([]byte, *model.AppError) {
if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 {
diff --git a/api/license.go b/api/license.go
new file mode 100644
index 000000000..5b3809651
--- /dev/null
+++ b/api/license.go
@@ -0,0 +1,100 @@
+// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package api
+
+import (
+ "bytes"
+ l4g "github.com/alecthomas/log4go"
+ "github.com/gorilla/mux"
+ "github.com/mattermost/platform/model"
+ "github.com/mattermost/platform/utils"
+ "io"
+ "net/http"
+ "strings"
+)
+
+func InitLicense(r *mux.Router) {
+ l4g.Debug("Initializing license api routes")
+
+ sr := r.PathPrefix("/license").Subrouter()
+ sr.Handle("/add", ApiAdminSystemRequired(addLicense)).Methods("POST")
+ sr.Handle("/remove", ApiAdminSystemRequired(removeLicense)).Methods("POST")
+}
+
+func addLicense(c *Context, w http.ResponseWriter, r *http.Request) {
+ c.LogAudit("attempt")
+ err := r.ParseMultipartForm(model.MAX_FILE_SIZE)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ m := r.MultipartForm
+
+ fileArray, ok := m.File["license"]
+ if !ok {
+ c.Err = model.NewAppError("addLicense", "No file under 'license' in request", "")
+ c.Err.StatusCode = http.StatusBadRequest
+ return
+ }
+
+ if len(fileArray) <= 0 {
+ c.Err = model.NewAppError("addLicense", "Empty array under 'license' in request", "")
+ c.Err.StatusCode = http.StatusBadRequest
+ return
+ }
+
+ fileData := fileArray[0]
+
+ file, err := fileData.Open()
+ defer file.Close()
+ if err != nil {
+ c.Err = model.NewAppError("addLicense", "Could not open license file", err.Error())
+ return
+ }
+
+ buf := bytes.NewBuffer(nil)
+ io.Copy(buf, file)
+
+ data := buf.Bytes()
+
+ var license *model.License
+ if success, licenseStr := utils.ValidateLicense(data); success {
+ license = model.LicenseFromJson(strings.NewReader(licenseStr))
+
+ if ok := utils.SetLicense(license); !ok {
+ c.LogAudit("failed - expired or non-started license")
+ c.Err = model.NewAppError("addLicense", "License is either expired or has not yet started.", "")
+ return
+ }
+
+ if err := writeFileLocally(data, utils.LicenseLocation()); err != nil {
+ c.LogAudit("failed - could not save license file")
+ c.Err = model.NewAppError("addLicense", "License did not save properly.", "path="+utils.LicenseLocation())
+ utils.RemoveLicense()
+ return
+ }
+ } else {
+ c.LogAudit("failed - invalid license")
+ c.Err = model.NewAppError("addLicense", "Invalid license file.", "")
+ return
+ }
+
+ c.LogAudit("success")
+ w.Write([]byte(license.ToJson()))
+}
+
+func removeLicense(c *Context, w http.ResponseWriter, r *http.Request) {
+ c.LogAudit("")
+
+ if ok := utils.RemoveLicense(); !ok {
+ c.LogAudit("failed - could not remove license file")
+ c.Err = model.NewAppError("removeLicense", "License did not remove properly.", "")
+ return
+ }
+
+ rdata := map[string]string{}
+ rdata["status"] = "ok"
+ w.Write([]byte(model.MapToJson(rdata)))
+}
diff --git a/api/post.go b/api/post.go
index be1ecd96a..42c3c304d 100644
--- a/api/post.go
+++ b/api/post.go
@@ -185,6 +185,28 @@ func CreateWebhookPost(c *Context, channelId, text, overrideUsername, overrideIc
attachment["text"] = aText
list[i] = attachment
}
+ if _, ok := attachment["pretext"]; ok {
+ aText := attachment["pretext"].(string)
+ aText = linkWithTextRegex.ReplaceAllString(aText, "[${2}](${1})")
+ attachment["pretext"] = aText
+ list[i] = attachment
+ }
+ if fVal, ok := attachment["fields"]; ok {
+ if fields, ok := fVal.([]interface{}); ok {
+ // parse attachment field links into Markdown format
+ for j, fInt := range fields {
+ field := fInt.(map[string]interface{})
+ if _, ok := field["text"]; ok {
+ fText := field["text"].(string)
+ fText = linkWithTextRegex.ReplaceAllString(fText, "[${2}](${1})")
+ field["text"] = fText
+ fields[j] = field
+ }
+ }
+ attachment["fields"] = fields
+ list[i] = attachment
+ }
+ }
}
post.AddProp(key, list)
}
@@ -370,7 +392,7 @@ func handleWebhookEventsAndForget(c *Context, post *model.Post, team *model.Team
// copy the context and create a mock session for posting the message
mockSession := model.Session{UserId: hook.CreatorId, TeamId: hook.TeamId, IsOAuth: false}
- newContext := &Context{mockSession, model.NewId(), "", c.Path, nil, c.teamURLValid, c.teamURL, c.siteURL, 0}
+ newContext := &Context{mockSession, model.NewId(), "", c.Path, nil, c.teamURLValid, c.teamURL, c.siteURL, 0, c.T}
if text, ok := respProps["text"]; ok {
if _, err := CreateWebhookPost(newContext, post.ChannelId, text, respProps["username"], respProps["icon_url"], post.Props, post.Type); err != nil {
@@ -632,15 +654,22 @@ func sendNotificationsAndForget(c *Context, post *model.Post, team *model.Team,
alreadySeen := make(map[string]string)
for _, session := range sessions {
- if len(session.DeviceId) > 0 && alreadySeen[session.DeviceId] == "" && strings.HasPrefix(session.DeviceId, "apple:") {
+ if len(session.DeviceId) > 0 && alreadySeen[session.DeviceId] == "" &&
+ (strings.HasPrefix(session.DeviceId, model.PUSH_NOTIFY_APPLE+":") || strings.HasPrefix(session.DeviceId, model.PUSH_NOTIFY_ANDROID+":")) {
alreadySeen[session.DeviceId] = session.DeviceId
msg := model.PushNotification{}
- msg.Platform = model.PUSH_NOTIFY_APPLE
msg.Badge = 1
- msg.DeviceId = strings.TrimPrefix(session.DeviceId, "apple:")
msg.ServerId = utils.CfgDiagnosticId
+ if strings.HasPrefix(session.DeviceId, model.PUSH_NOTIFY_APPLE+":") {
+ msg.Platform = model.PUSH_NOTIFY_APPLE
+ msg.DeviceId = strings.TrimPrefix(session.DeviceId, model.PUSH_NOTIFY_APPLE+":")
+ } else if strings.HasPrefix(session.DeviceId, model.PUSH_NOTIFY_ANDROID+":") {
+ msg.Platform = model.PUSH_NOTIFY_ANDROID
+ msg.DeviceId = strings.TrimPrefix(session.DeviceId, model.PUSH_NOTIFY_ANDROID+":")
+ }
+
if channel.Type == model.CHANNEL_DIRECT {
msg.Message = senderName + " sent you a direct message"
} else {
diff --git a/api/user.go b/api/user.go
index d014ab995..a6b4fb654 100644
--- a/api/user.go
+++ b/api/user.go
@@ -122,6 +122,11 @@ func createUser(c *Context, w http.ResponseWriter, r *http.Request) {
user.EmailVerified = true
}
+ if !CheckUserDomain(user, utils.Cfg.TeamSettings.RestrictCreationToDomains) {
+ c.Err = model.NewAppError("createUser", "The email you provided does not belong to an accepted domain. Please contact your administrator or sign up with a different email.", "")
+ return
+ }
+
ruser, err := CreateUser(team, user)
if err != nil {
c.Err = err
@@ -136,19 +141,29 @@ func createUser(c *Context, w http.ResponseWriter, r *http.Request) {
}
+func CheckUserDomain(user *model.User, domains string) bool {
+ if len(domains) == 0 {
+ return true
+ }
+
+ domainArray := strings.Fields(strings.TrimSpace(strings.ToLower(strings.Replace(strings.Replace(domains, "@", " ", -1), ",", " ", -1))))
+
+ matched := false
+ for _, d := range domainArray {
+ if strings.HasSuffix(user.Email, "@"+d) {
+ matched = true
+ break
+ }
+ }
+
+ return matched
+}
+
func IsVerifyHashRequired(user *model.User, team *model.Team, hash string) bool {
shouldVerifyHash := true
if team.Type == model.TEAM_INVITE && len(team.AllowedDomains) > 0 && len(hash) == 0 && user != nil {
- domains := strings.Fields(strings.TrimSpace(strings.ToLower(strings.Replace(strings.Replace(team.AllowedDomains, "@", " ", -1), ",", " ", -1))))
-
- matched := false
- for _, d := range domains {
- if strings.HasSuffix(user.Email, "@"+d) {
- matched = true
- break
- }
- }
+ matched := CheckUserDomain(user, team.AllowedDomains)
if matched {
shouldVerifyHash = false