OnIncomingStateRequest is called when a client makes a /rooms/{roomID}/state request. It will fetch all the state events from the specified room and will append the necessary keys to them if applicable before returning them. Returns an error if something went wrong in the process. TODO: Check if the
(ctx context.Context, device *userapi.Device, rsAPI api.ClientRoomserverAPI, roomID string)
| 42 | // is publicly visible. Current behaviour is returning an empty array if the |
| 43 | // user cannot see the room's history. |
| 44 | func OnIncomingStateRequest(ctx context.Context, device *userapi.Device, rsAPI api.ClientRoomserverAPI, roomID string) util.JSONResponse { |
| 45 | var worldReadable bool |
| 46 | var wantLatestState bool |
| 47 | |
| 48 | // First of all, get the latest state of the room. We need to do this |
| 49 | // so that we can look at the history visibility of the room. If the |
| 50 | // room is world-readable then we will always return the latest state. |
| 51 | stateRes := api.QueryLatestEventsAndStateResponse{} |
| 52 | if err := rsAPI.QueryLatestEventsAndState(ctx, &api.QueryLatestEventsAndStateRequest{ |
| 53 | RoomID: roomID, |
| 54 | StateToFetch: []gomatrixserverlib.StateKeyTuple{}, |
| 55 | }, &stateRes); err != nil { |
| 56 | util.GetLogger(ctx).WithError(err).Error("queryAPI.QueryLatestEventsAndState failed") |
| 57 | return jsonerror.InternalServerError() |
| 58 | } |
| 59 | if !stateRes.RoomExists { |
| 60 | return util.JSONResponse{ |
| 61 | Code: http.StatusForbidden, |
| 62 | JSON: jsonerror.Forbidden("room does not exist"), |
| 63 | } |
| 64 | } |
| 65 | |
| 66 | // Look at the room state and see if we have a history visibility event |
| 67 | // that marks the room as world-readable. If we don't then we assume that |
| 68 | // the room is not world-readable. |
| 69 | for _, ev := range stateRes.StateEvents { |
| 70 | if ev.Type() == gomatrixserverlib.MRoomHistoryVisibility { |
| 71 | content := map[string]string{} |
| 72 | if err := json.Unmarshal(ev.Content(), &content); err != nil { |
| 73 | util.GetLogger(ctx).WithError(err).Error("json.Unmarshal for history visibility failed") |
| 74 | return jsonerror.InternalServerError() |
| 75 | } |
| 76 | if visibility, ok := content["history_visibility"]; ok { |
| 77 | worldReadable = visibility == "world_readable" |
| 78 | break |
| 79 | } |
| 80 | } |
| 81 | } |
| 82 | |
| 83 | // If the room isn't world-readable then we will instead try to find out |
| 84 | // the state of the room based on the user's membership. If the user is |
| 85 | // in the room then we'll want the latest state. If the user has never |
| 86 | // been in the room and the room isn't world-readable, then we won't |
| 87 | // return any state. If the user was in the room previously but is no |
| 88 | // longer then we will return the state at the time that the user left. |
| 89 | // membershipRes will only be populated if the room is not world-readable. |
| 90 | var membershipRes api.QueryMembershipForUserResponse |
| 91 | if !worldReadable { |
| 92 | // The room isn't world-readable so try to work out based on the |
| 93 | // user's membership if we want the latest state or not. |
| 94 | err := rsAPI.QueryMembershipForUser(ctx, &api.QueryMembershipForUserRequest{ |
| 95 | RoomID: roomID, |
| 96 | UserID: device.UserID, |
| 97 | }, &membershipRes) |
| 98 | if err != nil { |
| 99 | util.GetLogger(ctx).WithError(err).Error("Failed to QueryMembershipForUser") |
| 100 | return jsonerror.InternalServerError() |
| 101 | } |
no test coverage detected