From 46881a68b2559b5a428176ee3e2abbb6825bb3a3 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Tue, 2 Jul 2019 17:09:08 +0100 Subject: [PATCH] Encode URLs properly We were escaping the URL before performing any pattern matching on it. This meant that if you sent data that URLdecoded to a "/", it would count as a "/" in the URL, potentially causing a 404. This was causing some flaky tests with some randomly-generated query parameters. Now, we keep URLs encoded while doing the pattern matching, and only afterwards do we URL decode each query parameter individually before passing them to their respective handler functions. --- clientapi/routing/joinroom.go | 5 +- clientapi/routing/routing.go | 115 ++++++++++++++++++++++++------ common/basecomponent/base.go | 2 +- common/routing.go | 35 +++++++++ federationapi/routing/routing.go | 65 +++++++++++++---- go.mod | 2 +- go.sum | 5 ++ mediaapi/routing/routing.go | 2 +- publicroomsapi/routing/routing.go | 10 ++- syncapi/routing/routing.go | 15 +++- testfile | 2 + 11 files changed, 213 insertions(+), 45 deletions(-) create mode 100644 common/routing.go diff --git a/clientapi/routing/joinroom.go b/clientapi/routing/joinroom.go index c98688de0..d763e578e 100644 --- a/clientapi/routing/joinroom.go +++ b/clientapi/routing/joinroom.go @@ -86,7 +86,10 @@ func JoinRoomByIDOrAlias( } return util.JSONResponse{ Code: http.StatusBadRequest, - JSON: jsonerror.BadJSON("Invalid first character for room ID or alias"), + JSON: jsonerror.BadJSON( + fmt.Sprintf("Invalid first character '%s' for room ID or alias", + []rune(roomIDOrAlias)[0]), // Wrapping with []rune makes this call UTF-8 safe + ), } } diff --git a/clientapi/routing/routing.go b/clientapi/routing/routing.go index b0ced79e7..6673cdb3d 100644 --- a/clientapi/routing/routing.go +++ b/clientapi/routing/routing.go @@ -90,7 +90,10 @@ func Setup( ).Methods(http.MethodPost, http.MethodOptions) r0mux.Handle("/join/{roomIDOrAlias}", common.MakeAuthAPI("join", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } return JoinRoomByIDOrAlias( req, device, vars["roomIDOrAlias"], cfg, federation, producer, queryAPI, aliasAPI, keyRing, accountDB, ) @@ -98,19 +101,28 @@ func Setup( ).Methods(http.MethodPost, http.MethodOptions) r0mux.Handle("/rooms/{roomID}/{membership:(?:join|kick|ban|unban|leave|invite)}", common.MakeAuthAPI("membership", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } return SendMembership(req, accountDB, device, vars["roomID"], vars["membership"], cfg, queryAPI, asAPI, producer) }), ).Methods(http.MethodPost, http.MethodOptions) r0mux.Handle("/rooms/{roomID}/send/{eventType}", common.MakeAuthAPI("send_message", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } return SendEvent(req, device, vars["roomID"], vars["eventType"], nil, nil, cfg, queryAPI, producer, nil) }), ).Methods(http.MethodPost, http.MethodOptions) r0mux.Handle("/rooms/{roomID}/send/{eventType}/{txnID}", common.MakeAuthAPI("send_message", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } txnID := vars["txnID"] return SendEvent(req, device, vars["roomID"], vars["eventType"], &txnID, nil, cfg, queryAPI, producer, transactionsCache) @@ -118,7 +130,10 @@ func Setup( ).Methods(http.MethodPut, http.MethodOptions) r0mux.Handle("/rooms/{roomID}/state/{eventType:[^/]+/?}", common.MakeAuthAPI("send_message", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } emptyString := "" eventType := vars["eventType"] // If there's a trailing slash, remove it @@ -130,7 +145,10 @@ func Setup( ).Methods(http.MethodPut, http.MethodOptions) r0mux.Handle("/rooms/{roomID}/state/{eventType}/{stateKey}", common.MakeAuthAPI("send_message", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } stateKey := vars["stateKey"] return SendEvent(req, device, vars["roomID"], vars["eventType"], nil, &stateKey, cfg, queryAPI, producer, nil) }), @@ -150,21 +168,30 @@ func Setup( r0mux.Handle("/directory/room/{roomAlias}", common.MakeExternalAPI("directory_room", func(req *http.Request) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } return DirectoryRoom(req, vars["roomAlias"], federation, &cfg, aliasAPI) }), ).Methods(http.MethodGet, http.MethodOptions) r0mux.Handle("/directory/room/{roomAlias}", common.MakeAuthAPI("directory_room", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } return SetLocalAlias(req, device, vars["roomAlias"], &cfg, aliasAPI) }), ).Methods(http.MethodPut, http.MethodOptions) r0mux.Handle("/directory/room/{roomAlias}", common.MakeAuthAPI("directory_room", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } return RemoveLocalAlias(req, device, vars["roomAlias"], aliasAPI) }), ).Methods(http.MethodDelete, http.MethodOptions) @@ -183,7 +210,10 @@ func Setup( r0mux.Handle("/rooms/{roomID}/typing/{userID}", common.MakeAuthAPI("rooms_typing", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } return SendTyping(req, device, vars["roomID"], vars["userID"], accountDB, typingProducer) }), ).Methods(http.MethodPut, http.MethodOptions) @@ -223,14 +253,20 @@ func Setup( r0mux.Handle("/user/{userId}/filter", common.MakeAuthAPI("put_filter", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } return PutFilter(req, device, accountDB, vars["userId"]) }), ).Methods(http.MethodPost, http.MethodOptions) r0mux.Handle("/user/{userId}/filter/{filterId}", common.MakeAuthAPI("get_filter", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } return GetFilter(req, device, accountDB, vars["userId"], vars["filterId"]) }), ).Methods(http.MethodGet, http.MethodOptions) @@ -239,21 +275,30 @@ func Setup( r0mux.Handle("/profile/{userID}", common.MakeExternalAPI("profile", func(req *http.Request) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } return GetProfile(req, accountDB, vars["userID"], asAPI) }), ).Methods(http.MethodGet, http.MethodOptions) r0mux.Handle("/profile/{userID}/avatar_url", common.MakeExternalAPI("profile_avatar_url", func(req *http.Request) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } return GetAvatarURL(req, accountDB, vars["userID"], asAPI) }), ).Methods(http.MethodGet, http.MethodOptions) r0mux.Handle("/profile/{userID}/avatar_url", common.MakeAuthAPI("profile_avatar_url", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } return SetAvatarURL(req, accountDB, device, vars["userID"], userUpdateProducer, &cfg, producer, queryAPI) }), ).Methods(http.MethodPut, http.MethodOptions) @@ -262,14 +307,20 @@ func Setup( r0mux.Handle("/profile/{userID}/displayname", common.MakeExternalAPI("profile_displayname", func(req *http.Request) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } return GetDisplayName(req, accountDB, vars["userID"], asAPI) }), ).Methods(http.MethodGet, http.MethodOptions) r0mux.Handle("/profile/{userID}/displayname", common.MakeAuthAPI("profile_displayname", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } return SetDisplayName(req, accountDB, device, vars["userID"], userUpdateProducer, &cfg, producer, queryAPI) }), ).Methods(http.MethodPut, http.MethodOptions) @@ -339,28 +390,40 @@ func Setup( r0mux.Handle("/user/{userID}/account_data/{type}", common.MakeAuthAPI("user_account_data", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } return SaveAccountData(req, accountDB, device, vars["userID"], "", vars["type"], syncProducer) }), ).Methods(http.MethodPut, http.MethodOptions) r0mux.Handle("/user/{userID}/rooms/{roomID}/account_data/{type}", common.MakeAuthAPI("user_account_data", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } return SaveAccountData(req, accountDB, device, vars["userID"], vars["roomID"], vars["type"], syncProducer) }), ).Methods(http.MethodPut, http.MethodOptions) r0mux.Handle("/rooms/{roomID}/members", common.MakeAuthAPI("rooms_members", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } return GetMemberships(req, device, vars["roomID"], false, cfg, queryAPI) }), ).Methods(http.MethodGet, http.MethodOptions) r0mux.Handle("/rooms/{roomID}/joined_members", common.MakeAuthAPI("rooms_members", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } return GetMemberships(req, device, vars["roomID"], true, cfg, queryAPI) }), ).Methods(http.MethodGet, http.MethodOptions) @@ -380,14 +443,20 @@ func Setup( r0mux.Handle("/devices/{deviceID}", common.MakeAuthAPI("get_device", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } return GetDeviceByID(req, deviceDB, device, vars["deviceID"]) }), ).Methods(http.MethodGet, http.MethodOptions) r0mux.Handle("/devices/{deviceID}", common.MakeAuthAPI("device_data", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } return UpdateDeviceByID(req, deviceDB, device, vars["deviceID"]) }), ).Methods(http.MethodPut, http.MethodOptions) diff --git a/common/basecomponent/base.go b/common/basecomponent/base.go index d1f507544..6a20aca3b 100644 --- a/common/basecomponent/base.go +++ b/common/basecomponent/base.go @@ -71,7 +71,7 @@ func NewBaseDendrite(cfg *config.Dendrite, componentName string) *BaseDendrite { componentName: componentName, tracerCloser: closer, Cfg: cfg, - APIMux: mux.NewRouter(), + APIMux: mux.NewRouter().UseEncodedPath(), KafkaConsumer: kafkaConsumer, KafkaProducer: kafkaProducer, } diff --git a/common/routing.go b/common/routing.go new file mode 100644 index 000000000..02f62770e --- /dev/null +++ b/common/routing.go @@ -0,0 +1,35 @@ +// Copyright 2019 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 common + +import ( + "net/url" +) + +// URLDecodeVarMap is a function that iterates through each of the items in a +// map, URL decodes the values, and returns a new map with the decoded values +// under the same key names +func URLDecodeVarMap(vars map[string]string) (decodedVars map[string]string, err error) { + decodedVars = make(map[string]string, len(vars)) + for key, value := range vars { + decoded, err := url.QueryUnescape(value) + if err != nil { + return make(map[string]string, 0), err + } + decodedVars[key] = decoded + } + + return decodedVars, err +} diff --git a/federationapi/routing/routing.go b/federationapi/routing/routing.go index 035d54aa1..7b003d7ba 100644 --- a/federationapi/routing/routing.go +++ b/federationapi/routing/routing.go @@ -64,7 +64,10 @@ func Setup( v1fedmux.Handle("/send/{txnID}/", common.MakeFedAPI( "federation_send", cfg.Matrix.ServerName, keys, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse { - vars := mux.Vars(httpReq) + vars, err := common.URLDecodeVarMap(mux.Vars(httpReq)) + if err != nil { + return util.ErrorResponse(err) + } return Send( httpReq, request, gomatrixserverlib.TransactionID(vars["txnID"]), cfg, query, producer, keys, federation, @@ -75,7 +78,10 @@ func Setup( v1fedmux.Handle("/invite/{roomID}/{eventID}", common.MakeFedAPI( "federation_invite", cfg.Matrix.ServerName, keys, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse { - vars := mux.Vars(httpReq) + vars, err := common.URLDecodeVarMap(mux.Vars(httpReq)) + if err != nil { + return util.ErrorResponse(err) + } return Invite( httpReq, request, vars["roomID"], vars["eventID"], cfg, producer, keys, @@ -92,7 +98,10 @@ func Setup( v1fedmux.Handle("/exchange_third_party_invite/{roomID}", common.MakeFedAPI( "exchange_third_party_invite", cfg.Matrix.ServerName, keys, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse { - vars := mux.Vars(httpReq) + vars, err := common.URLDecodeVarMap(mux.Vars(httpReq)) + if err != nil { + return util.ErrorResponse(err) + } return ExchangeThirdPartyInvite( httpReq, request, vars["roomID"], query, cfg, federation, producer, ) @@ -102,7 +111,10 @@ func Setup( v1fedmux.Handle("/event/{eventID}", common.MakeFedAPI( "federation_get_event", cfg.Matrix.ServerName, keys, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse { - vars := mux.Vars(httpReq) + vars, err := common.URLDecodeVarMap(mux.Vars(httpReq)) + if err != nil { + return util.ErrorResponse(err) + } return GetEvent( httpReq.Context(), request, query, vars["eventID"], ) @@ -112,7 +124,10 @@ func Setup( v1fedmux.Handle("/state/{roomID}", common.MakeFedAPI( "federation_get_event_auth", cfg.Matrix.ServerName, keys, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse { - vars := mux.Vars(httpReq) + vars, err := common.URLDecodeVarMap(mux.Vars(httpReq)) + if err != nil { + return util.ErrorResponse(err) + } return GetState( httpReq.Context(), request, query, vars["roomID"], ) @@ -122,7 +137,10 @@ func Setup( v1fedmux.Handle("/state_ids/{roomID}", common.MakeFedAPI( "federation_get_event_auth", cfg.Matrix.ServerName, keys, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse { - vars := mux.Vars(httpReq) + vars, err := common.URLDecodeVarMap(mux.Vars(httpReq)) + if err != nil { + return util.ErrorResponse(err) + } return GetStateIDs( httpReq.Context(), request, query, vars["roomID"], ) @@ -150,7 +168,10 @@ func Setup( v1fedmux.Handle("/user/devices/{userID}", common.MakeFedAPI( "federation_user_devices", cfg.Matrix.ServerName, keys, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse { - vars := mux.Vars(httpReq) + vars, err := common.URLDecodeVarMap(mux.Vars(httpReq)) + if err != nil { + return util.ErrorResponse(err) + } return GetUserDevices( httpReq, deviceDB, vars["userID"], ) @@ -160,7 +181,10 @@ func Setup( v1fedmux.Handle("/make_join/{roomID}/{userID}", common.MakeFedAPI( "federation_make_join", cfg.Matrix.ServerName, keys, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse { - vars := mux.Vars(httpReq) + vars, err := common.URLDecodeVarMap(mux.Vars(httpReq)) + if err != nil { + return util.ErrorResponse(err) + } roomID := vars["roomID"] userID := vars["userID"] return MakeJoin( @@ -172,7 +196,10 @@ func Setup( v1fedmux.Handle("/send_join/{roomID}/{userID}", common.MakeFedAPI( "federation_send_join", cfg.Matrix.ServerName, keys, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse { - vars := mux.Vars(httpReq) + vars, err := common.URLDecodeVarMap(mux.Vars(httpReq)) + if err != nil { + return util.ErrorResponse(err) + } roomID := vars["roomID"] userID := vars["userID"] return SendJoin( @@ -184,7 +211,10 @@ func Setup( v1fedmux.Handle("/make_leave/{roomID}/{userID}", common.MakeFedAPI( "federation_make_leave", cfg.Matrix.ServerName, keys, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse { - vars := mux.Vars(httpReq) + vars, err := common.URLDecodeVarMap(mux.Vars(httpReq)) + if err != nil { + return util.ErrorResponse(err) + } roomID := vars["roomID"] userID := vars["userID"] return MakeLeave( @@ -196,7 +226,10 @@ func Setup( v1fedmux.Handle("/send_leave/{roomID}/{userID}", common.MakeFedAPI( "federation_send_leave", cfg.Matrix.ServerName, keys, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse { - vars := mux.Vars(httpReq) + vars, err := common.URLDecodeVarMap(mux.Vars(httpReq)) + if err != nil { + return util.ErrorResponse(err) + } roomID := vars["roomID"] userID := vars["userID"] return SendLeave( @@ -215,7 +248,10 @@ func Setup( v1fedmux.Handle("/get_missing_events/{roomID}", common.MakeFedAPI( "federation_get_missing_events", cfg.Matrix.ServerName, keys, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse { - vars := mux.Vars(httpReq) + vars, err := common.URLDecodeVarMap(mux.Vars(httpReq)) + if err != nil { + return util.ErrorResponse(err) + } return GetMissingEvents(httpReq, request, query, vars["roomID"]) }, )).Methods(http.MethodPost) @@ -223,7 +259,10 @@ func Setup( v1fedmux.Handle("/backfill/{roomID}/", common.MakeFedAPI( "federation_backfill", cfg.Matrix.ServerName, keys, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse { - vars := mux.Vars(httpReq) + vars, err := common.URLDecodeVarMap(mux.Vars(httpReq)) + if err != nil { + return util.ErrorResponse(err) + } return Backfill(httpReq, request, query, vars["roomID"], cfg) }, )).Methods(http.MethodGet) diff --git a/go.mod b/go.mod index 574905727..072d9ef30 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/golang/snappy v0.0.0-20170119014723-7db9049039a0 github.com/google/shlex v0.0.0-20150127133951-6f45313302b9 github.com/gorilla/context v1.1.1 - github.com/gorilla/mux v1.3.0 + github.com/gorilla/mux v1.7.3 github.com/jaegertracing/jaeger-client-go v0.0.0-20170921145708-3ad49a1d839b github.com/jaegertracing/jaeger-lib v0.0.0-20170920222118-21a3da6d66fe github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6 diff --git a/go.sum b/go.sum index 250b300b6..ef6e94e10 100644 --- a/go.sum +++ b/go.sum @@ -10,6 +10,7 @@ github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE github.com/crossdock/crossdock-go v0.0.0-20160816171116-049aabb0122b/go.mod h1:v9FBN7gdVTpiD/+LZ7Po0UKvROyT87uLVxTHVky/dlQ= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/eapache/go-resiliency v0.0.0-20160104191539-b86b1ec0dd42 h1:f8ERmXYuaC+kCSv2w+y3rBK/oVu6If4DEm3jywJJ0hc= github.com/eapache/go-resiliency v0.0.0-20160104191539-b86b1ec0dd42/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= @@ -27,6 +28,8 @@ github.com/google/shlex v0.0.0-20150127133951-6f45313302b9/go.mod h1:RpwtwJQFrIE github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.3.0 h1:HwSEKGN6U5T2aAQTfu5pW8fiwjSp3IgwdRbkICydk/c= github.com/gorilla/mux v1.3.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= github.com/jaegertracing/jaeger-client-go v0.0.0-20170921145708-3ad49a1d839b/go.mod h1:HWG7INeOG1ZE17I/S8eeb+svquXmBS/hf1Obi6hJUyQ= github.com/jaegertracing/jaeger-lib v0.0.0-20170920222118-21a3da6d66fe/go.mod h1:VqeqQrZmZr9G4WdLw4ei9tAHU54iJRkfoFHvTTQn4jQ= @@ -117,6 +120,7 @@ golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613 h1:MQ/ZZiDsUapFFiMS+vzwXk golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/net v0.0.0-20170927055102-0a9397675ba3 h1:tTDpczhDVjW6WN3DinzKcw5juwkDTVn22I7MNlfxSXM= golang.org/x/net v0.0.0-20170927055102-0a9397675ba3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190301231341-16b79f2e4e95 h1:fY7Dsw114eJN4boqzVSbpVHO6rTdhq6/GnXeu+PKnzU= golang.org/x/net v0.0.0-20190301231341-16b79f2e4e95/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/sys v0.0.0-20171012164349-43eea11bc926 h1:PY6OU86NqbyZiOzaPnDw6oOjAGtYQqIua16z6y9QkwE= golang.org/x/sys v0.0.0-20171012164349-43eea11bc926/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -134,4 +138,5 @@ gopkg.in/macaroon.v2 v2.0.0/go.mod h1:+I6LnTMkm/uV5ew/0nsulNjL16SK4+C8yDmRUzHR17 gopkg.in/macaroon.v2 v2.1.0/go.mod h1:OUb+TQP/OP0WOerC2Jp/3CwhIKyIa9kQjuc7H24e6/o= gopkg.in/yaml.v2 v2.0.0-20171116090243-287cf08546ab h1:yZ6iByf7GKeJ3gsd1Dr/xaj1DyJ//wxKX1Cdh8LhoAw= gopkg.in/yaml.v2 v2.0.0-20171116090243-287cf08546ab/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/mediaapi/routing/routing.go b/mediaapi/routing/routing.go index fb983ccc2..323834efd 100644 --- a/mediaapi/routing/routing.go +++ b/mediaapi/routing/routing.go @@ -87,7 +87,7 @@ func makeDownloadAPI( // Content-Type will be overridden in case of returning file data, else we respond with JSON-formatted errors w.Header().Set("Content-Type", "application/json") - vars := mux.Vars(req) + vars, _ := common.URLDecodeVarMap(mux.Vars(req)) Download( w, req, diff --git a/publicroomsapi/routing/routing.go b/publicroomsapi/routing/routing.go index 6a4b79b7e..279a1b059 100644 --- a/publicroomsapi/routing/routing.go +++ b/publicroomsapi/routing/routing.go @@ -41,14 +41,20 @@ func Setup(apiMux *mux.Router, deviceDB *devices.Database, publicRoomsDB *storag r0mux.Handle("/directory/list/room/{roomID}", common.MakeExternalAPI("directory_list", func(req *http.Request) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } return directory.GetVisibility(req, publicRoomsDB, vars["roomID"]) }), ).Methods(http.MethodGet, http.MethodOptions) // TODO: Add AS support r0mux.Handle("/directory/list/room/{roomID}", common.MakeAuthAPI("directory_list", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } return directory.SetVisibility(req, publicRoomsDB, vars["roomID"]) }), ).Methods(http.MethodPut, http.MethodOptions) diff --git a/syncapi/routing/routing.go b/syncapi/routing/routing.go index 93d939c30..fcc96512f 100644 --- a/syncapi/routing/routing.go +++ b/syncapi/routing/routing.go @@ -45,17 +45,26 @@ func Setup(apiMux *mux.Router, srp *sync.RequestPool, syncDB *storage.SyncServer })).Methods(http.MethodGet, http.MethodOptions) r0mux.Handle("/rooms/{roomID}/state", common.MakeAuthAPI("room_state", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } return OnIncomingStateRequest(req, syncDB, vars["roomID"]) })).Methods(http.MethodGet, http.MethodOptions) r0mux.Handle("/rooms/{roomID}/state/{type}", common.MakeAuthAPI("room_state", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } return OnIncomingStateTypeRequest(req, syncDB, vars["roomID"], vars["type"], "") })).Methods(http.MethodGet, http.MethodOptions) r0mux.Handle("/rooms/{roomID}/state/{type}/{stateKey}", common.MakeAuthAPI("room_state", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { - vars := mux.Vars(req) + vars, err := common.URLDecodeVarMap(mux.Vars(req)) + if err != nil { + return util.ErrorResponse(err) + } return OnIncomingStateTypeRequest(req, syncDB, vars["roomID"], vars["type"], vars["stateKey"]) })).Methods(http.MethodGet, http.MethodOptions) } diff --git a/testfile b/testfile index ea6fc9172..6e2fb4edf 100644 --- a/testfile +++ b/testfile @@ -142,3 +142,5 @@ Trying to get push rules with unknown rule_id fails with 404 Events come down the correct room local user can join room with version 5 User can invite local user to room with version 5 +Should reject keys claiming to belong to a different user +Enabling an unknown default rule fails with 404