fedsender: GetServerKeys -> QueryServerKeys

As it now checks a cache and can return multiple responses
This commit is contained in:
Kegan Dougal 2021-07-15 16:52:49 +01:00
parent 82bcaaf69f
commit bbd7b7b4f5
7 changed files with 89 additions and 74 deletions

View file

@ -188,40 +188,52 @@ func NotaryKeys(
} }
response.ServerKeys = []json.RawMessage{} response.ServerKeys = []json.RawMessage{}
for serverName := range req.ServerKeys { for serverName, kidToCriteria := range req.ServerKeys {
var keys *gomatrixserverlib.ServerKeys var keyList []gomatrixserverlib.ServerKeys
if serverName == cfg.Matrix.ServerName { if serverName == cfg.Matrix.ServerName {
if k, err := localKeys(cfg, time.Now().Add(cfg.Matrix.KeyValidityPeriod)); err == nil { if k, err := localKeys(cfg, time.Now().Add(cfg.Matrix.KeyValidityPeriod)); err == nil {
keys = k keyList = append(keyList, *k)
} else { } else {
return util.ErrorResponse(err) return util.ErrorResponse(err)
} }
} else { } else {
if k, err := fsAPI.GetServerKeys(httpReq.Context(), serverName); err == nil { kids := make([]gomatrixserverlib.KeyID, len(kidToCriteria))
keys = &k i := 0
} else { for kid := range kidToCriteria {
kids[i] = kid
i++
}
var resp federationSenderAPI.QueryServerKeysResponse
err := fsAPI.QueryServerKeys(httpReq.Context(), &federationSenderAPI.QueryServerKeysRequest{
ServerName: serverName,
OptionalKeyIDs: kids,
}, &resp)
if err != nil {
return util.ErrorResponse(err) return util.ErrorResponse(err)
} }
keyList = append(keyList, resp.ServerKeys...)
} }
if keys == nil { if len(keyList) == 0 {
continue continue
} }
j, err := json.Marshal(keys) for _, keys := range keyList {
if err != nil { j, err := json.Marshal(keys)
logrus.WithError(err).Errorf("Failed to marshal %q response", serverName) if err != nil {
return jsonerror.InternalServerError() logrus.WithError(err).Errorf("Failed to marshal %q response", serverName)
} return jsonerror.InternalServerError()
}
js, err := gomatrixserverlib.SignJSON( js, err := gomatrixserverlib.SignJSON(
string(cfg.Matrix.ServerName), cfg.Matrix.KeyID, cfg.Matrix.PrivateKey, j, string(cfg.Matrix.ServerName), cfg.Matrix.KeyID, cfg.Matrix.PrivateKey, j,
) )
if err != nil { if err != nil {
logrus.WithError(err).Errorf("Failed to sign %q response", serverName) logrus.WithError(err).Errorf("Failed to sign %q response", serverName)
return jsonerror.InternalServerError() return jsonerror.InternalServerError()
} }
response.ServerKeys = append(response.ServerKeys, js) response.ServerKeys = append(response.ServerKeys, js)
}
} }
return util.JSONResponse{ return util.JSONResponse{

View file

@ -20,7 +20,6 @@ type FederationClient interface {
ClaimKeys(ctx context.Context, s gomatrixserverlib.ServerName, oneTimeKeys map[string]map[string]string) (res gomatrixserverlib.RespClaimKeys, 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) QueryKeys(ctx context.Context, s gomatrixserverlib.ServerName, keys map[string][]string) (res gomatrixserverlib.RespQueryKeys, err error)
GetEvent(ctx context.Context, s gomatrixserverlib.ServerName, eventID string) (res gomatrixserverlib.Transaction, err error) GetEvent(ctx context.Context, s gomatrixserverlib.ServerName, eventID string) (res gomatrixserverlib.Transaction, err error)
GetServerKeys(ctx context.Context, matrixServer gomatrixserverlib.ServerName) (gomatrixserverlib.ServerKeys, error)
MSC2836EventRelationships(ctx context.Context, dst gomatrixserverlib.ServerName, r gomatrixserverlib.MSC2836EventRelationshipsRequest, roomVersion gomatrixserverlib.RoomVersion) (res gomatrixserverlib.MSC2836EventRelationshipsResponse, 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, r gomatrixserverlib.MSC2946SpacesRequest) (res gomatrixserverlib.MSC2946SpacesResponse, err error) MSC2946Spaces(ctx context.Context, dst gomatrixserverlib.ServerName, roomID string, r gomatrixserverlib.MSC2946SpacesRequest) (res gomatrixserverlib.MSC2946SpacesResponse, err error)
LookupServerKeys(ctx context.Context, s gomatrixserverlib.ServerName, keyRequests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp) ([]gomatrixserverlib.ServerKeys, error) LookupServerKeys(ctx context.Context, s gomatrixserverlib.ServerName, keyRequests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp) ([]gomatrixserverlib.ServerKeys, error)
@ -41,6 +40,8 @@ func (e *FederationClientError) Error() string {
type FederationSenderInternalAPI interface { type FederationSenderInternalAPI interface {
FederationClient FederationClient
QueryServerKeys(ctx context.Context, request *QueryServerKeysRequest, response *QueryServerKeysResponse) error
// PerformDirectoryLookup looks up a remote room ID from a room alias. // PerformDirectoryLookup looks up a remote room ID from a room alias.
PerformDirectoryLookup( PerformDirectoryLookup(
ctx context.Context, ctx context.Context,
@ -94,6 +95,15 @@ type FederationSenderInternalAPI interface {
) error ) error
} }
type QueryServerKeysRequest struct {
ServerName gomatrixserverlib.ServerName
OptionalKeyIDs []gomatrixserverlib.KeyID
}
type QueryServerKeysResponse struct {
ServerKeys []gomatrixserverlib.ServerKeys
}
type PerformDirectoryLookupRequest struct { type PerformDirectoryLookupRequest struct {
RoomAlias string `json:"room_alias"` RoomAlias string `json:"room_alias"`
ServerName gomatrixserverlib.ServerName `json:"server_name"` ServerName gomatrixserverlib.ServerName `json:"server_name"`

View file

@ -202,20 +202,6 @@ func (a *FederationSenderInternalAPI) GetEvent(
return ires.(gomatrixserverlib.Transaction), nil return ires.(gomatrixserverlib.Transaction), nil
} }
func (a *FederationSenderInternalAPI) GetServerKeys(
ctx context.Context, s gomatrixserverlib.ServerName,
) (gomatrixserverlib.ServerKeys, error) {
ctx, cancel := context.WithTimeout(ctx, time.Second*30)
defer cancel()
ires, err := a.doRequest(s, func() (interface{}, error) {
return a.federation.GetServerKeys(ctx, s)
})
if err != nil {
return gomatrixserverlib.ServerKeys{}, err
}
return ires.(gomatrixserverlib.ServerKeys), nil
}
func (a *FederationSenderInternalAPI) LookupServerKeys( func (a *FederationSenderInternalAPI) LookupServerKeys(
ctx context.Context, s gomatrixserverlib.ServerName, keyRequests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp, ctx context.Context, s gomatrixserverlib.ServerName, keyRequests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp,
) ([]gomatrixserverlib.ServerKeys, error) { ) ([]gomatrixserverlib.ServerKeys, error) {

View file

@ -2,8 +2,12 @@ package internal
import ( import (
"context" "context"
"fmt"
"time"
"github.com/matrix-org/dendrite/federationsender/api" "github.com/matrix-org/dendrite/federationsender/api"
"github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util"
) )
// QueryJoinedHostServerNamesInRoom implements api.FederationSenderInternalAPI // QueryJoinedHostServerNamesInRoom implements api.FederationSenderInternalAPI
@ -20,3 +24,30 @@ func (f *FederationSenderInternalAPI) QueryJoinedHostServerNamesInRoom(
return return
} }
func (a *FederationSenderInternalAPI) QueryServerKeys(
ctx context.Context, req *api.QueryServerKeysRequest, res *api.QueryServerKeysResponse,
) error {
ctx, cancel := context.WithTimeout(ctx, time.Second*30)
defer cancel()
ires, err := a.doRequest(req.ServerName, func() (interface{}, error) {
return a.federation.GetServerKeys(ctx, req.ServerName)
})
if err != nil {
// try to load from the cache
serverKeysResponses, dbErr := a.db.GetNotaryKeys(ctx, req.ServerName, req.OptionalKeyIDs)
if dbErr != nil {
return fmt.Errorf("server returned %s, and db returned %s", err, dbErr)
}
res.ServerKeys = serverKeysResponses
return nil
}
serverKeys := ires.(gomatrixserverlib.ServerKeys)
// cache it!
if err = a.db.UpdateNotaryKeys(context.Background(), req.ServerName, serverKeys); err != nil {
// non-fatal, still return the response
util.GetLogger(ctx).WithError(err).Warn("failed to UpdateNotaryKeys")
}
res.ServerKeys = []gomatrixserverlib.ServerKeys{serverKeys}
return nil
}

View file

@ -15,6 +15,7 @@ import (
// HTTP paths for the internal HTTP API // HTTP paths for the internal HTTP API
const ( const (
FederationSenderQueryJoinedHostServerNamesInRoomPath = "/federationsender/queryJoinedHostServerNamesInRoom" FederationSenderQueryJoinedHostServerNamesInRoomPath = "/federationsender/queryJoinedHostServerNamesInRoom"
FederationSenderQueryServerKeysPath = "/federationsender/queryServerKeys"
FederationSenderPerformDirectoryLookupRequestPath = "/federationsender/performDirectoryLookup" FederationSenderPerformDirectoryLookupRequestPath = "/federationsender/performDirectoryLookup"
FederationSenderPerformJoinRequestPath = "/federationsender/performJoinRequest" FederationSenderPerformJoinRequestPath = "/federationsender/performJoinRequest"
@ -31,7 +32,6 @@ const (
FederationSenderLookupStatePath = "/federationsender/client/lookupState" FederationSenderLookupStatePath = "/federationsender/client/lookupState"
FederationSenderLookupStateIDsPath = "/federationsender/client/lookupStateIDs" FederationSenderLookupStateIDsPath = "/federationsender/client/lookupStateIDs"
FederationSenderGetEventPath = "/federationsender/client/getEvent" FederationSenderGetEventPath = "/federationsender/client/getEvent"
FederationSenderGetServerKeysPath = "/federationsender/client/getServerKeys"
FederationSenderLookupServerKeysPath = "/federationsender/client/lookupServerKeys" FederationSenderLookupServerKeysPath = "/federationsender/client/lookupServerKeys"
FederationSenderEventRelationshipsPath = "/federationsender/client/msc2836eventRelationships" FederationSenderEventRelationshipsPath = "/federationsender/client/msc2836eventRelationships"
FederationSenderSpacesSummaryPath = "/federationsender/client/msc2946spacesSummary" FederationSenderSpacesSummaryPath = "/federationsender/client/msc2946spacesSummary"
@ -377,31 +377,14 @@ func (h *httpFederationSenderInternalAPI) GetEvent(
return *response.Res, nil return *response.Res, nil
} }
type getServerKeys struct { func (h *httpFederationSenderInternalAPI) QueryServerKeys(
S gomatrixserverlib.ServerName ctx context.Context, req *api.QueryServerKeysRequest, res *api.QueryServerKeysResponse,
ServerKeys gomatrixserverlib.ServerKeys ) error {
Err *api.FederationClientError span, ctx := opentracing.StartSpanFromContext(ctx, "QueryServerKeys")
}
func (h *httpFederationSenderInternalAPI) GetServerKeys(
ctx context.Context, s gomatrixserverlib.ServerName,
) (gomatrixserverlib.ServerKeys, error) {
span, ctx := opentracing.StartSpanFromContext(ctx, "GetServerKeys")
defer span.Finish() defer span.Finish()
request := getServerKeys{ apiURL := h.federationSenderURL + FederationSenderQueryServerKeysPath
S: s, return httputil.PostJSON(ctx, span, h.httpClient, apiURL, req, res)
}
var response getServerKeys
apiURL := h.federationSenderURL + FederationSenderGetServerKeysPath
err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, &request, &response)
if err != nil {
return gomatrixserverlib.ServerKeys{}, err
}
if response.Err != nil {
return gomatrixserverlib.ServerKeys{}, response.Err
}
return response.ServerKeys, nil
} }
type lookupServerKeys struct { type lookupServerKeys struct {

View file

@ -264,25 +264,17 @@ func AddRoutes(intAPI api.FederationSenderInternalAPI, internalAPIMux *mux.Route
}), }),
) )
internalAPIMux.Handle( internalAPIMux.Handle(
FederationSenderGetServerKeysPath, FederationSenderQueryServerKeysPath,
httputil.MakeInternalAPI("GetServerKeys", func(req *http.Request) util.JSONResponse { httputil.MakeInternalAPI("QueryServerKeys", func(req *http.Request) util.JSONResponse {
var request getServerKeys var request api.QueryServerKeysRequest
var response api.QueryServerKeysResponse
if err := json.NewDecoder(req.Body).Decode(&request); err != nil { if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
return util.MessageResponse(http.StatusBadRequest, err.Error()) return util.MessageResponse(http.StatusBadRequest, err.Error())
} }
res, err := intAPI.GetServerKeys(req.Context(), request.S) if err := intAPI.QueryServerKeys(req.Context(), &request, &response); err != nil {
if err != nil { return util.ErrorResponse(err)
ferr, ok := err.(*api.FederationClientError)
if ok {
request.Err = ferr
} else {
request.Err = &api.FederationClientError{
Err: err.Error(),
}
}
} }
request.ServerKeys = res return util.JSONResponse{Code: http.StatusOK, JSON: &response}
return util.JSONResponse{Code: http.StatusOK, JSON: request}
}), }),
) )
internalAPIMux.Handle( internalAPIMux.Handle(

View file

@ -533,3 +533,4 @@ Inbound federation can receive invite and reject when remote is unreachable
Remote servers cannot set power levels in rooms without existing powerlevels Remote servers cannot set power levels in rooms without existing powerlevels
Remote servers should reject attempts by non-creators to set the power levels Remote servers should reject attempts by non-creators to set the power levels
Federation handles empty auth_events in state_ids sanely Federation handles empty auth_events in state_ids sanely
Key notary server should return an expired key if it can't find any others