mirror of
https://github.com/matrix-org/dendrite.git
synced 2026-01-17 11:03:11 -06:00
Issue: matrix room id does not always resolve to spaceId or channelId correctly. Root cause: The clientApi routing endpoint and the syncapi routing endpoint uses different stores to query for the current room states. One is correct, the other has incomplete events. Fix the issue by using the correct store in both routing code paths.
253 lines
8.8 KiB
Go
253 lines
8.8 KiB
Go
// Copyright 2017 Vector Creations Ltd
|
|
//
|
|
// 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 (
|
|
"net/http"
|
|
|
|
"github.com/gorilla/mux"
|
|
"github.com/matrix-org/gomatrixserverlib"
|
|
"github.com/matrix-org/util"
|
|
|
|
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
|
"github.com/matrix-org/dendrite/clientapi/routing"
|
|
"github.com/matrix-org/dendrite/internal/caching"
|
|
"github.com/matrix-org/dendrite/internal/fulltext"
|
|
"github.com/matrix-org/dendrite/internal/httputil"
|
|
"github.com/matrix-org/dendrite/roomserver/api"
|
|
"github.com/matrix-org/dendrite/setup/config"
|
|
"github.com/matrix-org/dendrite/syncapi/storage"
|
|
"github.com/matrix-org/dendrite/syncapi/sync"
|
|
|
|
authz "github.com/matrix-org/dendrite/authorization"
|
|
clientApiAuthz "github.com/matrix-org/dendrite/clientapi/authorization"
|
|
userapi "github.com/matrix-org/dendrite/userapi/api"
|
|
zion "github.com/matrix-org/dendrite/zion"
|
|
)
|
|
|
|
// Setup configures the given mux with sync-server listeners
|
|
//
|
|
// Due to Setup being used to call many other functions, a gocyclo nolint is
|
|
// applied:
|
|
// nolint: gocyclo
|
|
func Setup(
|
|
csMux *mux.Router, srp *sync.RequestPool, syncDB storage.Database,
|
|
userAPI userapi.SyncUserAPI,
|
|
rsAPI api.SyncRoomserverAPI,
|
|
crsAPI api.ClientRoomserverAPI,
|
|
cfg *config.SyncAPI,
|
|
clientCfg *config.ClientAPI,
|
|
lazyLoadCache caching.LazyLoadCache,
|
|
fts *fulltext.Search,
|
|
) {
|
|
authorization := clientApiAuthz.NewRoomserverAuthorization(clientCfg, crsAPI)
|
|
v1unstablemux := csMux.PathPrefix("/{apiversion:(?:v1|unstable)}/").Subrouter()
|
|
v3mux := csMux.PathPrefix("/{apiversion:(?:r0|v3)}/").Subrouter()
|
|
|
|
// TODO: Add AS support for all handlers below.
|
|
v3mux.Handle("/sync", httputil.MakeAuthAPI("sync", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
|
return srp.OnIncomingSyncRequest(req, device)
|
|
})).Methods(http.MethodGet, http.MethodOptions)
|
|
|
|
v3mux.Handle("/rooms/{roomID}/messages", httputil.MakeAuthAPI("room_messages", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
|
|
|
if err != nil {
|
|
return util.ErrorResponse(err)
|
|
}
|
|
|
|
isAllowed, err := authorization.IsAllowed(authz.AuthorizationArgs{
|
|
RoomId: vars["roomID"],
|
|
UserId: device.UserID,
|
|
Permission: authz.PermissionRead,
|
|
})
|
|
|
|
if err != nil {
|
|
switch err {
|
|
case zion.ErrSpaceDisabled, zion.ErrChannelDisabled:
|
|
// leave space / channel if it is disabled
|
|
resp := routing.LeaveRoomByID(req, device, crsAPI, vars["roomID"])
|
|
if resp.Code == 200 {
|
|
return util.JSONResponse{
|
|
Code: http.StatusUnauthorized,
|
|
JSON: jsonerror.ServerDisabledNoticeError(),
|
|
}
|
|
}
|
|
return resp
|
|
default:
|
|
// error client if something else is awry
|
|
return util.JSONResponse{
|
|
Code: http.StatusUnauthorized,
|
|
JSON: jsonerror.Forbidden("Unauthorised"),
|
|
}
|
|
}
|
|
}
|
|
|
|
if !isAllowed {
|
|
return util.JSONResponse{
|
|
Code: http.StatusUnauthorized,
|
|
JSON: jsonerror.Forbidden("Unauthorised"),
|
|
}
|
|
}
|
|
|
|
return OnIncomingMessagesRequest(req, syncDB, vars["roomID"], device, rsAPI, cfg, srp, lazyLoadCache)
|
|
})).Methods(http.MethodGet, http.MethodOptions)
|
|
|
|
v3mux.Handle("/rooms/{roomID}/event/{eventID}",
|
|
httputil.MakeAuthAPI("rooms_get_event", 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 GetEvent(req, device, vars["roomID"], vars["eventID"], cfg, syncDB, rsAPI)
|
|
}),
|
|
).Methods(http.MethodGet, http.MethodOptions)
|
|
|
|
v3mux.Handle("/user/{userId}/filter",
|
|
httputil.MakeAuthAPI("put_filter", 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 PutFilter(req, device, syncDB, vars["userId"])
|
|
}),
|
|
).Methods(http.MethodPost, http.MethodOptions)
|
|
|
|
v3mux.Handle("/user/{userId}/filter/{filterId}",
|
|
httputil.MakeAuthAPI("get_filter", 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 GetFilter(req, device, syncDB, vars["userId"], vars["filterId"])
|
|
}),
|
|
).Methods(http.MethodGet, http.MethodOptions)
|
|
|
|
v3mux.Handle("/keys/changes", httputil.MakeAuthAPI("keys_changes", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
|
return srp.OnIncomingKeyChangeRequest(req, device)
|
|
})).Methods(http.MethodGet, http.MethodOptions)
|
|
|
|
v3mux.Handle("/rooms/{roomId}/context/{eventId}",
|
|
httputil.MakeAuthAPI(gomatrixserverlib.Join, 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 Context(
|
|
req, device,
|
|
rsAPI, syncDB,
|
|
vars["roomId"], vars["eventId"],
|
|
lazyLoadCache,
|
|
)
|
|
}),
|
|
).Methods(http.MethodGet, http.MethodOptions)
|
|
|
|
v1unstablemux.Handle("/rooms/{roomId}/relations/{eventId}",
|
|
httputil.MakeAuthAPI(gomatrixserverlib.Join, 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 Relations(
|
|
req, device, syncDB, rsAPI,
|
|
vars["roomId"], vars["eventId"], "", "",
|
|
)
|
|
}),
|
|
).Methods(http.MethodGet, http.MethodOptions)
|
|
|
|
v1unstablemux.Handle("/rooms/{roomId}/relations/{eventId}/{relType}",
|
|
httputil.MakeAuthAPI(gomatrixserverlib.Join, 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 Relations(
|
|
req, device, syncDB, rsAPI,
|
|
vars["roomId"], vars["eventId"], vars["relType"], "",
|
|
)
|
|
}),
|
|
).Methods(http.MethodGet, http.MethodOptions)
|
|
|
|
v1unstablemux.Handle("/rooms/{roomId}/relations/{eventId}/{relType}/{eventType}",
|
|
httputil.MakeAuthAPI(gomatrixserverlib.Join, 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 Relations(
|
|
req, device, syncDB, rsAPI,
|
|
vars["roomId"], vars["eventId"], vars["relType"], vars["eventType"],
|
|
)
|
|
}),
|
|
).Methods(http.MethodGet, http.MethodOptions)
|
|
|
|
v3mux.Handle("/search",
|
|
httputil.MakeAuthAPI("search", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
|
if !cfg.Fulltext.Enabled {
|
|
return util.JSONResponse{
|
|
Code: http.StatusNotImplemented,
|
|
JSON: jsonerror.Unknown("Search has been disabled by the server administrator."),
|
|
}
|
|
}
|
|
var nextBatch *string
|
|
if err := req.ParseForm(); err != nil {
|
|
return jsonerror.InternalServerError()
|
|
}
|
|
if req.Form.Has("next_batch") {
|
|
nb := req.FormValue("next_batch")
|
|
nextBatch = &nb
|
|
}
|
|
return Search(req, device, syncDB, fts, nextBatch)
|
|
}),
|
|
).Methods(http.MethodPost, http.MethodOptions)
|
|
|
|
v3mux.Handle("/rooms/{roomID}/members",
|
|
httputil.MakeAuthAPI("rooms_members", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
|
if err != nil {
|
|
return util.ErrorResponse(err)
|
|
}
|
|
var membership, notMembership *string
|
|
if req.URL.Query().Has("membership") {
|
|
m := req.URL.Query().Get("membership")
|
|
membership = &m
|
|
}
|
|
if req.URL.Query().Has("not_membership") {
|
|
m := req.URL.Query().Get("not_membership")
|
|
notMembership = &m
|
|
}
|
|
|
|
at := req.URL.Query().Get("at")
|
|
return GetMemberships(req, device, vars["roomID"], syncDB, rsAPI, false, membership, notMembership, at)
|
|
}),
|
|
).Methods(http.MethodGet, http.MethodOptions)
|
|
|
|
v3mux.Handle("/rooms/{roomID}/joined_members",
|
|
httputil.MakeAuthAPI("rooms_members", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
|
if err != nil {
|
|
return util.ErrorResponse(err)
|
|
}
|
|
at := req.URL.Query().Get("at")
|
|
membership := gomatrixserverlib.Join
|
|
return GetMemberships(req, device, vars["roomID"], syncDB, rsAPI, true, &membership, nil, at)
|
|
}),
|
|
).Methods(http.MethodGet, http.MethodOptions)
|
|
}
|