diff --git a/clientapi/jsonerror/jsonerror.go b/clientapi/jsonerror/jsonerror.go index cde3eb825..74a8178a6 100644 --- a/clientapi/jsonerror/jsonerror.go +++ b/clientapi/jsonerror/jsonerror.go @@ -169,15 +169,16 @@ func NotTrusted(serverName string) *MatrixError { Err: fmt.Sprintf("Untrusted server '%s'", serverName), } } + // BadAlias is an error which is returned when one or more aliases within a // m.room.canonical_alias event do not point to the room ID for which the state // event is to be sent to. func BadAlias(msg string) *MatrixError { - return &MatrixError{"M_BAD_ALIAS", msg} + return &MatrixError{"M_BAD_ALIAS", msg} } // InvalidParam is an error return when an alias from a m.room.canonical_alias // contains a malformed alias func InvalidParam(msg string) *MatrixError { - return &MatrixError{"M_INVALID_PARAM", msg} + return &MatrixError{"M_INVALID_PARAM", msg} } diff --git a/clientapi/routing/directory.go b/clientapi/routing/directory.go index 92d37f622..473b6071a 100644 --- a/clientapi/routing/directory.go +++ b/clientapi/routing/directory.go @@ -15,14 +15,14 @@ package routing import ( + "encoding/json" "fmt" "net/http" - "encoding/json" "github.com/matrix-org/dendrite/clientapi/httputil" "github.com/matrix-org/dendrite/clientapi/jsonerror" - "github.com/matrix-org/dendrite/internal/eventutil" federationSenderAPI "github.com/matrix-org/dendrite/federationsender/api" + "github.com/matrix-org/dendrite/internal/eventutil" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/userapi/api" @@ -196,7 +196,7 @@ func RemoveLocalAlias( req *http.Request, device *api.Device, alias string, - cfg *config.ClientAPI, + cfg *config.ClientAPI, rsAPI roomserverAPI.RoomserverInternalAPI, ) util.JSONResponse { queryReq := roomserverAPI.RemoveRoomAliasRequest{ @@ -223,19 +223,22 @@ func RemoveLocalAlias( } } - var updatedCanonicalAlias *eventutil.CanonicalAlias - updated, resErr := getUpdatedCanonicalAliasState(req, device, queryRes.RoomID, alias, rsAPI, updatedCanonicalAlias) - if resErr != nil { - return *resErr; - } - // If the alias removed is one of the alt_aliases or the canonical one, - // we need to also remove it from the canonical_alias event - if updated { - resErr := updateCanonicalAlias(req, device, queryRes.RoomID, cfg, rsAPI, updatedCanonicalAlias) - if resErr != nil { - return *resErr; - } - } + updatedCanonicalAlias := eventutil.CanonicalAlias{ + Alias: "", + AltAliases: []string{""}, + } + updated, resErr := getUpdatedCanonicalAliasState(req, queryRes.RoomID, alias, rsAPI, &updatedCanonicalAlias) + if resErr != nil { + return *resErr + } + // If the alias removed is one of the alt_aliases or the canonical one, + // we need to also remove it from the canonical_alias event + if updated { + resErr := updateCanonicalAlias(req, device, queryRes.RoomID, cfg, rsAPI, &updatedCanonicalAlias) + if resErr != nil { + return *resErr + } + } return util.JSONResponse{ Code: http.StatusOK, @@ -245,109 +248,105 @@ func RemoveLocalAlias( func getUpdatedCanonicalAliasState( req *http.Request, - device *api.Device, roomID string, - alias string, + alias string, rsAPI roomserverAPI.RoomserverInternalAPI, - updatedCanonicalAlias *eventutil.CanonicalAlias, -) ( bool, *util.JSONResponse ) { - updated := false - stateTuple := gomatrixserverlib.StateKeyTuple{ - EventType: gomatrixserverlib.MRoomCanonicalAlias, - StateKey: "", - } - stateReq := roomserverAPI.QueryCurrentStateRequest { - RoomID: roomID, - StateTuples: []gomatrixserverlib.StateKeyTuple{stateTuple}, - } - stateRes := &roomserverAPI.QueryCurrentStateResponse{} - err := rsAPI.QueryCurrentState(req.Context(), &stateReq, stateRes) - if err != nil { - util.GetLogger(req.Context()).WithError(err).Error("Query state failed") - resErr := jsonerror.InternalServerError() - return false, &resErr - } + updatedCanonicalAlias *eventutil.CanonicalAlias, +) (bool, *util.JSONResponse) { + updated := false + stateTuple := gomatrixserverlib.StateKeyTuple{ + EventType: gomatrixserverlib.MRoomCanonicalAlias, + StateKey: "", + } + stateReq := roomserverAPI.QueryCurrentStateRequest{ + RoomID: roomID, + StateTuples: []gomatrixserverlib.StateKeyTuple{stateTuple}, + } + stateRes := &roomserverAPI.QueryCurrentStateResponse{} + err := rsAPI.QueryCurrentState(req.Context(), &stateReq, stateRes) + if err != nil { + util.GetLogger(req.Context()).WithError(err).Error("Query state failed") + resErr := jsonerror.InternalServerError() + return false, &resErr + } - updatedCanonicalAlias = &eventutil.CanonicalAlias { - Alias: "", - AltAliases: []string{""}, - } - // We try to get the current canonical_alias state, and if found compare its content - // to the removed alias - if canonicalAliasEvent, ok := stateRes.StateEvents[stateTuple]; ok { - canonicalAliasContent := eventutil.CanonicalAlias { - Alias: "", - AltAliases: []string{""}, - } - err := json.Unmarshal(canonicalAliasEvent.Content(), &canonicalAliasContent) - if err != nil { - util.GetLogger(req.Context()).WithError(err).Error("Get canonical_alias event content failed") - resErr := jsonerror.InternalServerError() - return false, &resErr - } - if alias == canonicalAliasContent.Alias { - updated = true - } else { - updatedCanonicalAlias.Alias = canonicalAliasContent.Alias - } - for _, s := range(canonicalAliasContent.AltAliases) { - if alias == s { - updated = true - } else { - updatedCanonicalAlias.AltAliases = append(updatedCanonicalAlias.AltAliases, s) - } - } - } - return updated, nil + // We try to get the current canonical_alias state, and if found compare its content + // to the removed alias + if canonicalAliasEvent, ok := stateRes.StateEvents[stateTuple]; ok { + canonicalAliasContent := eventutil.CanonicalAlias{ + Alias: "", + AltAliases: []string{""}, + } + // TODO handle differently malformed event? + err := json.Unmarshal(canonicalAliasEvent.Content(), &canonicalAliasContent) + if err != nil { + util.GetLogger(req.Context()).WithError(err).Error("Get canonical_alias event content failed") + resErr := jsonerror.InternalServerError() + return false, &resErr + } + if alias == canonicalAliasContent.Alias { + updated = true + } else { + updatedCanonicalAlias.Alias = canonicalAliasContent.Alias + } + for _, s := range canonicalAliasContent.AltAliases { + if alias == s { + updated = true + } else { + updatedCanonicalAlias.AltAliases = append(updatedCanonicalAlias.AltAliases, s) + } + } + } + return updated, nil } func updateCanonicalAlias( req *http.Request, device *api.Device, roomID string, - cfg *config.ClientAPI, + cfg *config.ClientAPI, rsAPI roomserverAPI.RoomserverInternalAPI, - updatedCanonicalAlias *eventutil.CanonicalAlias, + updatedCanonicalAlias *eventutil.CanonicalAlias, ) *util.JSONResponse { - var stateKey = "" - // We create a new canonical_alias event with the new alias and alt_aliase - // May cause some auth problems - builder := gomatrixserverlib.EventBuilder { - Sender: device.UserID, - RoomID: roomID, - Type: gomatrixserverlib.MRoomCanonicalAlias, - StateKey: &stateKey, - } - err := builder.SetContent(updatedCanonicalAlias) - if err != nil { - util.GetLogger(req.Context()).WithError(err).Error("builder.SetContent failed") - resErr := jsonerror.InternalServerError() - return &resErr - } + var stateKey = "" + // We create a new canonical_alias event with the new alias and alt_aliase + // May cause some auth problems + builder := gomatrixserverlib.EventBuilder{ + Sender: device.UserID, + RoomID: roomID, + Type: gomatrixserverlib.MRoomCanonicalAlias, + StateKey: &stateKey, + } + err := builder.SetContent(updatedCanonicalAlias) + if err != nil { + util.GetLogger(req.Context()).WithError(err).Error("builder.SetContent failed") + resErr := jsonerror.InternalServerError() + return &resErr + } - evTime, err := httputil.ParseTSParam(req) - if err != nil { - return &util.JSONResponse{ - Code: http.StatusBadRequest, - JSON: jsonerror.InvalidArgumentValue(err.Error()), - } - } + evTime, err := httputil.ParseTSParam(req) + if err != nil { + return &util.JSONResponse{ + Code: http.StatusBadRequest, + JSON: jsonerror.InvalidArgumentValue(err.Error()), + } + } - // Build the event - e, err := eventutil.QueryAndBuildEvent(req.Context(), &builder, cfg.Matrix, evTime, rsAPI, nil) - if err != nil { - util.GetLogger(req.Context()).WithError(err).Errorf("failed to QueryAndBuildEvent") - resErr := jsonerror.InternalServerError() - return &resErr - } - // Send the event to the room server - err = roomserverAPI.SendEvents(req.Context(), rsAPI, roomserverAPI.KindNew, []*gomatrixserverlib.HeaderedEvent{e}, cfg.Matrix.ServerName, nil) - if err != nil { - util.GetLogger(req.Context()).WithError(err).Errorf("failed to SendEvents") - resErr := jsonerror.InternalServerError() - return &resErr - } - return nil + // Build the event + e, err := eventutil.QueryAndBuildEvent(req.Context(), &builder, cfg.Matrix, evTime, rsAPI, nil) + if err != nil { + util.GetLogger(req.Context()).WithError(err).Errorf("failed to QueryAndBuildEvent") + resErr := jsonerror.InternalServerError() + return &resErr + } + // Send the event to the room server + err = roomserverAPI.SendEvents(req.Context(), rsAPI, roomserverAPI.KindNew, []*gomatrixserverlib.HeaderedEvent{e}, cfg.Matrix.ServerName, nil) + if err != nil { + util.GetLogger(req.Context()).WithError(err).Errorf("failed to SendEvents") + resErr := jsonerror.InternalServerError() + return &resErr + } + return nil } type roomVisibility struct { diff --git a/clientapi/routing/sendevent.go b/clientapi/routing/sendevent.go index dfbfef9c3..5998c22ec 100644 --- a/clientapi/routing/sendevent.go +++ b/clientapi/routing/sendevent.go @@ -15,8 +15,8 @@ package routing import ( - "context" - "encoding/json" + "context" + "encoding/json" "net/http" "sync" "time" @@ -71,7 +71,7 @@ func SendEvent( req *http.Request, device *userapi.Device, roomID, eventType string, txnID, stateKey *string, - federation *gomatrixserverlib.FederationClient, + federation *gomatrixserverlib.FederationClient, cfg *config.ClientAPI, rsAPI api.RoomserverInternalAPI, txnCache *transactions.Cache, @@ -157,7 +157,7 @@ func generateSendEvent( req *http.Request, device *userapi.Device, roomID, eventType string, stateKey *string, - federation *gomatrixserverlib.FederationClient, + federation *gomatrixserverlib.FederationClient, cfg *config.ClientAPI, rsAPI api.RoomserverInternalAPI, ) (*gomatrixserverlib.Event, *util.JSONResponse) { @@ -233,95 +233,94 @@ func generateSendEvent( } } - // If the event is a canonical_alias one, we have to check if each alias is correctly formed - // and if each alias exists pointing to the correct room - if eventType == gomatrixserverlib.MRoomCanonicalAlias { - var content *eventutil.CanonicalAlias - err = json.Unmarshal(builder.Content, &content) - if err != nil { - return nil, &util.JSONResponse{ - Code: http.StatusBadRequest, - JSON: jsonerror.BadJSON(err.Error()), - } - } + // If the event is a canonical_alias one, we have to check if each alias is correctly formed + // and if each alias exists pointing to the correct room + if eventType == gomatrixserverlib.MRoomCanonicalAlias { + var content *eventutil.CanonicalAlias + err = json.Unmarshal(builder.Content, &content) + if err != nil { + return nil, &util.JSONResponse{ + Code: http.StatusBadRequest, + JSON: jsonerror.BadJSON(err.Error()), + } + } - queryRes := api.GetAliasesForRoomIDResponse { - Aliases: make([]string, 1), - } + queryRes := api.GetAliasesForRoomIDResponse{ + Aliases: make([]string, 1), + } - err = rsAPI.GetAliasesForRoomID( - req.Context(), - &api.GetAliasesForRoomIDRequest { - RoomID: roomID, - }, - &queryRes, - ) - if err != nil { - resErr := jsonerror.InternalServerError() - return nil, &resErr - } + err = rsAPI.GetAliasesForRoomID( + req.Context(), + &api.GetAliasesForRoomIDRequest{ + RoomID: roomID, + }, + &queryRes, + ) + if err != nil { + resErr := jsonerror.InternalServerError() + return nil, &resErr + } - //TODO: maybe do something like synapse where state is retrieved in order to only check new aliases - for _, alias := range content.AltAliases { - resErr = checkAlias(req.Context(), device, alias, queryRes.Aliases, federation, cfg) - if resErr != nil { - return nil, resErr - } - } + //TODO: maybe do something like synapse where state is retrieved in order to only check new aliases + for _, alias := range content.AltAliases { + resErr = checkAlias(req.Context(), alias, queryRes.Aliases, federation, cfg) + if resErr != nil { + return nil, resErr + } + } - if content.Alias != "" { - resErr = checkAlias(req.Context(), device, content.Alias, queryRes.Aliases, federation, cfg) - if resErr != nil { - return nil, resErr - } - } - } + if content.Alias != "" { + resErr = checkAlias(req.Context(), content.Alias, queryRes.Aliases, federation, cfg) + if resErr != nil { + return nil, resErr + } + } + } return e.Event, nil } func checkAlias( - ctx context.Context, - device *userapi.Device, + ctx context.Context, alias string, - roomAliases []string, - federation *gomatrixserverlib.FederationClient, + roomAliases []string, + federation *gomatrixserverlib.FederationClient, cfg *config.ClientAPI, ) *util.JSONResponse { - _, domain, err := gomatrixserverlib.SplitID('#', alias) - if err != nil { - return &util.JSONResponse{ - Code: http.StatusBadRequest, - JSON: jsonerror.InvalidParam("Room alias must be in the form '#localpart:domain'"), - } - } - found := false - for _, s := range roomAliases { - if alias == s { - found = true - break - } - } - if !found { - if domain == cfg.Matrix.ServerName { - return &util.JSONResponse{ - Code: http.StatusBadRequest, - JSON: jsonerror.BadAlias("Canonical alias not present in the room aliases"), - } - } - fedRes, fedErr := federation.LookupRoomAlias(ctx, domain, alias) - if fedErr != nil { - // TODO: Return 502 if the remote server errored. - // TODO: Return 504 if the remote server timed out. - util.GetLogger(ctx).WithError(fedErr).Error("federation.LookupRoomAlias failed") - resErr := jsonerror.InternalServerError() - return &resErr - } - if fedRes.RoomID == "" { - return &util.JSONResponse{ - Code: http.StatusBadRequest, - JSON: jsonerror.BadAlias("Canonical alias not present in the room aliases"), - } - } - } - return nil + _, domain, err := gomatrixserverlib.SplitID('#', alias) + if err != nil { + return &util.JSONResponse{ + Code: http.StatusBadRequest, + JSON: jsonerror.InvalidParam("Room alias must be in the form '#localpart:domain'"), + } + } + found := false + for _, s := range roomAliases { + if alias == s { + found = true + break + } + } + if !found { + if domain == cfg.Matrix.ServerName { + return &util.JSONResponse{ + Code: http.StatusBadRequest, + JSON: jsonerror.BadAlias("Canonical alias not present in the room aliases"), + } + } + fedRes, fedErr := federation.LookupRoomAlias(ctx, domain, alias) + if fedErr != nil { + // TODO: Return 502 if the remote server errored. + // TODO: Return 504 if the remote server timed out. + util.GetLogger(ctx).WithError(fedErr).Error("federation.LookupRoomAlias failed") + resErr := jsonerror.InternalServerError() + return &resErr + } + if fedRes.RoomID == "" { + return &util.JSONResponse{ + Code: http.StatusBadRequest, + JSON: jsonerror.BadAlias("Canonical alias not present in the room aliases"), + } + } + } + return nil } diff --git a/internal/eventutil/eventcontent.go b/internal/eventutil/eventcontent.go index df17f43ab..294cffd25 100644 --- a/internal/eventutil/eventcontent.go +++ b/internal/eventutil/eventcontent.go @@ -38,8 +38,8 @@ type HistoryVisibilityContent struct { // CanonicalAlias is the event content for https://matrix.org/docs/spec/client_server/r0.6.0#m-room-canonical-alias type CanonicalAlias struct { - Alias string `json:"alias,omitempty"` - AltAliases []string `json:"alt_aliases,omitempty"` + Alias string `json:"alias,omitempty"` + AltAliases []string `json:"alt_aliases,omitempty"` } // InitialPowerLevelsContent returns the initial values for m.room.power_levels on room creation diff --git a/roomserver/api/alias.go b/roomserver/api/alias.go index bd1af0498..f7d2a32bb 100644 --- a/roomserver/api/alias.go +++ b/roomserver/api/alias.go @@ -83,6 +83,6 @@ type RemoveRoomAliasResponse struct { Found bool `json:"found"` // Did we remove it? Removed bool `json:"removed"` - // The room ID the alias refers to - RoomID string `json:"room_id"` + // The room ID the alias refers to + RoomID string `json:"room_id"` } diff --git a/roomserver/internal/alias.go b/roomserver/internal/alias.go index 8f2597424..55d1042c3 100644 --- a/roomserver/internal/alias.go +++ b/roomserver/internal/alias.go @@ -154,7 +154,7 @@ func (r *RoomserverInternalAPI) RemoveRoomAlias( if err != nil { return fmt.Errorf("r.DB.GetRoomIDForAlias: %w", err) } - response.RoomID = roomID + response.RoomID = roomID if roomID == "" { response.Found = false response.Removed = false