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
main
Brendan Abolivier 2017-09-11 19:08:24 +01:00 committed by Mark Haines
parent 6cb9d900b9
commit 28346b39e8
2 changed files with 44 additions and 9 deletions

View File

@ -79,10 +79,9 @@ func Setup(
}, },
)) ))
v1fedmux.Handle("/3pid/onbind", common.MakeFedAPI( v1fedmux.Handle("/3pid/onbind", common.MakeAPI("3pid_onbind",
"3pid_onbind", cfg.Matrix.ServerName, keys, func(req *http.Request) util.JSONResponse {
func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse { return writers.CreateInvitesFrom3PIDInvites(req, query, cfg, producer, federation)
return writers.CreateInvitesFrom3PIDInvites(httpReq, query, cfg, producer)
}, },
)) ))

View File

@ -16,6 +16,7 @@ package writers
import ( import (
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"net/http" "net/http"
"time" "time"
@ -28,6 +29,8 @@ import (
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util" "github.com/matrix-org/util"
"github.com/Sirupsen/logrus"
) )
type invite struct { type invite struct {
@ -48,7 +51,7 @@ type invites struct {
// CreateInvitesFrom3PIDInvites implements POST /_matrix/federation/v1/3pid/onbind // CreateInvitesFrom3PIDInvites implements POST /_matrix/federation/v1/3pid/onbind
func CreateInvitesFrom3PIDInvites( func CreateInvitesFrom3PIDInvites(
req *http.Request, queryAPI api.RoomserverQueryAPI, cfg config.Dendrite, req *http.Request, queryAPI api.RoomserverQueryAPI, cfg config.Dendrite,
producer *producers.RoomserverProducer, producer *producers.RoomserverProducer, federation *gomatrixserverlib.FederationClient,
) util.JSONResponse { ) util.JSONResponse {
var body invites var body invites
if reqErr := httputil.UnmarshalJSONRequest(req, &body); reqErr != nil { if reqErr := httputil.UnmarshalJSONRequest(req, &body); reqErr != nil {
@ -57,7 +60,7 @@ func CreateInvitesFrom3PIDInvites(
evs := []gomatrixserverlib.Event{} evs := []gomatrixserverlib.Event{}
for _, inv := range body.Invites { for _, inv := range body.Invites {
event, err := createInviteFrom3PIDInvite(queryAPI, cfg, inv) event, err := createInviteFrom3PIDInvite(queryAPI, cfg, inv, federation)
if err != nil { if err != nil {
return httputil.LogThenError(req, err) return httputil.LogThenError(req, err)
} }
@ -83,6 +86,7 @@ func CreateInvitesFrom3PIDInvites(
// necessary data to do so. // necessary data to do so.
func createInviteFrom3PIDInvite( func createInviteFrom3PIDInvite(
queryAPI api.RoomserverQueryAPI, cfg config.Dendrite, inv invite, queryAPI api.RoomserverQueryAPI, cfg config.Dendrite, inv invite,
federation *gomatrixserverlib.FederationClient,
) (*gomatrixserverlib.Event, error) { ) (*gomatrixserverlib.Event, error) {
// Build the event // Build the event
builder := &gomatrixserverlib.EventBuilder{ builder := &gomatrixserverlib.EventBuilder{
@ -120,11 +124,11 @@ func createInviteFrom3PIDInvite(
} }
if !queryRes.RoomExists { if !queryRes.RoomExists {
// TODO: Use federation to auth the event // Use federation to auth the event
return nil, nil return nil, sendToRemoteServer(inv, federation, cfg, *builder)
} }
// Finish building the event // Auth the event locally
builder.Depth = queryRes.Depth builder.Depth = queryRes.Depth
builder.PrevEvents = queryRes.LatestEvents builder.PrevEvents = queryRes.LatestEvents
@ -154,6 +158,38 @@ func createInviteFrom3PIDInvite(
return &event, nil 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 // 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. // 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 // If such an event is found, fills the "display_name" attribute of the