diff options
author | kegsay <kegan@matrix.org> | 2022-05-06 12:39:26 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-06 12:39:26 +0100 |
commit | 85704eff207f7690d197172abb991ae1ac238239 (patch) | |
tree | 3d43faf35034c270ebaf40a27a75a646e40829d7 /federationapi | |
parent | 4705f5761e620e7f8a35151eeb2007e884847152 (diff) |
Clean up interface definitions (#2427)
* tidy up interfaces
* remove unused GetCreatorIDForAlias
* Add RoomserverUserAPI interface
* Define more interfaces
* Use AppServiceInternalAPI for consistent naming
* clean up federationapi constructor a bit
* Fix monolith in -http mode
Diffstat (limited to 'federationapi')
-rw-r--r-- | federationapi/api/api.go | 76 | ||||
-rw-r--r-- | federationapi/federationapi.go | 17 | ||||
-rw-r--r-- | federationapi/federationapi_test.go | 4 | ||||
-rw-r--r-- | federationapi/internal/perform.go | 30 | ||||
-rw-r--r-- | federationapi/inthttp/client.go | 13 | ||||
-rw-r--r-- | federationapi/inthttp/server.go | 14 | ||||
-rw-r--r-- | federationapi/routing/devices.go | 2 | ||||
-rw-r--r-- | federationapi/routing/keys.go | 4 | ||||
-rw-r--r-- | federationapi/routing/routing.go | 118 | ||||
-rw-r--r-- | federationapi/routing/send.go | 4 |
10 files changed, 151 insertions, 131 deletions
diff --git a/federationapi/api/api.go b/federationapi/api/api.go index 87b03718..fc25194e 100644 --- a/federationapi/api/api.go +++ b/federationapi/api/api.go @@ -10,30 +10,6 @@ import ( "github.com/matrix-org/gomatrixserverlib" ) -// FederationClient is a subset of gomatrixserverlib.FederationClient functions which the fedsender -// implements as proxy calls, with built-in backoff/retries/etc. Errors returned from functions in -// this interface are of type FederationClientError -type FederationClient interface { - gomatrixserverlib.FederatedStateClient - GetUserDevices(ctx context.Context, s gomatrixserverlib.ServerName, userID string) (res gomatrixserverlib.RespUserDevices, err error) - ClaimKeys(ctx context.Context, s gomatrixserverlib.ServerName, oneTimeKeys map[string]map[string]string) (res gomatrixserverlib.RespClaimKeys, err error) - QueryKeys(ctx context.Context, s gomatrixserverlib.ServerName, keys map[string][]string) (res gomatrixserverlib.RespQueryKeys, err error) - MSC2836EventRelationships(ctx context.Context, dst gomatrixserverlib.ServerName, r gomatrixserverlib.MSC2836EventRelationshipsRequest, roomVersion gomatrixserverlib.RoomVersion) (res gomatrixserverlib.MSC2836EventRelationshipsResponse, err error) - MSC2946Spaces(ctx context.Context, dst gomatrixserverlib.ServerName, roomID string, suggestedOnly bool) (res gomatrixserverlib.MSC2946SpacesResponse, err error) - LookupServerKeys(ctx context.Context, s gomatrixserverlib.ServerName, keyRequests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp) ([]gomatrixserverlib.ServerKeys, error) -} - -// FederationClientError is returned from FederationClient methods in the event of a problem. -type FederationClientError struct { - Err string - RetryAfter time.Duration - Blacklisted bool -} - -func (e *FederationClientError) Error() string { - return fmt.Sprintf("%s - (retry_after=%s, blacklisted=%v)", e.Err, e.RetryAfter.String(), e.Blacklisted) -} - // FederationInternalAPI is used to query information from the federation sender. type FederationInternalAPI interface { FederationClient @@ -43,22 +19,7 @@ type FederationInternalAPI interface { QueryServerKeys(ctx context.Context, request *QueryServerKeysRequest, response *QueryServerKeysResponse) error - // Query the server names of the joined hosts in a room. - // Unlike QueryJoinedHostsInRoom, this function returns a de-duplicated slice - // containing only the server names (without information for membership events). - // The response will include this server if they are joined to the room. - QueryJoinedHostServerNamesInRoom( - ctx context.Context, - request *QueryJoinedHostServerNamesInRoomRequest, - response *QueryJoinedHostServerNamesInRoomResponse, - ) error - // Notifies the federation sender that these servers may be online and to retry sending messages. - PerformServersAlive( - ctx context.Context, - request *PerformServersAliveRequest, - response *PerformServersAliveResponse, - ) error - // Broadcasts an EDU to all servers in rooms we are joined to. + // Broadcasts an EDU to all servers in rooms we are joined to. Used in the yggdrasil demos. PerformBroadcastEDU( ctx context.Context, request *PerformBroadcastEDURequest, @@ -67,6 +28,10 @@ type FederationInternalAPI interface { } type ClientFederationAPI interface { + // Query the server names of the joined hosts in a room. + // Unlike QueryJoinedHostsInRoom, this function returns a de-duplicated slice + // containing only the server names (without information for membership events). + // The response will include this server if they are joined to the room. QueryJoinedHostServerNamesInRoom(ctx context.Context, request *QueryJoinedHostServerNamesInRoomRequest, response *QueryJoinedHostServerNamesInRoomResponse) error } @@ -95,6 +60,30 @@ type RoomserverFederationAPI interface { LookupMissingEvents(ctx context.Context, s gomatrixserverlib.ServerName, roomID string, missing gomatrixserverlib.MissingEvents, roomVersion gomatrixserverlib.RoomVersion) (res gomatrixserverlib.RespMissingEvents, err error) } +// FederationClient is a subset of gomatrixserverlib.FederationClient functions which the fedsender +// implements as proxy calls, with built-in backoff/retries/etc. Errors returned from functions in +// this interface are of type FederationClientError +type FederationClient interface { + gomatrixserverlib.FederatedStateClient + GetUserDevices(ctx context.Context, s gomatrixserverlib.ServerName, userID string) (res gomatrixserverlib.RespUserDevices, err error) + ClaimKeys(ctx context.Context, s gomatrixserverlib.ServerName, oneTimeKeys map[string]map[string]string) (res gomatrixserverlib.RespClaimKeys, err error) + QueryKeys(ctx context.Context, s gomatrixserverlib.ServerName, keys map[string][]string) (res gomatrixserverlib.RespQueryKeys, err error) + MSC2836EventRelationships(ctx context.Context, dst gomatrixserverlib.ServerName, r gomatrixserverlib.MSC2836EventRelationshipsRequest, roomVersion gomatrixserverlib.RoomVersion) (res gomatrixserverlib.MSC2836EventRelationshipsResponse, err error) + MSC2946Spaces(ctx context.Context, dst gomatrixserverlib.ServerName, roomID string, suggestedOnly bool) (res gomatrixserverlib.MSC2946SpacesResponse, err error) + LookupServerKeys(ctx context.Context, s gomatrixserverlib.ServerName, keyRequests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp) ([]gomatrixserverlib.ServerKeys, error) +} + +// FederationClientError is returned from FederationClient methods in the event of a problem. +type FederationClientError struct { + Err string + RetryAfter time.Duration + Blacklisted bool +} + +func (e *FederationClientError) Error() string { + return fmt.Sprintf("%s - (retry_after=%s, blacklisted=%v)", e.Err, e.RetryAfter.String(), e.Blacklisted) +} + type QueryServerKeysRequest struct { ServerName gomatrixserverlib.ServerName KeyIDToCriteria map[gomatrixserverlib.KeyID]gomatrixserverlib.PublicKeyNotaryQueryCriteria @@ -174,13 +163,6 @@ type PerformInviteResponse struct { Event *gomatrixserverlib.HeaderedEvent `json:"event"` } -type PerformServersAliveRequest struct { - Servers []gomatrixserverlib.ServerName -} - -type PerformServersAliveResponse struct { -} - // QueryJoinedHostServerNamesInRoomRequest is a request to QueryJoinedHostServerNames type QueryJoinedHostServerNamesInRoomRequest struct { RoomID string `json:"room_id"` diff --git a/federationapi/federationapi.go b/federationapi/federationapi.go index 632994db..e52377c9 100644 --- a/federationapi/federationapi.go +++ b/federationapi/federationapi.go @@ -50,8 +50,8 @@ func AddPublicRoutes( federation *gomatrixserverlib.FederationClient, keyRing gomatrixserverlib.JSONVerifier, rsAPI roomserverAPI.FederationRoomserverAPI, - federationAPI federationAPI.FederationInternalAPI, - keyAPI keyserverAPI.KeyInternalAPI, + fedAPI federationAPI.FederationInternalAPI, + keyAPI keyserverAPI.FederationKeyAPI, servers federationAPI.ServersInRoomProvider, ) { cfg := &base.Cfg.FederationAPI @@ -67,12 +67,23 @@ func AddPublicRoutes( UserAPI: userAPI, } + // the federationapi component is a bit unique in that it attaches public routes AND serves + // internal APIs (because it used to be 2 components: the 2nd being fedsender). As a result, + // the constructor shape is a bit wonky in that it is not valid to AddPublicRoutes without a + // concrete impl of FederationInternalAPI as the public routes and the internal API _should_ + // be the same thing now. + f, ok := fedAPI.(*internal.FederationInternalAPI) + if !ok { + panic("federationapi.AddPublicRoutes called with a FederationInternalAPI impl which was not " + + "FederationInternalAPI. This is a programming error.") + } + routing.Setup( base.PublicFederationAPIMux, base.PublicKeyAPIMux, base.PublicWellKnownAPIMux, cfg, - rsAPI, federationAPI, keyRing, + rsAPI, f, keyRing, federation, userAPI, keyAPI, mscCfg, servers, producer, ) diff --git a/federationapi/federationapi_test.go b/federationapi/federationapi_test.go index 68724164..eedebc6c 100644 --- a/federationapi/federationapi_test.go +++ b/federationapi/federationapi_test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/matrix-org/dendrite/federationapi" + "github.com/matrix-org/dendrite/federationapi/internal" "github.com/matrix-org/dendrite/internal/test" "github.com/matrix-org/dendrite/setup/base" "github.com/matrix-org/dendrite/setup/config" @@ -27,10 +28,9 @@ func TestRoomsV3URLEscapeDoNot404(t *testing.T) { cfg.FederationAPI.Database.ConnectionString = config.DataSource("file::memory:") base := base.NewBaseDendrite(cfg, "Monolith") keyRing := &test.NopJSONVerifier{} - fsAPI := base.FederationAPIHTTPClient() // TODO: This is pretty fragile, as if anything calls anything on these nils this test will break. // Unfortunately, it makes little sense to instantiate these dependencies when we just want to test routing. - federationapi.AddPublicRoutes(base, nil, nil, keyRing, nil, fsAPI, nil, nil) + federationapi.AddPublicRoutes(base, nil, nil, keyRing, nil, &internal.FederationInternalAPI{}, nil, nil) baseURL, cancel := test.ListenAndServe(t, base.PublicFederationAPIMux, true) defer cancel() serverName := gomatrixserverlib.ServerName(strings.TrimPrefix(baseURL, "https://")) diff --git a/federationapi/internal/perform.go b/federationapi/internal/perform.go index aac36cc7..577cb70e 100644 --- a/federationapi/internal/perform.go +++ b/federationapi/internal/perform.go @@ -564,20 +564,6 @@ func (r *FederationInternalAPI) PerformInvite( } // PerformServersAlive implements api.FederationInternalAPI -func (r *FederationInternalAPI) PerformServersAlive( - ctx context.Context, - request *api.PerformServersAliveRequest, - response *api.PerformServersAliveResponse, -) (err error) { - for _, srv := range request.Servers { - _ = r.db.RemoveServerFromBlacklist(srv) - r.queues.RetryServer(srv) - } - - return nil -} - -// PerformServersAlive implements api.FederationInternalAPI func (r *FederationInternalAPI) PerformBroadcastEDU( ctx context.Context, request *api.PerformBroadcastEDURequest, @@ -600,18 +586,18 @@ func (r *FederationInternalAPI) PerformBroadcastEDU( if err = r.queues.SendEDU(edu, r.cfg.Matrix.ServerName, destinations); err != nil { return fmt.Errorf("r.queues.SendEDU: %w", err) } - - wakeReq := &api.PerformServersAliveRequest{ - Servers: destinations, - } - wakeRes := &api.PerformServersAliveResponse{} - if err := r.PerformServersAlive(ctx, wakeReq, wakeRes); err != nil { - return fmt.Errorf("r.PerformServersAlive: %w", err) - } + r.MarkServersAlive(destinations) return nil } +func (r *FederationInternalAPI) MarkServersAlive(destinations []gomatrixserverlib.ServerName) { + for _, srv := range destinations { + _ = r.db.RemoveServerFromBlacklist(srv) + r.queues.RetryServer(srv) + } +} + func sanityCheckAuthChain(authChain []*gomatrixserverlib.Event) error { // sanity check we have a create event and it has a known room version for _, ev := range authChain { diff --git a/federationapi/inthttp/client.go b/federationapi/inthttp/client.go index 01ca6595..295ddc49 100644 --- a/federationapi/inthttp/client.go +++ b/federationapi/inthttp/client.go @@ -23,7 +23,6 @@ const ( FederationAPIPerformLeaveRequestPath = "/federationapi/performLeaveRequest" FederationAPIPerformInviteRequestPath = "/federationapi/performInviteRequest" FederationAPIPerformOutboundPeekRequestPath = "/federationapi/performOutboundPeekRequest" - FederationAPIPerformServersAlivePath = "/federationapi/performServersAlive" FederationAPIPerformBroadcastEDUPath = "/federationapi/performBroadcastEDU" FederationAPIGetUserDevicesPath = "/federationapi/client/getUserDevices" @@ -97,18 +96,6 @@ func (h *httpFederationInternalAPI) PerformOutboundPeek( return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } -func (h *httpFederationInternalAPI) PerformServersAlive( - ctx context.Context, - request *api.PerformServersAliveRequest, - response *api.PerformServersAliveResponse, -) error { - span, ctx := opentracing.StartSpanFromContext(ctx, "PerformServersAlive") - defer span.Finish() - - apiURL := h.federationAPIURL + FederationAPIPerformServersAlivePath - return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) -} - // QueryJoinedHostServerNamesInRoom implements FederationInternalAPI func (h *httpFederationInternalAPI) QueryJoinedHostServerNamesInRoom( ctx context.Context, diff --git a/federationapi/inthttp/server.go b/federationapi/inthttp/server.go index ca4930f2..28e52b32 100644 --- a/federationapi/inthttp/server.go +++ b/federationapi/inthttp/server.go @@ -82,20 +82,6 @@ func AddRoutes(intAPI api.FederationInternalAPI, internalAPIMux *mux.Router) { }), ) internalAPIMux.Handle( - FederationAPIPerformServersAlivePath, - httputil.MakeInternalAPI("PerformServersAliveRequest", func(req *http.Request) util.JSONResponse { - var request api.PerformServersAliveRequest - var response api.PerformServersAliveResponse - if err := json.NewDecoder(req.Body).Decode(&request); err != nil { - return util.MessageResponse(http.StatusBadRequest, err.Error()) - } - if err := intAPI.PerformServersAlive(req.Context(), &request, &response); err != nil { - return util.ErrorResponse(err) - } - return util.JSONResponse{Code: http.StatusOK, JSON: &response} - }), - ) - internalAPIMux.Handle( FederationAPIPerformBroadcastEDUPath, httputil.MakeInternalAPI("PerformBroadcastEDU", func(req *http.Request) util.JSONResponse { var request api.PerformBroadcastEDURequest diff --git a/federationapi/routing/devices.go b/federationapi/routing/devices.go index 57286fa9..1a092645 100644 --- a/federationapi/routing/devices.go +++ b/federationapi/routing/devices.go @@ -26,7 +26,7 @@ import ( // GetUserDevices for the given user id func GetUserDevices( req *http.Request, - keyAPI keyapi.KeyInternalAPI, + keyAPI keyapi.FederationKeyAPI, userID string, ) util.JSONResponse { var res keyapi.QueryDeviceMessagesResponse diff --git a/federationapi/routing/keys.go b/federationapi/routing/keys.go index 49a6c558..b1a9b671 100644 --- a/federationapi/routing/keys.go +++ b/federationapi/routing/keys.go @@ -37,7 +37,7 @@ type queryKeysRequest struct { // QueryDeviceKeys returns device keys for users on this server. // https://matrix.org/docs/spec/server_server/latest#post-matrix-federation-v1-user-keys-query func QueryDeviceKeys( - httpReq *http.Request, request *gomatrixserverlib.FederationRequest, keyAPI api.KeyInternalAPI, thisServer gomatrixserverlib.ServerName, + httpReq *http.Request, request *gomatrixserverlib.FederationRequest, keyAPI api.FederationKeyAPI, thisServer gomatrixserverlib.ServerName, ) util.JSONResponse { var qkr queryKeysRequest err := json.Unmarshal(request.Content(), &qkr) @@ -89,7 +89,7 @@ type claimOTKsRequest struct { // ClaimOneTimeKeys claims OTKs for users on this server. // https://matrix.org/docs/spec/server_server/latest#post-matrix-federation-v1-user-keys-claim func ClaimOneTimeKeys( - httpReq *http.Request, request *gomatrixserverlib.FederationRequest, keyAPI api.KeyInternalAPI, thisServer gomatrixserverlib.ServerName, + httpReq *http.Request, request *gomatrixserverlib.FederationRequest, keyAPI api.FederationKeyAPI, thisServer gomatrixserverlib.ServerName, ) util.JSONResponse { var cor claimOTKsRequest err := json.Unmarshal(request.Content(), &cor) diff --git a/federationapi/routing/routing.go b/federationapi/routing/routing.go index 51adc279..9f95ed07 100644 --- a/federationapi/routing/routing.go +++ b/federationapi/routing/routing.go @@ -18,10 +18,14 @@ import ( "context" "fmt" "net/http" + "sync" + "time" + "github.com/getsentry/sentry-go" "github.com/gorilla/mux" "github.com/matrix-org/dendrite/clientapi/jsonerror" federationAPI "github.com/matrix-org/dendrite/federationapi/api" + fedInternal "github.com/matrix-org/dendrite/federationapi/internal" "github.com/matrix-org/dendrite/federationapi/producers" "github.com/matrix-org/dendrite/internal" "github.com/matrix-org/dendrite/internal/httputil" @@ -48,11 +52,11 @@ func Setup( fedMux, keyMux, wkMux *mux.Router, cfg *config.FederationAPI, rsAPI roomserverAPI.FederationRoomserverAPI, - fsAPI federationAPI.FederationInternalAPI, + fsAPI *fedInternal.FederationInternalAPI, keys gomatrixserverlib.JSONVerifier, federation *gomatrixserverlib.FederationClient, userAPI userapi.FederationUserAPI, - keyAPI keyserverAPI.KeyInternalAPI, + keyAPI keyserverAPI.FederationKeyAPI, mscCfg *config.MSCs, servers federationAPI.ServersInRoomProvider, producer *producers.SyncAPIProducer, @@ -65,7 +69,7 @@ func Setup( v1fedmux := fedMux.PathPrefix("/v1").Subrouter() v2fedmux := fedMux.PathPrefix("/v2").Subrouter() - wakeup := &httputil.FederationWakeups{ + wakeup := &FederationWakeups{ FsAPI: fsAPI, } @@ -119,7 +123,7 @@ func Setup( v2keysmux.Handle("/query/{serverName}/{keyID}", notaryKeys).Methods(http.MethodGet) mu := internal.NewMutexByRoom() - v1fedmux.Handle("/send/{txnID}", httputil.MakeFedAPI( + v1fedmux.Handle("/send/{txnID}", MakeFedAPI( "federation_send", cfg.Matrix.ServerName, keys, wakeup, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest, vars map[string]string) util.JSONResponse { return Send( @@ -129,7 +133,7 @@ func Setup( }, )).Methods(http.MethodPut, http.MethodOptions) - v1fedmux.Handle("/invite/{roomID}/{eventID}", httputil.MakeFedAPI( + v1fedmux.Handle("/invite/{roomID}/{eventID}", MakeFedAPI( "federation_invite", cfg.Matrix.ServerName, keys, wakeup, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest, vars map[string]string) util.JSONResponse { if roomserverAPI.IsServerBannedFromRoom(httpReq.Context(), rsAPI, vars["roomID"], request.Origin()) { @@ -145,7 +149,7 @@ func Setup( }, )).Methods(http.MethodPut, http.MethodOptions) - v2fedmux.Handle("/invite/{roomID}/{eventID}", httputil.MakeFedAPI( + v2fedmux.Handle("/invite/{roomID}/{eventID}", MakeFedAPI( "federation_invite", cfg.Matrix.ServerName, keys, wakeup, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest, vars map[string]string) util.JSONResponse { if roomserverAPI.IsServerBannedFromRoom(httpReq.Context(), rsAPI, vars["roomID"], request.Origin()) { @@ -167,7 +171,7 @@ func Setup( }, )).Methods(http.MethodPost, http.MethodOptions) - v1fedmux.Handle("/exchange_third_party_invite/{roomID}", httputil.MakeFedAPI( + v1fedmux.Handle("/exchange_third_party_invite/{roomID}", MakeFedAPI( "exchange_third_party_invite", cfg.Matrix.ServerName, keys, wakeup, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest, vars map[string]string) util.JSONResponse { return ExchangeThirdPartyInvite( @@ -176,7 +180,7 @@ func Setup( }, )).Methods(http.MethodPut, http.MethodOptions) - v1fedmux.Handle("/event/{eventID}", httputil.MakeFedAPI( + v1fedmux.Handle("/event/{eventID}", MakeFedAPI( "federation_get_event", cfg.Matrix.ServerName, keys, wakeup, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest, vars map[string]string) util.JSONResponse { return GetEvent( @@ -185,7 +189,7 @@ func Setup( }, )).Methods(http.MethodGet) - v1fedmux.Handle("/state/{roomID}", httputil.MakeFedAPI( + v1fedmux.Handle("/state/{roomID}", MakeFedAPI( "federation_get_state", cfg.Matrix.ServerName, keys, wakeup, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest, vars map[string]string) util.JSONResponse { if roomserverAPI.IsServerBannedFromRoom(httpReq.Context(), rsAPI, vars["roomID"], request.Origin()) { @@ -200,7 +204,7 @@ func Setup( }, )).Methods(http.MethodGet) - v1fedmux.Handle("/state_ids/{roomID}", httputil.MakeFedAPI( + v1fedmux.Handle("/state_ids/{roomID}", MakeFedAPI( "federation_get_state_ids", cfg.Matrix.ServerName, keys, wakeup, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest, vars map[string]string) util.JSONResponse { if roomserverAPI.IsServerBannedFromRoom(httpReq.Context(), rsAPI, vars["roomID"], request.Origin()) { @@ -215,7 +219,7 @@ func Setup( }, )).Methods(http.MethodGet) - v1fedmux.Handle("/event_auth/{roomID}/{eventID}", httputil.MakeFedAPI( + v1fedmux.Handle("/event_auth/{roomID}/{eventID}", MakeFedAPI( "federation_get_event_auth", cfg.Matrix.ServerName, keys, wakeup, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest, vars map[string]string) util.JSONResponse { if roomserverAPI.IsServerBannedFromRoom(httpReq.Context(), rsAPI, vars["roomID"], request.Origin()) { @@ -230,7 +234,7 @@ func Setup( }, )).Methods(http.MethodGet) - v1fedmux.Handle("/query/directory", httputil.MakeFedAPI( + v1fedmux.Handle("/query/directory", MakeFedAPI( "federation_query_room_alias", cfg.Matrix.ServerName, keys, wakeup, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest, vars map[string]string) util.JSONResponse { return RoomAliasToID( @@ -239,7 +243,7 @@ func Setup( }, )).Methods(http.MethodGet) - v1fedmux.Handle("/query/profile", httputil.MakeFedAPI( + v1fedmux.Handle("/query/profile", MakeFedAPI( "federation_query_profile", cfg.Matrix.ServerName, keys, wakeup, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest, vars map[string]string) util.JSONResponse { return GetProfile( @@ -248,7 +252,7 @@ func Setup( }, )).Methods(http.MethodGet) - v1fedmux.Handle("/user/devices/{userID}", httputil.MakeFedAPI( + v1fedmux.Handle("/user/devices/{userID}", MakeFedAPI( "federation_user_devices", cfg.Matrix.ServerName, keys, wakeup, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest, vars map[string]string) util.JSONResponse { return GetUserDevices( @@ -258,7 +262,7 @@ func Setup( )).Methods(http.MethodGet) if mscCfg.Enabled("msc2444") { - v1fedmux.Handle("/peek/{roomID}/{peekID}", httputil.MakeFedAPI( + v1fedmux.Handle("/peek/{roomID}/{peekID}", MakeFedAPI( "federation_peek", cfg.Matrix.ServerName, keys, wakeup, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest, vars map[string]string) util.JSONResponse { if roomserverAPI.IsServerBannedFromRoom(httpReq.Context(), rsAPI, vars["roomID"], request.Origin()) { @@ -289,7 +293,7 @@ func Setup( )).Methods(http.MethodPut, http.MethodDelete) } - v1fedmux.Handle("/make_join/{roomID}/{userID}", httputil.MakeFedAPI( + v1fedmux.Handle("/make_join/{roomID}/{userID}", MakeFedAPI( "federation_make_join", cfg.Matrix.ServerName, keys, wakeup, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest, vars map[string]string) util.JSONResponse { if roomserverAPI.IsServerBannedFromRoom(httpReq.Context(), rsAPI, vars["roomID"], request.Origin()) { @@ -320,7 +324,7 @@ func Setup( }, )).Methods(http.MethodGet) - v1fedmux.Handle("/send_join/{roomID}/{eventID}", httputil.MakeFedAPI( + v1fedmux.Handle("/send_join/{roomID}/{eventID}", MakeFedAPI( "federation_send_join", cfg.Matrix.ServerName, keys, wakeup, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest, vars map[string]string) util.JSONResponse { if roomserverAPI.IsServerBannedFromRoom(httpReq.Context(), rsAPI, vars["roomID"], request.Origin()) { @@ -352,7 +356,7 @@ func Setup( }, )).Methods(http.MethodPut) - v2fedmux.Handle("/send_join/{roomID}/{eventID}", httputil.MakeFedAPI( + v2fedmux.Handle("/send_join/{roomID}/{eventID}", MakeFedAPI( "federation_send_join", cfg.Matrix.ServerName, keys, wakeup, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest, vars map[string]string) util.JSONResponse { if roomserverAPI.IsServerBannedFromRoom(httpReq.Context(), rsAPI, vars["roomID"], request.Origin()) { @@ -369,7 +373,7 @@ func Setup( }, )).Methods(http.MethodPut) - v1fedmux.Handle("/make_leave/{roomID}/{eventID}", httputil.MakeFedAPI( + v1fedmux.Handle("/make_leave/{roomID}/{eventID}", MakeFedAPI( "federation_make_leave", cfg.Matrix.ServerName, keys, wakeup, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest, vars map[string]string) util.JSONResponse { if roomserverAPI.IsServerBannedFromRoom(httpReq.Context(), rsAPI, vars["roomID"], request.Origin()) { @@ -386,7 +390,7 @@ func Setup( }, )).Methods(http.MethodGet) - v1fedmux.Handle("/send_leave/{roomID}/{eventID}", httputil.MakeFedAPI( + v1fedmux.Handle("/send_leave/{roomID}/{eventID}", MakeFedAPI( "federation_send_leave", cfg.Matrix.ServerName, keys, wakeup, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest, vars map[string]string) util.JSONResponse { if roomserverAPI.IsServerBannedFromRoom(httpReq.Context(), rsAPI, vars["roomID"], request.Origin()) { @@ -418,7 +422,7 @@ func Setup( }, )).Methods(http.MethodPut) - v2fedmux.Handle("/send_leave/{roomID}/{eventID}", httputil.MakeFedAPI( + v2fedmux.Handle("/send_leave/{roomID}/{eventID}", MakeFedAPI( "federation_send_leave", cfg.Matrix.ServerName, keys, wakeup, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest, vars map[string]string) util.JSONResponse { if roomserverAPI.IsServerBannedFromRoom(httpReq.Context(), rsAPI, vars["roomID"], request.Origin()) { @@ -442,7 +446,7 @@ func Setup( }, )).Methods(http.MethodGet) - v1fedmux.Handle("/get_missing_events/{roomID}", httputil.MakeFedAPI( + v1fedmux.Handle("/get_missing_events/{roomID}", MakeFedAPI( "federation_get_missing_events", cfg.Matrix.ServerName, keys, wakeup, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest, vars map[string]string) util.JSONResponse { if roomserverAPI.IsServerBannedFromRoom(httpReq.Context(), rsAPI, vars["roomID"], request.Origin()) { @@ -455,7 +459,7 @@ func Setup( }, )).Methods(http.MethodPost) - v1fedmux.Handle("/backfill/{roomID}", httputil.MakeFedAPI( + v1fedmux.Handle("/backfill/{roomID}", MakeFedAPI( "federation_backfill", cfg.Matrix.ServerName, keys, wakeup, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest, vars map[string]string) util.JSONResponse { if roomserverAPI.IsServerBannedFromRoom(httpReq.Context(), rsAPI, vars["roomID"], request.Origin()) { @@ -474,14 +478,14 @@ func Setup( }), ).Methods(http.MethodGet, http.MethodPost) - v1fedmux.Handle("/user/keys/claim", httputil.MakeFedAPI( + v1fedmux.Handle("/user/keys/claim", MakeFedAPI( "federation_keys_claim", cfg.Matrix.ServerName, keys, wakeup, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest, vars map[string]string) util.JSONResponse { return ClaimOneTimeKeys(httpReq, request, keyAPI, cfg.Matrix.ServerName) }, )).Methods(http.MethodPost) - v1fedmux.Handle("/user/keys/query", httputil.MakeFedAPI( + v1fedmux.Handle("/user/keys/query", MakeFedAPI( "federation_keys_query", cfg.Matrix.ServerName, keys, wakeup, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest, vars map[string]string) util.JSONResponse { return QueryDeviceKeys(httpReq, request, keyAPI, cfg.Matrix.ServerName) @@ -518,3 +522,67 @@ func ErrorIfLocalServerNotInRoom( } return nil } + +// MakeFedAPI makes an http.Handler that checks matrix federation authentication. +func MakeFedAPI( + metricsName string, + serverName gomatrixserverlib.ServerName, + keyRing gomatrixserverlib.JSONVerifier, + wakeup *FederationWakeups, + f func(*http.Request, *gomatrixserverlib.FederationRequest, map[string]string) util.JSONResponse, +) http.Handler { + h := func(req *http.Request) util.JSONResponse { + fedReq, errResp := gomatrixserverlib.VerifyHTTPRequest( + req, time.Now(), serverName, keyRing, + ) + if fedReq == nil { + return errResp + } + // add the user to Sentry, if enabled + hub := sentry.GetHubFromContext(req.Context()) + if hub != nil { + hub.Scope().SetTag("origin", string(fedReq.Origin())) + hub.Scope().SetTag("uri", fedReq.RequestURI()) + } + defer func() { + if r := recover(); r != nil { + if hub != nil { + hub.CaptureException(fmt.Errorf("%s panicked", req.URL.Path)) + } + // re-panic to return the 500 + panic(r) + } + }() + go wakeup.Wakeup(req.Context(), fedReq.Origin()) + vars, err := httputil.URLDecodeMapValues(mux.Vars(req)) + if err != nil { + return util.MatrixErrorResponse(400, "M_UNRECOGNISED", "badly encoded query params") + } + + jsonRes := f(req, fedReq, vars) + // do not log 4xx as errors as they are client fails, not server fails + if hub != nil && jsonRes.Code >= 500 { + hub.Scope().SetExtra("response", jsonRes) + hub.CaptureException(fmt.Errorf("%s returned HTTP %d", req.URL.Path, jsonRes.Code)) + } + return jsonRes + } + return httputil.MakeExternalAPI(metricsName, h) +} + +type FederationWakeups struct { + FsAPI *fedInternal.FederationInternalAPI + origins sync.Map +} + +func (f *FederationWakeups) Wakeup(ctx context.Context, origin gomatrixserverlib.ServerName) { + key, keyok := f.origins.Load(origin) + if keyok { + lastTime, ok := key.(time.Time) + if ok && time.Since(lastTime) < time.Minute { + return + } + } + f.FsAPI.MarkServersAlive([]gomatrixserverlib.ServerName{origin}) + f.origins.Store(origin, time.Now()) +} diff --git a/federationapi/routing/send.go b/federationapi/routing/send.go index b9b6d33b..55a11367 100644 --- a/federationapi/routing/send.go +++ b/federationapi/routing/send.go @@ -83,7 +83,7 @@ func Send( txnID gomatrixserverlib.TransactionID, cfg *config.FederationAPI, rsAPI api.FederationRoomserverAPI, - keyAPI keyapi.KeyInternalAPI, + keyAPI keyapi.FederationKeyAPI, keys gomatrixserverlib.JSONVerifier, federation *gomatrixserverlib.FederationClient, mu *internal.MutexByRoom, @@ -183,7 +183,7 @@ func Send( type txnReq struct { gomatrixserverlib.Transaction rsAPI api.FederationRoomserverAPI - keyAPI keyapi.KeyInternalAPI + keyAPI keyapi.FederationKeyAPI ourServerName gomatrixserverlib.ServerName keys gomatrixserverlib.JSONVerifier federation txnFederationClient |