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 pathmain
parent
6cb9d900b9
commit
28346b39e8
|
@ -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)
|
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue