diff options
author | Neil Alexander <neilalexander@users.noreply.github.com> | 2021-07-21 16:53:50 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-21 16:53:50 +0100 |
commit | c1447a58e5de5408d80e0de84c0424342121b06c (patch) | |
tree | 860e76d35790c547df26cb554632e9d1cbc76287 /clientapi | |
parent | f0f8c7f0553b55c2e83400ca812b9d64bac00511 (diff) |
Various alias fixes (#1934)
* Generate m.room.canonical_alias instead of legacy m.room.aliases
* Add omitempty tags
* Add aliases endpoint to client API
* Check power levels when setting aliases
* Don't return null on /aliases
* Don't return error if the state event fails
* Update sytest-whitelist
* Don't send updated m.room.canonical_alias events
* Don't check PLs after all because for local aliases they are apparently irrelevant
* Fix some bugs
* Allow deleting a local alias with enough PL
* Fix some more bugs
* Update sytest-whitelist
* Fix copyright notices
* Review comments
Diffstat (limited to 'clientapi')
-rw-r--r-- | clientapi/routing/aliases.go | 96 | ||||
-rw-r--r-- | clientapi/routing/createroom.go | 2 | ||||
-rw-r--r-- | clientapi/routing/directory.go | 42 | ||||
-rw-r--r-- | clientapi/routing/routing.go | 8 |
4 files changed, 119 insertions, 29 deletions
diff --git a/clientapi/routing/aliases.go b/clientapi/routing/aliases.go new file mode 100644 index 00000000..8c483053 --- /dev/null +++ b/clientapi/routing/aliases.go @@ -0,0 +1,96 @@ +// Copyright 2021 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 ( + "fmt" + "net/http" + + "github.com/matrix-org/dendrite/clientapi/jsonerror" + "github.com/matrix-org/dendrite/roomserver/api" + userapi "github.com/matrix-org/dendrite/userapi/api" + "github.com/matrix-org/gomatrixserverlib" + + "github.com/matrix-org/util" +) + +// GetAliases implements GET /_matrix/client/r0/rooms/{roomId}/aliases +func GetAliases( + req *http.Request, rsAPI api.RoomserverInternalAPI, device *userapi.Device, roomID string, +) util.JSONResponse { + stateTuple := gomatrixserverlib.StateKeyTuple{ + EventType: gomatrixserverlib.MRoomHistoryVisibility, + StateKey: "", + } + stateReq := &api.QueryCurrentStateRequest{ + RoomID: roomID, + StateTuples: []gomatrixserverlib.StateKeyTuple{stateTuple}, + } + stateRes := &api.QueryCurrentStateResponse{} + if err := rsAPI.QueryCurrentState(req.Context(), stateReq, stateRes); err != nil { + util.GetLogger(req.Context()).WithError(err).Error("rsAPI.QueryCurrentState failed") + return util.ErrorResponse(fmt.Errorf("rsAPI.QueryCurrentState: %w", err)) + } + + visibility := "invite" + if historyVisEvent, ok := stateRes.StateEvents[stateTuple]; ok { + var err error + visibility, err = historyVisEvent.HistoryVisibility() + if err != nil { + util.GetLogger(req.Context()).WithError(err).Error("historyVisEvent.HistoryVisibility failed") + return util.ErrorResponse(fmt.Errorf("historyVisEvent.HistoryVisibility: %w", err)) + } + } + if visibility != gomatrixserverlib.WorldReadable { + queryReq := api.QueryMembershipForUserRequest{ + RoomID: roomID, + UserID: device.UserID, + } + var queryRes api.QueryMembershipForUserResponse + if err := rsAPI.QueryMembershipForUser(req.Context(), &queryReq, &queryRes); err != nil { + util.GetLogger(req.Context()).WithError(err).Error("rsAPI.QueryMembershipsForRoom failed") + return jsonerror.InternalServerError() + } + if !queryRes.IsInRoom { + return util.JSONResponse{ + Code: http.StatusForbidden, + JSON: jsonerror.Forbidden("You aren't a member of this room."), + } + } + } + + aliasesReq := api.GetAliasesForRoomIDRequest{ + RoomID: roomID, + } + aliasesRes := api.GetAliasesForRoomIDResponse{} + if err := rsAPI.GetAliasesForRoomID(req.Context(), &aliasesReq, &aliasesRes); err != nil { + util.GetLogger(req.Context()).WithError(err).Error("rsAPI.GetAliasesForRoomID failed") + return util.ErrorResponse(fmt.Errorf("rsAPI.GetAliasesForRoomID: %w", err)) + } + + response := struct { + Aliases []string `json:"aliases"` + }{ + Aliases: aliasesRes.Aliases, + } + if response.Aliases == nil { + response.Aliases = []string{} // pleases sytest + } + + return util.JSONResponse{ + Code: 200, + JSON: response, + } +} diff --git a/clientapi/routing/createroom.go b/clientapi/routing/createroom.go index 4219bb37..b3b996ec 100644 --- a/clientapi/routing/createroom.go +++ b/clientapi/routing/createroom.go @@ -383,7 +383,6 @@ func createRoom( // 10- m.room.topic (opt) // 11- invite events (opt) - with is_direct flag if applicable TODO // 12- 3pid invite events (opt) TODO - // 13- m.room.aliases event for HS (if alias specified) TODO // This differs from Synapse slightly. Synapse would vary the ordering of 3-7 // depending on if those events were in "initial_state" or not. This made it // harder to reason about, hence sticking to a strict static ordering. @@ -404,7 +403,6 @@ func createRoom( if aliasEvent != nil { // TODO: bit of a chicken and egg problem here as the alias doesn't exist and cannot until we have made the room. // This means we might fail creating the alias but say the canonical alias is something that doesn't exist. - // m.room.aliases is handled when we call roomserver.SetRoomAlias eventsToMake = append(eventsToMake, *aliasEvent) } diff --git a/clientapi/routing/directory.go b/clientapi/routing/directory.go index 0e994b64..ae466065 100644 --- a/clientapi/routing/directory.go +++ b/clientapi/routing/directory.go @@ -113,13 +113,12 @@ func DirectoryRoom( } // SetLocalAlias implements PUT /directory/room/{roomAlias} -// TODO: Check if the user has the power level to set an alias func SetLocalAlias( req *http.Request, device *api.Device, alias string, cfg *config.ClientAPI, - aliasAPI roomserverAPI.RoomserverInternalAPI, + rsAPI roomserverAPI.RoomserverInternalAPI, ) util.JSONResponse { _, domain, err := gomatrixserverlib.SplitID('#', alias) if err != nil { @@ -172,7 +171,7 @@ func SetLocalAlias( Alias: alias, } var queryRes roomserverAPI.SetRoomAliasResponse - if err := aliasAPI.SetRoomAlias(req.Context(), &queryReq, &queryRes); err != nil { + if err := rsAPI.SetRoomAlias(req.Context(), &queryReq, &queryRes); err != nil { util.GetLogger(req.Context()).WithError(err).Error("aliasAPI.SetRoomAlias failed") return jsonerror.InternalServerError() } @@ -195,43 +194,32 @@ func RemoveLocalAlias( req *http.Request, device *api.Device, alias string, - aliasAPI roomserverAPI.RoomserverInternalAPI, + rsAPI roomserverAPI.RoomserverInternalAPI, ) util.JSONResponse { - - creatorQueryReq := roomserverAPI.GetCreatorIDForAliasRequest{ - Alias: alias, + queryReq := roomserverAPI.RemoveRoomAliasRequest{ + Alias: alias, + UserID: device.UserID, } - var creatorQueryRes roomserverAPI.GetCreatorIDForAliasResponse - if err := aliasAPI.GetCreatorIDForAlias(req.Context(), &creatorQueryReq, &creatorQueryRes); err != nil { - util.GetLogger(req.Context()).WithError(err).Error("aliasAPI.GetCreatorIDForAlias failed") + var queryRes roomserverAPI.RemoveRoomAliasResponse + if err := rsAPI.RemoveRoomAlias(req.Context(), &queryReq, &queryRes); err != nil { + util.GetLogger(req.Context()).WithError(err).Error("aliasAPI.RemoveRoomAlias failed") return jsonerror.InternalServerError() } - if creatorQueryRes.UserID == "" { + if !queryRes.Found { return util.JSONResponse{ Code: http.StatusNotFound, - JSON: jsonerror.NotFound("Alias does not exist"), + JSON: jsonerror.NotFound("The alias does not exist."), } } - if creatorQueryRes.UserID != device.UserID { - // TODO: Still allow deletion if user is admin + if !queryRes.Removed { return util.JSONResponse{ Code: http.StatusForbidden, - JSON: jsonerror.Forbidden("You do not have permission to delete this alias"), + JSON: jsonerror.Forbidden("You do not have permission to remove this alias."), } } - queryReq := roomserverAPI.RemoveRoomAliasRequest{ - Alias: alias, - UserID: device.UserID, - } - var queryRes roomserverAPI.RemoveRoomAliasResponse - if err := aliasAPI.RemoveRoomAlias(req.Context(), &queryReq, &queryRes); err != nil { - util.GetLogger(req.Context()).WithError(err).Error("aliasAPI.RemoveRoomAlias failed") - return jsonerror.InternalServerError() - } - return util.JSONResponse{ Code: http.StatusOK, JSON: struct{}{}, @@ -294,9 +282,9 @@ func SetVisibility( return jsonerror.InternalServerError() } - // NOTSPEC: Check if the user's power is greater than power required to change m.room.aliases event + // NOTSPEC: Check if the user's power is greater than power required to change m.room.canonical_alias event power, _ := gomatrixserverlib.NewPowerLevelContentFromEvent(queryEventsRes.StateEvents[0].Event) - if power.UserLevel(dev.UserID) < power.EventLevel(gomatrixserverlib.MRoomAliases, true) { + if power.UserLevel(dev.UserID) < power.EventLevel(gomatrixserverlib.MRoomCanonicalAlias, true) { return util.JSONResponse{ Code: http.StatusForbidden, JSON: jsonerror.Forbidden("userID doesn't have power level to change visibility"), diff --git a/clientapi/routing/routing.go b/clientapi/routing/routing.go index 37279e8e..d768247a 100644 --- a/clientapi/routing/routing.go +++ b/clientapi/routing/routing.go @@ -275,6 +275,14 @@ func Setup( return OnIncomingStateRequest(req.Context(), device, rsAPI, vars["roomID"]) })).Methods(http.MethodGet, http.MethodOptions) + r0mux.Handle("/rooms/{roomID}/aliases", httputil.MakeAuthAPI("aliases", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse { + vars, err := httputil.URLDecodeMapValues(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } + return GetAliases(req, rsAPI, device, vars["roomID"]) + })).Methods(http.MethodGet, http.MethodOptions) + r0mux.Handle("/rooms/{roomID}/state/{type:[^/]+/?}", httputil.MakeAuthAPI("room_state", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse { vars, err := httputil.URLDecodeMapValues(mux.Vars(req)) if err != nil { |