diff options
Diffstat (limited to 'clientapi/routing/memberships.go')
-rw-r--r-- | clientapi/routing/memberships.go | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/clientapi/routing/memberships.go b/clientapi/routing/memberships.go new file mode 100644 index 00000000..84be498d --- /dev/null +++ b/clientapi/routing/memberships.go @@ -0,0 +1,139 @@ +// Copyright 2024 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package routing + +import ( + "encoding/json" + "net/http" + + "github.com/matrix-org/dendrite/roomserver/api" + userapi "github.com/matrix-org/dendrite/userapi/api" + "github.com/matrix-org/gomatrixserverlib/spec" + "github.com/matrix-org/util" +) + +// https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-rooms-roomid-joined-members +type getJoinedMembersResponse struct { + Joined map[string]joinedMember `json:"joined"` +} + +type joinedMember struct { + DisplayName string `json:"display_name"` + AvatarURL string `json:"avatar_url"` +} + +// The database stores 'displayname' without an underscore. +// Deserialize into this and then change to the actual API response +type databaseJoinedMember struct { + DisplayName string `json:"displayname"` + AvatarURL string `json:"avatar_url"` +} + +// GetJoinedMembers implements +// +// GET /rooms/{roomId}/joined_members +func GetJoinedMembers( + req *http.Request, device *userapi.Device, roomID string, + rsAPI api.ClientRoomserverAPI, +) util.JSONResponse { + // Validate the userID + userID, err := spec.NewUserID(device.UserID, true) + if err != nil { + return util.JSONResponse{ + Code: http.StatusBadRequest, + JSON: spec.InvalidParam("Device UserID is invalid"), + } + } + + // Validate the roomID + validRoomID, err := spec.NewRoomID(roomID) + if err != nil { + return util.JSONResponse{ + Code: http.StatusBadRequest, + JSON: spec.InvalidParam("RoomID is invalid"), + } + } + + // Get the current memberships for the requesting user to determine + // if they are allowed to query this endpoint. + queryReq := api.QueryMembershipForUserRequest{ + RoomID: validRoomID.String(), + UserID: *userID, + } + + var queryRes api.QueryMembershipForUserResponse + if queryErr := rsAPI.QueryMembershipForUser(req.Context(), &queryReq, &queryRes); queryErr != nil { + util.GetLogger(req.Context()).WithError(queryErr).Error("rsAPI.QueryMembershipsForRoom failed") + return util.JSONResponse{ + Code: http.StatusInternalServerError, + JSON: spec.InternalServerError{}, + } + } + + if !queryRes.HasBeenInRoom { + return util.JSONResponse{ + Code: http.StatusForbidden, + JSON: spec.Forbidden("You aren't a member of the room and weren't previously a member of the room."), + } + } + + if !queryRes.IsInRoom { + return util.JSONResponse{ + Code: http.StatusForbidden, + JSON: spec.Forbidden("You aren't a member of the room and weren't previously a member of the room."), + } + } + + // Get the current membership events + var membershipsForRoomResp api.QueryMembershipsForRoomResponse + if err = rsAPI.QueryMembershipsForRoom(req.Context(), &api.QueryMembershipsForRoomRequest{ + JoinedOnly: true, + RoomID: validRoomID.String(), + }, &membershipsForRoomResp); err != nil { + util.GetLogger(req.Context()).WithError(err).Error("rsAPI.QueryEventsByID failed") + return util.JSONResponse{ + Code: http.StatusInternalServerError, + JSON: spec.InternalServerError{}, + } + } + + var res getJoinedMembersResponse + res.Joined = make(map[string]joinedMember) + for _, ev := range membershipsForRoomResp.JoinEvents { + var content databaseJoinedMember + if err := json.Unmarshal(ev.Content, &content); err != nil { + util.GetLogger(req.Context()).WithError(err).Error("failed to unmarshal event content") + return util.JSONResponse{ + Code: http.StatusInternalServerError, + JSON: spec.InternalServerError{}, + } + } + + userID, err := rsAPI.QueryUserIDForSender(req.Context(), *validRoomID, spec.SenderID(ev.Sender)) + if err != nil || userID == nil { + util.GetLogger(req.Context()).WithError(err).Error("rsAPI.QueryUserIDForSender failed") + return util.JSONResponse{ + Code: http.StatusInternalServerError, + JSON: spec.InternalServerError{}, + } + } + + res.Joined[userID.String()] = joinedMember(content) + } + return util.JSONResponse{ + Code: http.StatusOK, + JSON: res, + } +} |