From 9c954501a20895576290e92dce29a6e6a4cdb547 Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Wed, 23 Aug 2017 15:13:47 +0100 Subject: [PATCH] Implement /federation/v1/invite/{roomID}/{eventID} (#197) * Implement /federation/v1/invite/{roomID}/{eventID} * Use NotJSON instead of BadJSON when the JSON couldn't be decoded --- .../clientapi/producers/roomserver.go | 12 ++- .../dendrite/federationapi/routing/routing.go | 13 ++- .../dendrite/federationapi/writers/invite.go | 98 +++++++++++++++++++ .../dendrite/federationapi/writers/send.go | 7 +- 4 files changed, 124 insertions(+), 6 deletions(-) create mode 100644 src/github.com/matrix-org/dendrite/federationapi/writers/invite.go diff --git a/src/github.com/matrix-org/dendrite/clientapi/producers/roomserver.go b/src/github.com/matrix-org/dendrite/clientapi/producers/roomserver.go index d2404a7a4..cd146b856 100644 --- a/src/github.com/matrix-org/dendrite/clientapi/producers/roomserver.go +++ b/src/github.com/matrix-org/dendrite/clientapi/producers/roomserver.go @@ -78,10 +78,18 @@ func (c *RoomserverProducer) SendEventWithState(state gomatrixserverlib.RespStat return c.SendInputRoomEvents(ires) } -// SendInputRoomEvents writes the given input room events to the roomserver input log. The length of both -// arrays must match, and each element must correspond to the same event. +// SendInputRoomEvents writes the given input room events to the roomserver input API. func (c *RoomserverProducer) SendInputRoomEvents(ires []api.InputRoomEvent) error { request := api.InputRoomEventsRequest{InputRoomEvents: ires} var response api.InputRoomEventsResponse return c.InputAPI.InputRoomEvents(&request, &response) } + +// SendInvite writes the invite event to the roomserver input API. +func (c *RoomserverProducer) SendInvite(inviteEvent gomatrixserverlib.Event) error { + request := api.InputRoomEventsRequest{ + InputInviteEvents: []api.InputInviteEvent{{Event: inviteEvent}}, + } + var response api.InputRoomEventsResponse + return c.InputAPI.InputRoomEvents(&request, &response) +} 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 93edac7a2..7ed17210d 100644 --- a/src/github.com/matrix-org/dendrite/federationapi/routing/routing.go +++ b/src/github.com/matrix-org/dendrite/federationapi/routing/routing.go @@ -57,7 +57,7 @@ func Setup( v2keysmux.Handle("/server/{keyID}", localKeys) v2keysmux.Handle("/server/", localKeys) - v1fedmux.Handle("/send/{txnID}/", makeAPI("send", + v1fedmux.Handle("/send/{txnID}/", makeAPI("federation_send", func(req *http.Request) util.JSONResponse { vars := mux.Vars(req) return writers.Send( @@ -67,6 +67,17 @@ func Setup( ) }, )) + + v1fedmux.Handle("/invite/{roomID}/{eventID}", makeAPI("federation_invite", + func(req *http.Request) util.JSONResponse { + vars := mux.Vars(req) + return writers.Invite( + req, vars["roomID"], vars["eventID"], + time.Now(), + cfg, producer, keys, + ) + }, + )) } func makeAPI(metricsName string, f func(*http.Request) util.JSONResponse) http.Handler { diff --git a/src/github.com/matrix-org/dendrite/federationapi/writers/invite.go b/src/github.com/matrix-org/dendrite/federationapi/writers/invite.go new file mode 100644 index 000000000..dc89f4a75 --- /dev/null +++ b/src/github.com/matrix-org/dendrite/federationapi/writers/invite.go @@ -0,0 +1,98 @@ +package writers + +import ( + "encoding/json" + "net/http" + "time" + + "github.com/matrix-org/util" + + "github.com/matrix-org/dendrite/clientapi/httputil" + "github.com/matrix-org/dendrite/clientapi/jsonerror" + "github.com/matrix-org/dendrite/clientapi/producers" + "github.com/matrix-org/dendrite/common/config" + "github.com/matrix-org/gomatrixserverlib" +) + +// Invite implements /_matrix/federation/v1/invite/{roomID}/{eventID} +func Invite( + req *http.Request, + roomID string, + eventID string, + now time.Time, + cfg config.Dendrite, + producer *producers.RoomserverProducer, + keys gomatrixserverlib.KeyRing, +) util.JSONResponse { + request, errResp := gomatrixserverlib.VerifyHTTPRequest(req, now, cfg.Matrix.ServerName, keys) + if request == nil { + return errResp + } + + // Decode the event JSON from the request. + var event gomatrixserverlib.Event + if err := json.Unmarshal(request.Content(), &event); err != nil { + return util.JSONResponse{ + Code: 400, + JSON: jsonerror.NotJSON("The request body could not be decoded into valid JSON. " + err.Error()), + } + } + + // Check that the room ID is correct. + if event.RoomID() != roomID { + return util.JSONResponse{ + Code: 400, + JSON: jsonerror.BadJSON("The room ID in the request path must match the room ID in the invite event JSON"), + } + } + + // Check that the event ID is correct. + if event.EventID() != eventID { + return util.JSONResponse{ + Code: 400, + JSON: jsonerror.BadJSON("The event ID in the request path must match the event ID in the invite event JSON"), + } + } + + // Check that the event is from the server sending the request. + if event.Origin() != request.Origin() { + return util.JSONResponse{ + Code: 403, + JSON: jsonerror.Forbidden("The invite must be sent by the server it originated on"), + } + } + + // Check that the event is signed by the server sending the request. + verifyRequests := []gomatrixserverlib.VerifyJSONRequest{{ + ServerName: event.Origin(), + Message: event.JSON(), + AtTS: event.OriginServerTS(), + }} + verifyResults, err := keys.VerifyJSONs(verifyRequests) + if err != nil { + return httputil.LogThenError(req, err) + } + if verifyResults[0].Error != nil { + return util.JSONResponse{ + Code: 403, + JSON: jsonerror.Forbidden("The invite must be signed by the server it originated on"), + } + } + + // Sign the event so that other servers will know that we have received the invite. + signedEvent := event.Sign( + string(cfg.Matrix.ServerName), cfg.Matrix.KeyID, cfg.Matrix.PrivateKey, + ) + + // Add the invite event to the roomserver. + if err = producer.SendInvite(signedEvent); err != nil { + return httputil.LogThenError(req, err) + } + + // Return the signed event to the originating server, it should then tell + // the other servers in the room that we have been invited. + return util.JSONResponse{ + Code: 200, + JSON: &signedEvent, + } +} diff --git a/src/github.com/matrix-org/dendrite/federationapi/writers/send.go b/src/github.com/matrix-org/dendrite/federationapi/writers/send.go index 67ee6b027..ddae07555 100644 --- a/src/github.com/matrix-org/dendrite/federationapi/writers/send.go +++ b/src/github.com/matrix-org/dendrite/federationapi/writers/send.go @@ -3,6 +3,9 @@ package writers import ( "encoding/json" "fmt" + "net/http" + "time" + "github.com/matrix-org/dendrite/clientapi/httputil" "github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/clientapi/producers" @@ -10,8 +13,6 @@ import ( "github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/util" - "net/http" - "time" ) // Send implements /_matrix/federation/v1/send/{txnID} @@ -39,7 +40,7 @@ func Send( if err := json.Unmarshal(request.Content(), &t); err != nil { return util.JSONResponse{ Code: 400, - JSON: jsonerror.BadJSON("The request body could not be decoded into valid JSON. " + err.Error()), + JSON: jsonerror.NotJSON("The request body could not be decoded into valid JSON. " + err.Error()), } }