aboutsummaryrefslogtreecommitdiff
path: root/clientapi
diff options
context:
space:
mode:
authorNeil Alexander <neilalexander@users.noreply.github.com>2021-07-21 16:53:50 +0100
committerGitHub <noreply@github.com>2021-07-21 16:53:50 +0100
commitc1447a58e5de5408d80e0de84c0424342121b06c (patch)
tree860e76d35790c547df26cb554632e9d1cbc76287 /clientapi
parentf0f8c7f0553b55c2e83400ca812b9d64bac00511 (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.go96
-rw-r--r--clientapi/routing/createroom.go2
-rw-r--r--clientapi/routing/directory.go42
-rw-r--r--clientapi/routing/routing.go8
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 {