Check send join response

This commit is contained in:
Neil Alexander 2020-04-29 13:22:54 +01:00
parent 55e688b158
commit 4c66e0b445
8 changed files with 91 additions and 5 deletions

View file

@ -153,7 +153,7 @@ func main() {
asQuery := appservice.SetupAppServiceAPIComponent(
&base.Base, accountDB, deviceDB, federation, alias, query, transactions.New(),
)
fsAPI := federationsender.SetupFederationSenderComponent(&base.Base, federation, query, input)
fsAPI := federationsender.SetupFederationSenderComponent(&base.Base, federation, query, input, &keyRing)
clientapi.SetupClientAPIComponent(
&base.Base, deviceDB, accountDB,

View file

@ -16,6 +16,7 @@ package main
import (
"github.com/matrix-org/dendrite/common/basecomponent"
"github.com/matrix-org/dendrite/common/keydb"
"github.com/matrix-org/dendrite/federationsender"
)
@ -25,11 +26,13 @@ func main() {
defer base.Close() // nolint: errcheck
federation := base.CreateFederationClient()
keyDB := base.CreateKeyDB()
keyRing := keydb.CreateKeyRing(federation.Client, keyDB, cfg.Matrix.KeyPerspectives)
_, input, query := base.CreateHTTPRoomserverAPIs()
federationsender.SetupFederationSenderComponent(
base, federation, query, input,
base, federation, query, input, &keyRing,
)
base.SetupAndServeHTTP(string(base.Cfg.Bind.FederationSender), string(base.Cfg.Listen.FederationSender))

View file

@ -62,7 +62,7 @@ func main() {
asQuery := appservice.SetupAppServiceAPIComponent(
base, accountDB, deviceDB, federation, alias, query, transactions.New(),
)
fsAPI := federationsender.SetupFederationSenderComponent(base, federation, query, input)
fsAPI := federationsender.SetupFederationSenderComponent(base, federation, query, input, &keyRing)
input.SetFederationSenderAPI(fsAPI)
clientapi.SetupClientAPIComponent(

View file

@ -128,7 +128,7 @@ func main() {
asQuery := appservice.SetupAppServiceAPIComponent(
base, accountDB, deviceDB, federation, alias, query, transactions.New(),
)
fedSenderAPI := federationsender.SetupFederationSenderComponent(base, federation, query, input)
fedSenderAPI := federationsender.SetupFederationSenderComponent(base, federation, query, input, &keyRing)
input.SetFederationSenderAPI(fedSenderAPI)
clientapi.SetupClientAPIComponent(

View file

@ -36,6 +36,7 @@ func SetupFederationSenderComponent(
federation *gomatrixserverlib.FederationClient,
rsQueryAPI roomserverAPI.RoomserverQueryAPI,
rsInputAPI roomserverAPI.RoomserverInputAPI,
keyRing *gomatrixserverlib.KeyRing,
) api.FederationSenderInternalAPI {
federationSenderDB, err := storage.NewDatabase(string(base.Cfg.Database.FederationSender))
if err != nil {
@ -62,7 +63,7 @@ func SetupFederationSenderComponent(
}
queryAPI := query.NewFederationSenderInternalAPI(
federationSenderDB, base.Cfg, roomserverProducer, federation,
federationSenderDB, base.Cfg, roomserverProducer, federation, keyRing,
)
queryAPI.SetupHTTP(http.DefaultServeMux)

View file

@ -20,17 +20,20 @@ type FederationSenderInternalAPI struct {
cfg *config.Dendrite
producer *producers.RoomserverProducer
federation *gomatrixserverlib.FederationClient
keyRing *gomatrixserverlib.KeyRing
}
func NewFederationSenderInternalAPI(
db storage.Database, cfg *config.Dendrite,
producer *producers.RoomserverProducer,
federation *gomatrixserverlib.FederationClient,
keyRing *gomatrixserverlib.KeyRing,
) *FederationSenderInternalAPI {
return &FederationSenderInternalAPI{
db: db,
producer: producer,
federation: federation,
keyRing: keyRing,
}
}

View file

@ -6,6 +6,7 @@ import (
"time"
"github.com/matrix-org/dendrite/federationsender/api"
"github.com/matrix-org/dendrite/federationsender/query/perform"
"github.com/matrix-org/dendrite/roomserver/version"
"github.com/matrix-org/gomatrixserverlib"
)
@ -82,6 +83,14 @@ func (r *FederationSenderInternalAPI) PerformJoin(
return fmt.Errorf("r.federation.SendJoin: %w", err)
}
// Check that the send_join response was valid.
joinCtx := perform.JoinContext(r.federation, r.keyRing)
if err = joinCtx.CheckSendJoinResponse(
ctx, event, request.ServerName, respMakeJoin, respSendJoin,
); err != nil {
return fmt.Errorf("perform.JoinRequest.CheckSendJoinResponse: %w", err)
}
// If we successfully performed a send_join above then the other
// server now thinks we're a part of the room. Send the newly
// returned state to the roomserver to update our local view.

View file

@ -0,0 +1,70 @@
package perform
import (
"context"
"fmt"
"github.com/matrix-org/gomatrixserverlib"
)
// This file contains helpers for the PerformJoin function.
type joinContext struct {
federation *gomatrixserverlib.FederationClient
keyRing *gomatrixserverlib.KeyRing
}
// Returns a new join context.
func JoinContext(f *gomatrixserverlib.FederationClient, k *gomatrixserverlib.KeyRing) *joinContext {
return &joinContext{
federation: f,
keyRing: k,
}
}
// checkSendJoinResponse checks that all of the signatures are correct
// and that the join is allowed by the supplied state.
func (r joinContext) CheckSendJoinResponse(
ctx context.Context,
event gomatrixserverlib.Event,
server gomatrixserverlib.ServerName,
respMakeJoin gomatrixserverlib.RespMakeJoin,
respSendJoin gomatrixserverlib.RespSendJoin,
) error {
// A list of events that we have retried, if they were not included in
// the auth events supplied in the send_join.
retries := map[string]bool{}
retryCheck:
// TODO: Can we expand Check here to return a list of missing auth
// events rather than failing one at a time?
if err := respSendJoin.Check(ctx, r.keyRing, event); err != nil {
switch e := err.(type) {
case gomatrixserverlib.MissingAuthEventError:
// Check that we haven't already retried for this event, prevents
// us from ending up in endless loops
if !retries[e.AuthEventID] {
// Ask the server that we're talking to right now for the event
tx, txerr := r.federation.GetEvent(ctx, server, e.AuthEventID)
if txerr != nil {
return fmt.Errorf("r.federation.GetEvent: %w", txerr)
}
// For each event returned, add it to the auth events.
for _, pdu := range tx.PDUs {
ev, everr := gomatrixserverlib.NewEventFromUntrustedJSON(pdu, respMakeJoin.RoomVersion)
if everr != nil {
return fmt.Errorf("gomatrixserverlib.NewEventFromUntrustedJSON: %w", everr)
}
respSendJoin.AuthEvents = append(respSendJoin.AuthEvents, ev)
}
// Mark the event as retried and then give the check another go.
retries[e.AuthEventID] = true
goto retryCheck
}
return fmt.Errorf("respSendJoin (after retries): %w", e)
default:
return fmt.Errorf("respSendJoin: %w", err)
}
}
return nil
}