diff options
Diffstat (limited to 'api')
-rw-r--r-- | api/admin.go | 2 | ||||
-rw-r--r-- | api/channel.go | 186 | ||||
-rw-r--r-- | api/command_join.go | 2 | ||||
-rw-r--r-- | api/command_logout.go | 4 | ||||
-rw-r--r-- | api/command_msg.go | 2 | ||||
-rw-r--r-- | api/context.go | 2 | ||||
-rw-r--r-- | api/emoji.go | 10 | ||||
-rw-r--r-- | api/emoji_test.go | 2 | ||||
-rw-r--r-- | api/file.go | 346 | ||||
-rw-r--r-- | api/file_test.go | 31 | ||||
-rw-r--r-- | api/oauth.go | 34 | ||||
-rw-r--r-- | api/post.go | 21 | ||||
-rw-r--r-- | api/team.go | 5 | ||||
-rw-r--r-- | api/user.go | 682 | ||||
-rw-r--r-- | api/user_test.go | 26 | ||||
-rw-r--r-- | api/webrtc.go | 19 | ||||
-rw-r--r-- | api/webrtc_test.go | 3 |
17 files changed, 230 insertions, 1147 deletions
diff --git a/api/admin.go b/api/admin.go index 2b5afc47a..300796bad 100644 --- a/api/admin.go +++ b/api/admin.go @@ -665,7 +665,7 @@ func adminResetMfa(c *Context, w http.ResponseWriter, r *http.Request) { return } - if err := DeactivateMfa(userId); err != nil { + if err := app.DeactivateMfa(userId); err != nil { c.Err = err return } diff --git a/api/channel.go b/api/channel.go index f0d520b4e..590409921 100644 --- a/api/channel.go +++ b/api/channel.go @@ -119,7 +119,7 @@ func createDirectChannel(c *Context, w http.ResponseWriter, r *http.Request) { return } - if sc, err := CreateDirectChannel(c.Session.UserId, userId); err != nil { + if sc, err := app.CreateDirectChannel(c.Session.UserId, userId); err != nil { c.Err = err return } else { @@ -127,33 +127,6 @@ func createDirectChannel(c *Context, w http.ResponseWriter, r *http.Request) { } } -func CreateDirectChannel(userId string, otherUserId string) (*model.Channel, *model.AppError) { - uc := app.Srv.Store.User().Get(otherUserId) - - if uresult := <-uc; uresult.Err != nil { - return nil, model.NewLocAppError("CreateDirectChannel", "api.channel.create_direct_channel.invalid_user.app_error", nil, otherUserId) - } - - if result := <-app.Srv.Store.Channel().CreateDirectChannel(userId, otherUserId); result.Err != nil { - if result.Err.Id == store.CHANNEL_EXISTS_ERROR { - return result.Data.(*model.Channel), nil - } else { - return nil, result.Err - } - } else { - channel := result.Data.(*model.Channel) - - app.InvalidateCacheForUser(userId) - app.InvalidateCacheForUser(otherUserId) - - message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_DIRECT_ADDED, "", channel.Id, "", nil) - message.Add("teammate_id", otherUserId) - go app.Publish(message) - - return channel, nil - } -} - func CanManageChannel(c *Context, channel *model.Channel) bool { if channel.Type == model.CHANNEL_OPEN && !HasPermissionToChannelContext(c, channel.Id, model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES) { return false @@ -229,7 +202,9 @@ func updateChannel(c *Context, w http.ResponseWriter, r *http.Request) { return } else { if oldChannelDisplayName != channel.DisplayName { - go PostUpdateChannelDisplayNameMessage(c, channel.Id, oldChannelDisplayName, channel.DisplayName) + if err := app.PostUpdateChannelDisplayNameMessage(c.Session.UserId, channel.Id, c.TeamId, oldChannelDisplayName, channel.DisplayName); err != nil { + l4g.Error(err.Error()) + } } c.LogAudit("name=" + channel.Name) w.Write([]byte(oldChannel.ToJson())) @@ -277,76 +252,15 @@ func updateChannelHeader(c *Context, w http.ResponseWriter, r *http.Request) { c.Err = ucresult.Err return } else { - go PostUpdateChannelHeaderMessage(c, channel.Id, oldChannelHeader, channelHeader) + if err := app.PostUpdateChannelHeaderMessage(c.Session.UserId, channel.Id, c.TeamId, oldChannelHeader, channelHeader); err != nil { + l4g.Error(err.Error()) + } c.LogAudit("name=" + channel.Name) w.Write([]byte(channel.ToJson())) } } } -func PostUpdateChannelHeaderMessage(c *Context, channelId string, oldChannelHeader, newChannelHeader string) { - uc := app.Srv.Store.User().Get(c.Session.UserId) - - if uresult := <-uc; uresult.Err != nil { - l4g.Error(utils.T("api.channel.post_update_channel_header_message_and_forget.retrieve_user.error"), uresult.Err) - return - } else { - user := uresult.Data.(*model.User) - - var message string - if oldChannelHeader == "" { - message = fmt.Sprintf(utils.T("api.channel.post_update_channel_header_message_and_forget.updated_to"), user.Username, newChannelHeader) - } else if newChannelHeader == "" { - message = fmt.Sprintf(utils.T("api.channel.post_update_channel_header_message_and_forget.removed"), user.Username, oldChannelHeader) - } else { - message = fmt.Sprintf(utils.T("api.channel.post_update_channel_header_message_and_forget.updated_from"), user.Username, oldChannelHeader, newChannelHeader) - } - - post := &model.Post{ - ChannelId: channelId, - Message: message, - Type: model.POST_HEADER_CHANGE, - UserId: c.Session.UserId, - Props: model.StringInterface{ - "old_header": oldChannelHeader, - "new_header": newChannelHeader, - }, - } - - if _, err := app.CreatePost(post, c.TeamId, false); err != nil { - l4g.Error(utils.T("api.channel.post_update_channel_header_message_and_forget.join_leave.error"), err) - } - } -} - -func PostUpdateChannelDisplayNameMessage(c *Context, channelId string, oldChannelDisplayName, newChannelDisplayName string) { - uc := app.Srv.Store.User().Get(c.Session.UserId) - - if uresult := <-uc; uresult.Err != nil { - l4g.Error(utils.T("api.channel.post_update_channel_displayname_message_and_forget.retrieve_user.error"), uresult.Err) - return - } else { - user := uresult.Data.(*model.User) - - message := fmt.Sprintf(utils.T("api.channel.post_update_channel_displayname_message_and_forget.updated_from"), user.Username, oldChannelDisplayName, newChannelDisplayName) - - post := &model.Post{ - ChannelId: channelId, - Message: message, - Type: model.POST_DISPLAYNAME_CHANGE, - UserId: c.Session.UserId, - Props: model.StringInterface{ - "old_displayname": oldChannelDisplayName, - "new_displayname": newChannelDisplayName, - }, - } - - if _, err := app.CreatePost(post, c.TeamId, false); err != nil { - l4g.Error(utils.T("api.channel.post_update_channel_displayname_message_and_forget.create_post.error"), err) - } - } -} - func updateChannelPurpose(c *Context, w http.ResponseWriter, r *http.Request) { props := model.MapFromJson(r.Body) channelId := props["channel_id"] @@ -473,84 +387,34 @@ func join(c *Context, w http.ResponseWriter, r *http.Request) { channelId := params["channel_id"] channelName := params["channel_name"] - var outChannel *model.Channel = nil + var channel *model.Channel + var err *model.AppError if channelId != "" { - if err, channel := JoinChannelById(c, c.Session.UserId, channelId); err != nil { - c.Err = err - c.Err.StatusCode = http.StatusForbidden - return - } else { - outChannel = channel - } + channel, err = app.GetChannel(channelId) } else if channelName != "" { - if err, channel := JoinChannelByName(c, c.Session.UserId, c.TeamId, channelName); err != nil { - c.Err = err - c.Err.StatusCode = http.StatusForbidden - return - } else { - outChannel = channel - } + channel, err = app.GetChannelByName(channelName, c.TeamId) } else { c.SetInvalidParam("join", "channel_id, channel_name") return } - w.Write([]byte(outChannel.ToJson())) -} - -func JoinChannelByName(c *Context, userId string, teamId string, channelName string) (*model.AppError, *model.Channel) { - channelChannel := app.Srv.Store.Channel().GetByName(teamId, channelName) - userChannel := app.Srv.Store.User().Get(userId) - - return joinChannel(c, channelChannel, userChannel) -} - -func JoinChannelById(c *Context, userId string, channelId string) (*model.AppError, *model.Channel) { - channelChannel := app.Srv.Store.Channel().Get(channelId, true) - userChannel := app.Srv.Store.User().Get(userId) - - return joinChannel(c, channelChannel, userChannel) -} - -func joinChannel(c *Context, channelChannel store.StoreChannel, userChannel store.StoreChannel) (*model.AppError, *model.Channel) { - if cresult := <-channelChannel; cresult.Err != nil { - return cresult.Err, nil - } else if uresult := <-userChannel; uresult.Err != nil { - return uresult.Err, nil - } else { - channel := cresult.Data.(*model.Channel) - user := uresult.Data.(*model.User) - if mresult := <-app.Srv.Store.Channel().GetMember(channel.Id, user.Id); mresult.Err == nil && mresult.Data != nil { - // the user is already in the channel so just return successful - return nil, channel - } + if err != nil { + c.Err = err + return + } + if channel.Type == model.CHANNEL_OPEN { if !HasPermissionToTeamContext(c, channel.TeamId, model.PERMISSION_JOIN_PUBLIC_CHANNELS) { - return c.Err, nil - } - - if channel.Type == model.CHANNEL_OPEN { - if _, err := app.AddUserToChannel(user, channel); err != nil { - return err, nil - } - go PostUserAddRemoveMessage(c, channel.Id, fmt.Sprintf(utils.T("api.channel.join_channel.post_and_forget"), user.Username), model.POST_JOIN_LEAVE) - } else { - return model.NewLocAppError("join", "api.channel.join_channel.permissions.app_error", nil, ""), nil + return } - return nil, channel } -} -func PostUserAddRemoveMessage(c *Context, channelId string, message, postType string) { - post := &model.Post{ - ChannelId: channelId, - Message: message, - Type: postType, - UserId: c.Session.UserId, - } - if _, err := app.CreatePost(post, c.TeamId, false); err != nil { - l4g.Error(utils.T("api.channel.post_user_add_remove_message_and_forget.error"), err) + if err = app.JoinChannel(channel, c.Session.UserId); err != nil { + c.Err = err + return } + + w.Write([]byte(channel.ToJson())) } func leave(c *Context, w http.ResponseWriter, r *http.Request) { @@ -601,7 +465,7 @@ func leave(c *Context, w http.ResponseWriter, r *http.Request) { RemoveUserFromChannel(c.Session.UserId, c.Session.UserId, channel) - go PostUserAddRemoveMessage(c, channel.Id, fmt.Sprintf(utils.T("api.channel.leave.left"), user.Username), model.POST_JOIN_LEAVE) + go app.PostUserAddRemoveMessage(c.Session.UserId, channel.Id, channel.TeamId, fmt.Sprintf(utils.T("api.channel.leave.left"), user.Username), model.POST_JOIN_LEAVE) result := make(map[string]string) result["id"] = channel.Id @@ -902,7 +766,7 @@ func addMember(c *Context, w http.ResponseWriter, r *http.Request) { c.LogAudit("name=" + channel.Name + " user_id=" + userId) - go PostUserAddRemoveMessage(c, channel.Id, fmt.Sprintf(utils.T("api.channel.add_member.added"), nUser.Username, oUser.Username), model.POST_ADD_REMOVE) + go app.PostUserAddRemoveMessage(c.Session.UserId, channel.Id, channel.TeamId, fmt.Sprintf(utils.T("api.channel.add_member.added"), nUser.Username, oUser.Username), model.POST_ADD_REMOVE) <-app.Srv.Store.Channel().UpdateLastViewedAt([]string{id}, oUser.Id) w.Write([]byte(cm.ToJson())) @@ -956,7 +820,7 @@ func removeMember(c *Context, w http.ResponseWriter, r *http.Request) { c.LogAudit("name=" + channel.Name + " user_id=" + userIdToRemove) - go PostUserAddRemoveMessage(c, channel.Id, fmt.Sprintf(utils.T("api.channel.remove_member.removed"), oUser.Username), model.POST_ADD_REMOVE) + go app.PostUserAddRemoveMessage(c.Session.UserId, channel.Id, channel.TeamId, fmt.Sprintf(utils.T("api.channel.remove_member.removed"), oUser.Username), model.POST_ADD_REMOVE) result := make(map[string]string) result["channel_id"] = channel.Id diff --git a/api/command_join.go b/api/command_join.go index 2210d2857..bad176656 100644 --- a/api/command_join.go +++ b/api/command_join.go @@ -45,7 +45,7 @@ func (me *JoinProvider) DoCommand(c *Context, args *model.CommandArgs, message s return &model.CommandResponse{Text: c.T("api.command_join.fail.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL} } - if err, _ := JoinChannelById(c, c.Session.UserId, channel.Id); err != nil { + if err := app.JoinChannel(channel, c.Session.UserId); err != nil { return &model.CommandResponse{Text: c.T("api.command_join.fail.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL} } diff --git a/api/command_logout.go b/api/command_logout.go index 00375bb58..0eaa9a0ba 100644 --- a/api/command_logout.go +++ b/api/command_logout.go @@ -4,6 +4,7 @@ package api import ( + "github.com/mattermost/platform/app" "github.com/mattermost/platform/model" ) @@ -38,8 +39,7 @@ func (me *LogoutProvider) DoCommand(c *Context, args *model.CommandArgs, message // We can't actually remove the user's cookie from here so we just dump their session and let the browser figure it out if c.Session.Id != "" { - RevokeSessionById(c, c.Session.Id) - if c.Err != nil { + if err := app.RevokeSessionById(c.Session.Id); err != nil { return FAIL } return SUCCESS diff --git a/api/command_msg.go b/api/command_msg.go index 36a9344ea..86203c2cd 100644 --- a/api/command_msg.go +++ b/api/command_msg.go @@ -66,7 +66,7 @@ func (me *msgProvider) DoCommand(c *Context, args *model.CommandArgs, message st targetChannelId := "" if channel := <-app.Srv.Store.Channel().GetByName(c.TeamId, channelName); channel.Err != nil { if channel.Err.Id == "store.sql_channel.get_by_name.missing.app_error" { - if directChannel, err := CreateDirectChannel(c.Session.UserId, userProfile.Id); err != nil { + if directChannel, err := app.CreateDirectChannel(c.Session.UserId, userProfile.Id); err != nil { c.Err = err return &model.CommandResponse{Text: c.T("api.command_msg.dm_fail.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL} } else { diff --git a/api/context.go b/api/context.go index c2036ed81..349cbd5b6 100644 --- a/api/context.go +++ b/api/context.go @@ -469,7 +469,7 @@ func (c *Context) CheckTeamId() { return } } else { - // just return because it fail on the HasPermissionToContext and the error is already on the Context c.Err + // HasPermissionToContext automatically fills the Context error return } } diff --git a/api/emoji.go b/api/emoji.go index fd78d5bd6..fb511cd03 100644 --- a/api/emoji.go +++ b/api/emoji.go @@ -163,7 +163,7 @@ func uploadEmojiImage(id string, imageData *multipart.FileHeader) *model.AppErro if err := gif.EncodeAll(newbuf, resized_gif); err != nil { return model.NewLocAppError("uploadEmojiImage", "api.emoji.upload.large_image.gif_encode_error", nil, "") } - if err := WriteFile(newbuf.Bytes(), getEmojiImagePath(id)); err != nil { + if err := app.WriteFile(newbuf.Bytes(), getEmojiImagePath(id)); err != nil { return err } } @@ -175,13 +175,13 @@ func uploadEmojiImage(id string, imageData *multipart.FileHeader) *model.AppErro if err := png.Encode(newbuf, resized_image); err != nil { return model.NewLocAppError("uploadEmojiImage", "api.emoji.upload.large_image.encode_error", nil, "") } - if err := WriteFile(newbuf.Bytes(), getEmojiImagePath(id)); err != nil { + if err := app.WriteFile(newbuf.Bytes(), getEmojiImagePath(id)); err != nil { return err } } } } else { - if err := WriteFile(buf.Bytes(), getEmojiImagePath(id)); err != nil { + if err := app.WriteFile(buf.Bytes(), getEmojiImagePath(id)); err != nil { return err } } @@ -236,7 +236,7 @@ func deleteEmoji(c *Context, w http.ResponseWriter, r *http.Request) { } func deleteEmojiImage(id string) { - if err := MoveFile(getEmojiImagePath(id), "emoji/"+id+"/image_deleted"); err != nil { + if err := app.MoveFile(getEmojiImagePath(id), "emoji/"+id+"/image_deleted"); err != nil { l4g.Error("Failed to rename image when deleting emoji %v", id) } } @@ -275,7 +275,7 @@ func getEmojiImage(c *Context, w http.ResponseWriter, r *http.Request) { } else { var img []byte - if data, err := ReadFile(getEmojiImagePath(id)); err != nil { + if data, err := app.ReadFile(getEmojiImagePath(id)); err != nil { c.Err = model.NewLocAppError("getEmojiImage", "api.emoji.get_image.read.app_error", nil, err.Error()) return } else { diff --git a/api/emoji_test.go b/api/emoji_test.go index 243703193..73440ba15 100644 --- a/api/emoji_test.go +++ b/api/emoji_test.go @@ -317,7 +317,7 @@ func createTestPng(t *testing.T, width int, height int) []byte { func createTestEmoji(t *testing.T, emoji *model.Emoji, imageData []byte) *model.Emoji { emoji = store.Must(app.Srv.Store.Emoji().Save(emoji)).(*model.Emoji) - if err := WriteFile(imageData, "emoji/"+emoji.Id+"/image"); err != nil { + if err := app.WriteFile(imageData, "emoji/"+emoji.Id+"/image"); err != nil { store.Must(app.Srv.Store.Emoji().Delete(emoji.Id, time.Now().Unix())) t.Fatalf("failed to write image: %v", err.Error()) } diff --git a/api/file.go b/api/file.go index 179c658cd..b0cedde40 100644 --- a/api/file.go +++ b/api/file.go @@ -5,24 +5,17 @@ package api import ( "bytes" - "crypto/sha256" - "encoding/base64" - "fmt" "image" "image/color" "image/draw" _ "image/gif" "image/jpeg" "io" - "io/ioutil" "net/http" "net/url" - "os" - "path" "path/filepath" "strconv" "strings" - "sync" l4g "github.com/alecthomas/log4go" "github.com/disintegration/imaging" @@ -32,8 +25,6 @@ import ( "github.com/mattermost/platform/utils" "github.com/rwcarlsen/goexif/exif" _ "golang.org/x/image/bmp" - - s3 "github.com/minio/minio-go" ) const ( @@ -182,7 +173,7 @@ func doUploadFile(teamId string, channelId string, userId string, rawFilename st info.ThumbnailPath = pathPrefix + nameWithoutExtension + "_thumb.jpg" } - if err := WriteFile(data, info.Path); err != nil { + if err := app.WriteFile(data, info.Path); err != nil { return nil, err } @@ -285,7 +276,7 @@ func generateThumbnailImage(img image.Image, thumbnailPath string, width int, he return } - if err := WriteFile(buf.Bytes(), thumbnailPath); err != nil { + if err := app.WriteFile(buf.Bytes(), thumbnailPath); err != nil { l4g.Error(utils.T("api.file.handle_images_forget.upload_thumb.error"), thumbnailPath, err) return } @@ -306,7 +297,7 @@ func generatePreviewImage(img image.Image, previewPath string, width int) { return } - if err := WriteFile(buf.Bytes(), previewPath); err != nil { + if err := app.WriteFile(buf.Bytes(), previewPath); err != nil { l4g.Error(utils.T("api.file.handle_images_forget.upload_preview.error"), previewPath, err) return } @@ -319,7 +310,7 @@ func getFile(c *Context, w http.ResponseWriter, r *http.Request) { return } - if data, err := ReadFile(info.Path); err != nil { + if data, err := app.ReadFile(info.Path); err != nil { c.Err = err c.Err.StatusCode = http.StatusNotFound } else if err := writeFileResponse(info.Name, info.MimeType, data, w, r); err != nil { @@ -341,7 +332,7 @@ func getFileThumbnail(c *Context, w http.ResponseWriter, r *http.Request) { return } - if data, err := ReadFile(info.ThumbnailPath); err != nil { + if data, err := app.ReadFile(info.ThumbnailPath); err != nil { c.Err = err c.Err.StatusCode = http.StatusNotFound } else if err := writeFileResponse(info.Name, "", data, w, r); err != nil { @@ -363,7 +354,7 @@ func getFilePreview(c *Context, w http.ResponseWriter, r *http.Request) { return } - if data, err := ReadFile(info.PreviewPath); err != nil { + if data, err := app.ReadFile(info.PreviewPath); err != nil { c.Err = err c.Err.StatusCode = http.StatusNotFound } else if err := writeFileResponse(info.Name, "", data, w, r); err != nil { @@ -400,7 +391,7 @@ func getPublicFile(c *Context, w http.ResponseWriter, r *http.Request) { hash := r.URL.Query().Get("h") if len(hash) > 0 { - correctHash := generatePublicLinkHash(info.Id, *utils.Cfg.FileSettings.PublicLinkSalt) + correctHash := app.GeneratePublicLinkHash(info.Id, *utils.Cfg.FileSettings.PublicLinkSalt) if hash != correctHash { c.Err = model.NewLocAppError("getPublicFile", "api.file.get_file.public_invalid.app_error", nil, "") @@ -413,7 +404,7 @@ func getPublicFile(c *Context, w http.ResponseWriter, r *http.Request) { return } - if data, err := ReadFile(info.Path); err != nil { + if data, err := app.ReadFile(info.Path); err != nil { c.Err = err c.Err.StatusCode = http.StatusNotFound } else if err := writeFileResponse(info.Name, info.MimeType, data, w, r); err != nil { @@ -482,7 +473,7 @@ func getPublicFileOld(c *Context, w http.ResponseWriter, r *http.Request) { hash := r.URL.Query().Get("h") if len(hash) > 0 { - correctHash := generatePublicLinkHash(filename, *utils.Cfg.FileSettings.PublicLinkSalt) + correctHash := app.GeneratePublicLinkHash(filename, *utils.Cfg.FileSettings.PublicLinkSalt) if hash != correctHash { c.Err = model.NewLocAppError("getPublicFile", "api.file.get_file.public_invalid.app_error", nil, "") @@ -511,7 +502,7 @@ func getPublicFileOld(c *Context, w http.ResponseWriter, r *http.Request) { return } - if data, err := ReadFile(info.Path); err != nil { + if data, err := app.ReadFile(info.Path); err != nil { c.Err = err c.Err.StatusCode = http.StatusNotFound } else if err := writeFileResponse(info.Name, info.MimeType, data, w, r); err != nil { @@ -560,320 +551,5 @@ func getPublicLink(c *Context, w http.ResponseWriter, r *http.Request) { return } - w.Write([]byte(model.StringToJson(generatePublicLink(c.GetSiteURL(), info)))) -} - -func generatePublicLink(siteURL string, info *model.FileInfo) string { - hash := generatePublicLinkHash(info.Id, *utils.Cfg.FileSettings.PublicLinkSalt) - return fmt.Sprintf("%s%s/public/files/%v/get?h=%s", siteURL, model.API_URL_SUFFIX, info.Id, hash) -} - -func generatePublicLinkHash(fileId, salt string) string { - hash := sha256.New() - hash.Write([]byte(salt)) - hash.Write([]byte(fileId)) - - return base64.RawURLEncoding.EncodeToString(hash.Sum(nil)) -} - -var fileMigrationLock sync.Mutex - -// Creates and stores FileInfos for a post created before the FileInfos table existed. -func migrateFilenamesToFileInfos(post *model.Post) []*model.FileInfo { - if len(post.Filenames) == 0 { - l4g.Warn(utils.T("api.file.migrate_filenames_to_file_infos.no_filenames.warn"), post.Id) - return []*model.FileInfo{} - } - - cchan := app.Srv.Store.Channel().Get(post.ChannelId, true) - - // There's a weird bug that rarely happens where a post ends up with duplicate Filenames so remove those - filenames := utils.RemoveDuplicatesFromStringArray(post.Filenames) - - var channel *model.Channel - if result := <-cchan; result.Err != nil { - l4g.Error(utils.T("api.file.migrate_filenames_to_file_infos.channel.app_error"), post.Id, post.ChannelId, result.Err) - return []*model.FileInfo{} - } else { - channel = result.Data.(*model.Channel) - } - - // Find the team that was used to make this post since its part of the file path that isn't saved in the Filename - var teamId string - if channel.TeamId == "" { - // This post was made in a cross-team DM channel so we need to find where its files were saved - teamId = findTeamIdForFilename(post, filenames[0]) - } else { - teamId = channel.TeamId - } - - // Create FileInfo objects for this post - infos := make([]*model.FileInfo, 0, len(filenames)) - if teamId == "" { - l4g.Error(utils.T("api.file.migrate_filenames_to_file_infos.team_id.error"), post.Id, filenames) - } else { - for _, filename := range filenames { - info := getInfoForFilename(post, teamId, filename) - if info == nil { - continue - } - - infos = append(infos, info) - } - } - - // Lock to prevent only one migration thread from trying to update the post at once, preventing duplicate FileInfos from being created - fileMigrationLock.Lock() - defer fileMigrationLock.Unlock() - - if result := <-app.Srv.Store.Post().Get(post.Id); result.Err != nil { - l4g.Error(utils.T("api.file.migrate_filenames_to_file_infos.get_post_again.app_error"), post.Id, result.Err) - return []*model.FileInfo{} - } else if newPost := result.Data.(*model.PostList).Posts[post.Id]; len(newPost.Filenames) != len(post.Filenames) { - // Another thread has already created FileInfos for this post, so just return those - if result := <-app.Srv.Store.FileInfo().GetForPost(post.Id); result.Err != nil { - l4g.Error(utils.T("api.file.migrate_filenames_to_file_infos.get_post_file_infos_again.app_error"), post.Id, result.Err) - return []*model.FileInfo{} - } else { - l4g.Debug(utils.T("api.file.migrate_filenames_to_file_infos.not_migrating_post.debug"), post.Id) - return result.Data.([]*model.FileInfo) - } - } - - l4g.Debug(utils.T("api.file.migrate_filenames_to_file_infos.migrating_post.debug"), post.Id) - - savedInfos := make([]*model.FileInfo, 0, len(infos)) - fileIds := make([]string, 0, len(filenames)) - for _, info := range infos { - if result := <-app.Srv.Store.FileInfo().Save(info); result.Err != nil { - l4g.Error(utils.T("api.file.migrate_filenames_to_file_infos.save_file_info.app_error"), post.Id, info.Id, info.Path, result.Err) - continue - } - - savedInfos = append(savedInfos, info) - fileIds = append(fileIds, info.Id) - } - - // Copy and save the updated post - newPost := &model.Post{} - *newPost = *post - - newPost.Filenames = []string{} - newPost.FileIds = fileIds - - // Update Posts to clear Filenames and set FileIds - if result := <-app.Srv.Store.Post().Update(newPost, post); result.Err != nil { - l4g.Error(utils.T("api.file.migrate_filenames_to_file_infos.save_post.app_error"), post.Id, newPost.FileIds, post.Filenames, result.Err) - return []*model.FileInfo{} - } else { - return savedInfos - } -} - -func findTeamIdForFilename(post *model.Post, filename string) string { - split := strings.SplitN(filename, "/", 5) - id := split[3] - name, _ := url.QueryUnescape(split[4]) - - // This post is in a direct channel so we need to figure out what team the files are stored under. - if result := <-app.Srv.Store.Team().GetTeamsByUserId(post.UserId); result.Err != nil { - l4g.Error(utils.T("api.file.migrate_filenames_to_file_infos.teams.app_error"), post.Id, result.Err) - } else if teams := result.Data.([]*model.Team); len(teams) == 1 { - // The user has only one team so the post must've been sent from it - return teams[0].Id - } else { - for _, team := range teams { - path := fmt.Sprintf("teams/%s/channels/%s/users/%s/%s/%s", team.Id, post.ChannelId, post.UserId, id, name) - if _, err := ReadFile(path); err == nil { - // Found the team that this file was posted from - return team.Id - } - } - } - - return "" -} - -func getInfoForFilename(post *model.Post, teamId string, filename string) *model.FileInfo { - // Find the path from the Filename of the form /{channelId}/{userId}/{uid}/{nameWithExtension} - split := strings.SplitN(filename, "/", 5) - if len(split) < 5 { - l4g.Error(utils.T("api.file.migrate_filenames_to_file_infos.unexpected_filename.error"), post.Id, filename) - return nil - } - - channelId := split[1] - userId := split[2] - oldId := split[3] - name, _ := url.QueryUnescape(split[4]) - - if split[0] != "" || split[1] != post.ChannelId || split[2] != post.UserId || strings.Contains(split[4], "/") { - l4g.Warn(utils.T("api.file.migrate_filenames_to_file_infos.mismatched_filename.warn"), post.Id, post.ChannelId, post.UserId, filename) - } - - pathPrefix := fmt.Sprintf("teams/%s/channels/%s/users/%s/%s/", teamId, channelId, userId, oldId) - path := pathPrefix + name - - // Open the file and populate the fields of the FileInfo - var info *model.FileInfo - if data, err := ReadFile(path); err != nil { - l4g.Error(utils.T("api.file.migrate_filenames_to_file_infos.file_not_found.error"), post.Id, filename, path, err) - return nil - } else { - var err *model.AppError - info, err = model.GetInfoForBytes(name, data) - if err != nil { - l4g.Warn(utils.T("api.file.migrate_filenames_to_file_infos.info.app_error"), post.Id, filename, err) - } - } - - // Generate a new ID because with the old system, you could very rarely get multiple posts referencing the same file - info.Id = model.NewId() - info.CreatorId = post.UserId - info.PostId = post.Id - info.CreateAt = post.CreateAt - info.UpdateAt = post.UpdateAt - info.Path = path - - if info.IsImage() { - nameWithoutExtension := name[:strings.LastIndex(name, ".")] - info.PreviewPath = pathPrefix + nameWithoutExtension + "_preview.jpg" - info.ThumbnailPath = pathPrefix + nameWithoutExtension + "_thumb.jpg" - } - - return info -} - -func WriteFile(f []byte, path string) *model.AppError { - if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 { - endpoint := utils.Cfg.FileSettings.AmazonS3Endpoint - accessKey := utils.Cfg.FileSettings.AmazonS3AccessKeyId - secretKey := utils.Cfg.FileSettings.AmazonS3SecretAccessKey - secure := *utils.Cfg.FileSettings.AmazonS3SSL - s3Clnt, err := s3.New(endpoint, accessKey, secretKey, secure) - if err != nil { - return model.NewLocAppError("WriteFile", "api.file.write_file.s3.app_error", nil, err.Error()) - } - bucket := utils.Cfg.FileSettings.AmazonS3Bucket - ext := filepath.Ext(path) - - if model.IsFileExtImage(ext) { - _, err = s3Clnt.PutObject(bucket, path, bytes.NewReader(f), model.GetImageMimeType(ext)) - } else { - _, err = s3Clnt.PutObject(bucket, path, bytes.NewReader(f), "binary/octet-stream") - } - if err != nil { - return model.NewLocAppError("WriteFile", "api.file.write_file.s3.app_error", nil, err.Error()) - } - } else if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_LOCAL { - if err := writeFileLocally(f, utils.Cfg.FileSettings.Directory+path); err != nil { - return err - } - } else { - return model.NewLocAppError("WriteFile", "api.file.write_file.configured.app_error", nil, "") - } - - return nil -} - -func MoveFile(oldPath, newPath string) *model.AppError { - if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 { - endpoint := utils.Cfg.FileSettings.AmazonS3Endpoint - accessKey := utils.Cfg.FileSettings.AmazonS3AccessKeyId - secretKey := utils.Cfg.FileSettings.AmazonS3SecretAccessKey - secure := *utils.Cfg.FileSettings.AmazonS3SSL - s3Clnt, err := s3.New(endpoint, accessKey, secretKey, secure) - if err != nil { - return model.NewLocAppError("moveFile", "api.file.write_file.s3.app_error", nil, err.Error()) - } - bucket := utils.Cfg.FileSettings.AmazonS3Bucket - - var copyConds = s3.NewCopyConditions() - if err = s3Clnt.CopyObject(bucket, newPath, "/"+path.Join(bucket, oldPath), copyConds); err != nil { - return model.NewLocAppError("moveFile", "api.file.move_file.delete_from_s3.app_error", nil, err.Error()) - } - if err = s3Clnt.RemoveObject(bucket, oldPath); err != nil { - return model.NewLocAppError("moveFile", "api.file.move_file.delete_from_s3.app_error", nil, err.Error()) - } - } else if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_LOCAL { - if err := os.MkdirAll(filepath.Dir(utils.Cfg.FileSettings.Directory+newPath), 0774); err != nil { - return model.NewLocAppError("moveFile", "api.file.move_file.rename.app_error", nil, err.Error()) - } - - if err := os.Rename(utils.Cfg.FileSettings.Directory+oldPath, utils.Cfg.FileSettings.Directory+newPath); err != nil { - return model.NewLocAppError("moveFile", "api.file.move_file.rename.app_error", nil, err.Error()) - } - } else { - return model.NewLocAppError("moveFile", "api.file.move_file.configured.app_error", nil, "") - } - - return nil -} - -func writeFileLocally(f []byte, path string) *model.AppError { - if err := os.MkdirAll(filepath.Dir(path), 0774); err != nil { - directory, _ := filepath.Abs(filepath.Dir(path)) - return model.NewLocAppError("WriteFile", "api.file.write_file_locally.create_dir.app_error", nil, "directory="+directory+", err="+err.Error()) - } - - if err := ioutil.WriteFile(path, f, 0644); err != nil { - return model.NewLocAppError("WriteFile", "api.file.write_file_locally.writing.app_error", nil, err.Error()) - } - - return nil -} - -func ReadFile(path string) ([]byte, *model.AppError) { - if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 { - endpoint := utils.Cfg.FileSettings.AmazonS3Endpoint - accessKey := utils.Cfg.FileSettings.AmazonS3AccessKeyId - secretKey := utils.Cfg.FileSettings.AmazonS3SecretAccessKey - secure := *utils.Cfg.FileSettings.AmazonS3SSL - s3Clnt, err := s3.New(endpoint, accessKey, secretKey, secure) - if err != nil { - return nil, model.NewLocAppError("ReadFile", "api.file.read_file.s3.app_error", nil, err.Error()) - } - bucket := utils.Cfg.FileSettings.AmazonS3Bucket - minioObject, err := s3Clnt.GetObject(bucket, path) - defer minioObject.Close() - if err != nil { - return nil, model.NewLocAppError("ReadFile", "api.file.read_file.s3.app_error", nil, err.Error()) - } - if f, err := ioutil.ReadAll(minioObject); err != nil { - return nil, model.NewLocAppError("ReadFile", "api.file.read_file.s3.app_error", nil, err.Error()) - } else { - return f, 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.NewLocAppError("ReadFile", "api.file.read_file.reading_local.app_error", nil, err.Error()) - } else { - return f, nil - } - } else { - return nil, model.NewLocAppError("ReadFile", "api.file.read_file.configured.app_error", nil, "") - } -} - -func openFileWriteStream(path string) (io.Writer, *model.AppError) { - if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 { - return nil, model.NewLocAppError("openFileWriteStream", "api.file.open_file_write_stream.s3.app_error", 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.NewLocAppError("openFileWriteStream", "api.file.open_file_write_stream.creating_dir.app_error", nil, err.Error()) - } - - if fileHandle, err := os.Create(utils.Cfg.FileSettings.Directory + path); err != nil { - return nil, model.NewLocAppError("openFileWriteStream", "api.file.open_file_write_stream.local_server.app_error", nil, err.Error()) - } else { - fileHandle.Chmod(0644) - return fileHandle, nil - } - } - - return nil, model.NewLocAppError("openFileWriteStream", "api.file.open_file_write_stream.configured.app_error", nil, "") -} - -func closeFileWriteStream(file io.Writer) { - file.(*os.File).Close() + w.Write([]byte(model.StringToJson(app.GeneratePublicLink(c.GetSiteURL(), info)))) } diff --git a/api/file_test.go b/api/file_test.go index 56e604fea..ce3e1fab4 100644 --- a/api/file_test.go +++ b/api/file_test.go @@ -508,7 +508,7 @@ func TestGetPublicFileOld(t *testing.T) { } func generatePublicLinkOld(siteURL, teamId, channelId, userId, filename string) string { - hash := generatePublicLinkHash(filename, *utils.Cfg.FileSettings.PublicLinkSalt) + hash := app.GeneratePublicLinkHash(filename, *utils.Cfg.FileSettings.PublicLinkSalt) return fmt.Sprintf("%s%s/public/files/get/%s/%s/%s/%s?h=%s", siteURL, model.API_URL_SUFFIX, teamId, channelId, userId, filename, hash) } @@ -581,29 +581,6 @@ func TestGetPublicLink(t *testing.T) { } } -func TestGeneratePublicLinkHash(t *testing.T) { - filename1 := model.NewId() + "/" + model.NewRandomString(16) + ".txt" - filename2 := model.NewId() + "/" + model.NewRandomString(16) + ".txt" - salt1 := model.NewRandomString(32) - salt2 := model.NewRandomString(32) - - hash1 := generatePublicLinkHash(filename1, salt1) - hash2 := generatePublicLinkHash(filename2, salt1) - hash3 := generatePublicLinkHash(filename1, salt2) - - if hash1 != generatePublicLinkHash(filename1, salt1) { - t.Fatal("hash should be equal for the same file name and salt") - } - - if hash1 == hash2 { - t.Fatal("hashes for different files should not be equal") - } - - if hash1 == hash3 { - t.Fatal("hashes for the same file with different salts should not be equal") - } -} - func TestMigrateFilenamesToFileInfos(t *testing.T) { th := Setup().InitBasic() @@ -740,7 +717,7 @@ func TestFindTeamIdForFilename(t *testing.T) { Filenames: []string{fmt.Sprintf("/%s/%s/%s/%s", channel1.Id, user1.Id, fileId1, "test.png")}, })).(*model.Post) - if teamId := findTeamIdForFilename(post1, post1.Filenames[0]); teamId != team1.Id { + if teamId := app.FindTeamIdForFilename(post1, post1.Filenames[0]); teamId != team1.Id { t.Fatal("file should've been found under team1") } @@ -753,7 +730,7 @@ func TestFindTeamIdForFilename(t *testing.T) { })).(*model.Post) Client.SetTeamId(team1.Id) - if teamId := findTeamIdForFilename(post2, post2.Filenames[0]); teamId != team2.Id { + if teamId := app.FindTeamIdForFilename(post2, post2.Filenames[0]); teamId != team2.Id { t.Fatal("file should've been found under team2") } } @@ -795,7 +772,7 @@ func TestGetInfoForFilename(t *testing.T) { Filenames: []string{fmt.Sprintf("/%s/%s/%s/%s", channel1.Id, user1.Id, fileId1, "test.png")}, })).(*model.Post) - if info := getInfoForFilename(post1, team1.Id, post1.Filenames[0]); info == nil { + if info := app.GetInfoForFilename(post1, team1.Id, post1.Filenames[0]); info == nil { t.Fatal("info shouldn't be nil") } else if info.Id == "" { t.Fatal("info.Id shouldn't be empty") diff --git a/api/oauth.go b/api/oauth.go index 80daf7415..b378eb2a3 100644 --- a/api/oauth.go +++ b/api/oauth.go @@ -250,32 +250,6 @@ func getAuthorizedApps(c *Context, w http.ResponseWriter, r *http.Request) { } } -func RevokeAccessToken(token string) *model.AppError { - - session, _ := app.GetSession(token) - schan := app.Srv.Store.Session().Remove(token) - - if result := <-app.Srv.Store.OAuth().GetAccessData(token); result.Err != nil { - return model.NewLocAppError("RevokeAccessToken", "api.oauth.revoke_access_token.get.app_error", nil, "") - } - - tchan := app.Srv.Store.OAuth().RemoveAccessData(token) - - if result := <-tchan; result.Err != nil { - return model.NewLocAppError("RevokeAccessToken", "api.oauth.revoke_access_token.del_token.app_error", nil, "") - } - - if result := <-schan; result.Err != nil { - return model.NewLocAppError("RevokeAccessToken", "api.oauth.revoke_access_token.del_session.app_error", nil, "") - } - - if session != nil { - app.RemoveAllSessionsForUserId(session.UserId) - } - - return nil -} - func GetAuthData(code string) *model.AuthData { if result := <-app.Srv.Store.OAuth().GetAuthData(code); result.Err != nil { l4g.Error(utils.T("api.oauth.get_auth_data.find.error"), code) @@ -311,7 +285,11 @@ func completeOAuth(c *Context, w http.ResponseWriter, r *http.Request) { action := props["action"] switch action { case model.OAUTH_ACTION_SIGNUP: - CreateOAuthUser(c, w, r, service, body, teamId) + if user, err := app.CreateOAuthUser(service, body, teamId); err != nil { + c.Err = err + } else { + doLogin(c, w, r, user, "") + } if c.Err == nil { http.Redirect(w, r, GetProtocol(r)+"://"+r.Host, http.StatusTemporaryRedirect) } @@ -931,7 +909,7 @@ func deauthorizeOAuthApp(c *Context, w http.ResponseWriter, r *http.Request) { accessData := result.Data.([]*model.AccessData) for _, a := range accessData { - if err := RevokeAccessToken(a.Token); err != nil { + if err := app.RevokeAccessToken(a.Token); err != nil { c.Err = err return } diff --git a/api/post.go b/api/post.go index 270ab72ca..bbdce78e8 100644 --- a/api/post.go +++ b/api/post.go @@ -362,13 +362,18 @@ func getPermalinkTmp(c *Context, w http.ResponseWriter, r *http.Request) { } post := list.Posts[list.Order[0]] - // Because we confuse permissions and membership in Mattermost's model, we have to just - // try to join the channel without checking if we already have permission to it. This is - // because system admins have permissions to every channel but are not nessisary a member - // of every channel. If we checked here then system admins would skip joining the channel and - // error when they tried to view it. - if err, _ := JoinChannelById(c, c.Session.UserId, post.ChannelId); err != nil { - // On error just return with permissions error + var channel *model.Channel + var err *model.AppError + if channel, err = app.GetChannel(post.ChannelId); err != nil { + c.Err = err + return + } + + if !HasPermissionToTeamContext(c, channel.TeamId, model.PERMISSION_JOIN_PUBLIC_CHANNELS) { + return + } + + if err = app.JoinChannel(channel, c.Session.UserId); err != nil { c.Err = err return } @@ -611,7 +616,7 @@ func getFileInfosForPost(c *Context, w http.ResponseWriter, r *http.Request) { if len(post.Filenames) > 0 { // The post has Filenames that need to be replaced with FileInfos - infos = migrateFilenamesToFileInfos(post) + infos = app.MigrateFilenamesToFileInfos(post) } } diff --git a/api/team.go b/api/team.go index a8ed90eb5..6f907a513 100644 --- a/api/team.go +++ b/api/team.go @@ -248,7 +248,10 @@ func revokeAllSessions(c *Context, w http.ResponseWriter, r *http.Request) { c.LogAudit("revoked_all=" + id) if session.IsOAuth { - RevokeAccessToken(session.Token) + if err := app.RevokeAccessToken(session.Token); err != nil { + c.Err = err + return + } } else { if result := <-app.Srv.Store.Session().Remove(session.Id); result.Err != nil { c.Err = result.Err diff --git a/api/user.go b/api/user.go index e3cae3704..701badfc9 100644 --- a/api/user.go +++ b/api/user.go @@ -7,16 +7,12 @@ import ( "bytes" b64 "encoding/base64" "fmt" - "hash/fnv" "html/template" "image" - "image/color" - "image/draw" _ "image/gif" _ "image/jpeg" "image/png" "io" - "io/ioutil" "net/http" "net/url" "strconv" @@ -25,7 +21,6 @@ import ( l4g "github.com/alecthomas/log4go" "github.com/disintegration/imaging" - "github.com/golang/freetype" "github.com/gorilla/mux" "github.com/mattermost/platform/app" "github.com/mattermost/platform/einterfaces" @@ -102,94 +97,50 @@ func createUser(c *Context, w http.ResponseWriter, r *http.Request) { return } - hash := r.URL.Query().Get("h") - teamId := "" - var team *model.Team - shouldSendWelcomeEmail := true user.EmailVerified = false - if len(hash) > 0 { - data := r.URL.Query().Get("d") - props := model.MapFromJson(strings.NewReader(data)) - - if !model.ComparePassword(hash, fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt)) { - c.Err = model.NewLocAppError("createUser", "api.user.create_user.signup_link_invalid.app_error", nil, "") - return - } + shouldSendWelcomeEmail := true - t, err := strconv.ParseInt(props["time"], 10, 64) - if err != nil || model.GetMillis()-t > 1000*60*60*48 { // 48 hours - c.Err = model.NewLocAppError("createUser", "api.user.create_user.signup_link_expired.app_error", nil, "") - return - } + hash := r.URL.Query().Get("h") + inviteId := r.URL.Query().Get("iid") - teamId = props["id"] + if !CheckUserDomain(user, utils.Cfg.TeamSettings.RestrictCreationToDomains) { + c.Err = model.NewLocAppError("createUser", "api.user.create_user.accepted_domain.app_error", nil, "") + return + } - // try to load the team to make sure it exists - if result := <-app.Srv.Store.Team().Get(teamId); result.Err != nil { - c.Err = result.Err + var ruser *model.User + var err *model.AppError + if len(hash) > 0 { + data := r.URL.Query().Get("d") + ruser, err = app.CreateUserWithHash(user, hash, data) + if err != nil { + c.Err = err return - } else { - team = result.Data.(*model.Team) } - user.Email = props["email"] - user.EmailVerified = true shouldSendWelcomeEmail = false - } - - inviteId := r.URL.Query().Get("iid") - if len(inviteId) > 0 { - if result := <-app.Srv.Store.Team().GetByInviteId(inviteId); result.Err != nil { - c.Err = result.Err + } else if len(inviteId) > 0 { + ruser, err = app.CreateUserWithInviteId(user, inviteId) + if err != nil { + c.Err = err return - } else { - team = result.Data.(*model.Team) - teamId = team.Id } - } - - firstAccount := false - if app.SessionCacheLength() == 0 { - if cr := <-app.Srv.Store.User().GetTotalUsersCount(); cr.Err != nil { - c.Err = cr.Err + } else { + if !app.IsFirstUserAccount() && !*utils.Cfg.TeamSettings.EnableOpenServer { + c.Err = model.NewLocAppError("createUser", "api.user.create_user.no_open_server", nil, "email="+user.Email) return - } else { - count := cr.Data.(int64) - if count <= 0 { - firstAccount = true - } } - } - - if !firstAccount && !*utils.Cfg.TeamSettings.EnableOpenServer && len(teamId) == 0 { - c.Err = model.NewLocAppError("createUser", "api.user.create_user.no_open_server", nil, "email="+user.Email) - return - } - - if !CheckUserDomain(user, utils.Cfg.TeamSettings.RestrictCreationToDomains) { - c.Err = model.NewLocAppError("createUser", "api.user.create_user.accepted_domain.app_error", nil, "") - return - } - - ruser, err := app.CreateUser(user) - if err != nil { - c.Err = err - return - } - if len(teamId) > 0 { - err := app.JoinUserToTeam(team, ruser) + ruser, err = app.CreateUser(user) if err != nil { c.Err = err return } - - go addDirectChannels(team.Id, ruser) } if shouldSendWelcomeEmail { - go sendWelcomeEmail(c, ruser.Id, ruser.Email, c.GetSiteURL(), ruser.EmailVerified) + sendWelcomeEmail(c, ruser.Id, ruser.Email, c.GetSiteURL(), ruser.EmailVerified) } w.Write([]byte(ruser.ToJson())) @@ -239,77 +190,6 @@ func IsVerifyHashRequired(user *model.User, team *model.Team, hash string) bool return shouldVerifyHash } -func CreateOAuthUser(c *Context, w http.ResponseWriter, r *http.Request, service string, userData io.Reader, teamId string) *model.User { - var user *model.User - provider := einterfaces.GetOauthProvider(service) - if provider == nil { - c.Err = model.NewLocAppError("CreateOAuthUser", "api.user.create_oauth_user.not_available.app_error", map[string]interface{}{"Service": strings.Title(service)}, "") - return nil - } else { - user = provider.GetUserFromJson(userData) - } - - if user == nil { - c.Err = model.NewLocAppError("CreateOAuthUser", "api.user.create_oauth_user.create.app_error", map[string]interface{}{"Service": service}, "") - return nil - } - - suchan := app.Srv.Store.User().GetByAuth(user.AuthData, service) - euchan := app.Srv.Store.User().GetByEmail(user.Email) - - found := true - count := 0 - for found { - if found = IsUsernameTaken(user.Username); found { - user.Username = user.Username + strconv.Itoa(count) - count += 1 - } - } - - if result := <-suchan; result.Err == nil { - c.Err = model.NewLocAppError("CreateOAuthUser", "api.user.create_oauth_user.already_used.app_error", - map[string]interface{}{"Service": service}, "email="+user.Email) - return nil - } - - if result := <-euchan; result.Err == nil { - authService := result.Data.(*model.User).AuthService - if authService == "" { - c.Err = model.NewLocAppError("CreateOAuthUser", "api.user.create_oauth_user.already_attached.app_error", - map[string]interface{}{"Service": service, "Auth": model.USER_AUTH_SERVICE_EMAIL}, "email="+user.Email) - } else { - c.Err = model.NewLocAppError("CreateOAuthUser", "api.user.create_oauth_user.already_attached.app_error", - map[string]interface{}{"Service": service, "Auth": authService}, "email="+user.Email) - } - return nil - } - - user.EmailVerified = true - - ruser, err := app.CreateUser(user) - if err != nil { - c.Err = err - return nil - } - - if len(teamId) > 0 { - err = app.JoinUserToTeamById(teamId, user) - if err != nil { - c.Err = err - return nil - } - - go addDirectChannels(teamId, user) - } - - doLogin(c, w, r, ruser, "") - if c.Err != nil { - return nil - } - - return ruser -} - func sendWelcomeEmail(c *Context, userId string, email string, siteURL string, verified bool) { rawUrl, _ := url.Parse(siteURL) @@ -339,43 +219,6 @@ func sendWelcomeEmail(c *Context, userId string, email string, siteURL string, v } } -func addDirectChannels(teamId string, user *model.User) { - var profiles map[string]*model.User - if result := <-app.Srv.Store.User().GetProfiles(teamId, 0, 100); result.Err != nil { - l4g.Error(utils.T("api.user.add_direct_channels_and_forget.failed.error"), user.Id, teamId, result.Err.Error()) - return - } else { - profiles = result.Data.(map[string]*model.User) - } - - var preferences model.Preferences - - for id := range profiles { - if id == user.Id { - continue - } - - profile := profiles[id] - - preference := model.Preference{ - UserId: user.Id, - Category: model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW, - Name: profile.Id, - Value: "true", - } - - preferences = append(preferences, preference) - - if len(preferences) >= 10 { - break - } - } - - if result := <-app.Srv.Store.Preference().Save(&preferences); result.Err != nil { - l4g.Error(utils.T("api.user.add_direct_channels_and_forget.failed.error"), user.Id, teamId, result.Err.Error()) - } -} - func SendVerifyEmail(c *Context, userId, userEmail, siteURL string) { link := fmt.Sprintf("%s/do_verify_email?uid=%s&hid=%s&email=%s", siteURL, userId, model.HashPassword(userId+utils.Cfg.EmailSettings.InviteSalt), url.QueryEscape(userEmail)) @@ -418,21 +261,19 @@ func login(c *Context, w http.ResponseWriter, r *http.Request) { if len(id) != 0 { c.LogAuditWithUserId(id, "attempt") - if result := <-app.Srv.Store.User().Get(id); result.Err != nil { + if user, err = app.GetUser(id); err != nil { c.LogAuditWithUserId(id, "failure") - c.Err = result.Err + c.Err = err c.Err.StatusCode = http.StatusBadRequest if einterfaces.GetMetricsInterface() != nil { einterfaces.GetMetricsInterface().IncrementLoginFail() } return - } else { - user = result.Data.(*model.User) } } else { c.LogAudit("attempt") - if user, err = getUserForLogin(loginId, ldapOnly); err != nil { + if user, err = app.GetUserForLogin(loginId, ldapOnly); err != nil { c.LogAudit("failure") c.Err = err if einterfaces.GetMetricsInterface() != nil { @@ -469,37 +310,6 @@ func login(c *Context, w http.ResponseWriter, r *http.Request) { w.Write([]byte(user.ToJson())) } -func getUserForLogin(loginId string, onlyLdap bool) (*model.User, *model.AppError) { - ldapAvailable := *utils.Cfg.LdapSettings.Enable && einterfaces.GetLdapInterface() != nil && utils.IsLicensed && *utils.License.Features.LDAP - - if result := <-app.Srv.Store.User().GetForLogin( - loginId, - *utils.Cfg.EmailSettings.EnableSignInWithUsername && !onlyLdap, - *utils.Cfg.EmailSettings.EnableSignInWithEmail && !onlyLdap, - ldapAvailable, - ); result.Err != nil && result.Err.Id == "store.sql_user.get_for_login.multiple_users" { - // don't fall back to LDAP in this case since we already know there's an LDAP user, but that it shouldn't work - result.Err.StatusCode = http.StatusBadRequest - return nil, result.Err - } else if result.Err != nil { - if !ldapAvailable { - // failed to find user and no LDAP server to fall back on - result.Err.StatusCode = http.StatusBadRequest - return nil, result.Err - } - - // fall back to LDAP server to see if we can find a user - if ldapUser, ldapErr := einterfaces.GetLdapInterface().GetUser(loginId); ldapErr != nil { - ldapErr.StatusCode = http.StatusBadRequest - return nil, ldapErr - } else { - return ldapUser, nil - } - } else { - return result.Data.(*model.User), nil - } -} - func LoginByOAuth(c *Context, w http.ResponseWriter, r *http.Request, service string, userData io.Reader) *model.User { buf := bytes.Buffer{} buf.ReadFrom(userData) @@ -521,20 +331,23 @@ func LoginByOAuth(c *Context, w http.ResponseWriter, r *http.Request, service st } var user *model.User - if result := <-app.Srv.Store.User().GetByAuth(&authData, service); result.Err != nil { - if result.Err.Id == store.MISSING_AUTH_ACCOUNT_ERROR { - return CreateOAuthUser(c, w, r, service, bytes.NewReader(buf.Bytes()), "") + var err *model.AppError + if user, err = app.GetUserByAuth(&authData, service); err != nil { + if err.Id == store.MISSING_AUTH_ACCOUNT_ERROR { + if user, err = app.CreateOAuthUser(service, bytes.NewReader(buf.Bytes()), ""); err != nil { + c.Err = err + return nil + } } - c.Err = result.Err + c.Err = err return nil - } else { - user = result.Data.(*model.User) - doLogin(c, w, r, user, "") - if c.Err != nil { - return nil - } - return user } + + doLogin(c, w, r, user, "") + if c.Err != nil { + return nil + } + return user } // User MUST be authenticated completely before calling Login @@ -558,9 +371,8 @@ func doLogin(c *Context, w http.ResponseWriter, r *http.Request, user *model.Use for _, session := range sessions { if session.DeviceId == deviceId { l4g.Debug(utils.T("api.user.login.revoking.app_error"), session.Id, user.Id) - RevokeSessionById(c, session.Id) - if c.Err != nil { - c.LogError(c.Err) + if err := app.RevokeSessionById(session.Id); err != nil { + c.LogError(err) c.Err = nil } } @@ -634,7 +446,12 @@ func doLogin(c *Context, w http.ResponseWriter, r *http.Request, user *model.Use func revokeSession(c *Context, w http.ResponseWriter, r *http.Request) { props := model.MapFromJson(r.Body) id := props["id"] - RevokeSessionById(c, id) + + if err := app.RevokeSessionById(id); err != nil { + c.Err = err + return + } + w.Write([]byte(model.MapToJson(props))) } @@ -652,23 +469,11 @@ func attachDeviceId(c *Context, w http.ResponseWriter, r *http.Request) { return } - // A special case where we logout of all other sessions with the same Id - if result := <-app.Srv.Store.Session().GetSessions(c.Session.UserId); result.Err != nil { - c.Err = result.Err + // A special case where we logout of all other sessions with the same device id + if err := app.RevokeSessionsForDeviceId(c.Session.UserId, deviceId, c.Session.Id); err != nil { + c.Err = err c.Err.StatusCode = http.StatusInternalServerError return - } else { - sessions := result.Data.([]*model.Session) - for _, session := range sessions { - if session.DeviceId == deviceId && session.Id != c.Session.Id { - l4g.Debug(utils.T("api.user.login.revoking.app_error"), session.Id, c.Session.UserId) - RevokeSessionById(c, session.Id) - if c.Err != nil { - c.LogError(c.Err) - c.Err = nil - } - } - } } app.RemoveAllSessionsForUserId(c.Session.UserId) @@ -694,34 +499,14 @@ func attachDeviceId(c *Context, w http.ResponseWriter, r *http.Request) { http.SetCookie(w, sessionCookie) - if result := <-app.Srv.Store.Session().UpdateDeviceId(c.Session.Id, deviceId, c.Session.ExpiresAt); result.Err != nil { - c.Err = result.Err + if err := app.AttachDeviceId(c.Session.Id, deviceId, c.Session.ExpiresAt); err != nil { + c.Err = err return } w.Write([]byte(model.MapToJson(props))) } -func RevokeSessionById(c *Context, sessionId string) { - if result := <-app.Srv.Store.Session().Get(sessionId); result.Err != nil { - c.Err = result.Err - } else { - session := result.Data.(*model.Session) - c.LogAudit("session_id=" + session.Id) - - if session.IsOAuth { - RevokeAccessToken(session.Token) - } else { - if result := <-app.Srv.Store.Session().Remove(session.Id); result.Err != nil { - c.Err = result.Err - } - } - - RevokeWebrtcToken(session.Id) - app.RemoveAllSessionsForUserId(session.UserId) - } -} - // IF YOU UPDATE THIS PLEASE UPDATE BELOW func RevokeAllSession(c *Context, userId string) { if result := <-app.Srv.Store.Session().GetSessions(userId); result.Err != nil { @@ -733,7 +518,7 @@ func RevokeAllSession(c *Context, userId string) { for _, session := range sessions { c.LogAuditWithUserId(userId, "session_id="+session.Id) if session.IsOAuth { - RevokeAccessToken(session.Token) + app.RevokeAccessToken(session.Token) } else { if result := <-app.Srv.Store.Session().Remove(session.Id); result.Err != nil { c.Err = result.Err @@ -741,7 +526,7 @@ func RevokeAllSession(c *Context, userId string) { } } - RevokeWebrtcToken(session.Id) + app.RevokeWebrtcToken(session.Id) } } @@ -758,14 +543,14 @@ func RevokeAllSessionsNoContext(userId string) *model.AppError { for _, session := range sessions { if session.IsOAuth { - RevokeAccessToken(session.Token) + app.RevokeAccessToken(session.Token) } else { if result := <-app.Srv.Store.Session().Remove(session.Id); result.Err != nil { return result.Err } } - RevokeWebrtcToken(session.Id) + app.RevokeWebrtcToken(session.Id) } } @@ -810,23 +595,26 @@ func Logout(c *Context, w http.ResponseWriter, r *http.Request) { c.LogAudit("") c.RemoveSessionCookie(w, r) if c.Session.Id != "" { - RevokeSessionById(c, c.Session.Id) + if err := app.RevokeSessionById(c.Session.Id); err != nil { + c.Err = err + return + } } } func getMe(c *Context, w http.ResponseWriter, r *http.Request) { - if result := <-app.Srv.Store.User().Get(c.Session.UserId); result.Err != nil { - c.Err = result.Err + if user, err := app.GetUser(c.Session.UserId); err != nil { + c.Err = err c.RemoveSessionCookie(w, r) l4g.Error(utils.T("api.user.get_me.getting.error"), c.Session.UserId) return - } else if HandleEtag(result.Data.(*model.User).Etag(utils.Cfg.PrivacySettings.ShowFullName, utils.Cfg.PrivacySettings.ShowEmailAddress), "Get Me", w, r) { + } else if HandleEtag(user.Etag(utils.Cfg.PrivacySettings.ShowFullName, utils.Cfg.PrivacySettings.ShowEmailAddress), "Get Me", w, r) { return } else { - result.Data.(*model.User).Sanitize(map[string]bool{}) - w.Header().Set(model.HEADER_ETAG_SERVER, result.Data.(*model.User).Etag(utils.Cfg.PrivacySettings.ShowFullName, utils.Cfg.PrivacySettings.ShowEmailAddress)) - w.Write([]byte(result.Data.(*model.User).ToJson())) + user.Sanitize(map[string]bool{}) + w.Header().Set(model.HEADER_ETAG_SERVER, user.Etag(utils.Cfg.PrivacySettings.ShowFullName, utils.Cfg.PrivacySettings.ShowEmailAddress)) + w.Write([]byte(user.ToJson())) return } } @@ -835,59 +623,36 @@ func getInitialLoad(c *Context, w http.ResponseWriter, r *http.Request) { il := model.InitialLoad{} - var cchan store.StoreChannel - - if app.SessionCacheLength() == 0 { - // Below is a special case when intializating a new server - // Lets check to make sure the server is really empty - - cchan = app.Srv.Store.User().GetTotalUsersCount() - } - if len(c.Session.UserId) != 0 { - uchan := app.Srv.Store.User().Get(c.Session.UserId) - pchan := app.Srv.Store.Preference().GetAll(c.Session.UserId) - tchan := app.Srv.Store.Team().GetTeamsByUserId(c.Session.UserId) + var err *model.AppError - il.TeamMembers = c.Session.TeamMembers - - if ru := <-uchan; ru.Err != nil { - c.Err = ru.Err + il.User, err = app.GetUser(c.Session.UserId) + if err != nil { + c.Err = err return - } else { - il.User = ru.Data.(*model.User) - il.User.Sanitize(map[string]bool{}) } + il.User.Sanitize(map[string]bool{}) - if rp := <-pchan; rp.Err != nil { - c.Err = rp.Err - return - } else { - il.Preferences = rp.Data.(model.Preferences) - } + il.Preferences, err = app.GetPreferencesForUser(c.Session.Id) - if rt := <-tchan; rt.Err != nil { - c.Err = rt.Err + il.Teams, err = app.GetTeamsForUser(c.Session.UserId) + if err != nil { + c.Err = err return - } else { - il.Teams = rt.Data.([]*model.Team) + } - for _, team := range il.Teams { - team.Sanitize() - } + for _, team := range il.Teams { + team.Sanitize() } + + il.TeamMembers = c.Session.TeamMembers } - if cchan != nil { - if cr := <-cchan; cr.Err != nil { - c.Err = cr.Err - return - } else { - count := cr.Data.(int64) - if count <= 0 { - il.NoAccounts = true - } - } + if app.SessionCacheLength() == 0 { + // Below is a special case when intializating a new server + // Lets check to make sure the server is really empty + + il.NoAccounts = app.IsFirstUserAccount() } il.ClientCfg = utils.ClientCfg @@ -905,16 +670,19 @@ func getUser(c *Context, w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) id := params["user_id"] - if result := <-app.Srv.Store.User().Get(id); result.Err != nil { - c.Err = result.Err + var user *model.User + var err *model.AppError + + if user, err = app.GetUser(id); err != nil { + c.Err = err return - } else if HandleEtag(result.Data.(*model.User).Etag(utils.Cfg.PrivacySettings.ShowFullName, utils.Cfg.PrivacySettings.ShowEmailAddress), "Get User", w, r) { + } else if HandleEtag(user.Etag(utils.Cfg.PrivacySettings.ShowFullName, utils.Cfg.PrivacySettings.ShowEmailAddress), "Get User", w, r) { return } else { - user := sanitizeProfile(c, result.Data.(*model.User)) + sanitizeProfile(c, user) w.Header().Set(model.HEADER_ETAG_SERVER, user.Etag(utils.Cfg.PrivacySettings.ShowFullName, utils.Cfg.PrivacySettings.ShowEmailAddress)) - w.Write([]byte(result.Data.(*model.User).ToJson())) + w.Write([]byte(user.ToJson())) return } } @@ -923,16 +691,19 @@ func getByUsername(c *Context, w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) username := params["username"] - if result := <-app.Srv.Store.User().GetByUsername(username); result.Err != nil { - c.Err = result.Err + var user *model.User + var err *model.AppError + + if user, err = app.GetUserByUsername(username); err != nil { + c.Err = err return - } else if HandleEtag(result.Data.(*model.User).Etag(utils.Cfg.PrivacySettings.ShowFullName, utils.Cfg.PrivacySettings.ShowEmailAddress), "Get By Username", w, r) { + } else if HandleEtag(user.Etag(utils.Cfg.PrivacySettings.ShowFullName, utils.Cfg.PrivacySettings.ShowEmailAddress), "Get By Username", w, r) { return } else { - user := sanitizeProfile(c, result.Data.(*model.User)) + sanitizeProfile(c, user) w.Header().Set(model.HEADER_ETAG_SERVER, user.Etag(utils.Cfg.PrivacySettings.ShowFullName, utils.Cfg.PrivacySettings.ShowEmailAddress)) - w.Write([]byte(result.Data.(*model.User).ToJson())) + w.Write([]byte(user.ToJson())) return } } @@ -941,16 +712,19 @@ func getByEmail(c *Context, w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) email := params["email"] - if result := <-app.Srv.Store.User().GetByEmail(email); result.Err != nil { - c.Err = result.Err + var user *model.User + var err *model.AppError + + if user, err = app.GetUserByEmail(email); err != nil { + c.Err = err return - } else if HandleEtag(result.Data.(*model.User).Etag(utils.Cfg.PrivacySettings.ShowFullName, utils.Cfg.PrivacySettings.ShowEmailAddress), "Get By Email", w, r) { + } else if HandleEtag(user.Etag(utils.Cfg.PrivacySettings.ShowFullName, utils.Cfg.PrivacySettings.ShowEmailAddress), "Get By Email", w, r) { return } else { - user := sanitizeProfile(c, result.Data.(*model.User)) + sanitizeProfile(c, user) w.Header().Set(model.HEADER_ETAG_SERVER, user.Etag(utils.Cfg.PrivacySettings.ShowFullName, utils.Cfg.PrivacySettings.ShowEmailAddress)) - w.Write([]byte(result.Data.(*model.User).ToJson())) + w.Write([]byte(user.ToJson())) return } } @@ -970,17 +744,18 @@ func getProfiles(c *Context, w http.ResponseWriter, r *http.Request) { return } - etag := (<-app.Srv.Store.User().GetEtagForAllProfiles()).Data.(string) + etag := app.GetUsersEtag() if HandleEtag(etag, "Get Profiles", w, r) { return } - if result := <-app.Srv.Store.User().GetAllProfiles(offset, limit); result.Err != nil { - c.Err = result.Err + var profiles map[string]*model.User + var profileErr *model.AppError + + if profiles, profileErr = app.GetUsers(offset, limit); profileErr != nil { + c.Err = profileErr return } else { - profiles := result.Data.(map[string]*model.User) - for k, p := range profiles { profiles[k] = sanitizeProfile(c, p) } @@ -1012,17 +787,18 @@ func getProfilesInTeam(c *Context, w http.ResponseWriter, r *http.Request) { return } - etag := (<-app.Srv.Store.User().GetEtagForProfiles(teamId)).Data.(string) + etag := app.GetUsersInTeamEtag(teamId) if HandleEtag(etag, "Get Profiles In Team", w, r) { return } - if result := <-app.Srv.Store.User().GetProfiles(teamId, offset, limit); result.Err != nil { - c.Err = result.Err + var profiles map[string]*model.User + var profileErr *model.AppError + + if profiles, profileErr = app.GetUsersInTeam(teamId, offset, limit); profileErr != nil { + c.Err = profileErr return } else { - profiles := result.Data.(map[string]*model.User) - for k, p := range profiles { profiles[k] = sanitizeProfile(c, p) } @@ -1058,12 +834,13 @@ func getProfilesInChannel(c *Context, w http.ResponseWriter, r *http.Request) { return } - if result := <-app.Srv.Store.User().GetProfilesInChannel(channelId, offset, limit, false); result.Err != nil { - c.Err = result.Err + var profiles map[string]*model.User + var profileErr *model.AppError + + if profiles, err = app.GetUsersInChannel(channelId, offset, limit); profileErr != nil { + c.Err = profileErr return } else { - profiles := result.Data.(map[string]*model.User) - for k, p := range profiles { profiles[k] = sanitizeProfile(c, p) } @@ -1098,12 +875,13 @@ func getProfilesNotInChannel(c *Context, w http.ResponseWriter, r *http.Request) return } - if result := <-app.Srv.Store.User().GetProfilesNotInChannel(c.TeamId, channelId, offset, limit); result.Err != nil { - c.Err = result.Err + var profiles map[string]*model.User + var profileErr *model.AppError + + if profiles, err = app.GetUsersNotInChannel(c.TeamId, channelId, offset, limit); profileErr != nil { + c.Err = profileErr return } else { - profiles := result.Data.(map[string]*model.User) - for k, p := range profiles { profiles[k] = sanitizeProfile(c, p) } @@ -1120,18 +898,10 @@ func getAudits(c *Context, w http.ResponseWriter, r *http.Request) { return } - userChan := app.Srv.Store.User().Get(id) - auditChan := app.Srv.Store.Audit().Get(id, 20) - - if c.Err = (<-userChan).Err; c.Err != nil { - return - } - - if result := <-auditChan; result.Err != nil { - c.Err = result.Err + if audits, err := app.GetAudits(id, 20); err != nil { + c.Err = err return } else { - audits := result.Data.(model.Audits) etag := audits.Etag() if HandleEtag(etag, "Get Audits", w, r) { @@ -1147,128 +917,29 @@ func getAudits(c *Context, w http.ResponseWriter, r *http.Request) { } } -func createProfileImage(username string, userId string) ([]byte, *model.AppError) { - colors := []color.NRGBA{ - {197, 8, 126, 255}, - {227, 207, 18, 255}, - {28, 181, 105, 255}, - {35, 188, 224, 255}, - {116, 49, 196, 255}, - {197, 8, 126, 255}, - {197, 19, 19, 255}, - {250, 134, 6, 255}, - {227, 207, 18, 255}, - {123, 201, 71, 255}, - {28, 181, 105, 255}, - {35, 188, 224, 255}, - {116, 49, 196, 255}, - {197, 8, 126, 255}, - {197, 19, 19, 255}, - {250, 134, 6, 255}, - {227, 207, 18, 255}, - {123, 201, 71, 255}, - {28, 181, 105, 255}, - {35, 188, 224, 255}, - {116, 49, 196, 255}, - {197, 8, 126, 255}, - {197, 19, 19, 255}, - {250, 134, 6, 255}, - {227, 207, 18, 255}, - {123, 201, 71, 255}, - } - - h := fnv.New32a() - h.Write([]byte(userId)) - seed := h.Sum32() - - initial := string(strings.ToUpper(username)[0]) - - fontBytes, err := ioutil.ReadFile(utils.FindDir("fonts") + utils.Cfg.FileSettings.InitialFont) - if err != nil { - return nil, model.NewLocAppError("createProfileImage", "api.user.create_profile_image.default_font.app_error", nil, err.Error()) - } - font, err := freetype.ParseFont(fontBytes) - if err != nil { - return nil, model.NewLocAppError("createProfileImage", "api.user.create_profile_image.default_font.app_error", nil, err.Error()) - } - - 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 - draw.Draw(dstImg, dstImg.Bounds(), &image.Uniform{color}, image.ZP, draw.Src) - size := float64((width + height) / 4) - - c := freetype.NewContext() - c.SetFont(font) - c.SetFontSize(size) - c.SetClip(dstImg.Bounds()) - c.SetDst(dstImg) - c.SetSrc(srcImg) - - pt := freetype.Pt(width/6, height*2/3) - _, err = c.DrawString(initial, pt) - if err != nil { - return nil, model.NewLocAppError("createProfileImage", "api.user.create_profile_image.initial.app_error", nil, err.Error()) - } - - buf := new(bytes.Buffer) - - if imgErr := png.Encode(buf, dstImg); imgErr != nil { - return nil, model.NewLocAppError("createProfileImage", "api.user.create_profile_image.encode.app_error", nil, imgErr.Error()) - } else { - return buf.Bytes(), nil - } -} - func getProfileImage(c *Context, w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) id := params["user_id"] - readFailed := false var etag string - if result := <-app.Srv.Store.User().Get(id); result.Err != nil { - c.Err = result.Err + if user, err := app.GetUser(id); err != nil { + c.Err = err return } else { - var img []byte - etag = strconv.FormatInt(result.Data.(*model.User).LastPictureUpdate, 10) + etag = strconv.FormatInt(user.LastPictureUpdate, 10) if HandleEtag(etag, "Profile Image", w, r) { return } - 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 - return - } - } else { - path := "users/" + id + "/profile.png" - - if data, err := ReadFile(path); err != nil { - readFailed = true - - if img, err = createProfileImage(result.Data.(*model.User).Username, id); err != nil { - c.Err = err - return - } - - if result.Data.(*model.User).LastPictureUpdate == 0 { - if err := WriteFile(img, path); err != nil { - c.Err = err - return - } - } - - } else { - img = data - } + var img []byte + img, err = app.GetProfileImage(user) + if err != nil { + c.Err = err + return } - if c.Session.UserId == id || readFailed { + if c.Session.UserId == id { w.Header().Set("Cache-Control", "max-age=300, public") // 5 mins } else { w.Header().Set("Cache-Control", "max-age=86400, public") // 24 hrs @@ -1353,7 +1024,7 @@ func uploadProfileImage(c *Context, w http.ResponseWriter, r *http.Request) { path := "users/" + c.Session.UserId + "/profile.png" - if err := WriteFile(buf.Bytes(), path); err != nil { + if err := app.WriteFile(buf.Bytes(), path); err != nil { c.Err = model.NewLocAppError("uploadProfileImage", "api.user.upload_profile_user.upload_profile.app_error", nil, "") return } @@ -2000,22 +1671,6 @@ func updateUserNotify(c *Context, w http.ResponseWriter, r *http.Request) { } } -// Check if the username is already used by another user. Return false if the username is invalid. -func IsUsernameTaken(name string) bool { - - if !model.IsValidUsername(name) { - return false - } - - if result := <-app.Srv.Store.User().GetByUsername(name); result.Err != nil { - return false - } else { - return true - } - - return false -} - func emailToOAuth(c *Context, w http.ResponseWriter, r *http.Request) { props := model.MapFromJson(r.Body) @@ -2336,7 +1991,7 @@ func resendVerification(c *Context, w http.ResponseWriter, r *http.Request) { return } - if user, error := getUserForLogin(email, false); error != nil { + if user, error := app.GetUserForLogin(email, false); error != nil { c.Err = error return } else { @@ -2403,13 +2058,13 @@ func updateMfa(c *Context, w http.ResponseWriter, r *http.Request) { c.LogAudit("attempt") if activate { - if err := ActivateMfa(c.Session.UserId, token); err != nil { + if err := app.ActivateMfa(c.Session.UserId, token); err != nil { c.Err = err return } c.LogAudit("success - activated") } else { - if err := DeactivateMfa(c.Session.UserId); err != nil { + if err := app.DeactivateMfa(c.Session.UserId); err != nil { c.Err = err return } @@ -2432,47 +2087,6 @@ func updateMfa(c *Context, w http.ResponseWriter, r *http.Request) { w.Write([]byte(model.MapToJson(rdata))) } -func ActivateMfa(userId, token string) *model.AppError { - mfaInterface := einterfaces.GetMfaInterface() - if mfaInterface == nil { - err := model.NewLocAppError("ActivateMfa", "api.user.update_mfa.not_available.app_error", nil, "") - err.StatusCode = http.StatusNotImplemented - return err - } - - var user *model.User - if result := <-app.Srv.Store.User().Get(userId); result.Err != nil { - return result.Err - } else { - user = result.Data.(*model.User) - } - - if len(user.AuthService) > 0 && user.AuthService != model.USER_AUTH_SERVICE_LDAP { - return model.NewLocAppError("ActivateMfa", "api.user.activate_mfa.email_and_ldap_only.app_error", nil, "") - } - - if err := mfaInterface.Activate(user, token); err != nil { - return err - } - - return nil -} - -func DeactivateMfa(userId string) *model.AppError { - mfaInterface := einterfaces.GetMfaInterface() - if mfaInterface == nil { - err := model.NewLocAppError("DeactivateMfa", "api.user.update_mfa.not_available.app_error", nil, "") - err.StatusCode = http.StatusNotImplemented - return err - } - - if err := mfaInterface.Deactivate(userId); err != nil { - return err - } - - return nil -} - func checkMfa(c *Context, w http.ResponseWriter, r *http.Request) { if !utils.IsLicensed || !*utils.License.Features.MFA || !*utils.Cfg.ServiceSettings.EnableMultifactorAuthentication { rdata := map[string]string{} @@ -2592,7 +2206,7 @@ func completeSaml(c *Context, w http.ResponseWriter, r *http.Request) { case model.OAUTH_ACTION_SIGNUP: teamId := relayProps["team_id"] if len(teamId) > 0 { - go addDirectChannels(teamId, user) + go app.AddDirectChannels(teamId, user) } break case model.OAUTH_ACTION_EMAIL_TO_SSO: diff --git a/api/user_test.go b/api/user_test.go index fa7f28e6b..3163de078 100644 --- a/api/user_test.go +++ b/api/user_test.go @@ -107,25 +107,6 @@ func TestCheckUserDomain(t *testing.T) { } } -func TestIsUsernameTaken(t *testing.T) { - th := Setup().InitBasic() - user := th.BasicUser - taken := IsUsernameTaken(user.Username) - - if !taken { - t.Logf("the username '%v' should be taken", user.Username) - t.FailNow() - } - - newUsername := "randomUsername" - taken = IsUsernameTaken(newUsername) - - if taken { - t.Logf("the username '%v' should not be taken", newUsername) - t.FailNow() - } -} - func TestLogin(t *testing.T) { th := Setup() Client := th.CreateClient() @@ -227,7 +208,10 @@ func TestLogin(t *testing.T) { data := model.MapToJson(props) hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt)) - ruser2, _ := Client.CreateUserFromSignup(&user2, data, hash) + ruser2, err := Client.CreateUserFromSignup(&user2, data, hash) + if err != nil { + t.Fatal(err) + } if _, err := Client.Login(ruser2.Data.(*model.User).Email, user2.Password); err != nil { t.Fatal("From verfied hash") @@ -686,7 +670,7 @@ func TestUserCreateImage(t *testing.T) { th := Setup() Client := th.CreateClient() - b, err := createProfileImage("Corey Hulen", "eo1zkdr96pdj98pjmq8zy35wba") + b, err := app.CreateProfileImage("Corey Hulen", "eo1zkdr96pdj98pjmq8zy35wba") if err != nil { t.Fatal(err) } diff --git a/api/webrtc.go b/api/webrtc.go index 7f30ffef9..15b7cfa4f 100644 --- a/api/webrtc.go +++ b/api/webrtc.go @@ -115,22 +115,3 @@ func closeBody(r *http.Response) { r.Body.Close() } } - -func RevokeWebrtcToken(sessionId string) { - token := base64.StdEncoding.EncodeToString([]byte(sessionId)) - data := make(map[string]string) - data["janus"] = "remove_token" - data["token"] = token - data["transaction"] = model.NewId() - data["admin_secret"] = *utils.Cfg.WebrtcSettings.GatewayAdminSecret - - rq, _ := http.NewRequest("POST", *utils.Cfg.WebrtcSettings.GatewayAdminUrl, strings.NewReader(model.MapToJson(data))) - rq.Header.Set("Content-Type", "application/json") - - // we do not care about the response - tr := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: *utils.Cfg.ServiceSettings.EnableInsecureOutgoingConnections}, - } - httpClient := &http.Client{Transport: tr} - httpClient.Do(rq) -} diff --git a/api/webrtc_test.go b/api/webrtc_test.go index 953333b09..21049d95d 100644 --- a/api/webrtc_test.go +++ b/api/webrtc_test.go @@ -5,6 +5,7 @@ package api import ( "fmt" + "github.com/mattermost/platform/app" "github.com/mattermost/platform/model" "github.com/mattermost/platform/utils" "testing" @@ -39,5 +40,5 @@ func TestWebrtcToken(t *testing.T) { fmt.Println("Turn Password", result["turn_password"]) } - RevokeWebrtcToken(sessionId) + app.RevokeWebrtcToken(sessionId) } |