OnIncomingStateTypeRequest is called when a client makes a rooms/{roomID}/state/{type}/{statekey} request. It will look in current state to see if there is an event with that type and state key, if there is then (by default) we return the content, otherwise a 404. If eventFormat=true, sends the whol
( ctx context.Context, device *userapi.Device, rsAPI api.ClientRoomserverAPI, roomID, evType, stateKey string, eventFormat bool, )
| 168 | // is then (by default) we return the content, otherwise a 404. |
| 169 | // If eventFormat=true, sends the whole event else just the content. |
| 170 | func OnIncomingStateTypeRequest( |
| 171 | ctx context.Context, device *userapi.Device, rsAPI api.ClientRoomserverAPI, |
| 172 | roomID, evType, stateKey string, eventFormat bool, |
| 173 | ) util.JSONResponse { |
| 174 | var worldReadable bool |
| 175 | var wantLatestState bool |
| 176 | |
| 177 | // Always fetch visibility so that we can work out whether to show |
| 178 | // the latest events or the last event from when the user was joined. |
| 179 | // Then include the requested event type and state key, assuming it |
| 180 | // isn't for the same. |
| 181 | stateToFetch := []gomatrixserverlib.StateKeyTuple{ |
| 182 | { |
| 183 | EventType: evType, |
| 184 | StateKey: stateKey, |
| 185 | }, |
| 186 | } |
| 187 | if evType != gomatrixserverlib.MRoomHistoryVisibility && stateKey != "" { |
| 188 | stateToFetch = append(stateToFetch, gomatrixserverlib.StateKeyTuple{ |
| 189 | EventType: gomatrixserverlib.MRoomHistoryVisibility, |
| 190 | StateKey: "", |
| 191 | }) |
| 192 | } |
| 193 | |
| 194 | // First of all, get the latest state of the room. We need to do this |
| 195 | // so that we can look at the history visibility of the room. If the |
| 196 | // room is world-readable then we will always return the latest state. |
| 197 | stateRes := api.QueryLatestEventsAndStateResponse{} |
| 198 | if err := rsAPI.QueryLatestEventsAndState(ctx, &api.QueryLatestEventsAndStateRequest{ |
| 199 | RoomID: roomID, |
| 200 | StateToFetch: stateToFetch, |
| 201 | }, &stateRes); err != nil { |
| 202 | util.GetLogger(ctx).WithError(err).Error("queryAPI.QueryLatestEventsAndState failed") |
| 203 | return jsonerror.InternalServerError() |
| 204 | } |
| 205 | |
| 206 | // Look at the room state and see if we have a history visibility event |
| 207 | // that marks the room as world-readable. If we don't then we assume that |
| 208 | // the room is not world-readable. |
| 209 | for _, ev := range stateRes.StateEvents { |
| 210 | if ev.Type() == gomatrixserverlib.MRoomHistoryVisibility { |
| 211 | content := map[string]string{} |
| 212 | if err := json.Unmarshal(ev.Content(), &content); err != nil { |
| 213 | util.GetLogger(ctx).WithError(err).Error("json.Unmarshal for history visibility failed") |
| 214 | return jsonerror.InternalServerError() |
| 215 | } |
| 216 | if visibility, ok := content["history_visibility"]; ok { |
| 217 | worldReadable = visibility == "world_readable" |
| 218 | break |
| 219 | } |
| 220 | } |
| 221 | } |
| 222 | |
| 223 | // If the room isn't world-readable then we will instead try to find out |
| 224 | // the state of the room based on the user's membership. If the user is |
| 225 | // in the room then we'll want the latest state. If the user has never |
| 226 | // been in the room and the room isn't world-readable, then we won't |
| 227 | // return any state. If the user was in the room previously but is no |
no test coverage detected