From 28346b39e8e6d666442b00fed79a07e695046855 Mon Sep 17 00:00:00 2001 From: Brendan Abolivier Date: Mon, 11 Sep 2017 19:08:24 +0100 Subject: [PATCH] 3PID invite exchange over federation (#222) * Use federation to auth the event if the server isn't in the room * Use MakeAPI for 3pid onbind handler as it isn't a standard federation request * Error check * Temporarily disable tests * Fix return on 3PID invite * Re-enable tests * Remove useless else * gb vendor update github.com/matrix-org/gomatrixserverlib * gb vendor update github.com/matrix-org/gomatrixserverlib * Implement same behaviour as synapse * Fix condition and array initialisation * Log errors on iteration and throw one if no server could be reached * Fix err not being initialised * Fix lint * Fix import path --- .../dendrite/federationapi/routing/routing.go | 7 ++- .../federationapi/writers/threepid.go | 46 +++++++++++++++++-- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/github.com/matrix-org/dendrite/federationapi/routing/routing.go b/src/github.com/matrix-org/dendrite/federationapi/routing/routing.go index 8d49800d5..c67f81124 100644 --- a/src/github.com/matrix-org/dendrite/federationapi/routing/routing.go +++ b/src/github.com/matrix-org/dendrite/federationapi/routing/routing.go @@ -79,10 +79,9 @@ func Setup( }, )) - v1fedmux.Handle("/3pid/onbind", common.MakeFedAPI( - "3pid_onbind", cfg.Matrix.ServerName, keys, - func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse { - return writers.CreateInvitesFrom3PIDInvites(httpReq, query, cfg, producer) + v1fedmux.Handle("/3pid/onbind", common.MakeAPI("3pid_onbind", + func(req *http.Request) util.JSONResponse { + return writers.CreateInvitesFrom3PIDInvites(req, query, cfg, producer, federation) }, )) diff --git a/src/github.com/matrix-org/dendrite/federationapi/writers/threepid.go b/src/github.com/matrix-org/dendrite/federationapi/writers/threepid.go index ad9b48569..9fab040ae 100644 --- a/src/github.com/matrix-org/dendrite/federationapi/writers/threepid.go +++ b/src/github.com/matrix-org/dendrite/federationapi/writers/threepid.go @@ -16,6 +16,7 @@ package writers import ( "encoding/json" + "errors" "fmt" "net/http" "time" @@ -28,6 +29,8 @@ import ( "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/util" + + "github.com/Sirupsen/logrus" ) type invite struct { @@ -48,7 +51,7 @@ type invites struct { // CreateInvitesFrom3PIDInvites implements POST /_matrix/federation/v1/3pid/onbind func CreateInvitesFrom3PIDInvites( req *http.Request, queryAPI api.RoomserverQueryAPI, cfg config.Dendrite, - producer *producers.RoomserverProducer, + producer *producers.RoomserverProducer, federation *gomatrixserverlib.FederationClient, ) util.JSONResponse { var body invites if reqErr := httputil.UnmarshalJSONRequest(req, &body); reqErr != nil { @@ -57,7 +60,7 @@ func CreateInvitesFrom3PIDInvites( evs := []gomatrixserverlib.Event{} for _, inv := range body.Invites { - event, err := createInviteFrom3PIDInvite(queryAPI, cfg, inv) + event, err := createInviteFrom3PIDInvite(queryAPI, cfg, inv, federation) if err != nil { return httputil.LogThenError(req, err) } @@ -83,6 +86,7 @@ func CreateInvitesFrom3PIDInvites( // necessary data to do so. func createInviteFrom3PIDInvite( queryAPI api.RoomserverQueryAPI, cfg config.Dendrite, inv invite, + federation *gomatrixserverlib.FederationClient, ) (*gomatrixserverlib.Event, error) { // Build the event builder := &gomatrixserverlib.EventBuilder{ @@ -120,11 +124,11 @@ func createInviteFrom3PIDInvite( } if !queryRes.RoomExists { - // TODO: Use federation to auth the event - return nil, nil + // Use federation to auth the event + return nil, sendToRemoteServer(inv, federation, cfg, *builder) } - // Finish building the event + // Auth the event locally builder.Depth = queryRes.Depth builder.PrevEvents = queryRes.LatestEvents @@ -154,6 +158,38 @@ func createInviteFrom3PIDInvite( return &event, nil } +// sendToRemoteServer uses federation to send an invite provided by an identity +// server to a remote server in case the current server isn't in the room the +// invite is for. +// Returns an error if it couldn't get the server names to reach or if all of +// them responded with an error. +func sendToRemoteServer( + inv invite, federation *gomatrixserverlib.FederationClient, cfg config.Dendrite, + builder gomatrixserverlib.EventBuilder, +) (err error) { + remoteServers := make([]gomatrixserverlib.ServerName, 2) + _, remoteServers[0], err = gomatrixserverlib.SplitID('@', inv.Sender) + if err != nil { + return + } + // Fallback to the room's server if the sender's domain is the same as + // the current server's + _, remoteServers[1], err = gomatrixserverlib.SplitID('!', inv.RoomID) + if err != nil { + return + } + + for _, server := range remoteServers { + err = federation.ExchangeThirdPartyInvite(server, builder) + if err == nil { + return + } + logrus.WithError(err).Warn("failed to send 3PID invite via %s", server) + } + + return errors.New("failed to send 3PID invite via any server") +} + // fillDisplayName looks in a list of auth events for a m.room.third_party_invite // event with the state key matching a given m.room.member event's content's token. // If such an event is found, fills the "display_name" attribute of the