From 17c60759c4ebee3dcf9481acf1b379274ac8b751 Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Wed, 23 Aug 2017 15:08:48 +0100 Subject: [PATCH 1/2] Add query API for listing active invites (#196) * Add query API for listing active invites This lists the invites for a user in a room that could be used to join the room over federation. * s/Lookup/Look up/ * Fix implements comments --- .../dendrite/clientapi/auth/auth.go | 2 +- .../dendrite/roomserver/alias/alias.go | 8 +- .../dendrite/roomserver/api/query.go | 35 +++++++++ .../dendrite/roomserver/input/authevents.go | 2 +- .../dendrite/roomserver/input/events.go | 6 +- .../dendrite/roomserver/query/query.go | 78 ++++++++++++++----- .../dendrite/roomserver/state/state.go | 14 ++-- .../dendrite/roomserver/storage/storage.go | 20 ++++- 8 files changed, 127 insertions(+), 38 deletions(-) diff --git a/src/github.com/matrix-org/dendrite/clientapi/auth/auth.go b/src/github.com/matrix-org/dendrite/clientapi/auth/auth.go index a661c1f81..24df90199 100644 --- a/src/github.com/matrix-org/dendrite/clientapi/auth/auth.go +++ b/src/github.com/matrix-org/dendrite/clientapi/auth/auth.go @@ -41,7 +41,7 @@ var tokenByteLength = 32 // DeviceDatabase represents a device database. type DeviceDatabase interface { - // Lookup the device matching the given access token. + // Look up the device matching the given access token. GetDeviceByAccessToken(token string) (*authtypes.Device, error) } diff --git a/src/github.com/matrix-org/dendrite/roomserver/alias/alias.go b/src/github.com/matrix-org/dendrite/roomserver/alias/alias.go index faf91bc47..51ac0b429 100644 --- a/src/github.com/matrix-org/dendrite/roomserver/alias/alias.go +++ b/src/github.com/matrix-org/dendrite/roomserver/alias/alias.go @@ -32,10 +32,10 @@ type RoomserverAliasAPIDatabase interface { // Save a given room alias with the room ID it refers to. // Returns an error if there was a problem talking to the database. SetRoomAlias(alias string, roomID string) error - // Lookup the room ID a given alias refers to. + // Look up the room ID a given alias refers to. // Returns an error if there was a problem talking to the database. GetRoomIDFromAlias(alias string) (string, error) - // Lookup all aliases referring to a given room ID. + // Look up all aliases referring to a given room ID. // Returns an error if there was a problem talking to the database. GetAliasesFromRoomID(roomID string) ([]string, error) // Remove a given room alias. @@ -86,7 +86,7 @@ func (r *RoomserverAliasAPI) GetAliasRoomID( request *api.GetAliasRoomIDRequest, response *api.GetAliasRoomIDResponse, ) error { - // Lookup the room ID in the database + // Look up the room ID in the database roomID, err := r.DB.GetRoomIDFromAlias(request.Alias) if err != nil { return err @@ -101,7 +101,7 @@ func (r *RoomserverAliasAPI) RemoveRoomAlias( request *api.RemoveRoomAliasRequest, response *api.RemoveRoomAliasResponse, ) error { - // Lookup the room ID in the database + // Look up the room ID in the database roomID, err := r.DB.GetRoomIDFromAlias(request.Alias) if err != nil { return err diff --git a/src/github.com/matrix-org/dendrite/roomserver/api/query.go b/src/github.com/matrix-org/dendrite/roomserver/api/query.go index f07da59e5..e9573d1b4 100644 --- a/src/github.com/matrix-org/dendrite/roomserver/api/query.go +++ b/src/github.com/matrix-org/dendrite/roomserver/api/query.go @@ -117,6 +117,23 @@ type QueryMembershipsForRoomResponse struct { HasBeenInRoom bool `json:"has_been_in_room"` } +// QueryInvitesForUserRequest is a request to QueryInvitesForUser +type QueryInvitesForUserRequest struct { + // The room ID to look up invites in. + RoomID string `json:"room_id"` + // The User ID to look up invites for. + TargetUserID string `json:"target_user_id"` +} + +// QueryInvitesForUserResponse is a response to QueryInvitesForUser +// This is used when accepting an invite or rejecting a invite to tell which +// remote matrix servers to contact. +type QueryInvitesForUserResponse struct { + // A list of matrix user IDs for each sender of an active invite targeting + // the requested user ID. + InviteSenderUserIDs []string `json:"invite_sender_user_ids"` +} + // RoomserverQueryAPI is used to query information from the room server. type RoomserverQueryAPI interface { // Query the latest events and state for a room from the room server. @@ -142,6 +159,12 @@ type RoomserverQueryAPI interface { request *QueryMembershipsForRoomRequest, response *QueryMembershipsForRoomResponse, ) error + + // Query a list of invite event senders for a user in a room. + QueryInvitesForUser( + request *QueryInvitesForUserRequest, + response *QueryInvitesForUserResponse, + ) error } // RoomserverQueryLatestEventsAndStatePath is the HTTP path for the QueryLatestEventsAndState API. @@ -156,6 +179,9 @@ const RoomserverQueryEventsByIDPath = "/api/roomserver/queryEventsByID" // RoomserverQueryMembershipsForRoomPath is the HTTP path for the QueryMembershipsForRoom API const RoomserverQueryMembershipsForRoomPath = "/api/roomserver/queryMembershipsForRoom" +// RoomserverQueryInvitesForUserPath is the HTTP path for the QueryInvitesForUser API +const RoomserverQueryInvitesForUserPath = "/api/roomserver/queryInvitesForUser" + // NewRoomserverQueryAPIHTTP creates a RoomserverQueryAPI implemented by talking to a HTTP POST API. // If httpClient is nil then it uses the http.DefaultClient func NewRoomserverQueryAPIHTTP(roomserverURL string, httpClient *http.Client) RoomserverQueryAPI { @@ -206,6 +232,15 @@ func (h *httpRoomserverQueryAPI) QueryMembershipsForRoom( return postJSON(h.httpClient, apiURL, request, response) } +// QueryInvitesForUser implements RoomserverQueryAPI +func (h *httpRoomserverQueryAPI) QueryInvitesForUser( + request *QueryInvitesForUserRequest, + response *QueryInvitesForUserResponse, +) error { + apiURL := h.roomserverURL + RoomserverQueryInvitesForUserPath + return postJSON(h.httpClient, apiURL, request, response) +} + func postJSON(httpClient *http.Client, apiURL string, request, response interface{}) error { jsonBytes, err := json.Marshal(request) if err != nil { diff --git a/src/github.com/matrix-org/dendrite/roomserver/input/authevents.go b/src/github.com/matrix-org/dendrite/roomserver/input/authevents.go index ef70a61ee..fbb7d7c0b 100644 --- a/src/github.com/matrix-org/dendrite/roomserver/input/authevents.go +++ b/src/github.com/matrix-org/dendrite/roomserver/input/authevents.go @@ -117,7 +117,7 @@ func loadAuthEvents( needed gomatrixserverlib.StateNeeded, state []types.StateEntry, ) (result authEvents, err error) { - // Lookup the numeric IDs for the state keys needed for auth. + // Look up the numeric IDs for the state keys needed for auth. var neededStateKeys []string neededStateKeys = append(neededStateKeys, needed.Member...) neededStateKeys = append(neededStateKeys, needed.ThirdPartyInvite...) diff --git a/src/github.com/matrix-org/dendrite/roomserver/input/events.go b/src/github.com/matrix-org/dendrite/roomserver/input/events.go index 82b4652e6..88c604478 100644 --- a/src/github.com/matrix-org/dendrite/roomserver/input/events.go +++ b/src/github.com/matrix-org/dendrite/roomserver/input/events.go @@ -29,18 +29,18 @@ type RoomEventDatabase interface { state.RoomStateDatabase // Stores a matrix room event in the database StoreEvent(event gomatrixserverlib.Event, authEventNIDs []types.EventNID) (types.RoomNID, types.StateAtEvent, error) - // Lookup the state entries for a list of string event IDs + // Look up the state entries for a list of string event IDs // Returns an error if the there is an error talking to the database // Returns a types.MissingEventError if the event IDs aren't in the database. StateEntriesForEventIDs(eventIDs []string) ([]types.StateEntry, error) // Set the state at an event. SetState(eventNID types.EventNID, stateNID types.StateSnapshotNID) error - // Lookup the latest events in a room in preparation for an update. + // Look up the latest events in a room in preparation for an update. // The RoomRecentEventsUpdater must have Commit or Rollback called on it if this doesn't return an error. // Returns the latest events in the room and the last eventID sent to the log along with an updater. // If this returns an error then no further action is required. GetLatestEventsForUpdate(roomNID types.RoomNID) (updater types.RoomRecentEventsUpdater, err error) - // Lookup the string event IDs for a list of numeric event IDs + // Look up the string event IDs for a list of numeric event IDs EventIDs(eventNIDs []types.EventNID) (map[types.EventNID]string, error) // Build a membership updater for the target user in a room. MembershipUpdater(roomID, targerUserID string) (types.MembershipUpdater, error) diff --git a/src/github.com/matrix-org/dendrite/roomserver/query/query.go b/src/github.com/matrix-org/dendrite/roomserver/query/query.go index 84f5d44c3..a4eccb59f 100644 --- a/src/github.com/matrix-org/dendrite/roomserver/query/query.go +++ b/src/github.com/matrix-org/dendrite/roomserver/query/query.go @@ -29,36 +29,31 @@ import ( // RoomserverQueryAPIDatabase has the storage APIs needed to implement the query API. type RoomserverQueryAPIDatabase interface { state.RoomStateDatabase - // Lookup the numeric ID for the room. + // Look up the numeric ID for the room. // Returns 0 if the room doesn't exists. // Returns an error if there was a problem talking to the database. RoomNID(roomID string) (types.RoomNID, error) - // Lookup event references for the latest events in the room and the current state snapshot. + // Look up event references for the latest events in the room and the current state snapshot. // Returns the latest events, the current state and the maximum depth of the latest events plus 1. // Returns an error if there was a problem talking to the database. LatestEventIDs(roomNID types.RoomNID) ([]gomatrixserverlib.EventReference, types.StateSnapshotNID, int64, error) - // Lookup the numeric IDs for a list of events. + // Look up the numeric IDs for a list of events. // Returns an error if there was a problem talking to the database. EventNIDs(eventIDs []string) (map[string]types.EventNID, error) - // Save a given room alias with the room ID it refers to. - // Returns an error if there was a problem talking to the database. - SetRoomAlias(alias string, roomID string) error - // Lookup the room ID a given alias refers to. - // Returns an error if there was a problem talking to the database. - GetRoomIDFromAlias(alias string) (string, error) - // Lookup all aliases referring to a given room ID. - // Returns an error if there was a problem talking to the database. - GetAliasesFromRoomID(roomID string) ([]string, error) - // Remove a given room alias. - // Returns an error if there was a problem talking to the database. - RemoveRoomAlias(alias string) error - // Lookup the join events for all members in a room as requested by a given + // Look up the join events for all members in a room as requested by a given // user. If the user is currently in the room, returns the room's current // members, if not returns an empty array (TODO: Fix it) // If the user requesting the list of members has never been in the room, // returns nil. // If there was an issue retrieving the events, returns an error. GetMembershipEvents(roomNID types.RoomNID, requestSenderUserID string) (events []types.Event, err error) + // Look up the active invites targeting a user in a room and return the + // numeric state key IDs for the user IDs who sent them. + // Returns an error if there was a problem talking to the database. + GetInvitesForUser(roomNID types.RoomNID, targetUserNID types.EventStateKeyNID) (senderUserNIDs []types.EventStateKeyNID, err error) + // Look up the string event state keys for a list of numeric event state keys + // Returns an error if there was a problem talking to the database. + EventStateKeys([]types.EventStateKeyNID) (map[types.EventStateKeyNID]string, error) } // RoomserverQueryAPI is an implementation of api.RoomserverQueryAPI @@ -86,7 +81,7 @@ func (r *RoomserverQueryAPI) QueryLatestEventsAndState( return err } - // Lookup the currrent state for the requested tuples. + // Look up the currrent state for the requested tuples. stateEntries, err := state.LoadStateAtSnapshotForStringTuples(r.DB, currentStateSnapshotNID, request.StateToFetch) if err != nil { return err @@ -127,7 +122,7 @@ func (r *RoomserverQueryAPI) QueryStateAfterEvents( } response.PrevEventsExist = true - // Lookup the currrent state for the requested tuples. + // Look up the currrent state for the requested tuples. stateEntries, err := state.LoadStateAfterEventsForStringTuples(r.DB, prevStates, request.StateToFetch) if err != nil { return err @@ -220,6 +215,39 @@ func (r *RoomserverQueryAPI) QueryMembershipsForRoom( return nil } +// QueryInvitesForUser implements api.RoomserverQueryAPI +func (r *RoomserverQueryAPI) QueryInvitesForUser( + request *api.QueryInvitesForUserRequest, + response *api.QueryInvitesForUserResponse, +) error { + roomNID, err := r.DB.RoomNID(request.RoomID) + if err != nil { + return err + } + + targetUserNIDs, err := r.DB.EventStateKeyNIDs([]string{request.TargetUserID}) + if err != nil { + return err + } + targetUserNID := targetUserNIDs[request.TargetUserID] + + senderUserNIDs, err := r.DB.GetInvitesForUser(roomNID, targetUserNID) + if err != nil { + return err + } + + senderUserIDs, err := r.DB.EventStateKeys(senderUserNIDs) + if err != nil { + return err + } + + for _, senderUserID := range senderUserIDs { + response.InviteSenderUserIDs = append(response.InviteSenderUserIDs, senderUserID) + } + + return nil +} + // SetupHTTP adds the RoomserverQueryAPI handlers to the http.ServeMux. func (r *RoomserverQueryAPI) SetupHTTP(servMux *http.ServeMux) { servMux.Handle( @@ -278,4 +306,18 @@ func (r *RoomserverQueryAPI) SetupHTTP(servMux *http.ServeMux) { return util.JSONResponse{Code: 200, JSON: &response} }), ) + servMux.Handle( + api.RoomserverQueryInvitesForUserPath, + common.MakeAPI("queryInvitesForUser", func(req *http.Request) util.JSONResponse { + var request api.QueryInvitesForUserRequest + var response api.QueryInvitesForUserResponse + if err := json.NewDecoder(req.Body).Decode(&request); err != nil { + return util.ErrorResponse(err) + } + if err := r.QueryInvitesForUser(&request, &response); err != nil { + return util.ErrorResponse(err) + } + return util.JSONResponse{Code: 200, JSON: &response} + }), + ) } diff --git a/src/github.com/matrix-org/dendrite/roomserver/state/state.go b/src/github.com/matrix-org/dendrite/roomserver/state/state.go index b5454c0cd..3c2780aeb 100644 --- a/src/github.com/matrix-org/dendrite/roomserver/state/state.go +++ b/src/github.com/matrix-org/dendrite/roomserver/state/state.go @@ -30,30 +30,30 @@ import ( type RoomStateDatabase interface { // Store the room state at an event in the database AddState(roomNID types.RoomNID, stateBlockNIDs []types.StateBlockNID, state []types.StateEntry) (types.StateSnapshotNID, error) - // Lookup the state of a room at each event for a list of string event IDs. + // Look up the state of a room at each event for a list of string event IDs. // Returns an error if there is an error talking to the database // Returns a types.MissingEventError if the room state for the event IDs aren't in the database StateAtEventIDs(eventIDs []string) ([]types.StateAtEvent, error) - // Lookup the numeric IDs for a list of string event types. + // Look up the numeric IDs for a list of string event types. // Returns a map from string event type to numeric ID for the event type. EventTypeNIDs(eventTypes []string) (map[string]types.EventTypeNID, error) - // Lookup the numeric IDs for a list of string event state keys. + // Look up the numeric IDs for a list of string event state keys. // Returns a map from string state key to numeric ID for the state key. EventStateKeyNIDs(eventStateKeys []string) (map[string]types.EventStateKeyNID, error) - // Lookup the numeric state data IDs for each numeric state snapshot ID + // Look up the numeric state data IDs for each numeric state snapshot ID // The returned slice is sorted by numeric state snapshot ID. StateBlockNIDs(stateNIDs []types.StateSnapshotNID) ([]types.StateBlockNIDList, error) - // Lookup the state data for each numeric state data ID + // Look up the state data for each numeric state data ID // The returned slice is sorted by numeric state data ID. StateEntries(stateBlockNIDs []types.StateBlockNID) ([]types.StateEntryList, error) - // Lookup the state data for the state key tuples for each numeric state block ID + // Look up the state data for the state key tuples for each numeric state block ID // This is used to fetch a subset of the room state at a snapshot. // If a block doesn't contain any of the requested tuples then it can be discarded from the result. // The returned slice is sorted by numeric state block ID. StateEntriesForTuples(stateBlockNIDs []types.StateBlockNID, stateKeyTuples []types.StateKeyTuple) ( []types.StateEntryList, error, ) - // Lookup the Events for a list of numeric event IDs. + // Look up the Events for a list of numeric event IDs. // Returns a sorted list of events. Events(eventNIDs []types.EventNID) ([]types.Event, error) } diff --git a/src/github.com/matrix-org/dendrite/roomserver/storage/storage.go b/src/github.com/matrix-org/dendrite/roomserver/storage/storage.go index fbbc723ee..7e90aebbd 100644 --- a/src/github.com/matrix-org/dendrite/roomserver/storage/storage.go +++ b/src/github.com/matrix-org/dendrite/roomserver/storage/storage.go @@ -161,7 +161,12 @@ func (d *Database) EventStateKeyNIDs(eventStateKeys []string) (map[string]types. return d.statements.bulkSelectEventStateKeyNID(eventStateKeys) } -// EventNIDs implements query.RoomQueryDatabase +// EventStateKeys implements query.RoomserverQueryAPIDatabase +func (d *Database) EventStateKeys(eventStateKeyNIDs []types.EventStateKeyNID) (map[types.EventStateKeyNID]string, error) { + return d.statements.bulkSelectEventStateKey(eventStateKeyNIDs) +} + +// EventNIDs implements query.RoomserverQueryAPIDatabase func (d *Database) EventNIDs(eventIDs []string) (map[string]types.EventNID, error) { return d.statements.bulkSelectEventNID(eventIDs) } @@ -336,7 +341,7 @@ func (d *Database) RoomNID(roomID string) (types.RoomNID, error) { return roomNID, err } -// LatestEventIDs implements query.RoomserverQueryAPIDB +// LatestEventIDs implements query.RoomserverQueryAPIDatabase func (d *Database) LatestEventIDs(roomNID types.RoomNID) ([]gomatrixserverlib.EventReference, types.StateSnapshotNID, int64, error) { eventNIDs, currentStateSnapshotNID, err := d.statements.selectLatestEventNIDs(roomNID) if err != nil { @@ -353,6 +358,13 @@ func (d *Database) LatestEventIDs(roomNID types.RoomNID) ([]gomatrixserverlib.Ev return references, currentStateSnapshotNID, depth, nil } +// GetInvitesForUser implements query.RoomserverQueryAPIDatabase +func (d *Database) GetInvitesForUser( + roomNID types.RoomNID, targetUserNID types.EventStateKeyNID, +) (senderUserIDs []types.EventStateKeyNID, err error) { + return d.statements.selectInviteActiveForUserInRoom(targetUserNID, roomNID) +} + // SetRoomAlias implements alias.RoomserverAliasAPIDB func (d *Database) SetRoomAlias(alias string, roomID string) error { return d.statements.insertRoomAlias(alias, roomID) @@ -494,7 +506,7 @@ func (u *membershipUpdater) SetToJoin(senderUserID string, eventID string, isUpd } } - // Lookup the NID of the new join event + // Look up the NID of the new join event nIDs, err := u.d.EventNIDs([]string{eventID}) if err != nil { return nil, err @@ -524,7 +536,7 @@ func (u *membershipUpdater) SetToLeave(senderUserID string, eventID string) ([]s return nil, err } - // Lookup the NID of the new leave event + // Look up the NID of the new leave event nIDs, err := u.d.EventNIDs([]string{eventID}) if err != nil { return nil, err From 9c954501a20895576290e92dce29a6e6a4cdb547 Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Wed, 23 Aug 2017 15:13:47 +0100 Subject: [PATCH 2/2] 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()), } }