From fa807d8e436e87b8c1749ea54c293a15c67f7f29 Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Wed, 27 Apr 2016 16:02:58 -0400 Subject: Fixing permalinks to channels your not a memeber of (#2805) --- api/api.go | 6 +++-- api/channel.go | 65 ++++++++++++++++++++++++++++++++++++----------------- api/channel_test.go | 32 +++++++++++++++++++++++++- api/command_join.go | 2 +- api/post.go | 48 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 128 insertions(+), 25 deletions(-) (limited to 'api') diff --git a/api/api.go b/api/api.go index e9a95b125..fc81dda3a 100644 --- a/api/api.go +++ b/api/api.go @@ -24,8 +24,9 @@ type Routes struct { Teams *mux.Router // 'api/v3/teams' NeedTeam *mux.Router // 'api/v3/teams/{team_id:[A-Za-z0-9]+}' - Channels *mux.Router // 'api/v3/teams/{team_id:[A-Za-z0-9]+}/channels' - NeedChannel *mux.Router // 'api/v3/teams/{team_id:[A-Za-z0-9]+}/channels/{channel_id:[A-Za-z0-9]+}' + Channels *mux.Router // 'api/v3/teams/{team_id:[A-Za-z0-9]+}/channels' + NeedChannel *mux.Router // 'api/v3/teams/{team_id:[A-Za-z0-9]+}/channels/{channel_id:[A-Za-z0-9]+}' + NeedChannelName *mux.Router // 'api/v3/teams/{team_id:[A-Za-z0-9]+}/channels/name/{channel_name:[A-Za-z0-9-]+}' Posts *mux.Router // 'api/v3/teams/{team_id:[A-Za-z0-9]+}/channels/{channel_id:[A-Za-z0-9]+}/posts' NeedPost *mux.Router // 'api/v3/teams/{team_id:[A-Za-z0-9]+}/channels/{channel_id:[A-Za-z0-9]+}/posts/{post_id:[A-Za-z0-9]+}' @@ -56,6 +57,7 @@ func InitApi() { BaseRoutes.NeedTeam = BaseRoutes.Teams.PathPrefix("/{team_id:[A-Za-z0-9]+}").Subrouter() BaseRoutes.Channels = BaseRoutes.NeedTeam.PathPrefix("/channels").Subrouter() BaseRoutes.NeedChannel = BaseRoutes.Channels.PathPrefix("/{channel_id:[A-Za-z0-9]+}").Subrouter() + BaseRoutes.NeedChannelName = BaseRoutes.Channels.PathPrefix("/name/{channel_name:[A-Za-z0-9-]+}").Subrouter() BaseRoutes.Posts = BaseRoutes.NeedChannel.PathPrefix("/posts").Subrouter() BaseRoutes.NeedPost = BaseRoutes.Posts.PathPrefix("/{post_id:[A-Za-z0-9]+}").Subrouter() BaseRoutes.Commands = BaseRoutes.NeedTeam.PathPrefix("/commands").Subrouter() diff --git a/api/channel.go b/api/channel.go index 871477824..d47109045 100644 --- a/api/channel.go +++ b/api/channel.go @@ -8,6 +8,7 @@ import ( l4g "github.com/alecthomas/log4go" "github.com/gorilla/mux" "github.com/mattermost/platform/model" + "github.com/mattermost/platform/store" "github.com/mattermost/platform/utils" "net/http" "strconv" @@ -31,6 +32,8 @@ func InitChannel() { BaseRoutes.Channels.Handle("/update_purpose", ApiUserRequired(updateChannelPurpose)).Methods("POST") BaseRoutes.Channels.Handle("/update_notify_props", ApiUserRequired(updateNotifyProps)).Methods("POST") + BaseRoutes.NeedChannelName.Handle("/join", ApiUserRequired(join)).Methods("POST") + BaseRoutes.NeedChannel.Handle("/", ApiUserRequiredActivity(getChannel, false)).Methods("GET") BaseRoutes.NeedChannel.Handle("/extra_info", ApiUserRequired(getChannelExtraInfo)).Methods("GET") BaseRoutes.NeedChannel.Handle("/extra_info/{member_limit:-?[0-9]+}", ApiUserRequired(getChannelExtraInfo)).Methods("GET") @@ -423,48 +426,68 @@ func join(c *Context, w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) channelId := params["channel_id"] + channelName := params["channel_name"] - JoinChannel(c, channelId, "") - - if c.Err != nil { + var outChannel *model.Channel = nil + 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 + } + } 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 + } + } else { + c.SetInvalidParam("join", "channel_id, channel_name") return } + w.Write([]byte(outChannel.ToJson())) +} - result := make(map[string]string) - result["id"] = channelId - w.Write([]byte(model.MapToJson(result))) +func JoinChannelByName(c *Context, userId string, teamId string, channelName string) (*model.AppError, *model.Channel) { + channelChannel := Srv.Store.Channel().GetByName(teamId, channelName) + userChannel := Srv.Store.User().Get(userId) + + return joinChannel(c, channelChannel, userChannel) } -func JoinChannel(c *Context, channelId string, role string) { +func JoinChannelById(c *Context, userId string, channelId string) (*model.AppError, *model.Channel) { + channelChannel := Srv.Store.Channel().Get(channelId) + userChannel := Srv.Store.User().Get(userId) - sc := Srv.Store.Channel().Get(channelId) - uc := Srv.Store.User().Get(c.Session.UserId) + return joinChannel(c, channelChannel, userChannel) +} - if cresult := <-sc; cresult.Err != nil { - c.Err = cresult.Err - return - } else if uresult := <-uc; uresult.Err != nil { - c.Err = uresult.Err - return +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 !c.HasPermissionsToTeam(channel.TeamId, "join") { - return + return c.Err, nil } if channel.Type == model.CHANNEL_OPEN { if _, err := AddUserToChannel(user, channel); err != nil { - c.Err = err - return + return err, nil } PostUserAddRemoveMessageAndForget(c, channel.Id, fmt.Sprintf(utils.T("api.channel.join_channel.post_and_forget"), user.Username)) } else { - c.Err = model.NewLocAppError("join", "api.channel.join_channel.permissions.app_error", nil, "") - c.Err.StatusCode = http.StatusForbidden - return + return model.NewLocAppError("join", "api.channel.join_channel.permissions.app_error", nil, ""), nil } + return nil, channel } } diff --git a/api/channel_test.go b/api/channel_test.go index 23dd77698..8ac785f77 100644 --- a/api/channel_test.go +++ b/api/channel_test.go @@ -395,7 +395,7 @@ func TestGetChannelCounts(t *testing.T) { } -func TestJoinChannel(t *testing.T) { +func TestJoinChannelById(t *testing.T) { th := Setup().InitBasic() Client := th.BasicClient team := th.BasicTeam @@ -425,6 +425,36 @@ func TestJoinChannel(t *testing.T) { } } +func TestJoinChannelByName(t *testing.T) { + th := Setup().InitBasic() + Client := th.BasicClient + team := th.BasicTeam + + channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id} + channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel) + + channel3 := &model.Channel{DisplayName: "B Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id} + channel3 = Client.Must(Client.CreateChannel(channel3)).Data.(*model.Channel) + + th.LoginBasic2() + + Client.Must(Client.JoinChannelByName(channel1.Name)) + + if _, err := Client.JoinChannelByName(channel3.Name); err == nil { + t.Fatal("shouldn't be able to join secret group") + } + + rchannel := Client.Must(Client.CreateDirectChannel(th.BasicUser.Id)).Data.(*model.Channel) + + user3 := th.CreateUser(th.BasicClient) + LinkUserToTeam(user3, team) + Client.LoginByEmail(team.Name, user3.Email, "pwd") + + if _, err := Client.JoinChannelByName(rchannel.Name); err == nil { + t.Fatal("shoudn't be able to join direct channel") + } +} + func TestLeaveChannel(t *testing.T) { th := Setup().InitBasic() Client := th.BasicClient diff --git a/api/command_join.go b/api/command_join.go index f59925c06..af4443306 100644 --- a/api/command_join.go +++ b/api/command_join.go @@ -46,7 +46,7 @@ func (me *JoinProvider) DoCommand(c *Context, channelId string, message string) return &model.CommandResponse{Text: c.T("api.command_join.fail.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL} } - JoinChannel(c, v.Id, "") + JoinChannelById(c, c.Session.UserId, v.Id) if c.Err != nil { c.Err = nil diff --git a/api/post.go b/api/post.go index 4eb87349e..7899145a6 100644 --- a/api/post.go +++ b/api/post.go @@ -27,6 +27,7 @@ func InitPost() { BaseRoutes.NeedTeam.Handle("/posts/search", ApiUserRequired(searchPosts)).Methods("GET") BaseRoutes.NeedTeam.Handle("/posts/{post_id}", ApiUserRequired(getPostById)).Methods("GET") + BaseRoutes.NeedTeam.Handle("/pltmp/{post_id}", ApiUserRequired(getPermalinkTmp)).Methods("GET") BaseRoutes.Posts.Handle("/create", ApiUserRequired(createPost)).Methods("POST") BaseRoutes.Posts.Handle("/update", ApiUserRequired(updatePost)).Methods("POST") @@ -1089,6 +1090,53 @@ func getPostById(c *Context, w http.ResponseWriter, r *http.Request) { } } +func getPermalinkTmp(c *Context, w http.ResponseWriter, r *http.Request) { + params := mux.Vars(r) + + postId := params["post_id"] + if len(postId) != 26 { + c.SetInvalidParam("getPermalinkTmp", "postId") + return + } + + if result := <-Srv.Store.Post().Get(postId); result.Err != nil { + c.Err = result.Err + return + } else { + list := result.Data.(*model.PostList) + + if len(list.Order) != 1 { + c.Err = model.NewLocAppError("getPermalinkTmp", "api.post_get_post_by_id.get.app_error", nil, "") + return + } + post := list.Posts[list.Order[0]] + + if !c.HasPermissionsToTeam(c.TeamId, "permalink") { + return + } + + cchan := Srv.Store.Channel().CheckPermissionsTo(c.TeamId, post.ChannelId, c.Session.UserId) + if !c.HasPermissionsToChannel(cchan, "getPermalinkTmp") { + // If we don't have permissions attempt to join the channel to fix the problem + if err, _ := JoinChannelById(c, c.Session.UserId, post.ChannelId); err != nil { + // On error just return with permissions error + c.Err = err + return + } else { + // If we sucessfully joined the channel then clear the permissions error and continue + c.Err = nil + } + } + + if HandleEtag(list.Etag(), w, r) { + return + } + + w.Header().Set(model.HEADER_ETAG_SERVER, list.Etag()) + w.Write([]byte(list.ToJson())) + } +} + func deletePost(c *Context, w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) -- cgit v1.2.3-1-g7c22